diff --git a/build/check-doc-drift.mjs b/build/check-doc-drift.mjs index eee04f7..a263a22 100644 --- a/build/check-doc-drift.mjs +++ b/build/check-doc-drift.mjs @@ -1674,6 +1674,17 @@ for (const name of skills) { lines.forEach((l, i) => { for (const t of helperCodeTexts(l, inFence(i))) { if (!t.includes("capture.mjs") || !t.includes("--paginate")) continue; + // Issue #10 (rung 5 — copies held to a shape): an --out carrying the + // {page} placeholder must be QUOTED. Windows PowerShell consumes the + // braces of an unquoted value (measured 2026-09-14: argv arrives as + // `…-`), and the shipped fences are the only home of that fact. + const outVal = /--out\s+(\S+)/.exec(t)?.[1] ?? ""; + if (outVal.includes("{page}") && !/^(['"]).*\1$/.test(outVal)) { + fail( + `${rel}:${i + 1}: paginate fence's --out carries {page} unquoted — Windows PowerShell consumes the braces; ` + + `quote the value ('-{page}.json') (issue #10)`, + ); + } const cmd = t.split(/\s--\s/)[1] ?? ""; for (const [needle, path] of Object.entries(PAGINATE_STATED_PATHS)) { if (new RegExp("(^|\\s)" + needle.replace(/ /g, "\\s+") + "(\\s|$)").test(cmd) && !t.includes(`--items-path ${path}`)) { diff --git a/build/check-stale-facts.mjs b/build/check-stale-facts.mjs index 96bfda1..92b9e08 100644 --- a/build/check-stale-facts.mjs +++ b/build/check-stale-facts.mjs @@ -520,6 +520,11 @@ const FACT_CARRIERS = [ // The read-verb allowlist is re-audited by hand at each adoption; pinning // the audit note's version stamp forces that re-audit when the pin moves. { re: /read actions in the v(\d+\.\d+\.\d+) catalog/, expect: meta.cliVersion, what: "read-verb allowlist audit version" }, + // The auth-death sentence the spawn-capable scripts classify a token + // death by (F-458) is the CLI's own re-login instruction, read from the + // installed package's auth module; the version stamp beside it forces + // a re-read of that file when the pin moves. + { re: /\/\/ v(\d+\.\d+\.\d+) package's dist\/core\/auth\/index\.js/, expect: meta.cliVersion, what: "auth-death literal audit version" }, ], }, ]; diff --git a/build/test-check-doc-drift.mjs b/build/test-check-doc-drift.mjs index 69c70e6..b7b0f7b 100644 --- a/build/test-check-doc-drift.mjs +++ b/build/test-check-doc-drift.mjs @@ -1110,6 +1110,24 @@ try { res.status === 1 && /rp list.*does not state its rows path/.test(res.stderr) && /--items-path data\.data/.test(res.stderr), res.stderr); } finally { snap.restore(); } } + // (j) issue #10: a paginate fence whose --out carries {page} UNQUOTED must + // go red — Windows PowerShell consumes the braces, and nothing but the + // fence carries the quoting. Mutant: strip the quotes from the audit rules + // fence. + { + const auditRel = "plugins/gs-superadmin/skills/audit/SKILL.md"; + const snap = snapshotFiles([at(auditRel)]); + try { + mutate(auditRel, (s) => { + const q = "--out '.gs-superadmin/tmp/audit-rules-{page}.json'"; + if (!s.includes(q)) throw new Error("audit rules fence no longer carries the quoted {page} --out — fixture stale"); + return s.replace(q, "--out .gs-superadmin/tmp/audit-rules-{page}.json"); + }); + const res = run(); + check("check 14j: a paginate fence with an UNQUOTED {page} --out goes red (issue #10)", + res.status === 1 && /audit\/SKILL\.md:\d+: paginate fence's --out carries \{page\} unquoted/.test(res.stderr), res.stderr); + } finally { snap.restore(); } + } } // ── check 10i (F-394): the BARE placeholder spelling inside a fence ──────── diff --git a/build/test-check-stale-facts.mjs b/build/test-check-stale-facts.mjs index 3ad6de5..3c3389d 100644 --- a/build/test-check-stale-facts.mjs +++ b/build/test-check-stale-facts.mjs @@ -81,9 +81,11 @@ function runRig(files) { ); // All three F-280 carriers live in doc-lib since the shared-gate hoist // (B5 W4/DS-17 + its review round). + // …plus the auth-death literal's audit stamp (F-458), same home. writeFileSync( join(rig, "plugins", "gs-superadmin", "scripts", "doc-lib.mjs"), - `// strict writers went 29 → 0; POST reads 59 → 0\n// read actions in the v${PIN} catalog audited\n`, + `// strict writers went 29 → 0; POST reads 59 → 0\n// read actions in the v${PIN} catalog audited\n` + + `// the sentence every auth-path throw in the\n// v${PIN} package's dist/core/auth/index.js ends with\n`, ); // Coverage floor (F-101): the checker requires ≥40 tracked .md files with // some nested — filler carries no version/count/flag tokens. diff --git a/dev/FEEDBACK.md b/dev/FEEDBACK.md index f1415dc..a14f6d4 100644 --- a/dev/FEEDBACK.md +++ b/dev/FEEDBACK.md @@ -146,8 +146,9 @@ what the gate counts (F-444). The gate refuses both. Sections from F-360 on; the rule also reads the archive. -Under test: dev · hb-20260911-04 · 2026-09-11 -Blind spots (hb-20260911-04): post-merge close-out of PR 16 on dev: nothing new is under test; the F-449 arms were measured on the sandbox by the tester round (both CLEARED). Still unmeasured on any tenant: everything the next rounds bank (Session B onward, handoffs/ — local-only, untracked), and F-459 (documented entries with no doc_path) which is OPEN for Session C1 and reproducible only on the three July-crawled sandbox domains +Under test: round-b-describe-loop · hb-20260914-01 · 2026-09-14 +Blind spots (hb-20260914-01): two live arms this builder cannot run, banked in dev/VALIDATION.md (Session B sections): (1) F-456 — a deep-ingest of the connectors-chains lane through describe-batch with the RECORDED describe command, no --command, no manual fallback, no --normalize, plus one chain through the capture helper; (2) F-458 / #13 — one describe-batch run PAST the token half-life from a terminal, reading aborted.reason auth with failures empty in the summary and zero auth-failed entries in the manifest, then a resume after gs-admin login (optionally #13 live on a small domain with a mismatched describe, stopping after exactly 5 spawns). Also unwalked here: the setup skill (slash-only) and the fence-only edits in audit, deprecate, email-report, refresh — Session B-V walks them. Not a blind spot: the DB-1 shell side was measured on Windows PowerShell 5.1 on this machine, and every other claim is a committed fixture. +Walk (hb-20260914-01): 2026-09-14 (tester) — 2026-09-14 (tester, Session B-V) — five SKILL.md walked in the consumer workspace, the plugin loaded from the working tree. Slash-only, each typed once by Bradley: setup — Phases 1-3 executed (plugin link current; manifest init existed; scaffold apply refreshed operating-model.md with 0 offers; catalog and cheatsheet generated at 1.0.9, 188 commands, all three post-conditions pass; §4-§7 already in place, no ask), paused by Bradley's choice through the F-458 timed run, then Phase 4 executed: 18 exhaustive sweeps (12 reconciled, 6 unverified with no payload total) and 18 upserts, 17 ok; FIRST ASK = the scorecard-schemes refusal (recorded modifiedAt is a per-call generated timestamp, KI-016; remedy --no-date-field --allow-redate) — DECLINED by Bradley, walk stopped there; the candidate diff also held 4 undecided (data-designer sources fields/objects, rules-engine rules sources fields/objects). Phase 5 (this round's changed stop-rule and batch-sizing prose) NOT walked in setup itself — its describe-batch behaviour was exercised through the F-456/F-458 arms instead. audit — first ask: depth (syntax); the changed rules fence ran verbatim on Windows PowerShell 5.1, reconciled 477 of 477 over 3 correctly named page files; report written, stopped before renames. deprecate — first ask: the required asset argument; the changed live-search fence ran verbatim on PowerShell 5.1 (reconciled 1 of 1, exact match to the KB key); plan presented and DECLINED at the approval gate, so step 4's schedule fence is unwalked. refresh — no ask; the changed exhaustive fence ran verbatim on PowerShell 5.1 for re chains list (reconciled 19 of 19) and its upsert returned unchanged 19, warnings [] — stopped at that first artifact. Model-invocable, invoked by the tester: email-report audit-active — the quoted program-list fence ran verbatim on PowerShell 5.1, reconciled 1084 of 1084 over 6 page files; report written. Guard wiring: `gs-admin re r delete-schedule --id guard-wiring-probe-hb-20260914-01` drew the hook's ask (rendered text relayed by Bradley, naming both tenants and the PRODUCTION warning) — DECLINED, never executed; separately the hook refused a sweep loop whose gs-admin subcommand sat in a shell variable, with its spell-it-literally hint, before anything ran.