Merge bugfix/floor-guard-xit-boundary into develop
This commit is contained in:
@@ -42,7 +42,7 @@ rules:
|
||||
| BLK-020 | 2026-09-02 | notify-attention: both channels dead on one VS Code client — 2026-09-02 | resolved |
|
||||
| BLK-021 | 2026-09-22 | Bash tool dead mid-session ("every command exits 1"): /tmp usrquota blown by a dead session's probe HOMEs — 2… | open |
|
||||
| BLK-022 | 2026-09-22 | `hooks/guard-bash.sh` withheld by the safety classifier; executable spec shipped instead — 2026-09-22 | open |
|
||||
| BLK-023 | 2026-09-28 | floor-guard SKIP pattern `xit(` (Jasmine) matches any `exit(` in python/JS test helpers → false ECARTS; workaround: no `exit(` in inline python, bash derives rc from output — 2026-09-28 | open |
|
||||
| BLK-023 | 2026-09-28 | floor-guard SKIP pattern `xit(` (Jasmine) matches any `exit(` in python/JS test helpers → false ECARTS; workaround: no `exit(` in inline python, bash derives rc from output — 2026-09-28 | resolved |
|
||||
|
||||
---
|
||||
|
||||
@@ -267,4 +267,4 @@ rules:
|
||||
- **Friction**: fresh verifier returned ECARTS(1) on a fully conform diff: `FLOOR SKIP lib/tests/profile-census.test.sh:116 sys.exit(1 if violations else 0)`. One re-dispatch spent on a tool artefact.
|
||||
- **Real cause**: `lib/floor-guard.sh` SKIP_SUBSTRINGS holds the bare fragment `'xit('` to catch Jasmine's `xit(…)`; `skip_kind()` is a plain substring match, so `sys.exit(`, `SystemExit(`, `process.exit(` all hit.
|
||||
- **Solution**: workaround applied — the inline python prints violations only, the bash wrapper derives the return code from the captured output (no `exit(` anywhere). Root fix pending: word-bound the pattern (`(^|[^a-zA-Z_.])xit\(`) or match `xit(` only in JS/TS test files; hotfix-sized.
|
||||
- **Status**: open. Links [[BDR-105]], [[BDR-102]] (floor-guard origin), [[EVAL-034]].
|
||||
- **Status**: resolved 2026-09-28 — hotfix 0deb559 (bugfix/floor-guard-xit-boundary): the four bare Jasmine identifiers moved into `SKIP_IDENT_RE` with lookbehind `(?<![A-Za-z0-9_.])`, dotted/decorator forms stay substrings; fixtures SKIP_EXIT_CLEAN (RED before, GREEN after) + xit/fit/fdescribe flags. Residual `shortcut:` in the guard: `def fit(` / `function xit(` still match, `xit (` / `xit.each(` still do not (as before). Links [[BDR-105]], [[BDR-102]] (floor-guard origin), [[EVAL-034]].
|
||||
|
||||
@@ -540,3 +540,4 @@ rules:
|
||||
- User: "quand on détecte qu'on a besoin de 21st, on demande de log si c'est pas fait et on attend". /feat by hand on the same branch: design gate gains exit 12 `SIGN-IN REQUIRED` (three-state whoami probe, unknown → 11 with diagnostic, explicit "proceed without 21st" only skip); challenge round dropped my shared-helper idea (would break 4 fixture suites + change installer semantics) and my in-session `export TWENTYFIRST_TOKEN` remedy (env does not persist across tool calls). Executor DONE first pass, GATE 0 MET, verifier CONFORME 7/7, security PASS, 8/8 hermetic. Gate now exits 12 live here until `21st login`.
|
||||
- User go "merge le tout, écris les registres, fais le tier 2": tier 1 registries (BDR-105, LRN-175..178, BLK-023, EVAL-034) written, feature/skill-catalog-prune finished → develop c39c0e1. Tier 2 on feature/superpowers-vendored: 7 superpowers skills vendored at v6.4.1 through lib/vendor-skills.sh (`always_on` lock class for doctor-vendored), plugin + marketplace uninstalled, settings.json hand-edited, citers by bare name, doctrine map. Challenge round: correctness FATAL(5) caught my map text containing the forbidden `superpowers` colon form; confirmation caught an identifier wrapped across lines (grep is line-based). Executors 2/2 DONE, GATE 0 MET, verifier CONFORME 12/12, security PASS. Catalog 82 skills, passive plugin cost 670 t, injection gone; harness hot-loaded the bare names in-session. 18f8c89 ddea411. UNMERGED — human gate. [[BDR-106]]
|
||||
- User go "merge le tier 2": feature/superpowers-vendored merged into develop via `gitflow finish` → 65665a5, no conflict, pushed, copies removed by the lib. develop == origin/develop, no working branch anywhere. Whole skill-catalog prune (BDR-105 + BDR-106) on develop: catalog 82 skills, plugin passive cost 670 t, no session injection. Open for the user: `21st login`, claude.ai skills off, floor-guard `xit(` hotfix (BLK-023), two /tmp fixture dirs, other machines `make plugin` + `make link` + uninstall the cached plugin.
|
||||
- /hotfix BLK-023 (user: "fais le hotfix du floor-guard"): `skip_kind` substring match → `xit(` ⊂ `exit(`. Fix 0deb559 on bugfix/floor-guard-xit-boundary: bare Jasmine names via `SKIP_IDENT_RE` lookbehind, 4 flip fixtures (12/12). 3 challengers (2 SOLID, robustness CONCERNS(2): fixture line itself flaggable on a test path → waiver comment outside the echo; my criterion-2 live oracle vacuous → dropped — same LRN-173 class, plus I wrote a heredoc CHECK again before catching it, [[LRN-176]]). Hotfixer DONE first pass, oracles MET, security PASS. UNMERGED — human gate.
|
||||
|
||||
@@ -75,7 +75,8 @@ frontend-design@claude-plugins-official` (byte-identical to the managed copy).
|
||||
floor-guard `xit(` pattern, EVAL challenge round), journal. UNMERGED — human
|
||||
gate. After merge on any other machine: `make link` + `bash lib/profile.sh
|
||||
set full` (NOT `apply`: additive). Follow-ups: floor-guard `xit(` → word
|
||||
boundary (hotfix); gates.sh could refuse a CHECK holding `<<`; optional
|
||||
boundary (hotfix DONE 0deb559, bugfix/floor-guard-xit-boundary, UNMERGED);
|
||||
gates.sh could refuse a CHECK holding `<<`; optional
|
||||
doctor info line for the claude.ai synced bucket; `21st login`; claude.ai
|
||||
skills useless in CLI off (built-in-browser, chrome-browser, computer-use,
|
||||
skill-creator, import-memory). Tier 2 superpowers vendoring next.
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
# CONTRACT — floor-guard-xit-boundary
|
||||
- date: 2026-09-28 | flow: hotfix (bugfix/* off develop) | branch: bugfix/floor-guard-xit-boundary
|
||||
- status: active
|
||||
|
||||
## REQUEST (verbatim — IMMUTABLE)
|
||||
> fais le hotfix du floor-guard
|
||||
> BLK-023: lib/floor-guard.sh SKIP pattern `xit(` (meant for Jasmine's xit) matches any `exit(` / `SystemExit(` / `process.exit(` in python or JS test helpers → false FLOOR SKIP finding (ECARTS on a conform diff, 2026-09-28). Fix: make the Jasmine match word-bounded so `sys.exit(` no longer trips it; keep `xit(` detection for a real Jasmine `xit(` at line start or after a non-identifier char. Add the two regression cases to lib/tests/floor-guard.test.sh (a python `sys.exit(1)` line must NOT flag; a JS ` xit('skipped', ...)` line MUST flag).
|
||||
|
||||
## CLARIFICATIONS
|
||||
- Pass A: silent autofill (hotfix). Pass B: nothing visible or public is open (an internal matcher; message text unchanged).
|
||||
- [challenge 2026-09-28: simplicity SOLID, correctness SOLID, robustness CONCERNS(2), all closed by named plan changes, r2] fixture echo lines in lib/tests/floor-guard.test.sh carry `# floor-guard: allow flip-test fixture` outside the echoed string (a test-path diff scan would flag the fixture itself; WAIVED on a test file is informational and authorized here); the vacuous live clause left criterion 2; `def fit(` / `function xit(` / `xit.each(` behave as before and are recorded as a `shortcut:` comment (upgrade path named there), out of hotfix scope.
|
||||
- Root cause (LOCATE): `skip_kind` (lib/floor-guard.sh:188-189) is a plain substring test over SKIP_SUBSTRINGS; the bare-identifier entries `'xit('`, `'fit('`, `'xdescribe('`, `'fdescribe('` therefore match inside longer identifiers (`exit(`, `SystemExit(`, `process.exit(`, `model.fit(`, `profit(`). The dotted/decorator entries (`.skip(`, `.only(`, `it.todo(`, `@pytest.mark.skip`, `@unittest.skip`, `t.Skip(`) are unaffected.
|
||||
- Fix (closed): the four bare identifiers move out of SKIP_SUBSTRINGS into one compiled regex with an identifier-boundary lookbehind, `(?<![A-Za-z0-9_.])(?:xit|fit|xdescribe|fdescribe)\(`, and `skip_kind` returns SKIP when either the remaining substrings or that regex match. Excluding `.` in the lookbehind also stops `model.fit(` (a method call) from flagging; a Jasmine focused/skipped block is always a bare call.
|
||||
|
||||
## ACCEPTANCE CRITERIA
|
||||
1. Symptom gone: test-file lines `process.exit(1);`, `model.fit(x);`, `profit(1)` produce no FLOOR SKIP (SKIP_EXIT_CLEAN is RED on the old matcher, GREEN after — the regression oracle); Jasmine ` xit(`, `fit(`, `fdescribe(` lines still do. [challenge: fixtures extended]
|
||||
CHECK: out=$(make test suite=lib/tests/floor-guard.test.sh 2>&1); echo "$out" | grep -qE 'FAIL=[1-9]' && { echo "$out" | tail -12; exit 1; }; for k in SKIP SKIP_EXIT_CLEAN SKIP_XIT_FLAGS SKIP_FIT_FLAGS SKIP_FDESCRIBE_FLAGS; do echo "$out" | grep -q "PASS $k" || { echo "missing PASS $k"; exit 1; }; done; echo FLOOR_SUITE_GREEN
|
||||
EXPECT: FLOOR_SUITE_GREEN
|
||||
EVIDENCE: MET exit=0 marker-found :: FLOOR_SUITE_GREEN
|
||||
2. Build/tests green: shellcheck on the test, bash syntax of the guard, the regex compiles, and the guard's own diff is clean (its new lines are not on a test path). [challenge: the former census clause was vacuous — the file no longer holds an `exit(` — and is dropped; SKIP_EXIT_CLEAN in criterion 1 is the regression proof]
|
||||
CHECK: shellcheck lib/tests/floor-guard.test.sh && bash -n lib/floor-guard.sh && python3 -c "import re;re.compile(r'(?<![A-Za-z0-9_.])(?:xit|fit|xdescribe|fdescribe)\(')" && bash lib/floor-guard.sh develop -- lib/floor-guard.sh 2>&1 | grep -q 'FLOOR GUARD: clean' && echo BUILD_OK
|
||||
EXPECT: BUILD_OK
|
||||
EVIDENCE: MET exit=0 marker-found :: BUILD_OK
|
||||
|
||||
## FILE SCOPE
|
||||
- lib/floor-guard.sh (SKIP_SUBSTRINGS + skip_kind), lib/tests/floor-guard.test.sh (two cases)
|
||||
@@ -0,0 +1,63 @@
|
||||
# PLAN — floor-guard-xit-boundary (hotfix, logic fix → challenged) — r2
|
||||
- r2 after 3 challengers (simplicity SOLID, correctness SOLID, robustness
|
||||
CONCERNS(2)): SKIP_IDENT_RE sits right under SKIP_SUBSTRINGS; the waiver
|
||||
instruction on the guard's own lines is gone (SKIP never scans
|
||||
lib/floor-guard.sh: no `test`/`spec` in its path); the new fixture echo
|
||||
lines in the TEST file carry `# floor-guard: allow flip-test fixture`
|
||||
OUTSIDE the echoed string (the test path contains `test`, so a later scan
|
||||
of that diff would flag the fixture itself); `def fit(` / `function xit(`
|
||||
/ `xit.each(` stay unmatched or matched as before and are recorded as a
|
||||
`shortcut:` comment; fixtures extended to prove the whole alternation.
|
||||
- date: 2026-09-28 | contract: contracts/2026-09-28-floor-guard-xit-boundary-1648.md
|
||||
- branch: bugfix/floor-guard-xit-boundary | executor: hotfixer (sonnet)
|
||||
|
||||
## Root cause
|
||||
lib/floor-guard.sh:99-102 SKIP_SUBSTRINGS = ('.skip(', '.only(', 'xit(',
|
||||
'xdescribe(', 'fit(', 'fdescribe(', 'it.todo(', '@pytest.mark.skip',
|
||||
'@unittest.skip', 't.Skip('); :188-189 `skip_kind(text)` = `any(p in text …)`.
|
||||
Plain substring: `xit(` ⊂ `exit(`, `SystemExit(`, `process.exit(`; `fit(` ⊂
|
||||
`profit(`, `model.fit(`. Only test files are scanned for SKIP (line_findings,
|
||||
`if test_file:`), so the false positive hits inline python/JS helpers inside
|
||||
test files — the 2026-09-28 case: `sys.exit(1 if violations else 0)` in
|
||||
lib/tests/profile-census.test.sh (BLK-023).
|
||||
|
||||
## The exact edit (lib/floor-guard.sh)
|
||||
1. SKIP_SUBSTRINGS keeps only the dotted/decorator forms:
|
||||
('.skip(', '.only(', 'it.todo(', '@pytest.mark.skip', '@unittest.skip', 't.Skip(').
|
||||
2. New `SKIP_IDENT_RE = re.compile(r'(?<![A-Za-z0-9_.])(?:xit|fit|xdescribe|fdescribe)\(')`
|
||||
DIRECTLY UNDER the SKIP_SUBSTRINGS tuple (per-kind grouping, like
|
||||
STUB_SUBSTRINGS + its regexes), with two comment lines: bare Jasmine/Jest
|
||||
focus-or-skip calls; the lookbehind keeps `exit(`, `SystemExit(`,
|
||||
`model.fit(` out. Plus one `# shortcut:` line: `def fit(` / `function
|
||||
xit(` still match (space before), `xit (` and `xit.each(` still do not
|
||||
(as before); upgrade path `(?<!def )(?<!function )` and `(?:\.each)?\s*\(`.
|
||||
3. `skip_kind(text)`: return 'SKIP' if any substring matches OR
|
||||
`SKIP_IDENT_RE.search(text)`; else None. Still ≤ 25 logic lines, one
|
||||
function.
|
||||
4. No waiver comment on the guard's own new lines: SKIP is only scanned on
|
||||
test files (`is_test_file`: `test`/`spec`/`__tests__` in the path) and
|
||||
lib/floor-guard.sh is not one; the new lines carry no SUPPRESS/STUB
|
||||
trigger either. Header comment line 27 unchanged.
|
||||
|
||||
## The exact edit (lib/tests/floor-guard.test.sh)
|
||||
After the SKIP block (:51-55), two blocks in the same style. Every `echo`
|
||||
that writes a trigger-looking line ends with the bash comment
|
||||
`# floor-guard: allow flip-test fixture` AFTER the closing quote (never
|
||||
inside the string): the test file's path contains `test`, so a later
|
||||
diff scan would otherwise flag the fixture line itself (informational
|
||||
WAIVED on a test file).
|
||||
- SKIP_EXIT_CLEAN: `d=$(mk_repo skipexit)`; append three lines to
|
||||
sample.test.js: `process.exit(1); // sys.exit(1)`, `model.fit(x);`,
|
||||
`const p = profit(1);`; run; `check_kind SKIP_EXIT_CLEAN "$rc" 0 "$out"
|
||||
'FLOOR GUARD: clean'`.
|
||||
- SKIP_XIT_FLAGS: `d=$(mk_repo skipxit)`; append ` xit('skipped', () => {});`
|
||||
(leading spaces on purpose); run; `check_kind SKIP_XIT_FLAGS "$rc" 2
|
||||
"$out" 'FLOOR SKIP'`. Then two more repos in the same block proving the
|
||||
rest of the alternation: `fit('focused', () => {});` → `check_kind
|
||||
SKIP_FIT_FLAGS … 2 … 'FLOOR SKIP'`; `fdescribe('focused', () => {});` →
|
||||
`check_kind SKIP_FDESCRIBE_FLAGS … 2 … 'FLOOR SKIP'`.
|
||||
Header comment (:2-3) gains "plus boundary cases for SKIP" after "one CLEAN
|
||||
fixture".
|
||||
|
||||
## Not changed
|
||||
Messages, exit codes, waiver syntax, other kinds, test harness helpers.
|
||||
+3
-1
@@ -81,7 +81,9 @@ Format follows [Keep a Changelog](https://keepachangelog.com/).
|
||||
`floor-guard: allow <reason>` waiver, rc 0/2/3. Mandatory verifier
|
||||
STEP 3 (`agents/verifier.md`), documented under GATE 1 of
|
||||
`lib/verify-secure-loop.md`. Suite `lib/tests/floor-guard.test.sh`: 6
|
||||
kinds plus a WAIVED and a CLEAN fixture, each flip-tested. Waivers
|
||||
kinds plus a WAIVED and a CLEAN fixture, each flip-tested, and SKIP
|
||||
boundary fixtures (bare `xit(`/`fit(`/`xdescribe(`/`fdescribe(` are
|
||||
word-bounded, so `exit(`, `model.fit(`, `profit(` stay clean). Waivers
|
||||
outside test files count as gaps unless the contract's CLARIFICATIONS
|
||||
names them (security-gate MEDIUM, user chose strict). Adapted from
|
||||
agent-skills `constraint-driven-development`.
|
||||
|
||||
+11
-3
@@ -97,9 +97,15 @@ SUPPRESS_SUBSTRINGS = (
|
||||
TS_EXPECT_ERROR = '@ts-expect-error' # floor-guard: allow pattern table
|
||||
|
||||
SKIP_SUBSTRINGS = (
|
||||
'.skip(', '.only(', 'xit(', 'xdescribe(', 'fit(', 'fdescribe(',
|
||||
'it.todo(', '@pytest.mark.skip', '@unittest.skip', 't.Skip(',
|
||||
'.skip(', '.only(', 'it.todo(', '@pytest.mark.skip', '@unittest.skip',
|
||||
't.Skip(',
|
||||
)
|
||||
# bare Jasmine/Jest focus-or-skip calls (xit/fit/xdescribe/fdescribe); the
|
||||
# lookbehind keeps `exit(`, `SystemExit(`, `model.fit(` out (BLK-023).
|
||||
SKIP_IDENT_RE = re.compile(r'(?<![A-Za-z0-9_.])(?:xit|fit|xdescribe|fdescribe)\(')
|
||||
# shortcut: `def fit(` / `function xit(` still match (space before), `xit (`
|
||||
# and `xit.each(` still do not — upgrade path (?<!def )(?<!function ) and
|
||||
# (?:\.each)?\s*\(.
|
||||
|
||||
STUB_SUBSTRINGS = (
|
||||
'not implemented', # floor-guard: allow pattern table
|
||||
@@ -186,7 +192,9 @@ def stub_kind(text):
|
||||
|
||||
|
||||
def skip_kind(text):
|
||||
return 'SKIP' if any(p in text for p in SKIP_SUBSTRINGS) else None
|
||||
if any(p in text for p in SKIP_SUBSTRINGS):
|
||||
return 'SKIP'
|
||||
return 'SKIP' if SKIP_IDENT_RE.search(text) else None
|
||||
|
||||
|
||||
def line_findings(path, lineno, text, test_file):
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
# lib/tests/floor-guard.test.sh — flip-tests for lib/floor-guard.sh: one RED
|
||||
# fixture per KIND, one WAIVED fixture, one CLEAN fixture. Each fixture is a
|
||||
# fresh throwaway repo under $WORK (`make test` exports
|
||||
# fixture per KIND, one WAIVED fixture, one CLEAN fixture, plus boundary
|
||||
# cases for SKIP. Each fixture is a fresh throwaway repo under $WORK
|
||||
# (`make test` exports
|
||||
# GIT_CONFIG_GLOBAL=/dev/null; core.hooksPath is also pinned per-repo so a
|
||||
# machine-wide hook never fires here). This file itself carries the trigger
|
||||
# strings for every kind — the self-run criterion excludes it by pathspec.
|
||||
@@ -54,6 +55,32 @@ echo "it.skip('later', () => {});" >> "$d/sample.test.js"
|
||||
out=$(cd "$d" && bash "$LIB" "$base" 2>&1); rc=$?
|
||||
check_kind SKIP "$rc" 2 "$out" 'FLOOR SKIP'
|
||||
|
||||
# ── SKIP_EXIT_CLEAN ───────────────────────────────────────────────────────
|
||||
d=$(mk_repo skipexit); base=$(git -C "$d" rev-parse HEAD)
|
||||
{
|
||||
echo 'process.exit(1); // sys.exit(1)' # floor-guard: allow flip-test fixture
|
||||
echo 'model.fit(x);' # floor-guard: allow flip-test fixture
|
||||
echo 'const p = profit(1);' # floor-guard: allow flip-test fixture
|
||||
} >> "$d/sample.test.js"
|
||||
out=$(cd "$d" && bash "$LIB" "$base" 2>&1); rc=$?
|
||||
check_kind SKIP_EXIT_CLEAN "$rc" 0 "$out" 'FLOOR GUARD: clean'
|
||||
|
||||
# ── SKIP_XIT_FLAGS / SKIP_FIT_FLAGS / SKIP_FDESCRIBE_FLAGS ────────────────
|
||||
d=$(mk_repo skipxit); base=$(git -C "$d" rev-parse HEAD)
|
||||
echo " xit('skipped', () => {});" >> "$d/sample.test.js" # floor-guard: allow flip-test fixture
|
||||
out=$(cd "$d" && bash "$LIB" "$base" 2>&1); rc=$?
|
||||
check_kind SKIP_XIT_FLAGS "$rc" 2 "$out" 'FLOOR SKIP'
|
||||
|
||||
d=$(mk_repo skipfit); base=$(git -C "$d" rev-parse HEAD)
|
||||
echo "fit('focused', () => {});" >> "$d/sample.test.js" # floor-guard: allow flip-test fixture
|
||||
out=$(cd "$d" && bash "$LIB" "$base" 2>&1); rc=$?
|
||||
check_kind SKIP_FIT_FLAGS "$rc" 2 "$out" 'FLOOR SKIP'
|
||||
|
||||
d=$(mk_repo skipfdescribe); base=$(git -C "$d" rev-parse HEAD)
|
||||
echo "fdescribe('focused', () => {});" >> "$d/sample.test.js" # floor-guard: allow flip-test fixture
|
||||
out=$(cd "$d" && bash "$LIB" "$base" 2>&1); rc=$?
|
||||
check_kind SKIP_FDESCRIBE_FLAGS "$rc" 2 "$out" 'FLOOR SKIP'
|
||||
|
||||
# ── DELETED_TEST ──────────────────────────────────────────────────────────
|
||||
d=$(mk_repo deleted); base=$(git -C "$d" rev-parse HEAD)
|
||||
rm "$d/sample.test.js"
|
||||
|
||||
Reference in New Issue
Block a user