Commit Graph
228 Commits
Author SHA1 Message Date
bchanot 3c59333fcf fix(push-guard): single reader, whole-word dir tokens, payload fallback, bad-value banner
Run D2 of manual-push mode (BDR-114).

- push-guard sources lib/gitflow.sh once (absolute path) and reads each
  candidate dir through gitflow_push_mode; a missing lib denies.
- Dir tokens are extracted as whole shell words: a fully quoted token
  (inner apostrophe allowed) is resolved, a backslash-escaped space is
  unescaped deterministically, a token mixing quoted and unquoted parts
  is refused (fail closed) instead of resolving to its parent.
- A payload jq cannot parse is scanned as raw text with its JSON escapes
  folded; a push-looking one gets the static deny through the trap.
- The 20-token cap runs before any per-token classification (a flood of
  20 000 tokens is refused in 0.13 s; T58 locks it under 5 s).
- `case "$mode"` has a deny default; missing core tools warn and allow.
- T42 compares the deny list against main (the last release) instead of
  HEAD; literal-true, mixed-token, broken-payload, lib-missing and
  banner-on-bad-value cases added (98 checks).
- session-start banner reads the mode through the verb and shows
  `push : manual (autopush bad)` on an unparseable value.
- tour hints quote "<abs project>".
2026-10-07 17:11:56 +02:00
bchanot 472cccbc52 fix(gitflow): every autopush reader fails closed and names an invalid value
Run D1 of manual-push mode (BDR-114). `git config --bool --default true
gitflow.autopush` only covered a MISSING key: an unparseable value made
git die with empty output, the `= false` test failed, and every push ran
again. A typo on a work machine silently re-enabled the pushes it was
meant to stop.

- lib/gitflow.sh: `_gitflow_push_off` reads the mode through the lib
  verb (`push-mode`); anything but `auto` is push-off, and the verb's
  stderr line names an invalid value during start/finish.
- Emitted post-commit/post-merge hooks (POSIX sh, standalone): push only
  when the key reads `true` or is unset; `false` exits quietly; any
  other result prints one stderr line ("NOT pushed, treated as manual
  push mode") and exits 0. Mirrors gitflow_push_mode.
- .githooks/ and githooks/ regenerated files-only through `emit-hook`
  (no config read or write; .git/config hash unchanged).
- hooks/unpushed-guard.sh: mode from the lib verb (absolute lib path
  resolved before any cd, no temp file); anything but auto is manual;
  the SessionStart line names an invalid or unreadable value.
- Tests: gitflow-test T18q block (invalid → start, hook and finish push
  nothing and say so; `true` → the hook pushes; emitted hook is
  POSIX-clean), unpushed-guard T14 rewritten.
2026-10-07 16:45:31 +02:00
bchanot 3881f462c6 fix(gitflow): run C polish — 5C coherence, sanitized verb stderr, hermetic suite
Closes the non-gap observations the gates left on runs C1/C2:

- capitalize STEP 5C/6: heading no longer says "+ push"; the --no-push
  fact read is its own paragraph and scoped to that path; the
  auto-persisted line requires finish rc 0 AND ahead = 0; rc 5/2/6
  (merged, branch not deleted) still report the push state; the
  "not on origin" line carries the once-a-remote-exists hint.
- gitflow.sh push-mode: the raw config value echoed on stderr is reduced
  to printable characters (LC_ALL=C, BSD tr safe) and capped at 64.
- gitflow-test.sh exports the hermetic git config env in the file, so a
  bare run on a global-manual machine stays green.
- client-handover-writer: the branch allowlist refuses a leading dash.
2026-10-07 14:35:08 +02:00
bchanot 5cf049d235 feat(gitflow): push-mode verb; /close reports the push state instead of pushing
Run C1 of manual-push mode (BDR-111/BDR-112).

- lib/gitflow.sh: `gitflow.sh push-mode` prints auto | manual | invalid
  (rc 0; an invalid value is named on stderr). It is the one reader a
  skill may call: the bare `git config … gitflow.*` read is denied to
  Claude since run B. Ignores GITFLOW_NO_PUSH by design (documented).
- skills/capitalize/SKILL.md STEP 5C: the explicit `git push origin
  develop` is gone — `finish` has pushed develop itself since BDR-095,
  mode-aware since run A. 5C is now three separate read-only calls
  (finish; push-mode; `git rev-list --count origin/develop..develop`)
  and prose outcomes keyed on the real ahead count: pushed / manual push
  mode, you push / not on origin / push FAILED / invalid value named,
  plus a finish-failure outcome (merge vs delete rc distinguished).
  STEP 6 closing lines and the recap carry every outcome; the
  `--no-push` line reads the branch's own ahead count ("this disk only"
  only when true). Invariant: no `git push` inside any Bash call; the
  user hints are prose.
- skills/close/SKILL.md, lib/gitflow-aiguillage.md: "push" claims
  qualified "in auto-push mode".
- lib/gitflow-test.sh T11b: six cases for the verb (default, true,
  false, non-boolean with stderr + rc 0, corrupt config, usage).

Polish items from the gates are listed in TODO.md (C1 polish).
2026-10-07 13:39:01 +02:00
bchanot 6468eda495 fix(push-guard): fail closed on token floods, git failures and quoted cd targets
Hardening after the security gate on a2ac018 (3 MEDIUM, all closed and
re-measured):

- dir tokens are deduplicated and capped: more than 20 distinct cd/-C
  targets in one command denies before any git fork (20000 tokens: 0.15 s
  against the 10 s hook timeout that used to turn a flood into an allow)
- a git or cd failure while reading gitflow.autopush denies instead of
  reading as auto (git absent, usage error, unenterable dir); the key
  being unset is the only "auto" answer; the decision is recorded only
  after one candidate was evaluated cleanly, else the EXIT trap denies
- cd/pushd/-C targets that follow a quote or backtick (bash -c '…') are
  extracted; quote characters are excluded from unquoted tokens

User decision (contract, gated): both fail-closed cases also fire in
auto mode on such pathological commands; silence in auto mode holds for
every ordinary push. Header limits list the residual misses (quotes or
backslashes inside a token, cumulative relative cd, unparseable payload)
backed by the soft_deny rule. Tests: 71 checks (T48–T50b added).
2026-10-07 12:34:56 +02:00
bchanot a2ac0189f7 feat(gitflow): push-guard hook denies Claude's git push in manual-push mode
Run B of manual-push mode (BDR-111). With `gitflow.autopush false`
nothing stops Claude from typing `git push` itself: the `ask` tier is
inert under auto mode. This adds the mechanical block the user chose.

- hooks/push-guard.sh (PreToolUse, matcher Bash|Monitor, timeout 10):
  detects a push in the command text (strict, quote-stripped loose and
  alias patterns; backslash-newline folded in bash, BSD sed/grep only),
  reads gitflow.autopush in the payload cwd and in every literal -C/cd
  dir the command names (global config counts outside a repo), denies
  with the documented JSON form and a reason that tells the user to run
  the command with `!`. Unparseable value = manual (fail closed); once
  a push is detected an EXIT trap emits a static deny on any internal
  error. jq missing = one stderr warning, allow (sibling-hook policy).
- settings.json: hook wiring; 18 deny entries closing the write forms
  of the human-only toggle (any `git … config` spelling, section
  removal/rename, `-c`, config env overrides, direct edits of git config
  files); one soft_deny on pushing in manual mode in any form, with no
  per-turn clearance; the routing-around rule names hook refusals.
- hooks/session-start.sh: `🔒 push : manual (autopush=false) — ! git push`
  banner line when the key reads false (padding in bytes).
- lib/tests/push-guard.test.sh: 61 checks (push forms, over-blocks,
  invalid value, global key, fail-closed trap, no-jq, wiring, banner).

Known limits are listed in the hook header; the soft_deny rule is the
backstop. Run C (skills that push on their own) and run D (fail-closed
readers everywhere) follow. Do not enable manual mode at work before C.
2026-10-07 12:24:35 +02:00
bchanot 2fc88304ac feat(gitflow): manual-push mode honoured by the lib, quiet unpushed-guard
`gitflow.autopush false` (human-set git config) now means "nothing is
pushed" end to end, not only in the post-commit/post-merge hooks:

- lib/gitflow.sh: `_gitflow_push_off` is the single reader of
  GITFLOW_NO_PUSH / gitflow.autopush for the lib's push sites; `start`
  and `finish` stop pushing in manual mode. `gitflow_delete` checks out
  the base that contains the branch and drops a lagging upstream before
  `git branch -d` (LRN-161: `-d` judges against the upstream when set).
  Skipped remote deletes say `left in place`; `_gitflow_sync_base`
  replaces the silent `pull --ff-only || true` and warns when a base is
  behind origin and cannot fast-forward.
- hooks/unpushed-guard.sh: manual mode is silent at Stop and gives one
  `ℹ manual push mode:` line at SessionStart counting every local
  branch; an unparseable value is named and treated as auto.
- CLAUDE.global.md: manual-push mode doctrine, "ahead = defect" scoped
  to auto mode.
- Tests: gitflow-test T18m block (T18m0, T18i-T18o, 7 cases),
  unpushed-guard T10-T16.

Follow-ups (TODO.md): run B push-guard hook + settings deny widening +
banner; run C skills that push on their own (/close STEP 5C, …).
Do not enable manual mode on the work machine before B and C land.
2026-10-06 17:49:20 +02:00
bchanot 0efdff0d55 fix(portability): make test green on macOS, GNU-only idioms replaced
The suite and seven libs assumed a GNU userland: `cmd | grep -q` under
pipefail (grep exits at the first match, the producer takes SIGPIPE,
rc 141 → 15 false "merged into" FAILs in gitflow-test), `sed -i` with no
suffix, `wc -l` padding compared as a string, `stat -c`, `touch -d`,
`realpath -m` (gstack-links refusal never fired), bare `timeout` off the
sanitized PATH (design gate READY BUT UNVERIFIED), `grep -oP` (update-all
emptied the plugin list). Thirteen suites were red on this machine.

Portable forms on the native userland of both OS: producer captured out
of the pipeline, `sed -i.bak` in tests and a temp-sibling `sed_profile`
on the user dotfile, `tr -d ' '`, python3 perms, `touch -t`, a
`realpath -m` emulation that refuses `..`, perl `alarm` for the 15 s
bound, `sed -n` token extraction. Regression tests: gstack-links T4b,
doctrine-citers Alphabet/Alpha flip, profile-set-managed T18 (failing CLI
no longer aborts `set`), new portability-census suite over the tracked
shell files. Linux run deferred (see TODO).
2026-10-06 15:10:20 +02:00
bastien 2560905be2 docs(toggle): higgsfield header line names the login too 2026-09-30 18:17:17 +02:00
bastien 4c7db8893b fix(higgsfield): report upstream drift on every enable; final review fixes 2026-09-30 16:35:45 +02:00
bastien a1f7893786 test(higgsfield): drop the two shellcheck suppressions in the suite 2026-09-30 16:17:34 +02:00
bastien bbd3d209d3 feat(update): refresh the Higgsfield CLI and skill pack 2026-09-30 16:10:08 +02:00
bastien 83043412d0 feat(install): Higgsfield step 8.6; login offers test stdin alone 2026-09-30 16:08:34 +02:00
bastien acb6cd7cb4 feat(toggle): higgsfield and higgsfield-websites toggles 2026-09-30 16:06:43 +02:00
bastien 21df604eb0 fix(higgsfield): guard the suite's cleanup trap 2026-09-30 16:05:37 +02:00
bastien 67b7c98d70 feat(higgsfield): skill pack sync helper and CLI probes, with suite 2026-09-30 16:03:49 +02:00
bastien 3ce0ff163e docs(effort): helper header names the signal trap and the quoted rejection 2026-09-29 16:48:14 +02:00
bastien 0c135a0ab7 fix(effort): five residual LOW on lib/effort-pins.sh
INT/TERM trap removes the mktemp sibling and exits 130 (traps restored,
never EXIT); re-read message honest and reached by a stubbed test; rejected
map line printed through printf %q; suite guards mktemp -d and skips the
read-only case under root. Cases T13b, T15, T15b, T16.
2026-09-29 16:45:57 +02:00
bastien bb46ee22eb fix(effort): harden lib/effort-pins.sh (security gate, 4 LOW)
Last map line without newline read; unclosed frontmatter skipped with an
err; level re-read after write, mismatch counted as failed; mktemp + cp -p
+ mv, temp removed on failure; rc 1 on any rejected or failed entry.
Cases T11-T14 in the fixture suite; contract criteria 8-9.
2026-09-29 15:36:18 +02:00
bastien cd3a745857 fix(effort): resync re-applies the pins after the 21st pack refresh, order locked
The 21st pack refresh (update-all 7.4) rewrites every 21st-* SKILL.md after
the superpowers refresh; the re-apply now sits after it, the census locks
the order in both scripts. Contract: criterion 3 anchor, shellcheck
directive authorized, tracked design-motion-principles copy gated.
2026-09-29 15:09:45 +02:00
bastien c859ae256f feat(effort): entry level on every skill next to its model pin (BDR-108)
- lib/effort-pins.txt (map) + lib/effort-pins.sh (idempotent re-apply)
  replace the hardcoded brainstorming/writing-plans loop; called after the
  last vendoring step of install-plugins.sh AND update-all.sh (the resync
  dropped the pins until the next make plugin)
- design stack high uniform (last loaded wins), superpowers, agent-skills,
  21st pack pinned from the map; skills-perso low, pdf-translate medium,
  site-motion high
- doctrine: design stack loads paired with the first Read; one level per
  stack (CLAUDE.global.md, lib/effort-shift.md)
- lib/effort-audit.py prints thinking coverage per scope (sub-agent records
  carry no thinking count on ~94 % of requests)
- census map-driven + fixture suite lib/tests/effort-pins.test.sh; docs
  README/USAGE/CHANGELOG; contract + TODO plan
2026-09-29 13:15:41 +02:00
bastien a5b3374fb2 fix(gitflow): push hook names itself in its failure message (post-merge said post-commit) 2026-09-29 13:05:31 +02:00
bastien 347073a0cc fix(gitflow): pre-commit gitleaks scan falls back to protect --staged on < 8.19
Ubuntu's gitleaks 8.16 package has no git subcommand, so the hook's
"unknown command" exit 1 blocked every commit as a leak. Probe
gitleaks git --help once, fall back to protect --staged; regenerate the
installed hooks. T16c simulates a missing binary with a /usr/bin symlink
farm minus gitleaks instead of a shorter PATH.
2026-09-28 21:40:58 +02:00
bastien 58c3a3e9b7 fix(effort): re-raise judgment dispatches, planning re-asserts, pairing caveat, dedupe audit script (final review I1-I3) 2026-09-28 20:48:27 +02:00
bastien a3b479e984 fix(effort): reflow effort-audit.py to 80 columns (R12) 2026-09-28 20:27:46 +02:00
bastien 98ef991958 docs(effort): BDR-107 id, CHANGELOG entry, spec corrected for the rulings (vendored pins, exclusions, pairing rule) 2026-09-28 20:20:05 +02:00
bastien 1e3339358c feat(effort): transcript audit script for the thinking/cost split 2026-09-28 20:14:00 +02:00
bastien dd9488964b feat(effort): re-assert the skill level after prose gates that end the turn 2026-09-28 20:04:11 +02:00
bastien 557e4cc317 feat(effort): max at the verify-secure caps and ship-feature 4b; STOP texts suggest /effort-max 2026-09-28 20:02:56 +02:00
bastien a117e7ed67 fix(effort): shifts are sent with the step's first tool call (harness pairing rule); challenge shifts under their heading; fence indentation 2026-09-28 19:55:47 +02:00
bastien 3c58160d0c feat(effort): wire phase shifts in the 13 orchestrators and the handover writer 2026-09-28 19:44:22 +02:00
bastien 4a450ea6bc feat(effort): five shifter skills, lib/effort-shift.md, model-gate second axis 2026-09-28 19:32:26 +02:00
bastien 3de9d4f85a fix(effort): find-docs is ctx7-generated and gitignored, no entry level (30 skills, not 31) 2026-09-28 19:23:43 +02:00
bastien bac235cb33 feat(effort): xhigh on the vendored brainstorming and writing-plans, re-applied at resync 2026-09-28 19:21:15 +02:00
bastien 94189adbc6 feat(effort): entry effort level on the 31 user-invoked skills (spec D3)
A/B /reconcile headless — BEFORE requests=18 output=12374 thinking=3135 effort={'high'} duration_ms=96518 / AFTER requests=15 output=9038 thinking=2248 effort={'low'} duration_ms=78410
2026-09-28 19:11:21 +02:00
bastien 9223fda99f feat(effort): pin effort on the 20 repo-authored agents (BDR-077 second axis) 2026-09-28 18:59:49 +02:00
bastien 45ae0d1217 feat(effort): session default high, env-var warning, live effort in statusline 2026-09-28 18:52:36 +02:00
bastien 5437638437 test(effort): census suite skeleton with flip-test and settings lock 2026-09-28 18:49:40 +02:00
bastien 0deb5594d5 fix(floor-guard): word-bound the bare Jasmine skip patterns
skip_kind matched SKIP_SUBSTRINGS as plain substrings, so 'xit(' hit
exit(, SystemExit( and process.exit(, and 'fit(' hit model.fit( and
profit(, flagging FLOOR SKIP on ordinary test-file lines (BLK-023). The
four bare identifiers (xit, fit, xdescribe, fdescribe) now match through
SKIP_IDENT_RE with an identifier-boundary lookbehind; the dotted and
decorator forms stay substrings. Flip-test fixtures cover the false
positive (RED before, GREEN after) and the three focus/skip calls.
2026-09-28 16:57:47 +02:00
bastien ddea411491 chore(config): superpowers citers by bare name, routing map, docs, settings
Every superpowers-prefixed skill call in ship-feature, init-project, tour,
deploy, audit-delta, plugin-advisor and lib/analyze-before-plan now names
the vendored skill directly. finishing-a-development-branch is described
as the upstream skill this config does not vendor (gitflow finish is the
integration path). CLAUDE.global.md Skill routing maps the four
non-vendored skills the vendored text still references. settings.json
loses the plugin key and its marketplace block; README, USAGE,
plugin-advisor and the profile skill describe superpowers as vendored
skills, always on, zero plugin cost. CHANGELOG entry with a known
residual.
2026-09-28 14:54:53 +02:00
bastien 18f8c898f8 feat(superpowers): vendor the 7 wired skills at v6.4.1, drop the plugin
plugins.lock.json gains a superpowers entry (obra/superpowers @ 5bf4e78,
path skills, per-skill file lists, always_on) that lib/vendor-skills.sh
fetches byte-for-byte: brainstorming, writing-plans,
subagent-driven-development, test-driven-development,
requesting-code-review, using-git-worktrees, writing-skills. install-plugins
STEP 8e vendors it, update-all refreshes it at the pin, link.sh links the
seven, .gitignore ignores them. The plugin is no longer installed or
protected: its 8 other skills duplicated personal flows and its
SessionStart injection cost ~900 tokens per start, clear and compact.
detect_superpowers is one file test on the linked skill; doctor and
session-start stop charging the injection. doctor-vendored gains an
always_on class (third lock column) so always-on externals are
link-checked instead of reported parked.
2026-09-28 14:54:52 +02:00
bastien bd3e525bb3 feat(design-gate): ask for 21st login and wait instead of skipping
The design gate checked the 21st CLI with command -v only, so an
installed-but-signed-out CLI read as READY and every 21st step failed
downstream. tool_active now probes 21st whoami through a three-state
function: signed in (TWENTYFIRST_TOKEN or API_KEY_21ST set, or 'Logged in
as'), signed out (exact 'Not logged in'), unknown (rc != 0, timeout,
unexpected output). Signed out is a new verdict, SIGN-IN REQUIRED, exit
12: design-gate.md tells the orchestrator to ask the user to run
! 21st login, end the turn, re-run the gate on their reply, and to skip
21st only on an explicit 'proceed without 21st', never silently. Unknown
surfaces as exit 11 with the whoami diagnostic and a CLI-runtime remedy,
so a node/PATH failure can never loop on a sign-in prompt. INCOMPLETE
still wins. Hermetic suite lib/tests/design-tool-gate.test.sh (stub CLI,
fixture repo through DESIGN_GATE_REPO_OVERRIDE) covers every state.
2026-09-28 12:51:55 +02:00
bastien 02b62f787e fix(gstack): one helper-link tree for every hardcoded path, honest doctor stats
gstack skills hardcode ~/.claude/skills/gstack/<path> for 83 shared assets
(bin, scripts/jargon-list.json, ETHOS.md, */sections, review/specialists,
make-pdf/dist, lib/diagram-render/dist, freeze/bin...) but only bin and
browse/dist were linked: make-pdf and diagram failed on every run, cso and
plan-*-review could not read their sections, the freeze hook exited 127.
lib/gstack-links.sh links every top-level entry except SKILL.md, skips
non-skill dirs holding a nested SKILL.md (browser-skills, openclaw,
node_modules), removes the global symlink gstack ./setup plants and refuses
a destination inside the submodule. link.sh, install-plugins.sh and
update-all.sh all call it (three hand-copied blocks gone).

doctor.sh counted 34 skills (find without -L) and zero chars for block
scalar descriptions; lib/doctor-skills.sh reuses the census parser and
counts through the symlinks. Plugin constants re-based on measured values;
install-plugins.sh notes why frontend-design@claude-plugins-official and
brightdata-plugin@synced stay off and describes security-guidance truthfully.
2026-09-28 11:48:45 +02:00
bastien f83f8f755b feat(profiles): prune the gstack catalog, add max, honor a removed denylist
Nine gstack skills leave every profile (ship is trunk-based on Gitea,
land-and-deploy auto-merges and deploys, setup-deploy, autoplan reads
paths that do not exist here, context-save has no restore, learn is an
unused parallel store, careful and guard hooks never fired, design-shotgun
needs an absent OpenAI key). lib/gstack-removed.sh is the single denylist;
profile.sh gstack on and toggle-external.sh enable gstack skip it.

full now carries everything every other profile carries (user rule), minus
the parked make-pdf, diagram and 21st-ai/ui-explore/ui-review, which live
in the new max profile together with pr-review-toolkit. The 21st trio also
leaves web, web-full and design (redundant with impeccable + ui-ux-pro-max).

lib/tests/profile-census.test.sh asserts the invariants live and on a
baseline fixture plus one mutant per invariant; gstack-removed.test.sh
covers both restore paths.
2026-09-28 11:48:44 +02:00
bastien 6394fa79fc feat(doctor): check the vendored external skills
lib/doctor-vendored.sh check_vendored_skills: every curl-pinned lock entry
has its files under skills-external/ (list, dict, single-path shapes),
every link.sh EXTERNAL_SKILLS name is symlinked into ~/.claude/skills when
the active profile lists it, parked names reported not failed, hints make
plugin / make link. Lock shape-validated (warn, never a traceback), profile
and item names allowlisted before becoming paths. Suite: 11 cases.
2026-09-28 04:11:16 +02:00
bastien 415b44ed25 fix(lib): vendor-skills validates lock fields, fullmatch guard
Two security-gate LOW notes closed on user ask: the SAFE guard uses
re.fullmatch so a trailing newline is rejected; commit (40 hex), source
(github.com owner/repo) and path (SAFE class, no traversal) are validated
before any URL is built, INVALID marker names the field. Suite 12 cases.
2026-09-28 02:35:52 +02:00
bastien ba14b5ea03 feat(skills): site-motion, site-level scroll and transition choreography
Personal skill distilling the MengTo motion pack invariants (LRN-141):
gates first (reduced motion renders final states, content visible without
JS, compositor-only, offscreen pause), one smooth-scroll engine with the
Lenis/ScrollTrigger sync, Astro ClientRouter lifecycle, numbered recipes
(reveal, scrub, sticky stack, video and image scrub, TreeWalker split,
progressive blur, marquee, WebGL budgets), upstream pitfalls, checklist.
Routed into the Build UI chain of CLAUDE.global.md and lib/design-gate.md.
2026-09-28 01:40:01 +02:00
bastien 2a1ad1797b feat(lib): vendor-skills helper, five MengTo scroll skills pinned
lib/vendor-skills.sh: vendor_pinned_skills <lock-key> [refresh], list or
dict lock shapes, lock read via python argv, traversal and charset guard
on lock values, VENDOR_BASE_URL honoured only as file:// (hermetic suite),
per-file tmp+mv, refresh skips a skill never installed. install-plugins.sh
Step 8e and update-all.sh 7.3 call it for agent-skills and mengto-skills.
Vendored at a965851: scroll-world-storytelling, build-threejs-scroll-worlds
(+5 references), scroll-scrubbed-visual-sequence, scroll-scrubbed-word-
reveal, scroll-progress-timeline; text files only. Registered in link.sh,
.gitignore, toggle-external, profile.sh and the design/web/web-full/full
profiles, which also list site-motion (personal). Suite: 8 cases.
2026-09-28 01:40:01 +02:00
bastien 6617889b77 feat(verifier): floor-guard waivers outside test files need a CLARIFICATIONS ack
Security-gate MEDIUM: a self-service floor-guard: allow <reason> neutralised
the detector in the same commit. User chose strict: the tool prints WAIVED,
the contract authorizes, the verifier counts the rest as gaps. BDR-102
amendment.
2026-09-27 21:20:36 +02:00
bastien 409db51af9 test(lib): skill-routing census, TF-IDF collisions across the live catalog
Top 10 description pairs, WARN >= 0.50, FAIL >= 0.75, fixture flip-test
with a positive control and a sensitivity re-run (2-doc corpora are
degenerate, LRN-172). Baseline 2026-09-27: 120 skills, max 0.52
(careful ~ guard). Adapted from agent-skills evals Tier 2.
2026-09-27 20:17:37 +02:00