forked from bchanot/claude
Merge bugfix/effort-pins-low into develop
This commit is contained in:
@@ -550,3 +550,5 @@ rules:
|
|||||||
- Effort round on feature/effort-round ([[BDR-108]]): user table re-applied to all 88 linked skills; 30 existing levels hold, 3 repo skills pinned, 25 vendored externals pinned from `lib/effort-pins.txt` via `lib/effort-pins.sh` after the LAST vendoring step of install + resync (resync had dropped the BDR-107 pins, [[BLK-024]]); design stack ONE level high ([[LRN-181]]); model pins stay aliases, trade-off = tier × effort ([[LRN-182]]). Verifier ECARTS(3) caught my re-apply placed before the late 21st refresh (rtk-truncated grep read as complete) → fresh executor, CONFORME 7/7 then 9/9 after the 4-LOW hardening; security PASS ×2; `make test` 44 suites rc 0. Sub-agent thinking found unmeasured, not ≈0 ([[EVAL-038]]). 5 residual LOW parked in TODO. UNMERGED — human gate.
|
- Effort round on feature/effort-round ([[BDR-108]]): user table re-applied to all 88 linked skills; 30 existing levels hold, 3 repo skills pinned, 25 vendored externals pinned from `lib/effort-pins.txt` via `lib/effort-pins.sh` after the LAST vendoring step of install + resync (resync had dropped the BDR-107 pins, [[BLK-024]]); design stack ONE level high ([[LRN-181]]); model pins stay aliases, trade-off = tier × effort ([[LRN-182]]). Verifier ECARTS(3) caught my re-apply placed before the late 21st refresh (rtk-truncated grep read as complete) → fresh executor, CONFORME 7/7 then 9/9 after the 4-LOW hardening; security PASS ×2; `make test` 44 suites rc 0. Sub-agent thinking found unmeasured, not ≈0 ([[EVAL-038]]). 5 residual LOW parked in TODO. UNMERGED — human gate.
|
||||||
|
|
||||||
- User go "merge le": feature/effort-round merged into develop via `gitflow finish` → 902bc76, no conflict, pushed (develop == origin/develop), local + origin copies removed by the lib. BDR-108 on develop; pins live on disk here, no `make plugin` needed; 5 residual LOW parked in TODO.
|
- User go "merge le": feature/effort-round merged into develop via `gitflow finish` → 902bc76, no conflict, pushed (develop == origin/develop), local + origin copies removed by the lib. BDR-108 on develop; pins live on disk here, no `make plugin` needed; 5 residual LOW parked in TODO.
|
||||||
|
- User go "fais les cinq low restants": bugfix/effort-pins-low, contract `2026-09-29-effort-pins-low-1644`, fresh bugfixer (T13b stub reaches the re-read branch, T15 self-kill INT fixture, T15b trap restore, T16 `%q`, T14 root SKIP, mktemp guard). GATE 0 MET, verifier CONFORME 5/5 with 3 mutation runs, security PASS (3 new LOW parked, none exploitable: control bytes via `%q`+`echo -e`, trap-install window, TERM rc). Suite 30/0. UNMERGED — human gate.
|
||||||
|
|
||||||
|
|||||||
@@ -19,8 +19,9 @@ quality/price trade-off is tier × effort, never version.
|
|||||||
- [x] S7 contract + GATE 0 + fresh verifier + security gate, make test, shellcheck — GATE 0 MET, verifier ECARTS(3) → executor moved the resync re-apply after the 21st refresh (real gap), scope gated, directive authorized → CONFORME 7/7; security PASS (4 LOW on the helper, see journal); make test 44 suites rc 0
|
- [x] S7 contract + GATE 0 + fresh verifier + security gate, make test, shellcheck — GATE 0 MET, verifier ECARTS(3) → executor moved the resync re-apply after the 21st refresh (real gap), scope gated, directive authorized → CONFORME 7/7; security PASS (4 LOW on the helper, see journal); make test 44 suites rc 0
|
||||||
- [x] S8 registries BDR-108, LRN-181, LRN-182, BLK-024, EVAL-038 (user go) + journal
|
- [x] S8 registries BDR-108, LRN-181, LRN-182, BLK-024, EVAL-038 (user go) + journal
|
||||||
- [x] S9 hardening of lib/effort-pins.sh (4 LOW, user go): fresh executor, T11-T14, verifier CONFORME 9/9, security PASS
|
- [x] S9 hardening of lib/effort-pins.sh (4 LOW, user go): fresh executor, T11-T14, verifier CONFORME 9/9, security PASS
|
||||||
- [ ] parked LOW (security re-gate 2026-09-29, none exploitable): no RETURN trap on the mktemp sibling (SIGINT during awk leaves `SKILL.md.XXXXXX`); T13 never reaches the post-write re-read branch (CRLF opener fails `_effort_pin_closed` first, fixture with LF delimiters + CRLF `name:` line would); T14 fails under root (chmod ignored); `WORK="$(mktemp -d)"` unguarded in the suite (`|| exit 1`); install-plugins.sh `err()` uses `echo -e` on the rejected map line
|
- [x] parked LOW (security re-gate 2026-09-29, none exploitable; done on bugfix/effort-pins-low, user go "fais les cinq low restants"): no RETURN trap on the mktemp sibling (SIGINT during awk leaves `SKILL.md.XXXXXX`); T13 never reaches the post-write re-read branch (CRLF opener fails `_effort_pin_closed` first, fixture with LF delimiters + CRLF `name:` line would); T14 fails under root (chmod ignored); `WORK="$(mktemp -d)"` unguarded in the suite (`|| exit 1`); install-plugins.sh `err()` uses `echo -e` on the rejected map line
|
||||||
- UNMERGED — human gate ("merge it")
|
- [ ] parked LOW round 2 (security gate on bugfix/effort-pins-low, none exploitable, diminishing returns): `%q` re-encodes real control bytes (ESC, CR) that the installer's `echo -e` err() would render (needs a malicious commit to the tracked map; strip `[[:cntrl:]]` before printing); INT/TERM trap installed after mktemp (microsecond window, install before with `tmp=""`); TERM exits 130 not 143; T15 fails closed when SIGINT is ignored at shell entry (nohup/async)
|
||||||
|
- bugfix/effort-pins-low UNMERGED — human gate ("merge it")
|
||||||
|
|
||||||
## 2026-09-28 — effort tiering: session high, agent pins, skill levels, phase shifts (feature/effort-tiering)
|
## 2026-09-28 — effort tiering: session high, agent pins, skill levels, phase shifts (feature/effort-tiering)
|
||||||
Spec `docs/superpowers/specs/2026-09-28-effort-tiering-design.md`, plan
|
Spec `docs/superpowers/specs/2026-09-28-effort-tiering-design.md`, plan
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
# CONTRACT — effort-pins-low
|
||||||
|
- date: 2026-09-29 | flow: bugfix by hand (bugfix/* off develop) | branch: bugfix/effort-pins-low
|
||||||
|
- status: active
|
||||||
|
|
||||||
|
## REQUEST (verbatim — IMMUTABLE)
|
||||||
|
> fais les cinq low restants
|
||||||
|
> [the five LOW parked in TODO after the 2026-09-29 security re-gate of BDR-108: no signal trap on the mktemp sibling; T13 never reaches the post-write re-read branch; T14 fails under root; `WORK="$(mktemp -d)"` unguarded in the suite; install-plugins.sh `err()` uses `echo -e` on the rejected map line]
|
||||||
|
|
||||||
|
## CLARIFICATIONS
|
||||||
|
- Pass A silent autofill (bugfix). Pass B: nothing visible or public opens; messages may change wording.
|
||||||
|
- LOW 1 (signal): `_effort_pin_write` installs an INT/TERM trap that removes `$tmp` and exits 130 for the duration of the cp/awk/mv chain, then restores the previous INT/TERM traps on every return path. NEVER an EXIT trap: install-plugins.sh runs a guarded-config EXIT trap the helper must not replace.
|
||||||
|
- LOW 2 (T13): the post-write re-read branch is unreachable through the file system once `_effort_pin_closed` has passed (the awk always inserts at the closing `---`); it stays as a post-condition of the awk, its message drops the misleading "(CRLF …)" hint, and a unit test reaches it by stubbing `_effort_pin_write` to a no-op inside a subshell that sourced the lib. T13 keeps proving a CRLF file is rejected (renamed to what it proves).
|
||||||
|
- LOW 3 (root): T14 prints a visible SKIP and counts nothing when `id -u` is 0 (chmod bits are ignored as root).
|
||||||
|
- LOW 4: `WORK="$(mktemp -d)" || exit 1` in the suite.
|
||||||
|
- LOW 5: the helper prints the rejected map line through `printf '%q'` so a caller's `echo -e` err() cannot interpret backslash escapes from map content; install-plugins.sh `err()` itself is untouched (other messages rely on `-e`).
|
||||||
|
|
||||||
|
## ACCEPTANCE CRITERIA
|
||||||
|
1. Signal safety: a SIGINT delivered during the awk write leaves no `SKILL.md.*` sibling and the process exits 130; on a normal return the previous INT/TERM trap state is restored and no EXIT trap was set. Case `T15-sigint-removes-temp` + `T15b-traps-restored`.
|
||||||
|
CHECK: out=$(make test suite=lib/tests/effort-pins.test.sh 2>&1); echo "$out" | grep -q 'effort-pins: [0-9]* pass, 0 fail' || { echo "$out" | grep FAIL; exit 1; }; for k in T15-sigint-removes-temp T15b-traps-restored; do echo "$out" | grep -q "PASS $k" || { echo "missing PASS $k"; exit 1; }; done; ! grep -qE 'trap [^#]*EXIT' lib/effort-pins.sh && echo SIGNAL_OK
|
||||||
|
EXPECT: SIGNAL_OK
|
||||||
|
EVIDENCE: MET exit=0 marker-found :: SIGNAL_OK
|
||||||
|
2. Re-read branch reached: a test stubs `_effort_pin_write` to a no-op and asserts `_effort_pin_apply_one` returns 1 with an err line naming the file; the message no longer mentions CRLF; T13 is renamed `T13-crlf-file-rejected`.
|
||||||
|
CHECK: out=$(make test suite=lib/tests/effort-pins.test.sh 2>&1); for k in T13-crlf-file-rejected T13b-reread-mismatch-fails; do echo "$out" | grep -q "PASS $k" || { echo "missing PASS $k"; exit 1; }; done; ! grep -q 'CRLF or malformed' lib/effort-pins.sh && echo REREAD_OK
|
||||||
|
EXPECT: REREAD_OK
|
||||||
|
EVIDENCE: MET exit=0 marker-found :: REREAD_OK
|
||||||
|
3. Suite hardening: `WORK` guarded, T14 skips visibly under root (the skip path is exercised by faking `id -u` through a function override in a subshell run of the T14 block, or by an explicit `EFFORT_PINS_TEST_FAKE_ROOT=1` hook read by the suite).
|
||||||
|
CHECK: grep -q 'WORK="$(mktemp -d)" || exit 1' lib/tests/effort-pins.test.sh && out=$(EFFORT_PINS_TEST_FAKE_ROOT=1 make test suite=lib/tests/effort-pins.test.sh 2>&1) && echo "$out" | grep -q 'SKIP T14' && echo "$out" | grep -q 'effort-pins: [0-9]* pass, 0 fail' && echo SUITE_OK
|
||||||
|
EXPECT: SUITE_OK
|
||||||
|
EVIDENCE: MET exit=0 marker-found :: SUITE_OK
|
||||||
|
4. Escape-safe rejection message: a map line `bad\tname high` (literal backslash-t) is rejected and the err text carries the shell-quoted form (`bad\\tname`), so an `echo -e` caller prints it verbatim. Case `T16-rejected-line-quoted`.
|
||||||
|
CHECK: out=$(make test suite=lib/tests/effort-pins.test.sh 2>&1); echo "$out" | grep -q 'PASS T16-rejected-line-quoted' && grep -q "printf '%q'" lib/effort-pins.sh && echo QUOTE_OK
|
||||||
|
EXPECT: QUOTE_OK
|
||||||
|
EVIDENCE: MET exit=0 marker-found :: QUOTE_OK
|
||||||
|
5. Everything else green: shellcheck on the helper and suite, effort-routing census, live tree idempotent (0 applied, 0 failed), doctrine-citers.
|
||||||
|
CHECK: shellcheck lib/effort-pins.sh lib/tests/effort-pins.test.sh && make test suite=lib/tests/effort-routing.test.sh 2>&1 | grep -q 'census: [0-9]* pass, 0 fail' && bash lib/effort-pins.sh 2>&1 | grep -q ' 0 applied, [0-9]* already at level, 0 failed' && make test suite=lib/tests/no-vacuous-locks.test.sh >/dev/null 2>&1 && echo STABLE_OK
|
||||||
|
EXPECT: STABLE_OK
|
||||||
|
EVIDENCE: MET exit=0 marker-found :: STABLE_OK
|
||||||
|
|
||||||
|
## FILE SCOPE
|
||||||
|
- lib/effort-pins.sh, lib/tests/effort-pins.test.sh
|
||||||
|
- .claude/tasks/TODO.md (parked LOW line ticked), CHANGELOG.md (Fixed line), this contract
|
||||||
@@ -463,6 +463,7 @@ Format follows [Keep a Changelog](https://keepachangelog.com/).
|
|||||||
plugin cache or `claude plugin list`.
|
plugin cache or `claude plugin list`.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
- `lib/effort-pins.sh` residual LOW (security re-gate of BDR-108): INT/TERM trap removes the mktemp sibling and exits 130 (never an EXIT trap, the installer owns one); the post-write re-read message no longer claims CRLF and is reached by a stubbed unit test; the rejected map line is printed through `printf '%q'` so a caller's `echo -e` cannot interpret map content; the fixture suite guards its `mktemp -d` and skips the read-only case visibly under root.
|
||||||
- `update-all.sh` re-fetched the vendored skills at every run but never re-applied the effort pins: brainstorming/writing-plans lost their xhigh until the next `make plugin` (BDR-107 gap, closed by `lib/effort-pins.sh`).
|
- `update-all.sh` re-fetched the vendored skills at every run but never re-applied the effort pins: brainstorming/writing-plans lost their xhigh until the next `make plugin` (BDR-107 gap, closed by `lib/effort-pins.sh`).
|
||||||
- **gitflow pre-commit blocked every commit with gitleaks 8.16** (Ubuntu's apt
|
- **gitflow pre-commit blocked every commit with gitleaks 8.16** (Ubuntu's apt
|
||||||
package): the hook ran `gitleaks git --staged`, a subcommand that exists from
|
package): the hook ran `gitleaks git --staged`, a subcommand that exists from
|
||||||
|
|||||||
+24
-12
@@ -6,12 +6,14 @@
|
|||||||
# it back after the last vendoring step of install-plugins.sh and
|
# it back after the last vendoring step of install-plugins.sh and
|
||||||
# update-all.sh. Idempotent: same level → untouched, other level →
|
# update-all.sh. Idempotent: same level → untouched, other level →
|
||||||
# replaced inside the frontmatter only, skill not vendored → skipped,
|
# replaced inside the frontmatter only, skill not vendored → skipped,
|
||||||
# malformed map line → rejected loudly, never applied. Four hardenings:
|
# malformed map line → rejected loudly, never applied. Hardenings: a map
|
||||||
# a map whose last line lacks a newline is still read; a SKILL.md whose
|
# whose last line lacks a newline is still read; a SKILL.md whose frontmatter
|
||||||
# frontmatter never closes is skipped untouched; the level is re-read after
|
# never closes is skipped untouched; the level is re-read after every write
|
||||||
# every write and a mismatch (CRLF, malformed) counts as failed; the write
|
# and a mismatch counts as failed; the write goes through a mktemp sibling
|
||||||
# goes through a mktemp sibling removed on any failure. Placement inside the
|
# removed on any failure and on INT/TERM (previous traps restored, never an
|
||||||
# frontmatter has no effect on the harness, which reads the key anywhere.
|
# EXIT trap: the installer owns one); the rejected map line is printed
|
||||||
|
# shell-quoted so a caller's `echo -e` cannot interpret it. Placement inside
|
||||||
|
# the frontmatter has no effect on the harness, which reads the key anywhere.
|
||||||
#
|
#
|
||||||
# Usage: source it, then `apply_effort_pins [repo-root]`
|
# Usage: source it, then `apply_effort_pins [repo-root]`
|
||||||
# or standalone: bash lib/effort-pins.sh [repo-root]
|
# or standalone: bash lib/effort-pins.sh [repo-root]
|
||||||
@@ -38,13 +40,22 @@ _effort_pin_closed() {
|
|||||||
awk 'NR==1&&/^---$/{p=1;next} p&&/^---$/{f=1;exit} END{exit !f}' "$1"
|
awk 'NR==1&&/^---$/{p=1;next} p&&/^---$/{f=1;exit} END{exit !f}' "$1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# _effort_pin_traps_restore <saved> — drop the INT/TERM handlers set for the
|
||||||
|
# write and re-install the caller's saved ones. No exit-time handler here.
|
||||||
|
_effort_pin_traps_restore() {
|
||||||
|
trap - INT TERM
|
||||||
|
[ -z "$1" ] || eval "$1"
|
||||||
|
}
|
||||||
|
|
||||||
# _effort_pin_write <skill-file> <name> <level> — replace the frontmatter
|
# _effort_pin_write <skill-file> <name> <level> — replace the frontmatter
|
||||||
# `effort:` line, or insert one after `name: <name>` (before the closing
|
# `effort:` line, or insert one after `name: <name>` (before the closing
|
||||||
# `---` when the frontmatter has no name line). Body lines never change.
|
# `---` when the frontmatter has no name line). Body lines never change.
|
||||||
# Writes a mktemp sibling then renames; any failure leaves no temp behind.
|
# Writes a mktemp sibling then renames; any failure leaves no temp behind.
|
||||||
_effort_pin_write() {
|
_effort_pin_write() {
|
||||||
local file="$1" name="$2" level="$3" tmp
|
local file="$1" name="$2" level="$3" tmp prev rc
|
||||||
tmp="$(mktemp "$file.XXXXXX")" || return 1
|
tmp="$(mktemp "$file.XXXXXX")" || return 1
|
||||||
|
prev="$(trap -p INT TERM)"
|
||||||
|
trap 'rm -f "$tmp"; exit 130' INT TERM
|
||||||
cp -p "$file" "$tmp" && awk -v n="$name" -v lvl="$level" '
|
cp -p "$file" "$tmp" && awk -v n="$name" -v lvl="$level" '
|
||||||
NR==1 && /^---$/ { fm=1; print; next }
|
NR==1 && /^---$/ { fm=1; print; next }
|
||||||
fm && /^---$/ {
|
fm && /^---$/ {
|
||||||
@@ -54,9 +65,10 @@ _effort_pin_write() {
|
|||||||
fm && /^effort: / { if (!done) { print "effort: " lvl; done=1 }; next }
|
fm && /^effort: / { if (!done) { print "effort: " lvl; done=1 }; next }
|
||||||
fm && $0 == "name: " n { print; if (!done) { print "effort: " lvl; done=1 }; next }
|
fm && $0 == "name: " n { print; if (!done) { print "effort: " lvl; done=1 }; next }
|
||||||
{ print }
|
{ print }
|
||||||
' "$file" > "$tmp" && mv "$tmp" "$file" && return 0
|
' "$file" > "$tmp" && mv "$tmp" "$file"; rc=$?
|
||||||
rm -f "$tmp"
|
[ "$rc" -eq 0 ] || rm -f "$tmp"
|
||||||
return 1
|
_effort_pin_traps_restore "$prev"
|
||||||
|
return "$rc"
|
||||||
}
|
}
|
||||||
|
|
||||||
# _effort_pin_apply_one <file> <name> <level> → rc 0 applied, 2 already at
|
# _effort_pin_apply_one <file> <name> <level> → rc 0 applied, 2 already at
|
||||||
@@ -71,7 +83,7 @@ _effort_pin_apply_one() {
|
|||||||
err "effort-pins: $file: write failed"; return 1
|
err "effort-pins: $file: write failed"; return 1
|
||||||
fi
|
fi
|
||||||
if [ "$(_effort_pin_current "$file")" != "$level" ]; then
|
if [ "$(_effort_pin_current "$file")" != "$level" ]; then
|
||||||
err "effort-pins: $file: level not applied (CRLF or malformed frontmatter?)"
|
err "effort-pins: $file: level not applied after write"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
@@ -87,7 +99,7 @@ apply_effort_pins() {
|
|||||||
case "$name" in ''|'#'*) continue ;; esac
|
case "$name" in ''|'#'*) continue ;; esac
|
||||||
if [ -n "$rest" ] || ! [[ "$name" =~ $EFFORT_PIN_NAME_RE ]] \
|
if [ -n "$rest" ] || ! [[ "$name" =~ $EFFORT_PIN_NAME_RE ]] \
|
||||||
|| ! [[ "$level" =~ $EFFORT_PIN_LEVEL_RE ]]; then
|
|| ! [[ "$level" =~ $EFFORT_PIN_LEVEL_RE ]]; then
|
||||||
err "effort-pins: rejected map line '$name $level $rest'"
|
err "effort-pins: rejected map line $(printf '%q' "$name $level $rest")"
|
||||||
rejected=$((rejected + 1)); continue
|
rejected=$((rejected + 1)); continue
|
||||||
fi
|
fi
|
||||||
file="$repo/skills-external/$name/SKILL.md"
|
file="$repo/skills-external/$name/SKILL.md"
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ check() { if [ "$2" = "$3" ]; then pass=$((pass+1)); echo "PASS $1"
|
|||||||
fm_effort() { awk 'NR==1&&/^---$/{p=1;next} p&&/^---$/{exit} p' "$1" \
|
fm_effort() { awk 'NR==1&&/^---$/{p=1;next} p&&/^---$/{exit} p' "$1" \
|
||||||
| sed -n 's/^effort: //p' | head -1; }
|
| sed -n 's/^effort: //p' | head -1; }
|
||||||
|
|
||||||
WORK="$(mktemp -d)"; trap 'rm -rf "$WORK"' EXIT
|
WORK="$(mktemp -d)" || exit 1; trap 'rm -rf "$WORK"' EXIT
|
||||||
REPO="$WORK/repo"; EXT="$REPO/skills-external"
|
REPO="$WORK/repo"; EXT="$REPO/skills-external"
|
||||||
mkdir -p "$REPO/lib" "$EXT/alpha" "$EXT/beta" "$EXT/gamma" "$EXT/noname"
|
mkdir -p "$REPO/lib" "$EXT/alpha" "$EXT/beta" "$EXT/gamma" "$EXT/noname"
|
||||||
printf -- '---\nname: alpha\ndescription: a\n---\nbody\n' > "$EXT/alpha/SKILL.md"
|
printf -- '---\nname: alpha\ndescription: a\n---\nbody\n' > "$EXT/alpha/SKILL.md"
|
||||||
@@ -77,15 +77,53 @@ mkrepo h13 crlf
|
|||||||
printf -- '---\r\nname: crlf\r\n---\r\nbody\r\n' > "$WORK/h13/skills-external/crlf/SKILL.md"
|
printf -- '---\r\nname: crlf\r\n---\r\nbody\r\n' > "$WORK/h13/skills-external/crlf/SKILL.md"
|
||||||
printf 'crlf high\n' > "$WORK/h13/lib/effort-pins.txt"
|
printf 'crlf high\n' > "$WORK/h13/lib/effort-pins.txt"
|
||||||
out="$(bash "$LIB" "$WORK/h13" 2>&1)"; rc=$?
|
out="$(bash "$LIB" "$WORK/h13" 2>&1)"; rc=$?
|
||||||
check T13-crlf-not-counted-applied \
|
check T13-crlf-file-rejected \
|
||||||
"$rc|$(printf '%s' "$out" | grep -c 'ERR ')|$(printf '%s' "$out" | grep -c ' 0 applied, ')" "1|1|1"
|
"$rc|$(printf '%s' "$out" | grep -c 'ERR ')|$(printf '%s' "$out" | grep -c ' 0 applied, ')" "1|1|1"
|
||||||
|
|
||||||
mkrepo h14 ro; d14="$WORK/h14/skills-external/ro"
|
# T13b: the post-write re-read branch, reached with a no-op write stub
|
||||||
printf -- '---\nname: ro\n---\nb\n' > "$d14/SKILL.md"
|
mkrepo h13b nowrite; f13b="$WORK/h13b/skills-external/nowrite/SKILL.md"
|
||||||
printf 'ro high\n' > "$WORK/h14/lib/effort-pins.txt"
|
printf -- '---\nname: nowrite\n---\nb\n' > "$f13b"
|
||||||
chmod 555 "$d14"; out="$(bash "$LIB" "$WORK/h14" 2>&1)"; rc=$?; chmod 755 "$d14"
|
out="$(bash -c 'source "$1"; _effort_pin_write() { return 0; }
|
||||||
check T14-write-failure-no-temp \
|
_effort_pin_apply_one "$2" nowrite high' _ "$LIB" "$f13b" 2>&1)"; rc=$?
|
||||||
"$rc|$(printf '%s' "$out" | grep -c 'ERR ')|$(find "$d14" -name 'SKILL.md.*' | wc -l)" "1|1|0"
|
check T13b-reread-mismatch-fails \
|
||||||
|
"$rc|$(printf '%s' "$out" | grep -c 'level not applied after write')" "1|1"
|
||||||
|
|
||||||
|
if [ "${EFFORT_PINS_TEST_FAKE_ROOT:-0}" = 1 ] || [ "$(id -u)" -eq 0 ]; then
|
||||||
|
echo "SKIP T14-write-failure-no-temp: chmod bits ignored as root"
|
||||||
|
else
|
||||||
|
mkrepo h14 ro; d14="$WORK/h14/skills-external/ro"
|
||||||
|
printf -- '---\nname: ro\n---\nb\n' > "$d14/SKILL.md"
|
||||||
|
printf 'ro high\n' > "$WORK/h14/lib/effort-pins.txt"
|
||||||
|
chmod 555 "$d14"; out="$(bash "$LIB" "$WORK/h14" 2>&1)"; rc=$?; chmod 755 "$d14"
|
||||||
|
check T14-write-failure-no-temp \
|
||||||
|
"$rc|$(printf '%s' "$out" | grep -c 'ERR ')|$(find "$d14" -name 'SKILL.md.*' | wc -l)" "1|1|0"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# T15: SIGINT during the awk write removes the temp sibling, exit 130
|
||||||
|
mkrepo h15 sig; d15="$WORK/h15/skills-external/sig"
|
||||||
|
printf -- '---\nname: sig\n---\nb\n' > "$d15/SKILL.md"
|
||||||
|
bash -c 'source "$1"; awk() { kill -INT $$; sleep 2; }
|
||||||
|
_effort_pin_write "$2" sig high' _ "$LIB" "$d15/SKILL.md" >/dev/null 2>&1
|
||||||
|
rc=$?
|
||||||
|
check T15-sigint-removes-temp \
|
||||||
|
"$rc|$(find "$d15" -name 'SKILL.md.*' | wc -l)" "130|0"
|
||||||
|
|
||||||
|
# T15b: previous INT trap restored on a normal return, no EXIT trap set
|
||||||
|
mkrepo h15b tr; d15b="$WORK/h15b/skills-external/tr"
|
||||||
|
printf -- '---\nname: tr\n---\nb\n' > "$d15b/SKILL.md"
|
||||||
|
out="$(bash -c 'source "$1"; trap "echo prev" INT
|
||||||
|
_effort_pin_write "$2" tr high
|
||||||
|
printf "INT:%s\n" "$(trap -p INT)"; printf "EXIT:%s\n" "$(trap -p EXIT)"' \
|
||||||
|
_ "$LIB" "$d15b/SKILL.md" 2>&1)"
|
||||||
|
check T15b-traps-restored \
|
||||||
|
"$(printf '%s' "$out" | grep -c "^INT:trap -- 'echo prev' SIGINT")|$(printf '%s' "$out" | grep -c '^EXIT:$')" "1|1"
|
||||||
|
|
||||||
|
# T16: a literal backslash-t in a map line is printed shell-quoted
|
||||||
|
mkrepo h16 q
|
||||||
|
printf 'bad\\tname high\n' > "$WORK/h16/lib/effort-pins.txt"
|
||||||
|
out="$(bash "$LIB" "$WORK/h16" 2>&1)"; rc=$?
|
||||||
|
check T16-rejected-line-quoted \
|
||||||
|
"$rc|$(printf '%s' "$out" | grep -cF 'bad\\tname')" "1|1"
|
||||||
|
|
||||||
echo "effort-pins: $pass pass, $fail fail"
|
echo "effort-pins: $pass pass, $fail fail"
|
||||||
[ "$fail" -eq 0 ]
|
[ "$fail" -eq 0 ]
|
||||||
|
|||||||
Reference in New Issue
Block a user