Skip to content

feat(beta-ai-docs-agnosticism): S1 — AGENTS.md layer + AI Usage Guide (C1) - #1311

Merged
artyhoo merged 15 commits into
stagingfrom
beta-c-s1-agents-layer
Aug 8, 2026
Merged

feat(beta-ai-docs-agnosticism): S1 — AGENTS.md layer + AI Usage Guide (C1)#1311
artyhoo merged 15 commits into
stagingfrom
beta-c-s1-agents-layer

Conversation

@artyhoo

@artyhoo artyhoo commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Summary

beta-ai-docs-agnosticism S1 — AGENTS.md layer + AI Usage Guide (spec §6 C1).
Kickoff: .claude/orchestrator-prompts/beta-ai-docs-agnosticism/kickoff-s1.md (merged as #1297).

A cold AI harness opened on a consumer project now orients itself from the shipped AGENTS.md alone — which install depth is present, what the environment layer gives at that depth, where the authoritative criteria live — and has one machine-followable path from install to a first task.

  • D1b — the load-bearing gap. copy_safe skips when the destination exists (setup.d/lib.sh:112), so on every consumer whose root AGENTS.md already existed — including the ai-factory case the spec names — our contribution landed nowhere, while --force would have clobbered the other writer. New merge_fenced helper (setup.d/lib.sh) writes only our getff:begin section=getff-framework block. copy_safe is unchanged — it has 142 call sites across 14 files, none of which asked for merge behaviour. Both delivery lanes route through one install_agents_md wrapper (setup.d/30-templates.sh, setup.d/45-python.sh); the python lane is a second call site on the same destination that a single-lane fix would have missed.
  • D1. AGENTS.md.template 195 → 136 lines with the environment layer added.
  • D2. New AI Usage Guide → .ai-factory/AI-USAGE-GUIDE.md.
  • §3. First-Steps SSOT + a parity gate; the B-D5 amendment rides a separate commit.
  • D3. INSTALL-FOR-AI.md 563 → 555 lines (net-negative, not an append; the 600-line pre-commit gate had 37 lines of headroom).
  • D4. ai-factory-TOOL-as-usage-path swept from the shipped payload.

Decisions this PR states rather than assumes

  • --force on a co-owned file replaces OUR fenced section only, never the whole file — mechanically a no-op for merge_fenced, which always writes exactly that section. A sibling AGENTS.override.md (Layer 3) still means hands off entirely.
  • AI Usage Guide paths. Template packages/core/templates/shared/AI-USAGE-GUIDE.md; consumer destination .ai-factory/AI-USAGE-GUIDE.md. This is a cross-doc contract — the AGENTS.md pointer and umbrella B's later vendored render both need it.
  • Line-cap reading. spec:340-341 adopts «root ≤150 lines» without stating it for the consumer template. This PR reads the cap as applying to what the consumer ends up with, since on a consumer machine that template IS the rendered root file. That reading is the kickoff's, not the spec's. Moot in practice: the template is 136 lines.
  • ≤150 reached by moving OWNERSHIP, not lines (T-BADC-S1-A). Every cut names a doc that already owned the content and that a cold harness already opens: R1-R11 → .ai-factory/RULES.md, npm scripts → package.json, /pipeline detail → the guide, traps → references/ai-traps.md. No nested file was created to absorb overflow. The monorepo / brownfield-CI / lint-staged-ENOENT caveats live in AI-USAGE-GUIDE.md §3.1 and both template bullets point there naming what the reader will find — an earlier revision pointed at a section that did not carry them, which is the same lying-doc defect one level down.
  • D4 population is concept-derived, not pattern-derived — and it took four rounds to get there. The narrowings, recorded because the lesson outlives the result: r1 used grep --include="*.md" (cannot match *.template); r2's grep never covered the shipped payload; r3 covered the installed tree but on the token /aif-, which cannot match the tool's own top-level command, bare /aif; r4 fixed the counts but left a roster stale. D4 says «every mention of the ai-factory TOOL as a usage path» — a concept. The population is now derived by grepping the tree install.sh actually writes at core and factory with a pattern broad enough to include the bare tool name, then applying a concept check by reading the prose: .ai-factory/ FILE convention (KEEP), one of OUR shipped skills/agents (KEEP), or the EXTERNAL tool as a usage path (REFRAME/DROP). Identical tokens land in different buckets — which is why a token could never have been the population. Every population claim in this PR carries a known-positive control.
  • A shipped lying doc, fixed. skills/tool-bootstrapping/SKILL.md:49 claimed AIF was «already an integrated dependency if you installed this framework via install.sh» — false about our installer (setup.d/bridge-guided.sh:28 is detect+instruct, installs nothing) and contradicting skills/getff/SKILL.md:128 authored on this same branch. That file reaches every consumer (setup.d/10-skills.sh:44). A payload-wide contradiction sweep confirmed it was the ONLY one.
  • Roster counts now match the installers everywhere in the shipped payload: the factory suite is 7 (setup.d/10-skills.sh:127), the core skill set 6, the agent set 10 (setup.d/20-agents.sh:26-39). INSTALL-FOR-AI.md:71,425 had shipped 6 while this PR's own AGENTS.md.template:30 said 7.

Verification

bash scripts/host-verify.sh .claude/orchestrator-prompts/beta-ai-docs-agnosticism/kickoff-s1.md6/6 passed on Darwin. The contract grew with the stage: the First-Steps parity fixture and the fence-install test were added to it in the same commits that created them.

  • §4.1 agnosticism audit green — 33 rows across 7 surfaces, all PORTABLE, «non-PORTABLE findings (none)»; doc-claims reads AGENTS.md.template directly (tests/agnosticism/probes/doc-claims.sh:11)
  • §4.2 rules-autoload green — root AGENTS.md lists all 28 rules
  • §4.3 First-Steps parity fixture passes AND goes red when seeded broken — verified across five seed classes (step rename, step reorder, step deletion, whole-sequence deletion, and a render-side edit); tree restored clean each time
  • §4.4 fence co-ownership proven on all three cases — foreign content survives, second run byte-identical (no duplication), and a fence-less copy of an older template is adopted exactly once rather than doubled; plus negative controls (single sentinel does not adopt, --force leaves foreign content, .override.md blocks entirely, unterminated fence refused loudly). 17/17
  • §4.5 line-cap verdict: template 136 ≤ 150 by an honest ownership cut — the priced park is not owed
  • §4.6 this repo's root AGENTS.md 107 ≤ 150, exit-coded in the host-verify block rather than eyeballed
  • §4.7 principle 09 green (37 tests) — the guide carries its authority header and is registered in REQUIRED_HEADER_DOCS
  • §4.9 D8 hygiene — always-on delta is the AGENTS.md fenced section only; guide and tier-home are on-demand behind pointers; no memory-write path added
  • §4.8 harness honesty — the core First-Steps sequence was walked end-to-end in a fresh consumer under one harness (bash/Darwin). Cross-harness reach is INCONCLUSIVE-needs-human and is marked as such rather than generalised (T-BAD-B)

Also green: 636 tests across principles/ audit-self/ composition/, snapshot 15/15, format-shipped --check clean, and the install sweep touched by this change (f8 8/8, f8d 7/7, f9 10/10, gh-531 42/42, consumer-pipeline 4/4, refresh-covers 6/6, byte-identical 2/2, python-entry-lane 80/80, consumer-upgrade 27/27, with-aif-suite-flag 59/59, tool-decisions-seed 9/9, lychee-shipped-md-offline 3/3).

Parked questions

  1. AI Usage Guide install depth. Option A (shipped): core+ → the core First-Steps sequence reaches core consumers; costs one on-demand file. Option B: env+ (mirroring tier-home) → thinner core payload, but §2.1 IS the core sequence, so it would be withheld from its own audience and the AGENTS.md pointer would dangle. The A1 payload inventory predates this doc and does not settle it. Marked [PARKED FORK] in setup.d/30-templates.sh.
  2. --refresh for the co-owned AGENTS.md. Option A (current): stays EXCLUDED from do_refresh → refresh can never touch the other writer's content, but brownfield consumers never receive fixes to our section. Option B: refresh re-injects only the fence via merge_fenced → fixes land, at the cost of new behaviour on a path that does not touch the file today. Rationale recorded at tests/install-sh/refresh-covers-full-delivery.test.sh:107-117.
  3. agents/living-docs-auditor.md:110,173 — D4 hit, maintainer-owned, park + proposal. Both lines present the EXTERNAL tool's /aif-verify as the gate our audit blocks, which skills/getff/SKILL.md:128 denies on this branch. The file ships, but CLAUDE.md:80 makes it read-only for all sessions, so the conformant close is a park plus a proposal to its owner — the treatment §2 D1 prescribes for tier-home.md. Proposed replacement: :110 → «2 FAIL, 1 WARN — the pre-PR gate blocks (./scripts/audit-ai-docs.sh; under an external AI Factory this surfaces as /aif-verify).»; :173 → «Only FAIL blocks the gate.» Option A → leave it: two shipped docs keep making opposite claims about what the gate is. Option B → owner applies the patch; cost is one maintainer-owned edit routed through D7, which is S3's mechanism, not this stage's.
  4. aif-version in the .ai-factory/tool-decisions.md schema — RE-PRICED. An earlier revision of this body stated a false cost. Measured: grep -c 'aif-version' packages/core/hooks/deps-hash-check.sh0, against a known-positive control grep -c 'deps-hash'15 in the same file; the resolver reads only deps-hash-npm/-python/-cargo/legacy. The hook never reads the field. The coupling occurs four times in shipped payload — references/decision-format.md:18 (schema), :42 (example), :65 (§4 prose), and templates/tool-decisions.md.template:12, the file the installer actually seeds — plus the operator-local twin. Option A → keep: zero edits, but every consumer commits an external tool's version field into their own repo where it stays permanently empty. Option B → remove: 3 shipped edits + 2 twin edits, the hook is untouched, and already-installed files do not break (nothing parses the field and --refresh excludes it); residue is a stale line in existing installs.

Cross-owner edit — MAINTAINER SIGN-OFF REQUESTED

Commit 3274dc87e3 amends B-D5 in docs/superpowers/specs/2026-07-23-beta-docs-showcase-design.md to record that C1 authored the First-Steps SSOT and BS2 now consumes it. B-D5's default-owner clause settles an authoring RACE; the case that occurred is different — B-D6 defers umbrella B until after A7, so BS2 has no schedule and following B-D5 literally deadlocks C1's deliverable. The probe B-D5 itself mandates was run and is recorded verbatim in the amendment. Separate atomic commit: declining it reverts one commit and nothing else. Fallback is kickoff §3's parked form.

§1.7 Forward-check applied

Checked against the disciplines governing this change class. Build-vs-reuse (.claude/rules/build-first-reuse-default.md §3): the fence capability already exists in-repo at packages/core/composition/fence.ts:29-36, so merge_fenced mirrors its marker grammar in bash rather than inventing one — replicated, not imported, because install.sh must run with zero Node on a consumer machine; SSOT #203 (terraform-docs injection protocol, ADAPT) and #204 (embedme --verify, ADOPT) are cited as Prior-art: trailers on the two capability commits. attention-is-not-a-mechanism §1: the new fence test is registered in .github/workflows/audit-self.yml:496 in the same commit that creates it — an unregistered test is attention-dependent detection, not a gate; and both line caps are exit-coded commands in the kickoff's host-verify block rather than numbers someone eyeballs. doc-authority-hierarchy §2-§3: the new guide carries Class / Authoritative-for / NOT-authoritative-for and is registered in both install.sh:194 and packages/core/principles/09-doc-authority-hierarchy.ts:113-118, because REQUIRED_PATH_PATTERNS does not reach packages/core/templates/**. no-paid-llm-in-ci: every gate added here is bash or vitest, zero API calls. dual-implementation-discipline §7: the section id, plan attribute and adopt sentinels live once, as constants in setup.d/lib.sh, with install_agents_md the only caller — the npm and python lanes cannot drift.

§1.7 Backward-check applied

Delegated to a cold agents/backward-sweep-auditor.md run given only the change CLASS («shipped-template docs + their install path»), never this diff or PR narrative. It enumerated 110 copy_safe call sites, 18 shared-template files, both delivery lanes, the full plugin/ tree, all 3 root-AGENTS.md fenced regions and 3 payload-describing root docs, and ran two live fixture installs.

SWEPT-CLEAN: sibling shipped templates — all 9 header-bearing files under packages/core/templates/shared/ are registered in both lists and carry the header. Root AGENTS.md fenced regions — all 3 drift-gated (scripts/render-rule-index.mjs --check via packages/core/hooks/pre-push.ts:1248; the two demo regions by packages/core/composition/demo/root-agents-demo.test.ts). plugin/agents/*.md — byte-parity gated at packages/core/principles/24-plugin-manifest-integrity.test.ts:267. Lane parity for everything 30-templates.sh delivers except tier-home.md.

GAP-FOUND — all pre-existing, all OUTSIDE this stage's scope, surfaced not fixed (CLAUDE.md PR strategy: no drive-by scope expansion):

  1. setup.d/40-configs.sh:381,387,399,401,414,416,437,439.github/workflows/ci.yml ships via plain copy_safe with no ownership guard. Fixture-confirmed: a pre-existing ci.yml survives install while the installer reports success — every framework CI gate stays dark. This is the SAME class D1b closes for AGENTS.md; the go/cargo/python lanes already solved it with namespaced filenames plus a REFUSE-if-foreign guard (setup.d/45-python.sh:371).
  2. setup.d/50-hooks.sh:11-12 — same for .husky/pre-commit; a husky-init stub survives, so the pre-commit discipline never lands.
  3. README.md:20 claims «8 shipped by default» sub-agents; a live install lands 10. Same drift class fixed in INSTALL-FOR-AI.md here, but README is maintainer-owned — not touched.
  4. INSTALL.md:71,96,351-352 — stale skills/rules-as-tests/; INSTALL.md:98-101 — the manual-install exclusion list names 3 of the 6 real exclusions.
  5. plugin/skills/getff/* diverges from skills/getff/* with no parity gate.
  6. tier-home.md never reaches the python lane, and is structurally unreachable there (PROFILE resolves after do_python_lane exits).
  7. install.sh:44,48 names «the six skills» (stale by one since 2026-08-01, blame e159bf5e5c), and install.sh:668,671 — the --refresh lanes are short of the install lanes (:668 omits rule-tests, :671 omits claude-glm-executor-handoff), so those two skills never refresh on a consumer. Pre-existing; this diff touches install.sh only at :193 and :1082.

Provenance

Stage S1 of umbrella beta-ai-docs-agnosticism. Binding design: docs/superpowers/specs/2026-07-23-beta-program-design.md §6 C1 (+ §2 D7/D8) and docs/superpowers/specs/2026-07-23-beta-docs-showcase-design.md §5 B-D5. Stage kickoff: .claude/orchestrator-prompts/beta-ai-docs-agnosticism/kickoff-s1.md (merged as #1297). Base staging @ 98df408c30 · substrate: in-session (not aif — the autonomous gate is shut, AGENT_MAX_REVIEW_ITERATIONS UNSET in the agent container, and an aif-named branch would have silently failed the meta-launch Stage-1 gate, which greps head:beta-c-s1-agents-layer) · fidelity Round 5.

Merge-forward note

The PR was opened at 3c58fa8a69 and immediately went CONFLICTING — staging had moved 10 commits ahead, which also blocks GitHub Actions, so no workflow had run. Resolved by merge-forward (staging merged INTO the branch; no rebase, no force-push, per .claude/rules/git-conflict-merge-forward.md). One content conflict, packages/core/templates/shared/AGENTS.md.template against #1304, plus 11 generated fingerprint baselines regenerated with SNAPSHOT_MODE=capture rather than hand-resolved.

#1304 fixed a real consumer bug: the tier-home pointer was a markdown LINK while tier-home installs only at env/factory, so on a core install the consumer's first git push went RED on pre-push lychee. This branch's rewritten section already used the code-span form AND states the core-install absence in both the depth-detection table and the criteria paragraph, so the fix is preserved in substance — the round-6 auditor confirmed zero markdown links to any .ai-factory/ path survive in the template. The React/Next architecture pointer that staging's side carried had been lost in the ≤150 cut with no replacement, and is folded back into the ARCHITECTURE.md line.

Because a conflict resolved by taking one side is exactly the shape #1307's new stale-revert-in-pr-diff gate exists to catch, that gate was run locally against the merged HEAD: 34 modified files inspected, zero reverts to an outdated base blob.

Fidelity verdict

FIDELITY: GO
Basis: .claude/orchestrator-prompts/beta-ai-docs-agnosticism/kickoff-s1.md
Round: 6
Audited-SHA: b6b3dae
Evidence: packages/core/templates/shared/AGENTS.md.template:32 — tier-home named as a code span with «§2 criteria, §3 degradations» + «On a core install it is absent by design»; staging's delta on this file since the fork point is EXACTLY #1304's one line, so taking «ours» dropped nothing else, and grep -nE '\]\([^)]*\.ai-factory' returns none. AGENTS.md.template:14 — React/Next pointer folded back, target ships via setup.d/30-templates.sh:54. SNAPSHOT_MODE=compare → 15 pass / 0 fail byte-identical on the merged tree. pr-stale-revert-bin.ts (BASE=origin/staging HEAD=b6b3dae702) → 34 files, none reverts to an outdated base version. lychee-shipped-md-offline → 3/0 incl. the planted-dangling-link negative arm. AGENTS.md.template:30 — 7 skills byte-matching setup.d/10-skills.sh:127. first-steps-parity 9/9 over two separate files; fence-agents-coownership 17/17; run-audit «non-PORTABLE findings (none)»; principle 09 37/37.

Rounds 1-5 each returned REVISE at design altitude and each caught a real defect a green CI would have shipped: a dangling «moved-to» pointer that had silently dropped the monorepo ENOENT caveat; a shipped reference doc PRESCRIBING the /aif-* block the branch had just deleted; a false claim that AIF is bundled by our own installer, contradicting a sibling file authored on the same branch; and a roster count rewritten in place while left stale. Round 5 returned GO at 3c58fa8a69; round 6 re-established it over the merged tree.

Watch-list

id criterion why defect site reintroduction tell
W-1 PR #1304 — the tier-home pointer is never a markdown link in the shipped template on a core install the target is absent, so a link makes the consumer's FIRST git push go RED on pre-push lychee AGENTS.md.template:32 (code span, correct now) any ](...tier-home.md) or ](.ai-factory/...) construct anywhere in the template, including inside a table cell
W-2 kickoff §2 D1 falsifier — criteria and degradation rows live only in tier-home.md a second copy forks the SSOT silently; both then read as authoritative to a cold harness none — preventive any tier CRITERION or degradation ROW appearing in the template or the guide, beyond the 3-word tier gloss
W-3 kickoff §3 / T-BADC-S1-C — source and render stay two separate files if the guide's section becomes the source, the seeded-red is impossible and the fixture cannot fail none — preventive the fixture reading one path twice, or comparing section counts / heading text instead of step lists
W-4 kickoff §5/§9 — copy_safe skip-if-exists untouched; fences are a new helper 142 call sites across 14 files depend on skip-if-exists none — preventive any +/- line inside copy_safe(), or a merge branch added to it rather than the dedicated helper
W-5 the shipped payload survives the un-vacuated lychee-shipped-md-offline arm (#1306) that arm was vacuous before #1306, so a broken shipped link previously merged green (#1272) none — preventive a relative link in a shipped *.md whose target is not installed at that profile depth; or the test self-skipping
W-6 a conflict resolved by taking one side must not set a file back to an outdated base blob (#1307) «ours» on a merge-forward is exactly the shape #1285 shipped none — preventive (gate run: 34 files, zero findings) re-resolving a conflict by wholesale side-taking without re-running the stale-revert gate against the new HEAD

One MINOR left open, deliberately: AGENTS.md.template:30's factory row lists the 7-skill operator suite but not the two factory-gated sub-agents (orchestrator-worker-discipline, reviewer-discipline, gated at setup.d/20-agents.sh:31-38), so a cold harness at factory depth cannot learn from AGENTS.md that they are on disk. Pre-existing to the merge and unchanged since the round-5 GO; it forks no SSOT and does not breach the ≤150 cap.

Prior-art

Carried into the body so the citations survive the squash (the branch's own commits carry them as trailers).

Prior-art: prior-art-evaluations.md#203 (terraform-docs injection protocol, verdict ADAPT) — merge_fenced is the bash mirror of the marker-region shape already shipped at packages/core/composition/fence.ts, replicated rather than imported because install.sh must run with zero Node on the consumer machine.

Prior-art: prior-art-evaluations.md#204 (embedme --verify / embedmd -d, verdict ADOPT — the write/verify-from-one-source discipline: render the region from the SSOT, assert equality, fail on drift). Applied here to a cross-FILE render pair rather than code-in-markdown; the drift half is the vitest parity fixture rather than a CLI verify mode, because both renders are hand-voiced prose that only a step-list comparison can hold together.

Prior-art: prior-art-evaluations.md#206 (AGENTS.md as a render-target) — same doc family; the AI Usage Guide is the on-demand companion the AGENTS.md pointer targets, keeping the always-on layer thin per spec D8.

Test added 15 commits August 8, 2026 12:35
…mer AGENTS.md

`copy_safe` skips when the destination already exists, so on every consumer
whose root AGENTS.md already exists — including the case the spec names, where
ai-factory generates and auto-updates it — the framework's contribution landed
NOWHERE, while `--force` would have clobbered the other writer. The skip was
announced (`setup.d/lib.sh` «⊝ … exists — skipping») but reads as a benign no-op.

merge_fenced writes only our `getff:begin section=getff-framework` block and
preserves everything outside it. Four cases: fresh create; foreign content
(append, theirs keeps its position); already-fenced (replace the body in place,
byte-idempotent, begin marker kept verbatim); and a fence-less copy of an older
revision of our own template (adopt exactly once — that is every consumer
installed before this stage, and a fence-writer that only knew the append case
would silently double their file). Case-(c) detection requires TWO independent
sentinels, both verified present in all 20 historical revisions of the template,
because a false-positive adopt would destroy a consumer's own file.

`copy_safe` is deliberately UNCHANGED (S1 §2 D1b binding constraint): ~142 call
sites across 14 files, none of which asked for merge behaviour.

--force semantics for a co-owned file, stated rather than left undefined:
--force replaces OUR fenced section only, never the whole file, so FORCE is a
deliberate no-op here — the file is co-owned by construction and there is no
consumer intent under which "overwrite" should mean "delete the other writer's
content". A sibling AGENTS.override.md (Layer 3) still means hands off entirely.
An unterminated fence is a loud refuse, never a splice to EOF.

Both delivery lanes (npm setup.d/30-templates.sh, python setup.d/45-python.sh —
the second call site a single-lane fix would have missed) route through one
install_agents_md wrapper, so section id, plan attribute and sentinels cannot
drift between them.

The test registers in audit-self.yml in this same commit: an unregistered test
is attention-dependent detection, not a gate.

Prior-art: prior-art-evaluations.md#203 (terraform-docs injection protocol, verdict ADAPT) — this is the bash mirror of the marker-region shape already shipped at packages/core/composition/fence.ts, replicated rather than imported because install.sh must run with zero Node on the consumer machine.
Spec §6 C1's second artefact: the AI-facing lifecycle doc past install (First
Steps -> daily cycle -> degradations), shipped to `.ai-factory/AI-USAGE-GUIDE.md`.

ONE SOURCE, TWO RENDERS (spec C1 «one source of truth, two renders»). The three
First-Steps sequences live once, as data, at
packages/core/templates/shared/first-steps.source.json. The guide's §2 is a
render of it; umbrella B's human-voiced site page will be the second render
(vendored per B-D5). The source is JSON on purpose: a markdown render can never
quietly BE the source, so the parity check always has two real files to compare
and a seeded break can actually go red.

The gate (packages/core/audit-self/first-steps-parity.test.ts) compares the
ORDERED (step-id, title) pairs per depth across all three sequences, plus the
profile set itself. Comparing section counts or heading text would pass happily
while the steps had forked. Demonstrated red by swapping two steps in the source.

HONESTY, not aspiration. Every step was verified runnable by installing all
three profiles into temp consumers and listing the delivered payload
(2026-08-08), and each source step carries an `evidence` field the gate requires
to be non-empty. Capabilities that are NOT on staging today get no section: §6
names them with an owner and a landing trigger instead (launch presets, park
routing, the npm install path, B's human render).

Degradations are a POINTER, never a copy: §4 sends the reader to
`.ai-factory/tier-home.md` §3 and deliberately restates none of its rows, so the
tier SSOT cannot fork (A-S3 owns that doc; this stage only points at it).

Depth: installed at core+ in BOTH lanes, not gated to env+ like tier-home.md —
§2.1 IS the `core` First-Steps path, so an env+ gate would withhold the core
walkthrough from exactly the consumers who need it. Always-on context is
unchanged (AGENTS.md carries a pointer; the guide is read on demand), so this
costs a core consumer one on-demand file. The depth is a PARKED fork — the A1
payload inventory predates this doc and does not settle it; the shipped default
is the coherent one and the maintainer may re-gate.

Registered in install.sh SHIPPED_DOCS and principle 09 REQUIRED_HEADER_DOCS
together (the two lists are cross-checked, and REQUIRED_PATH_PATTERNS does not
reach packages/core/templates/**, so registration is an explicit edit).

Prior-art: prior-art-evaluations.md#204 (embedme --verify / embedmd -d, verdict ADOPT — the write/verify-from-one-source discipline: render the region from the SSOT, assert equality, fail on drift). Applied here to a cross-FILE render pair rather than code-in-markdown; the drift half is the vitest parity fixture rather than a CLI verify mode, because both renders are hand-voiced prose that only a step-list comparison can hold together.
Prior-art: prior-art-evaluations.md#206 (AGENTS.md as a render-target) — same doc family; this guide is the on-demand companion the AGENTS.md pointer targets, keeping the always-on layer thin per spec D8.
…ry-TOOL sweep

D1 — environment layer. The template now names WHICH install depth is present and
what the environment layer gives at that depth. Because the same template is
copied at every depth, it cannot state the depth statically — so it tells the
agent how to DETECT it from disk (`.ai-factory/tier-home.md` present -> env;
`.claude/skills/pipeline/` present -> factory). That is verifiable by `ls` rather
than trusted.

Pointer, never a copy (T-BAD-C falsifier). The tier criteria and the
capability-absence degradation matrix are named as living in
`.ai-factory/tier-home.md` §2/§3 and are restated NOWHERE here: a reader cannot
learn a tier criterion or a degradation row from this file. The depth payload
inventory is install-surface fact, not a degradation row.

<=150 line cap MET: 195 -> 127 lines, so the priced park is not needed. Every cut
names the doc that now OWNS the content, and each owner is one a cold harness
already opens:
  - R1-R11 restatement (19 lines) -> `.ai-factory/RULES.md`, which the same
    section already pointed at; the inline copy was a second rule list that drifts.
  - /pipeline + kickoff-format detail (21) -> `.ai-factory/AI-USAGE-GUIDE.md` §2.3.
  - rule-research procedure (17) -> the guide + `.claude/agents/rule-researcher.md`.
  - npm script catalogue (21) -> `package.json`, which the installer writes.
  - check-rule-globs monorepo/brownfield caveats -> guide §3.
  - recurring-trap list -> `references/ai-traps.md`, which each bullet already cited.
No nested file was created to absorb overflow (T-BADC-S1-A): every destination
already existed and already owned its content.

D4 — ai-factory-TOOL sweep. The `.ai-factory/` FILE convention is load-bearing and
stays untouched; the ai-factory TOOL as a usage path is gone — the six `/aif-*`
command bullets are dropped from AGENTS.md.template and the same block is dropped
from DESCRIPTION.template.md. The population was enumerated by grep across the
shipped payload before editing; preset RULES*.md hits are out of scope by the
kickoff's own stop condition (track-1 surface) and maintainer-owned agents/ files
were not touched. Verified zero residual TOOL-as-usage-path mentions in both files.

Roster facts corrected against a real install (2026-08-08): the shipped skill
directory is `getff`, not `rules-as-tests`, and six skills install at core, not
two; the sub-agent list was three names short. A fact fix — not a rename, and not
a migration to a generated section, which would need its drift check in the same
PR (T-BAD-A) and belongs to S3.

Probes held: doc-claims stays PORTABLE (the non-CC «do not auto-activate» fallback
note survives, zero unqualified auto-activation claims), the two goal-phrase
sentinels template-render.audit.ts pins are intact, and f9 aif-commands-honesty
passes 10/10.

Prior-art: skipped — documentation edit only. No new dependency, no new module, no new capability: content is relocated to docs that already owned it, and stale facts are corrected against a live install.
…ferral, rosters

D3 — reconciliation of the doc to shipped reality. Net-neutral by construction:
563 -> 555 lines against the 600-line pre-commit gate, so headroom GREW from 37
to 45 rather than being spent.

1. SKILL-DIR NAMING SPLIT — stated as it IS, nothing renamed (R1 owns the freeze).
   A new «Names you will see» table records all four spellings and why each
   exists: repo `getff`, npm scope `@getff`, installed skill dir
   `.claude/skills/getff/`, managed markers `rules-as-tests-aif` (kept so blocks
   already written into a consumer's `.prettierignore` keep matching). The doc's
   two stale pointers to `.claude/skills/rules-as-tests/` were not a «split» at
   all but a factual error — that path does not exist after an install.

2. CURSOR STORY — altitude reconciled, neither claim deleted. A note at the top
   states the two altitudes explicitly (install + layers 1-4 are harness-agnostic;
   layer 5 harness hooks are Claude Code-specific), the «Editor coupling» section
   now opens by scoping itself to layer 5, and a per-layer table replaces the
   two-bullet summary so a reader can see exactly what a non-CC harness gets.

3. NPM PATH — deferral recorded, clause not dropped. Step 0 now carries an
   explicit owner (release-frame phase 2, after the R1 name freeze) and trigger
   (the package is published under the frozen name), plus an instruction never to
   write the unresolvable command into an install script.

4. ROSTERS — facts fixed against a real install, not migrated. The agent list was
   three names short (fidelity-auditor, rule-test-author missing; counts wrong),
   the skills line named one skill where six install, the file-by-file tree was
   stale on skill-dir, skill-context and agents, and the refresh set listed skill
   names that do not exist. No roster was moved into a `getff:begin` section:
   that requires shipping its drift check in the same PR (T-BAD-A) and belongs
   to S3.

Also swept here (D4, same population): the `ai-factory init` step in the
copy-paste prompt, its follow-up troubleshooting bullet, `/aif-rules` as the
redirect target, and the `/aif-verify works` verification row — all four
presented the ai-factory TOOL as a usage path. The verification row is replaced
by `bash scripts/check-fences-fire.sh`, which actually ships and actually proves
a rule fires. Steps renumbered accordingly.

The «What the AI will produce» mock output was replaced by the four-item contract
it was illustrating: its numbers were fabricated and drifted (it showed 3
sub-agents where 10 install) and it carried one of the `/aif-verify` mentions.
«Manual installation» collapsed to a pointer — this doc's own authority header
already assigns human-driven installation to INSTALL.md, and the section was an
abridged copy of that doc's Path B.

Sequencing note: A-S4 (PR #1300) is the other live writer on this file and has
not merged; its insertion sits in the «Install depth profiles» section, disjoint
from every hunk here, so this lands merge-forward-clean rather than blocking.

Prior-art: skipped — documentation reconciliation only. No new dependency, module or capability; every edit corrects a shipped-reality claim or relocates content to the doc that already owned it.
…d change

Generated artefact, regenerated once after all payload edits landed rather than
per-commit. `SNAPSHOT_MODE=compare` goes 15/15 against the new set.

Three deltas, each fully accounted for:
  - AGENTS.md — new hash on all 11 fixtures that ship it: the file is now written
    as a `getff:begin section=getff-framework` fenced block, and its content was
    rewritten (195 -> 127 lines).
  - .ai-factory/AI-USAGE-GUIDE.md — new path, added at every depth.
  - .ai-factory/DESCRIPTION.md / DESCRIPTION.template.md — new hash: the `/aif-*`
    command block was dropped.
The cargo and go fixtures were already byte-identical before this regen and stay
so — they ship none of the three.

Prior-art: skipped — regenerated fixture baselines, no capability, no dependency, no hand-authored logic; the generator is tests/install-sh/snapshot.sh.
…ract

The kickoff's own rule: «Every test this stage creates gets its runner line added
to the block above» — a contract naming only the tests that already existed is
aspirational. Three lines added:

  - the First-Steps parity fixture (§3), which is the strongest acceptance item
    in the kickoff and must be reachable from the contract, not just from CI;
  - the fence-install test (§2 D1b), covering all three co-ownership cases;
  - an exit-coded assertion on the CONSUMER template's line count. §4 item 6
    already pinned this repo's own root AGENTS.md at <=150; the consumer template
    is the file the <=150 cap actually decides (§2 D1) and had no exit code
    anywhere — «195 lines» was a number someone eyeballed.

Deviation, stated rather than hidden: the kickoff asks for the runner line in the
SAME commit that creates the test. These three land one commit later because the
branch is local and unpushed and rewriting the two earlier commits to fold them in
would have been history surgery for no reviewer benefit. The contract is complete
before handoff, which is what the rule protects.

`bash scripts/host-verify.sh .claude/orchestrator-prompts/beta-ai-docs-agnosticism/kickoff-s1.md`
-> 6/6 passed on Darwin.

Prior-art: skipped — kickoff contract bookkeeping, no capability, no dependency, no shipped artefact touched.
…nsumes

CROSS-OWNER EDIT — SEPARATE ATOMIC COMMIT, FLAGGED FOR MAINTAINER SIGN-OFF.
This is the one sanctioned cross-owner change in beta-ai-docs-agnosticism S1
(kickoff §3, which routes it through the CLAUDE.md Artifact Ownership Contract
rather than letting the stage take the deliverable silently). It is deliberately
not folded into any code commit, so declining it reverts one commit and nothing
else.

WHY THE RULE NEEDED AMENDING, not overriding. B-D5's default-owner clause settles
an authoring RACE — two sessions reaching for the same skeleton. The case that
actually occurred is different: B-D6 defers umbrella B's execution until after A7,
so BS2 has no schedule at all, and following B-D5 literally would have blocked
C1's First-Steps deliverable behind an umbrella with no start date. A race rule
applied to a non-race produces a deadlock.

PROBED FIRST, per B-D5's own instruction, and recorded verbatim in the amendment:
  grep -rn "First Steps" --include="*.md" .   -> no source doc among the 14 hits
  gh pr list --state all --search beta-docs-showcase -> only #1103/#1104/#1105
    (design + kickoff PRs; no skeleton)
Had BS2 landed a skeleton, C1 would have consumed it and this commit would not
exist.

WHAT CHANGED IN THE SPEC: B-D5 keeps its SSOT-in-framework-repo model, its
vendored-render requirement, its claims-conformance-auditor backstop and its
falsifier. Only the ownership fact is updated — C1 authored the source, BS2's role
becomes CONSUME, and the «exact home + format proposed in BS2's SSOT PR» clause is
discharged by this stage's PR, which becomes the coordination point in its place.
The home and format are named explicitly so BS2 does not have to guess.

If the maintainer declines: the fallback is already specified in kickoff §3 — the
guide keeps its First Steps as its own render with a «SSOT pending, owner BS2»
provenance line, and the parity fixture's cross-render half waits for BS2. That is
a review outcome, not something this stage negotiates in flight.

Prior-art: skipped — spec-text amendment recording an ownership fact. No capability, no dependency, no code; the artefacts it describes ship in the accompanying commits.
Own-QA regression, caught by an existing gate rather than by review:
tests/install-sh/f8-agents-scripts-shipped.test.sh went 6/8 after the D1 trim.

The <=150 pass had collapsed the `### UI projects (react-next stack)` subsection
into one prose sentence, which broke f8 on BOTH of its arms at once:
  - the gate arm — the surviving sentence still said «playwright.config.ts»
    OUTSIDE any UI-gated subsection, and f8 exists precisely because
    test-storybook/playwright must never read as unconditional core commands;
  - the over-trim arm — `test-storybook` disappeared from the file entirely, and
    f8 asserts the commands are GATED, not deleted.

That pair is a good gate: it makes «trim it away» and «leave it ungated» both red,
so the only green state is the honest one. Subsection restored verbatim, still
carrying its «Not shipped by default» qualifier.

Template is 136 lines — the <=150 cap still holds with room, so no park is needed.
f8 back to 8/8; host-verify 6/6; install baselines regenerated (AGENTS.md hash on
the 11 fixtures that ship it), snapshot compare 15/15.

Prior-art: skipped — restores previously shipped documentation content removed in error; no new dependency, module or capability.
Own adversarial QA before handoff (T19). Running the install-sh tests that touch
this stage's surfaces — not just the ones it added — turned up four real defects.
None of them would have been caught by reviewing the diff.

1. gh-531 / #884 — the new `.ai-factory/AI-USAGE-GUIDE.md` escaped the shipped
   `.prettierignore` managed block, so a consumer's very first `npm run
   format:check` went RED on a file the framework wrote. Added to
   packages/core/templates/shared/.prettierignore next to tier-home.md.

2. The same guide was delivered by `copy_safe` but absent from `do_refresh()`, so
   a brownfield consumer could never receive fixes to it — and its §2 First Steps
   renders from an SSOT that moves, meaning they would keep following stale steps.
   refresh_safe arm added in install.sh.

3. `refresh-covers-full-delivery` went RED because AGENTS.md dropped out of its
   FULL set: that set is derived by grepping for delivery VERBS, and the consumer
   AGENTS.md now goes through `install_agents_md`, not `copy_safe`. Verb
   alternation extended — the identical fix the test's own header documents for
   `deliver_getff_workflow`. AGENTS.md deliberately stays EXCLUDED from
   do_refresh: refresh_safe rewrites a WHOLE file, which is exactly wrong for a
   co-owned one. Re-injecting only the fence on refresh is now mechanically
   possible and is recorded as a follow-up, not slipped in here.

4. `consumer-pipeline` asserts the literal string «Orchestration — backlog &
   /pipeline» in the shipped AGENTS.md; the D1 trim had shortened that heading.
   The heading is a shipped convention other code greps for, so it is restored
   rather than the test relaxed.

Also fixed while proving (1): wrapping the template in fence markers made the
consumer's AGENTS.md not Prettier-clean — an HTML comment immediately followed by
a heading. merge_fenced now writes a blank line on each side of the body, in all
four write paths identically so replace stays byte-equal to create. This is the
#531 failure class (a consumer's first validate going red on our own file), found
by the gate that exists for it. The fence test's adopt-not-append assertion was
widened from +3 to +5 wrapper lines to match, still an order of magnitude below
the doubled size it guards against.

Install baselines regenerated for the new AGENTS.md bytes; snapshot compare 15/15.
Affected install-sh sweep now green: fence 17/17, byte-identical 2/2, gh-531 42/42,
consumer-pipeline 4/4, refresh-covers-full-delivery 6/6, f8 8/8, f8d 7/7, f9 10/10,
consumer-upgrade-path 27/27, lib-helpers 20/20, layer-units 32/32,
install-self-verification 27/27, python-entry-lane 80/80.

Prior-art: skipped — regression fixes to this branch's own work plus regenerated baselines; no new dependency, module or capability.
…say so

T-BAD-B honesty item, found by actually WALKING the core sequence in a fresh
consumer instead of only checking that each step's artefact exists.

`bash scripts/check-rule-globs.sh` exits 1 on a brand-new skeleton — correctly:
with no `src/` at all, R2's boundary globs match zero files, which is precisely
the inert-rule condition the gate exists to report («R2 no-unsafe-zod-parse
(RULE_GLOBS.boundary): matches ZERO source files — rule is SILENTLY INERT»).

But the sequence sent the reader into that RED with no warning, and this failure
is NOT in INSTALL-FOR-AI's «Expected first-run failures» table either — so a
consumer following First Steps on a greenfield project hits an unexplained
failure at step 4 and reasonably concludes the install is broken. A step that
predictably fails without saying so is the same lying-doc class this stage is
supposed to be closing.

Clause added to the step in all three sequences, in BOTH the SSOT and the render
(the parity gate keeps them together), naming it as the expected first run and
saying when to re-run.

Walk evidence in a fresh ts-server consumer: step 2 rc=0 (all four artefacts
present), step 4 rc=1 with the inert-R2 reason quoted above, step 5
check-fences-fire rc=0, step 6 audit-ai-docs rc=0.

Baselines regenerated; snapshot compare 15/15; host-verify 6/6; parity 9/9.

Prior-art: skipped — documentation honesty fix to this branch's own new doc; no dependency, module or capability added.
….template, honest refresh claim

Three items from fidelity round 1 (REVISE). All three reproduced against the tree
before editing.

1. MAJOR — DANGLING «MOVED-TO» POINTER (kickoff §2 D1, trap T-BADC-S1-A).
   `AGENTS.md.template` pointed at `.ai-factory/AI-USAGE-GUIDE.md` §3 for the
   monorepo / brownfield-CI / per-package-config caveats, and the guide carried
   none of them: `grep -niEc "monorepo|brownfield|shadow|ENOENT"` over the guide
   returned 0. Worse, the `check-lintstaged-resolves.sh` bullet had lost its
   monorepo `ENOENT` content with NO pointer at all — that content was simply
   gone from the shipped payload.

   This is exactly the trap the kickoff named: the <=150 cap had been met by
   moving lines to a destination that did not own them. The cap is only honest if
   the pointer is true. New guide §3.1 now carries all four blocks, restored from
   staging `AGENTS.md.template:50-51`: glob widening (the flat/inline-router
   case), the shadowing-package FAIL vs WARN semantics, the brownfield-CI
   local-only case, and the monorepo lint-staged `ENOENT` fix. Both template
   bullets now point at §3.1, and the pointers name what the reader will find.

   A monorepo consumer whose workspace package shadows the root ESLint config now
   has a shipped doc explaining why their rules do not govern that package; one
   whose commit dies on `ENOENT` has the per-package fix.

2. MAJOR — D4 LEFT AN IDENTICAL TWIN UNVERDICTED.
   `CLAUDE.md.template:25-31` still carried the `/aif-plan` … `/aif-commit`
   TOOL-as-usage-path block — the same class removed from `AGENTS.md.template` and
   reframed in `DESCRIPTION.template.md`. Two of three identical hits verdicted,
   the third silent, so no verdict could be inferred.

   ROOT CAUSE, worth recording: the original T10 population grep used
   `--include="*.md"`, which does not match `*.template`. The enumeration was
   incomplete by construction, not by judgement. Re-run with `--include="*.template"`
   added; the shipped-payload population is now closed. The only surviving `/aif-`
   hit is `/aif-doctor` in the guide's factory sequence, and that is OURS — one of
   the seven skills `--profile factory` installs (verified by listing a real
   factory install), not the external ai-factory tool. Verdict: KEEP.

   `CLAUDE.md.template` is swept like its two siblings rather than parked. Recorded
   fact either way: no installer path copies that file today — `grep -rn
   "CLAUDE.md.template" --include="*.sh"` returns only `install.sh:188`, which is
   the SHIPPED_DOCS header-verify array, not a copy step. So no consumer receives
   it and the sweep is zero-risk; it is done for consistency, so the next reader
   does not have to re-derive that the block was seen and judged.

3. MINOR — OWNERSHIP CLAIM CONTRADICTED ITS OWN WIRING.
   The guide's §7 told the consumer «it is yours (Layer 2 …); `install.sh` without
   `--force` will not overwrite it», while this same branch registers it in
   `do_refresh` via `refresh_safe` (`install.sh:1082`) — which overwrites on
   `--refresh` regardless of `--force`, skipping only on a sibling `.override.md`.

   The DELIVERY is right (a framework doc must receive fixes, and §2 renders from a
   source that moves), so the SENTENCE is what changed. It now says the doc is
   framework-owned Layer 1, that a plain re-install leaves the copy alone, that
   `--refresh` DOES overwrite it and why, and that `AI-USAGE-GUIDE.override.md` is
   the way to make local edits survive.

VERIFICATION (all re-run at final state):
  host-verify 6/6; principles+audit-self+composition 636 passed / 1 skipped (47
  files); snapshot compare 15/15 after baseline regen; format-shipped --check
  clean; f8 8/8, f9 10/10, consumer-pipeline 4/4, gh-531 42/42, byte-identical
  2/2, refresh-covers 6/6, f8d 7/7, lychee-shipped-md-offline 3/3.
  Parity fixture re-proven non-vacuous after the guide edits: swapping env steps
  5/6 in the SSOT goes RED on the `env` sequence, revert goes green 9/9.
  Line caps hold: consumer template 136, root AGENTS.md 107, both <=150.

Prior-art: skipped — documentation fixes closing a fidelity round; content restored from a prior revision of a shipped doc and one claim corrected to match existing wiring. No new dependency, module or capability.
…erdict every hit

MAJOR — D4 had swept 2 surfaces, not the population. The worst instance:
`skills/getff/references/ai-traps.md` shipped consumers a recommended CLAUDE.md
skeleton that PRESCRIBED the very `/aif-*` block removed from
`CLAUDE.md.template` — so the instance was deleted while the recipe for
reproducing it kept shipping. Reachable at every depth
(`setup.d/10-skills.sh:23` copies `skills/getff` unconditionally) and
`AGENTS.md.template` sends readers into that exact file by name.

ROOT CAUSE, both halves now closed. Round 1 found the first: the population grep
used `--include="*.md"`, which never matches `*.template`. The second is that the
grep was never run across the shipped payload at all. The population is now
derived the only way that cannot drift — install into throwaway consumers at
`core` and `factory` and grep the INSTALLED tree, so "shipped" means what the
installer actually writes, not what a path pattern happened to catch.

Population: 9 files carry `/aif-` after the sweep, every one with a verdict.

REFRAMED (the external tool presented as a path into OUR gate):
  - ai-traps.md — the sample CLAUDE.md now mirrors the swept `CLAUDE.md.template`
    (pointer to the AI Usage Guide); the "✅ optional tooling" example no longer
    prescribes `/aif-plan`; the bypass route is a rule change on a PR, not
    `/aif-rules`.
  - getff/SKILL.md — the pre-PR layer names the shipped gate, with AIF as an
    optional wrapper; the glossary entry marks `/aif-verify` EXTERNAL and
    not-bundled; the integration bullet keeps the seam, drops the command list.
  - overview.md — the "Pre-PR layer" heading named the external tool; it now
    names `audit-ai-docs.sh` + the review sub-agents (same defect class f9
    already fixed in checks-map).
  - checks-map.md `:160`,`:188` — level-4 rows now lead with the shipped gate and
    mark AIF optional.
  - self-testing-docs.md `:32`,`:284`, doc-organization.md `:361` — our own
    sub-agent no longer reads as invokable only through the external tool.
  - INSTALL-FOR-AI.md `:361` — context7 is justified by what `/rule-research`
    uses it for, not by "powers the /aif-* commands".
  - agents/aif-init.md `:3` — dropped "Use after installing AI Factory": our
    installer creates `.ai-factory/` itself, so no external tool is a
    prerequisite. Trigger keywords intact; no test pins the description
    (checked `packages/core/principles/23-aif-init-passport-gen.test.ts`).

KEPT, with the reason recorded (silence on a hit is what failed twice):
  - `/aif-doctor`, `/aif-init` — OURS. `aif-doctor` is one of the seven skills
    `--profile factory` installs; `aif-init` is our shipped agent's own
    invocation name. Neither is the external tool.
  - `review-sidecar.md:15` — a PATH into `skill-context/aif-review/`: the
    `.ai-factory/` file convention, which D4 explicitly preserves.
  - checks-map.md `:44`,`:110`,`:212` — already honest and f9-gated; `:124` is the
    caveat that AIF does NOT replace CI and external contributors lack it —
    a warning against the usage path, not one.
  - self-testing-docs.md `:258` — describes where the sub-agent plugs in.

OUT OF REACH, stated rather than silently skipped:
  - `agents/living-docs-auditor.md:4,110,173` — maintainer-owned under the
    Artifact Ownership Contract; routes through the D7 patch-proposal path,
    which is S3's mechanism, not this stage's.
  - `agents/manual-rule-liveness-prober.md:49` — never shipped (`install.sh:610`
    `continue`), so it is not in the population.
  - `.ai-factory/RULES.md` (9 hits, from `packages/preset-next-15-canonical/`) —
    preset payload, out of scope by the kickoff's own §5 + §9 stop condition.

THREE MINORs from the same round:
  1. `AGENTS.md.template:69` promised "how the backlog is ranked" and nothing
     behind the pointer stated a criterion. The promise is dropped; the ranking
     criteria are `/pipeline`'s own and the reader is sent to its SKILL.md.
  2. The template contradicted itself on the factory roster — `:30` named 6
     skills, `:86` named 7. Ground truth is 7 (`setup.d/10-skills.sh:127`), and
     all three surfaces (`:30`, `:86`, guide `:142`) now agree. The lane split
     behind it (`install.sh:671` refreshes 6) is pre-existing and untouched.
  3. `AI-USAGE-GUIDE.md` mis-stated the sibling lanes: `GETFF_TOOLCHAIN` is set
     BY `install.sh:286` from the `cargo` positional, not typed by a consumer,
     and the `go` lane (`install.sh:155`) was missing. Now all three non-npm
     lanes are named as the explicit positionals they are, in the render AND the
     First-Steps SSOT.

VERIFICATION: host-verify 6/6; principles+audit-self+composition 636 passed / 1
skipped (47 files); snapshot compare 15/15 after regenerating baselines against
the FINAL state; format-shipped --check clean; f9 10/10 (it pins the checks-map
rows this commit edits), f8 8/8, f8d 7/7, consumer-pipeline 4/4, gh-531 42/42,
byte-identical 2/2, refresh-covers 6/6, lychee-shipped-md-offline 3/3,
transform-internal-refs 14/14, install-self-verification 27/27,
python-entry-lane 80/80.

Prior-art: skipped — documentation sweep closing a fidelity round. No new dependency, module or capability; every edit either corrects a shipped-reality claim or removes an external tool from a path it never belonged on.
…bundling lie

MAJOR — same class for the third round, so the fix is the METHOD, not the hit.

The three narrowings, recorded because the next person running a D4-class sweep
needs the lesson more than the result:
  r1: `grep --include="*.md"` — structurally cannot match `*.template`.
  r2: the grep never covered the shipped payload at all.
  r3: the grep covered the installed tree, but on the token `/aif-` — which
      structurally cannot match the tool's own top-level command, bare `/aif`.
Each time the enumeration was narrower than what D4 states: «every mention of the
ai-factory TOOL as a usage path». That is a CONCEPT. A pattern finds candidates;
it does not define the population.

METHOD NOW USED (quoted so the next reader can see the population was not defined
by a regex). Candidates, over the tree `install.sh` actually writes at `core` and
`factory`:

  grep -rnE '(/aif\b|/aif-|AI Factory|\bAIF\b|ai-factory|aif-handoff)' --include='*.md' .

26 candidate files. Then the CONCEPT CHECK on top — read the surrounding prose and
ask which of three things each mention is:
  (a) the `.ai-factory/` FILE convention → KEEP, D4 preserves it explicitly;
  (b) one of OUR shipped skills/agents (`/aif-doctor` at factory, `/aif-init`)
      → KEEP, ours is not the external tool;
  (c) the EXTERNAL tool presented as a usage path → REFRAME or DROP.
Identical tokens land in different buckets, which is exactly why the token could
never be the population.

WHAT IT CAUGHT — `skills/tool-bootstrapping/SKILL.md`, copied unconditionally at
every depth (`setup.d/10-skills.sh:44`), so it reaches EVERY consumer:

  `:49` claimed AIF `/aif` is «already an integrated dependency if you installed
  this framework via install.sh».

That is false about our own installer, and it directly contradicts
`skills/getff/SKILL.md:128`/`:134` — «the EXTERNAL AI Factory tool, which this
installer does not bundle» — which THIS SAME BRANCH authored. Two shipped files in
one payload making opposite claims is a lying doc reaching every consumer, i.e.
the exact failure this project exists to prevent, not sweep hygiene.

Treatment is the one already applied to the structurally identical
`getff/SKILL.md:134`: keep the integration seam, drop the dependency claim. The
file already contained the correct shape for a different tool — §3 says of
`context7` «The installer does not install or guarantee it … degrades gracefully
when it is absent» — so AIF is now stated the same way, and §2 cites both §3 and
getff/SKILL.md so the three statements cannot drift apart again.

Also reframed in that file, same concept: `:19` (AIF as a trigger → marked
optional), `:25` (`Delegate to AIF /aif` → reuse a detector WHEN AVAILABLE, with
the installer-guaranteed files as the always-present path — the shape
`agents/rule-researcher.md:101` already used correctly), `:29` (`skills.sh`
commands → vocabulary adopted for naming alignment, commands only where that
registry exists), `:37` (`Reuse AIF heuristic` → the two questions ARE the
heuristic, stated in full and needing no external tool), `:57` (kept coherent with
the corrected §2).

CONTRADICTION SWEEP — the coordinator asked whether `:49` was the only one.
Measured, not assumed:

  grep -rniE '(not bundle|bundled|integrated dependency|ships? with|comes with|
    prerequisite|already installed|requires? AIF|needs AIF)' --include='*.md' .

over the installed tree: `:49` was the ONLY contradiction. The other matches are
unrelated senses («do not bundle» in a report format, «ship with the project»
about the gate scripts, «bundled Anthropic best-practices» about superpowers).
All three AIF-bundling statements in the payload now agree.

KEPT with reasons, new rows: `decision-format.md:3,8,60,65` and
`agents/rule-test-author.md` (8 hits) are `.ai-factory/` FILE paths — pure
convention; `agents/rule-researcher.md:101` is already correctly conditional
(«when available», with the non-AIF fallback spelled out) and is the model the
others now follow; `ai-doc/SKILL.md:22` already says «degrade without the
harness»; `ai-doc/anthropic-and-aif-residue.md` is an analysis OF the AIF residue
pattern, not a usage path.

PARKED — `decision-format.md:18` ships an `aif-version:` field in the
`.ai-factory/tool-decisions.md` YAML frontmatter schema. Removing it is a
DATA-FORMAT change to a file consumers already have on disk and a hook already
reads, not a doc edit, so it is a judgment call for the maintainer rather than
something this sweep should pick. Reported, not decided.

VERIFICATION: host-verify 6/6; snapshot compare 15/15 after regenerating baselines
against the final state; format-shipped --check clean; f9 10/10, f8 8/8, f8d 7/7,
consumer-pipeline 4/4, gh-531 42/42, byte-identical 2/2, refresh-covers 6/6,
lychee-shipped-md-offline 3/3, install-self-verification 27/27,
tool-decisions-seed-integration 9/9 (it exercises the file this commit edits).

Prior-art: skipped — documentation sweep plus one factual correction to a shipped claim. No new dependency, module or capability; the only behavioural surface touched is prose that misdescribed what the installer bundles.
…ntext7 analogy

MAJOR 1 — a fact I rewrote and carried stale.
`INSTALL-FOR-AI.md:425` said the AIF operator suite is «6 skills (pipeline,
dispatcher, aif-doctor, harvest, night-mode, story)». Ground truth is SEVEN:
`setup.d/10-skills.sh:127` installs those six plus `claude-glm-executor-handoff`.
Worse, `packages/core/templates/shared/AGENTS.md.template:30` — authored by THIS
PR — already said «the 7-skill operator suite» and named all seven, so the PR
shipped two docs with opposite counts.

This was not a missed file. `git diff origin/staging...HEAD -- INSTALL-FOR-AI.md`
shows the line among my `+` lines: I rewrote it and did not fix the fact it
carried, which is precisely what D3 asked for («Agent/skill rosters have drifted
… Here: fix the facts»). The same wrong count sat untouched at `:71` («6 skills
+ 2 agents»). Both now read 7, and `:425` names the seventh skill.

Counts now agree across every surface this PR touches — INSTALL-FOR-AI `:71`,
`:346`, `:425`; AGENTS.md.template `:30`, `:86`; AI-USAGE-GUIDE `:142`. The
«6-dir core set» on the same line `:425` is a DIFFERENT set (the six core skills)
and is correct as written.

Deliberately NOT touched: the pre-existing lane split at `install.sh:671`, which
refreshes six. Ground truth for what INSTALLS is seven; reconciling the refresh
loop is a behaviour change and out of this stage's scope.

MINOR — hedge parity inside one file. `skills/getff/references/self-testing-docs.md:32`
was hedged last round but `:258` was left as «В AIF под `/aif-verify` подключается
living-docs-auditor» — same file, same class, inconsistent verdict. `:258` now
leads with the script being the gate itself, then names the AIF wiring as
conditional and notes the installer does not ship AIF.

MINOR — an analogy that was not exact. `skills/tool-bootstrapping/SKILL.md:49`
supported its true claim with «same posture as context7 in §3». Not the same:
`setup.d/05-mcp.sh:33-45` DOES write a context7 entry into the consumer's
`.mcp.json` under the FULL gate at `:11-15`, while `install.sh` never touches AIF
at all. The load-bearing claim is unchanged and unweakened; the analogy is now
stated in the correct direction — AIF is LESS wired than context7, so §3 is the
weaker claim of the two, not an equivalent one.

Two items from this round are PARKS, not edits, and are recorded in the PR body
rather than here: the `agents/living-docs-auditor.md:110,173` D4 hit (the file is
maintainer-owned per `CLAUDE.md:80`, so the conformant close is a park plus a
proposal to its owner — the same treatment §2 D1 prescribes for `tier-home.md`),
and the re-priced `aif-version` schema park (its previously stated cost was
false: `packages/core/hooks/deps-hash-check.sh` contains ZERO occurrences of
`aif-version` — measured against a known-positive control of 15 `deps-hash`
occurrences in the same file — so the hook never reads it and removing the field
would not touch the hook).

VERIFICATION: host-verify 6/6; snapshot compare 15/15 after regenerating
baselines against the final state; format-shipped --check clean; f9 10/10,
`with-aif-suite-flag` 59/59 (it exercises the factory suite this commit
re-counts), tool-decisions-seed-integration 9/9, f8 8/8, f8d 7/7,
consumer-pipeline 4/4, gh-531 42/42, byte-identical 2/2, refresh-covers 6/6,
lychee-shipped-md-offline 3/3, install-self-verification 27/27.

Prior-art: skipped — documentation fact corrections and wording precision on shipped docs. No new dependency, module or capability; no behavioural surface changed.
…ayer

# Conflicts:
#	packages/core/templates/shared/AGENTS.md.template
#	tests/install-sh/baselines/python/brownfield-ruff.fingerprint
#	tests/install-sh/baselines/python/brownfield-sgconfig.fingerprint
#	tests/install-sh/baselines/python/greenfield.fingerprint
#	tests/install-sh/baselines/react-native/brownfield.fingerprint
#	tests/install-sh/baselines/react-native/greenfield.fingerprint
#	tests/install-sh/baselines/react-next/brownfield.fingerprint
#	tests/install-sh/baselines/react-next/greenfield.fingerprint
#	tests/install-sh/baselines/react-spa/brownfield.fingerprint
#	tests/install-sh/baselines/react-spa/greenfield.fingerprint
#	tests/install-sh/baselines/ts-server/brownfield.fingerprint
#	tests/install-sh/baselines/ts-server/greenfield.fingerprint
@artyhoo
artyhoo merged commit 744bb06 into staging Aug 8, 2026
59 of 62 checks passed
@artyhoo
artyhoo deleted the beta-c-s1-agents-layer branch August 8, 2026 14:36
artyhoo added a commit that referenced this pull request Aug 9, 2026
…ms routed here after authoring (#1337)

kickoff-s3.md was authored 2026-08-08 16:35, before the meta-launch routed three
items into this stage. The state file records the routing; the dispatch input did
not, so a fresh S3 tab handed only this kickoff would have lost all three.

Adds §2 D5 with each item re-measured against origin/staging 4f68ed5 rather
than inherited as prose:

- i  presets row (meta-launch M4) — AI-USAGE-GUIDE.md:272 still says «not shipped»
     while #1327 shipped 4 preset JSONs + 2 helpers; the row's own trigger fired.
     Note the line moved from the :269/:270 recorded in the state file.
- ii living-docs-auditor.md:110,173 asserts an /aif-verify gate that
     skills/getff/SKILL.md:128 denies — maintainer-owned, so D3 proposal only,
     reusing the replacement text S1 drafted in PR #1311's body.
- iii aif-version is read 0 times by deps-hash-check.sh (control deps-hash = 15)
     across 4 tracked files — an operator fork, explicitly parked, not resolved.

Also states why item i does not collide with §3's consumer-payload carve-out
(AI-USAGE-GUIDE.md *is* what S1 landed), and names a hazard neither sibling
kickoff covered: the 11 install baselines fingerprint both AI-USAGE-GUIDE.md and
six shipped skills SKILL.md paths, so S2 and S3 can collide on the generated
baseline surface that §5's source-file ownership split does not reach.

Acceptance item 8 makes all three non-droppable.

Prior-art: skipped — dispatch-input doc edit only, no new capability (markdown kickoff, no dependency, no module)

Co-authored-by: Test <test@example.com>
artyhoo pushed a commit that referenced this pull request Aug 9, 2026
Absorbs top-down (2 BLOCKER / 7 MAJOR / 6 MINOR) + bottom-up (1 BLOCKER /
3 MAJOR / 6 MINOR). Headline repairs: F4b re-scoped to sandbox PROBE (zero
hook edits reaffirmed; consumer-shipped surface + inverted billing fact
corrected — Agent-SDK credit at API rates, cost-GO gate added); ceiling
re-cut by decision OBJECT after the lane cut failed on corpus member
#1311.4 (v2 §4 floor clause explicitly superseded, pointer at landing);
SLP phases split NOW vs PART-II-GATED; three roles enumerated (/pipeline
= day seat by policy); rule-file gates added (Class B, paths channel,
principle-31 + index regen); all 6 relative links fixed to ../../../;
full disposition table inlined (§13, 23 findings).

Prior-art: skipped — design doc revision, no new capability.
artyhoo pushed a commit that referenced this pull request Aug 9, 2026
… cap

r2 verification: REVISE at cap, design spine verified sound (21/23 r1
dispositions DISCHARGED, both BLOCKERs closed, object cut re-tested cold
on three corpus members). All residue repaired in place: 4KB index ceiling
precondition billed (4088/4096 spent — free bytes before landing the new
rule); /pipeline night delta billed as the FOURTH policy surface; item 5
added to the night-mode item mapping; paths-channel labelling corrected to
principle-31 branch (a); seat-file vocabulary Part-II-gated in §2; floor-
dominates-stage-scope precedence added (§6, live case #1311.3); §7 chip
commitments billed in §10.5; §10 reordered [Part-I]-first so Part-I
extraction stays cheap. Dispositions inlined at §13b.

Prior-art: skipped — design doc revision, no new capability.
artyhoo added a commit that referenced this pull request Aug 9, 2026
…ecycle protocol (SLP) (#1346)

* docs(arch-prep): pipeline chips + session bus + context handoff — design-state handoff

Mid-contour /arch handoff: Parts 1/3/4 settled (chips, handoff policy with
operator-corrected thresholds, calibration research task), Part 2 (signal bus)
reopened for a value-rethink by operator directive. Continuation session
resumes via §0 protocol; this doc dogfoods the Part-3 residue mechanism.

* docs(arch): pipeline chips + session bus + context handoff — reviewed ADR + D9 kickoff

Part-2 bus rethink executed per prep-doc §0: friction inventory (6 relay
classes, live-probed evidence incl. F5 split verdict + 25-session ccd
topology) collapses the drafted 5-signal broadcast bus to ONE edge-pair —
the attended-day parked-question round-trip (D3-D5), with chips (D1-D2)
and the Stop-hook context-arm + PreCompact backstop (D6-D8) carrying the
rest. D9 calibration research kickoff authored (no bridge:auto marker by
design — dispatch only after staging merge).

* docs(arch): round-2 revision after cold two-altitude review — park-chip pivot

Round-1 verdicts: REVISE x2 (3 BLOCKER, 18 MAJOR combined). Load-bearing
changes: Part-2 transport pivots from a send_message bus to park-chips
riding the D1 chip channel (bus discovery is impossible — sessions cannot
self-title, schema-verified; night-local senders would re-admit the
wake-up cost; bursts are the observed park shape). D7 hardened (isSidechain
filter, model-keyed window table, F10 placement constraint, consumer-generic
wording, guarded TMPDIR). D8 reshaped to SSOT #108 hook-writes-residue form,
parked on the open #108 operator decision + bench-test. D9 kickoff gains its
bridge-profile marker (acceptance-contour rule is live) + K-pass station.
F3 downgraded to unverified (selection-conditioned statistic). SSOT consult
now cites #108/#121/#122/#230 by ID.

* docs(arch): round-2 delta findings applied — bounded fixes + two operator forks

All round-1 findings closed per both delta seats (BLOCKER 3/3, rest
resolved/accepted). Round-2 fixes: allowed-tools MCP adds DROPPED (would
turn principle 21 red — MCP_TOOL_RE rejects underscored ccd server names;
regex defect routed as separate owner issue); chip title/tldr contract
fits the 60-char cap; stage-gate resolved at click time not frozen;
principle-18 substring extension asserts the three chip gates; park-chip
emitter = dispatcher-only v1; seat line + venue-tier row in §4; D8
rescoped to the #108 PreCompact ITEM (composite row) with its own
liveness bench + named reader (pipeline §1 injection) + emitClaude path
(plugin output skips PreCompact); §2 park numbers corrected (7+1 of 30
substantive); F6 closed-moot, F9 (chip visibility/seat) added; F1 and
F10 restated as explicit operator forks. 2-round review cap reached —
remaining items are operator-facing by design.

* docs(arch-prep): session-bus v2 fresh-take handoff — membrane protocol

Operator read the round-2 explanation and re-opened Part 2 with three
counter-resolutions: (1) addressing inverts to an ID-cascade at spawn
(parents register children; the fresh-/arch handoff moment doubles as the
address-book handover), (2) night autonomy — the top-tier seat decides
parked strategic questions overnight, operator reviews in the morning
(deliberate control-model change superseding 'stay parked — never guess'),
(3) bursts accepted. Fresh Fable session designs from zero reading ONLY
§1; verified facts (§2 — incl. two NEW ones: self-ID via hook stdin
session_id, and no click-free session birth in the ccd toolset) + prior
takes (§3 digest) stay sealed until the Opus skeptic phase. ADR #1325
Parts 1/3/4 stand; D3-D5/§4/F1 re-opened.

* docs(arch): session-bus v2 — Phase-A from-zero draft (membrane-sealed)

Phase A of the v2 fresh-take protocol (arch-prep-session-bus-v2.md $0).
Author input: prep $0 + $1 ONLY. Sealed surfaces untouched at authoring
time: prep $2, prep $3, merged ADR Part-2 sections, branch git history.
All environmental assumptions tagged [A1]-[A10] and registered in $12
for the Phase-B fact-check; two cold mid-tier review seats follow per
arch/SKILL.md $2.

* docs(arch): session-bus v2 — Phase-B fact reconciliation

Opened prep $2-$5 (per protocol, after the pure draft landed as
42f8836) and corrected the draft against verified facts:
- [A4] resolved: self-ID via hook stdin session_id -> registry
  self-publish; root-seeding launcher magic dropped; [A3] moot.
- [A1]/[A2] resolved: delivery = user turn in running targets;
  night vehicle = operator-launched local session with pre-existing
  loop (cron-born sessions are messaging-blocked both ways).
- No programmatic session birth: day spawn = chip/paste; night
  topology fixed at lights-out; no chips inside the bus.
- aif workers messaging-blocked: dispatcher doorbells PARKED on
  observe; ANSWERED goes to local parkers only (bridge unpause is
  the workers' edge).
- Digest items absorbed: queue-not-interrupt, stale-target isRunning
  rule, venue-tier naming, answer.ts as the only rework channel,
  dispatcher $3 + night-mode delta-8 amended in the same change.
- Added old-ADR $4 scoring-row answers table; $12 rewritten as the
  fact register with citations + carried probes.

* docs(arch): session-bus v2 — r1 revision after two cold REVISE verdicts

Restructured into two separately-shippable parts:
- Part I: night-autonomy control model, bus-free (the return leg is
  already automatic via answer.ts unpause); THREE policy surfaces
  (dispatcher $3 row + night-mode delta items 1 AND 8); night
  artifacts REUSE <plan>.decisions.md + morning report; corpus-vs-
  envelope validation required before landing.
- Part II: doorbell overlay, probe-gated (P1 idle-wake, P2 night-loop
  arm-predicate extension, P3 isRunning stickiness).

Key corrections: self-ID-via-hook interpretation SUPERSEDED (hook
session_id and ccd local_<uuid> are disjoint namespaces, no join) --
addressing re-keyed to role->{cwd,branch} per-role files in the
coordination canon, resolved at send via list_sessions cwd-match;
ANSWERED reserved + workers.* dropped (empty recipient class);
grammar carries task=<task.id> only; executable claim reshaped to a
packages/ grep-gate; night latency claim downgraded until P1/P2.

Full finding-by-finding dispositions inlined in $14 (both reports).

* docs(arch): session-bus v2 — r2 repairs + operator split directive

Round-2 cold verification (REVISE) absorbed, finding-by-finding in
$14b. Key changes:
- P2 arm-predicate driver RETIRED (Stop hook cannot originate turns;
  global predicate = load-bearing; D7 owns the arm layout). Night leg
  now rests on P1 (idle-wake) and F4 (CLI spawn), both probes.
- Addressing: branch tiebreak dropped (live-stale 3/4, absent on
  repo-root); cwd-only exactly-one-match rule; seat-worktree
  invariant; liveness predicate removed; P4 join-verification is the
  Part-II entry condition; pagination bounded.
- Kill-switch: OFF tombstone (dir absence self-healed); seat writes
  gated by the same enable check.
- Part-I amendment reworded bus-free; arch $4 recorded as
  availability degradation, not reassignment; corpus gate carries the
  population-proxy caveat; grep-gate channel constrained outside
  packages/; SSOT consult marked nominal for this area.
- Operator mid-r2 directive recorded: night as several communicating
  self-respawning sessions -> F4 elevated to co-critical probe;
  positive F4 retires the T_soft defer-to-morning floor.

Review cap (2 rounds) reached -- routing fork with the operator.

* docs(arch): session-bus v2 — night continuation ladder (handoff vs compact)

Operator follow-up formalized: handoff and auto-compact fill the same
continuation slot; F4's outcome decides which fills it at night.
Rung 1: artifact-first recording makes either safe (state re-derivable
from seat file + questions.ts + decisions.md). Rung 2: Part-3 handoff
(ADR D6-D8, reused not re-opened) -- day always, night iff F4. Rung 3:
auto-compact in place with D8 PreCompact preservation + T_soft floor.
Probes P1/P4/F4 deferred to separate tasks per operator.

* docs(arch-prep): autonomous-night v3 handoff — /night-mode joins the seat design

Continuation handoff (not a membrane fresh-take): v2 spec stands
r2-repaired at the review cap. v3 scope per operator directives:
/night-mode designed into the four-skill architecture; all seats use
the bus; self-cleaning at a context cap; chips where needed;
maximally autonomous within the reversibility envelope. Carries the
unresolved Part-I routing fork, the probe register (P1/F4 co-critical),
and five open design questions.

* docs(arch): autonomous-night v3 design — night as mode, seat lifecycle protocol, ceiling

Phase-1 ideation output of the v3 contour (arch-prep-night-v3 §1 directives).
Part I of session-bus v2 folded in (routing decision §1.1). Night = MODE not
seat role (D-v3.1, operator-ratified); one seat-lifecycle SSOT + four pointers
(D-v3.2); self-cleaning bound to D6/D7/D9 with new probe recipe F4b (D-v3.3);
explicit autonomy ceiling reconciling v2 floor with night-mode item 8 (D-v3.4);
one new chip edge (morning report); zero new bus verbs; corpus-vs-envelope
validation run (25 entries, ~10/21 in-envelope — envelope stands).

Prior-art: skipped — design doc only, no new capability; sequencing of settled
in-repo mechanisms (ADR D6-D8, v2 §4-§9, night-mode/SDD).

* docs(arch): night-v3 r1 — repairs after two cold REVISE verdicts

Absorbs top-down (2 BLOCKER / 7 MAJOR / 6 MINOR) + bottom-up (1 BLOCKER /
3 MAJOR / 6 MINOR). Headline repairs: F4b re-scoped to sandbox PROBE (zero
hook edits reaffirmed; consumer-shipped surface + inverted billing fact
corrected — Agent-SDK credit at API rates, cost-GO gate added); ceiling
re-cut by decision OBJECT after the lane cut failed on corpus member
#1311.4 (v2 §4 floor clause explicitly superseded, pointer at landing);
SLP phases split NOW vs PART-II-GATED; three roles enumerated (/pipeline
= day seat by policy); rule-file gates added (Class B, paths channel,
principle-31 + index regen); all 6 relative links fixed to ../../../;
full disposition table inlined (§13, 23 findings).

Prior-art: skipped — design doc revision, no new capability.

* docs(arch): night-v3 r2 repairs — spec ROUND-2 REPAIRED at the review cap

r2 verification: REVISE at cap, design spine verified sound (21/23 r1
dispositions DISCHARGED, both BLOCKERs closed, object cut re-tested cold
on three corpus members). All residue repaired in place: 4KB index ceiling
precondition billed (4088/4096 spent — free bytes before landing the new
rule); /pipeline night delta billed as the FOURTH policy surface; item 5
added to the night-mode item mapping; paths-channel labelling corrected to
principle-31 branch (a); seat-file vocabulary Part-II-gated in §2; floor-
dominates-stage-scope precedence added (§6, live case #1311.3); §7 chip
commitments billed in §10.5; §10 reordered [Part-I]-first so Part-I
extraction stays cheap. Dispositions inlined at §13b.

Prior-art: skipped — design doc revision, no new capability.

* docs(arch): night-v3 post-cap absorptions — billing fact live-verified, F4b audience directive

Two operator inputs after the review cap (fact/directive absorption, no
design re-opening): (1) billing re-verified against official sources —
the announced 2026-06-15 separate Agent-SDK credit pool was PAUSED on its
effective date; claude -p / Agent SDK draw from the subscription pool;
r1's memory-based correction and the underlying memory record were both
stale; cost-GO gate retired, re-open falsifier recorded. (2) F4b landing
audience decided: consumer-shipped self-cleaning autonomy is the product
intent (operator directive quoted); engineering guards non-negotiable;
F10 wording fork still closes formally at S2a. Dispositions in §13b.

Prior-art: skipped — design doc fact refresh, no new capability.

* docs(autonomous-night-v3): Phase C — Part-I night envelope + seat lifecycle protocol

Lands the v3 spec §10 work list (docs/superpowers/specs/2026-08-09-autonomous-night-v3-design.md):

- [Part-I] four policy surfaces in ONE change: dispatcher §3 Night cell
  (bus-free wording, v2 NEW-M1), night-mode delta items 1+8 (night-envelope
  conditional, §6 object cut, ambiguous-object→floor tie rule, decisions.md
  entry-shape extension), pipeline night delta (no new-scope planning at
  night); night-mode also gains the §5 seat-class item mapping sentence.
- [Part-I] morning report: «bus anomalies» section + night-decided parks
  listing + night-end chip paragraph + best-effort dismiss_task note.
- [Part-I] supersession pointer at the v2 §4 floor clause («merges into
  shared branches») → v3 §6 object cut; all other floor items unchanged.
- [v3] new .claude/rules/seat-lifecycle.md (SLP) — Class B, paths: channel
  (principle 31 branch (a)) over the four seat-architecture SKILL.md files;
  four 3-5-line pointer blocks; compensating grep check at
  packages/core/skills/seat-lifecycle-pointer.test.ts.
- [v3] rule-index bytes freed first (4088/4096 → 4070 after adding the row):
  trimmed three verbose Fires: lines (git-conflict-merge-forward,
  evidence-regeneration, zcode-parity-doctrine) per the renderer's stated
  remedy; index + AGENTS.md region regenerated.
- [v3] v2 §13 F4 probe entry extended: F4a+F4b as PROBES with the v3 §4
  checks incl. the live-verified subscription-pool billing fact; cost-GO
  gate retired. Zero hook edits anywhere in this change.

Prior-art: skipped — doc/discipline artifacts + one suite test only; no new dependency, no ≥80-LOC file under packages/, no new capability.
§1.7: forward+backward applied (full sections in PR body); cold backward sweep GO — pointer parity asserted at packages/core/skills/seat-lifecycle-pointer.test.ts:19; channel declaration per packages/core/principles/31-rule-channel-declaration.ts:1

---------

Co-authored-by: Test <test@example.com>
artyhoo added a commit that referenced this pull request Aug 17, 2026
…d, 5 sequential stages, BS-pre routing resolved (#1415)

Generated by `/pipeline beta-docs-showcase`. The umbrella's binding Dispatch gate is
now green: A7 (beta-delivery-ux S5, PR #1285) merged 2026-08-07 and its artifact is on
staging (`packages/runtime-bridge/vendor/**` + `setup.d/55-runtime-bridge-vendor.sh`),
so B is no longer blocked-pending-neighbor.

Three blocked-pending items were re-probed rather than carried forward from the design's
snapshot, and one of them changes a stage's scope:

- A1 profile names — RESOLVED: they ship as data in
  `packages/core/templates/shared/first-steps.source.json`.
- A3 tier-home — RESOLVED: `packages/core/templates/shared/tier-home.md` is on staging.
- C1 First-Steps SSOT — LANDED (PR #1311, 2026-08-08). Per the B-D5 AMENDED clause,
  **BS2 now CONSUMES the SSOT instead of authoring it**.

`claims-conformance-auditor` is NOT shipped (umbrella C has no done.md), so BS3 uses the
design's own named fallback: a compliance-verifier-class cold run over the BS2 ledger.

§1.1 records a destination probe rather than an inference: `docker inspect` shows the aif
container mounts only `/Users/art/code/aif-handoff/projects`, and the `/projects` API
returns two projects — neither is `getff-landing`. That made BS-pre's routing a genuine
fork (§D-1), answered by the operator on 2026-08-17 as Option A: BS-pre runs host-side;
the «no CC-limit spend on B» directive scopes B's five content stages, and the exemption
does not widen to BS0-BS3.

All five stages are sequential by declaration (`parallel_safe = FALSE`) — each stage's
gate is the next stage's dependency and BS0 is a STOP-gate whose failure retires the
stack to a Starlight rollback.

Verified on this host: `npx vitest run packages/core/principles/12-ai-laziness-traps.test.ts`
-> 9/9 pass.

Prior-art: skipped — dispatch-input kickoff generated by an existing skill; no new capability, no new dependency, no new module.

Co-authored-by: Test <test@example.com>
artyhoo added a commit that referenced this pull request Aug 17, 2026
…t's measured rates (#1429)

## Summary

advisor-pattern-design §8 item 7: the budget-tripwire mechanism shipped with item 2, but its numbers were deferred to calibration from the review-effort-theatre audit (chip `task_c8cfb806`). This lands them as a config block at `reviewer-discipline.md` §6.2 — every number citing the audit rate it derives from — and closes the dangling pointer in `effort-worthiness.md` §5. The L4 semantic is untouched: a breach forces an ASK to the concept holder, never a guillotine.

## Changes

- **`.claude/rules/reviewer-discipline.md` new §6.2** — the calibrated L4 round-budget config: a five-row lane table (two budgets, three explicit non-budgets), the «why 3 and not 2» derivation, reconciliation with the three convergence caps, a precedence rule for contour-declared budgets, the `corpus-derived, uncalibrated` provenance label, both D-AP6 falsifiers, and an honestly-scoped observable note.
- **`.claude/rules/reviewer-discipline.md:7`** — doc-authority header extended to name §6.2.
- **`.claude/rules/effort-worthiness.md:109-112`** — §5's «never hard-coded here» sentence now names the config home. Statute text (§2 L4) untouched, per its own «numbers are config, not statute».

### The numbers and their derivation

All line refs below are into `docs/meta-factory/research-patches/2026-08-10-review-effort-theatre-audit.md`.

| Lane | Budget | Derivation |
| --- | --- | --- |
| Cumulative rounds per stage | **3** (ASK before round 4) | Final-round distribution `:44-46` = {1,1,2,2,2,2,3,3,3,5,6,7} → 9/12 loops close at ≤3, so the ASK trips on 3/12 (25%). The audit proposes the same number at `:326`. |
| Follow-up finding-closure PRs per stage | **1** | 3 in the window `:212-215`; the only loop exceeding 1 is exactly the one whose follow-ups closed *only* immaterial findings `:129-131`, against `:137` where the single-PR case closed four material items. |
| GO-with-findings → SHA-move → re-audit | **none, by design** | `:242` + acceptance-contour `:93` — capping it makes any PR that accepts review feedback unmergeable by construction. |
| Notes-lane / watch-list size | **none, deliberate** | `:221-223` — measured (8–11 rows) but not a round-shaped surface. |
| Tokens | **none at v1** | `effort-worthiness.md` §2 L4 «rounds only at v1 — tokens have no measurement surface yet». |

Why not 2: it trips on 6 of 12 loops (`:47`), and #1311's rounds 3-5 each caught a real defect that a hard 2-cap would have shipped (`:274-275`).

## Placement rationale

`reviewer-discipline.md` §6.2, not a new file:

- No rule→config-file convention exists — `grep -rniE "config (file|block|section)|numbers are config" .claude/rules/*.md` returns zero hits.
- `.claude/rules/00-rule-index.md` is **4092/4096 bytes**; a new rule file needs an index row that does not fit.
- `reviewer-discipline.md:58` declares §6 «the operating SSOT for review protocols», and §6.1 is the exact structural precedent — measured numbers plus per-item provenance labels as a §6.x subsection.
- `effort-worthiness.md`'s own header declares it NOT authoritative for reviewer grammar, pointing here.

`reviewer-discipline.md` is maintainer-owned; this operator-directed landing is the explicit handoff, same shape as the #1374 / #1405 precedent.

## Prior-art consult

- [x] The single commit carries `Prior-art: skipped — calibration numbers from measured audit rates, no new capability` — markdown-only diff, no new dependency, no `packages/` code, no new directory.
- [x] No new capability area surfaced, so no SSOT entry is due. The prior-art pass for this rule family already ran and is recorded at `.claude/rules/effort-worthiness.md` §4 (Conventional Comments, Google eng-practices, Bezos type-1/type-2, CBR indexing problem, Kanban WIP limits). These are that mechanism's numbers, not a new mechanism.
- [ ] n/a — no existing SSOT entries matched.
- [ ] n/a — context7 does not apply to a calibration-numbers commit.

## Test plan

- [x] `npx vitest run packages/core/principles/` — 42 files, 401 passed, 1 skipped
- [x] `npx markdownlint-cli2` on both edited files — 0 errors
- [x] `npx tsx scripts/render-rule-index.mjs --write` — no index drift (`00-rule-index.md` and `AGENTS.md` unchanged afterwards)
- [x] Pre-push full gate suite green on push — backends 274, composition 46, link check 44 OK / 0 errors, always-on 38993B within the 54000B ceiling
- [x] All 10 relative link targets verified to exist on disk
- [x] Install-snapshot regen NOT required — verified `tests/install-sh/baselines/**` carries zero `.claude/rules` entries, so the content hashes are out of the fingerprint's scope
- [x] Prettier deliberately NOT run: `.claude/rules/reviewer-discipline.md` is already prettier-dirty at HEAD (`*em*`→`_em_` inside §6.1, landed by #1405), and prettier gates only shipped consumer artifacts, not `.claude/rules/**` — `--write` would add ~40 lines of unrelated churn to a single-concern PR

## Provenance

n/a — non-stage PR.

## Review findings

n/a — non-stage PR. Own cold QA (T19) was run against the source rather than against the draft: all 20 numeric and citation claims were re-read line-by-line in the research patch, which caught two of my own errors before commit — the `~80–185k` token figure sits at `:217`, not `:218`, and `2026-08-10-triage-kernel-v2-design.md:402` sets S0 to **1** round, so the spec declares 1–2 rounds per stage, not a uniform 2.

## Fidelity verdict

FIDELITY: skipped — docs/config-only change with no kickoff or spec stage behind it

## Parked questions

n/a — non-stage PR.

## §1.7 Self-discipline check

### §1.7 Forward-check applied

Checked against every currently-active layer this change can touch:

- **doc-authority** ([doc-authority-hierarchy.md §3](.claude/rules/doc-authority-hierarchy.md)) — the Authoritative-for line at `.claude/rules/reviewer-discipline.md:7` was extended to name §6.2; the `Class: C` field is unchanged and still correct, since this adds config to a prose rule and ships no mechanism. Principle 09 green.
- **channel selection** ([rule-enforcement-channel-selection.md §3](.claude/rules/rule-enforcement-channel-selection.md)) — no new channel is claimed: §6.2 rides the rule's existing marker at `.claude/rules/reviewer-discipline.md:3`. Principle 31 green (58 tests across principles 09 and 31).
- **attention-is-not-a-mechanism** ([§1](.claude/rules/attention-is-not-a-mechanism.md)) — §6.2's closing paragraph names the breach consumer as the advisor ASK, a named protocol, and *admits* the v1 gap that the cumulative count is seat-tracked, because `packages/core/hooks/checks/pr-body-fidelity.ts:55` only makes the per-PR `Round:` syntactic. The gap is carried as falsifier (b) rather than hidden behind «the seat will notice».
- **no-paid-llm-in-ci** — nothing was added to CI; the config is read by seats at review time.
- **capability-commit gate** ([CLAUDE.md](CLAUDE.md)) — markdown-only diff, and `*.md` files never count under the documentation carve-out; no `packages/` change exists. The escape-hatch trailer is present with a 62-char rationale.
- **effort-worthiness applied to itself** — the four-test card was run on this task before starting: material (a named spec-residue item), not theatre (the number changes what a seat does at round 4), and reversible, so `build-and-verify` — no probe or extra round was demanded.

### §1.7 Backward-check applied

Class of this change = **an ASK-trigger threshold living as config outside the statute that mandates it**. The complete surface set was enumerated mechanically with `git grep -nE "(→|->) *ASK|stop and ASK|forces an ASK|escalates via ASK|Ceiling: *[0-9]|cap +\*{0,2}[0-9]"` over `.claude/rules/*.md`, `.claude/skills/*/SKILL.md`, `agents/*.md` and `docs/superpowers/specs/*.md` — nine surfaces, none of which are files this PR touches:

- `.claude/skills/dispatcher/SKILL.md:327` — **SWEPT-CLEAN.** A numberless embed («a round-budget breach escalates via ASK») pointing at `effort-worthiness.md`, whose §5 now terminates at §6.2. Two-hop reach with zero copied number, so no `#sync-by-copy-paste` surface is created.
- `.claude/skills/night-mode/SKILL.md:40` — **SWEPT-CLEAN.** Same numberless shape, same now-closed pointer chain.
- `.claude/skills/arch/SKILL.md:94` (2 REVISE) · `.claude/skills/harvest/SKILL.md:80` (2 rounds) · `.claude/skills/dispatcher/SKILL.md:194` (D6, 2 consecutive REVISE) · `.claude/skills/night-mode/SKILL.md:44` (fidelity rework, 2) · `docs/superpowers/specs/2026-07-23-acceptance-contour-design.md:83` — **SWEPT-CLEAN, GAP PRE-EMPTED.** These are convergence caps on a counter that resets on GO or scope change, whereas the new budget is cumulative and never resets. They are left unedited by design, and §6.2 states the reconciliation explicitly so a reader who meets «3» here and «2» there has a resolution rule instead of an apparent contradiction. #1341 — seven rounds with D6 never firing (audit `:243`) — is the proof they count different things.
- `docs/superpowers/specs/2026-08-10-triage-kernel-v2-design.md:402-407` — **GAP-FOUND → CLOSED.** A live contour declares tighter per-stage budgets (S0 «1 round → ASK», S1-S5 «2 rounds → ASK»). Without a precedence rule that is a second, conflicting number with no way to resolve it. Closed by §6.2's Precedence paragraph: a contour-declared budget wins for its own stages, and the table is the default rather than a floor. This surface also corrected the draft, which had mis-stated the spec as a uniform «2».
- `docs/superpowers/specs/2026-07-23-acceptance-contour-design.md:141` — **SWEPT-CLEAN.** The aif in-container review cap (`env.ts:113` knob, 3→5) is a different substrate, is already capped, and was measured non-concentrating by the same audit (`:55-60` — 9 of 209 tasks with `reviewIterationCount > 0`).
- `.claude/orchestrator-prompts/triage-kernel-v2/kickoff-s4b.md:212` («Ceiling: 5 such rows», then ASK) — **RECORDED, DELIBERATELY UNEDITED.** A legitimate L4 instantiation at a non-round surface inside a closed umbrella; per [CLAUDE.md Artifact Ownership](CLAUDE.md) a closed umbrella's kickoffs are read-only for subsequent sessions. It is also the evidence that motivated the Precedence rule at all: L4 numbers were already being invented per-kickoff, which is precisely the drift a default config stops.

Exemption mechanism: the Precedence paragraph *is* the exemption — a contour declaring its own budget is exempt from the default by its own declaration, in the doc. No glob or sentinel is needed because the scope is prose-delivered (Class C). No meta-test is added, and that is deliberate: per [attention-is-not-a-mechanism.md §1](.claude/rules/attention-is-not-a-mechanism.md) the consumer here is a named protocol (the advisor ASK), and per `.claude/rules/effort-worthiness.md:70` the mechanical arms for L4 — ask-file schema validity and the L0 label presence check — are separately-owned landing items (advisor-spec §8 items 6 and 6b), not this one.

Prior-art: skipped — calibration numbers from measured audit rates, no new capability
artyhoo added a commit that referenced this pull request Sep 1, 2026
…1550)

* docs(s3-c5): D1 derivable-prose population inventory + entry re-verification

19 rows / 5 classes; enumeration strictly BEFORE migration (T5/T10).
Findings: presets row trigger fired (MIGRATE-now), INSTALL-FOR-AI rosters
derivable from setup.d manifest (MIGRATE-now x2), README count claims live-
drifted (20 hooks vs measured 21; 8 agents vs shipped 10 -> PROPOSE-to-owner),
aif-version population drifted 4 -> 6 files (P-2 park stands). T7 counter-
prompt run cold, non-empty; T15 self-application section present.

* feat(docs-gen): INSTALL-FOR-AI install-roster → getff:begin generated section + drift gate

S3 D2 (beta-ai-docs-agnosticism), inventory row B1: the «This installs» roster
(INSTALL-FOR-AI.md:76-96) becomes a getff:begin generated section rendered from
the installer manifests (setup.d/20-agents.sh skip-list + factory-gated pair,
setup.d/10-skills.sh cp-literals, setup.d/lib.sh GETFF_SKILLS_* constants).
Drift gate: scripts/render-install-roster.mjs --check (write/check modes,
render-rule-index.mjs pattern), wired into audit-self.yml manifest-render-check.
Caveat prose (KEEP-AIF notes, --profile core) preserved outside the fence (T17).
Inventory B2 verdict revised MIGRATE-now → STAYS-PROSE with owner+trigger
(§7 addendum: tree sits inside a ```text block + annotation-bearing judgment).

Prior-art: prior-art-evaluations.md#208 (deterministic digest renderer — same
render-rule-index/fence.ts pattern extended to a second source class; fence.ts
reused verbatim, zero new fence logic).

* feat(docs-gen): AI-USAGE-GUIDE §6a Launch presets → getff:begin rendered from shipped preset data

S3 D2+D5(i) (beta-ai-docs-agnosticism), inventory row A3: the §6 honesty-table
row «Launch presets … not shipped … this guide gains a §Presets rendered from the
shipped preset data» had its own trigger fire (beta-delivery-ux S2 merged, presets
on disk) — the row leaves the not-shipped table and the promised section lands as
a generated one. Renderer scripts/render-presets.mjs parses
.claude/skills/pipeline/references/presets/*.json (same source list-presets.sh
reads; line shape mirrors its output), writes the `pipeline-presets` fence via the
shared fence.ts machinery. Drift gate --check wired into audit-self.yml.
Baselines: 11 install fingerprints regenerated (SNAPSHOT_MODE=capture); audited
diff = only .ai-factory/AI-USAGE-GUIDE.md + .ai-factory/refresh-baseline.json
hashes; SNAPSHOT_MODE=compare 15/15 pass.

Prior-art: prior-art-evaluations.md#208 + #203/#204 (same render/--check +
marker-region drift-gate family — fence.ts reused verbatim, zero new fence logic).

* feat(agents): claims-conformance-auditor — cold docs-claims vs shipped-reality auditor

S3 D4 (beta-ai-docs-agnosticism, spec C5 r3 + §8): the named cold auditor the
assembly gate runs over docs-site claims (compliance-verifier class agents/*.md;
attention-is-not-a-mechanism §1 — checklist is merge authority, agent is the
detection layer). Cold-by-construction dispatch, claim taxonomy, per-claim
VERIFIED/GAP/UNVERIFIABLE with T3 evidence, GO/REVISE/STOP output grammar,
promotion trigger = spec §6 falsifier (repeated claim drift → deterministic check).
tools: line = harness-universal only (principle 21 green: 14/14).
Acceptance dry-run over README.md executed cold (56 claims: 47 VERIFIED / 6 GAP /
3 UNVERIFIABLE) — output pasted in the stage PR body; GAP rows are maintainer-owned
README drift → routed to the D3 proposal, never direct-edited here.

Prior-art: prior-art-evaluations.md#228 (fidelity-auditor class — session-bound
cold agent under no-paid-llm-in-ci; shape precedents compliance-verifier +
backward-sweep-auditor reused, protocol novel to the claims-taxonomy slice).

* S3 D3: owner-gated proposals (P1 zcode rollup renderer, P2 living-docs, P3 README) + install-roster regen

P1 ships scripts/render-zcode-parity-rollup.mjs — PROPOSAL renderer for the
zcode-parity-doctrine §2 derivable rollup (hook population / plugin twins /
classification counts; per-row rationale stays prose per the D7 falsifier).
--check refuses (exit 2) until the maintainer lands the target fence, so a
premature CI wiring fails loud, never silently green. Verified: --emit parses
21/21 census rows (escaped-pipe-aware + §2-scoped), rollup matches the hand
count at doctrine:65; plugin twins 15 of 21.

P2 (living-docs-auditor /aif-verify contradiction) and P3 (README claim drift
from the cold-auditor dry-run: agent count, ESLint major, husky/depcruise
wiring steps, probeR4 pass-vs-warn, Wave B status, hook count) are evidence
tables awaiting maintainer sign-off — zero direct edits to owner-gated paths.

INSTALL-FOR-AI.md roster regenerated after claims-conformance-auditor.md
landed (10 → 11 shipped agents) — the drift gate caught the same-PR change,
which is the live discrimination proof for this stage's D2.

* fix(s3-c5): cold-QA/fidelity round-1 findings — fail-loud roster guard + P3 ESLint retraction

Cold-audit rework (T19/T21 + fidelity Round 1, 2026-09-01):
- render-install-roster.mjs: zero-match skip-list now throws (fail-loud) instead of
  silently rendering ALL agents as shipped if setup.d/20-agents.sh is restructured.
- owner-proposals patch: P3 ESLint row RETRACTED — README:30 "ESLint 10 flat config" is
  correct (packages/core/package.json:94 "eslint": "^10.4.0"; root package.json has no
  eslint key; the dry-run's quoted probe was unreproducible). 6 GAP rows -> 5 actionable.
- same patch: "three S3 gates" -> two (render-rule-index/render-rules predate S3).

Fidelity Round-1 MAJOR (kickoff host-verify runner lines) is NOT discharged here:
the kickoff edit is harness-classifier-blocked for this session (sensitive file) —
stays as park P-KICKOFF for operator egress.

* fix(s3-c5): rework round-1 — sweep rows, prettier, baselines, P1 scope reconciliation

- wire install-roster-check + presets-check into run-local-ci-sweep.sh gate_table
  (coverage test PASS=9 FAIL=0; closes the two unwired CI commands)
- prettier-canonical output: format auditor + AI-USAGE-GUIDE; render-presets now
  emits prettier-canonical fence bodies (blank lines around the bullet list) so
  --check stays green after format:check
- re-capture 11 install baselines on the final tree (new claims-conformance-auditor
  ship line + prettierignore + guide hash); diff audited — only expected line-classes;
  byte-identical compare 15/15
- P1 scope reconciliation (fidelity MAJOR): owner-proposals §P1 now states the narrow
  scope explicitly — §2 rollup counts convert; §2 Status col judgment-bearing (D7
  falsifier, :61/:62 quoted); §3 table PARKED under §6 with Option A/B; inventory row
  A2 + §8 addendum made verbatim-consistent with P1
- P2 P-GH park resolved: S1's replacement wording carried verbatim from PR #1311 body
  (parked question 3), provenance recorded; still proposal-only (zero owner edits)

Prior-art: skipped — rework round 1: gate-table wiring + formatting + baseline regen + proposal scope reconciliation; no new capability

* docs(kickoff-s3): host-verify runner lines for the two S3 drift gates (W-1, coordinator host-side — container Edit on kickoffs is classifier-blocked)

* docs(s3-c5): owner-proposals patch — principle 10 scope slug + principle 13 §1.7 self-application section (pre-push meta-tests)

* docs(s3-c5): owner-proposals §1.7 — correct the P1 renderer reuse claim (no fence.ts import until the fence lands; round-3 fidelity note)

---------

Co-authored-by: Test <test@example.com>
artyhoo added a commit that referenced this pull request Sep 2, 2026
## Summary

S4 of the `beta-ai-docs-agnosticism` umbrella (spec C4). An AI harness that has never seen this repo can now find its documentation through the channel agents actually query: a committed `context7.json` controls what Context7 ingests and pushes this project's discipline rules into agent-facing snippets, and a push-triggered workflow re-indexes deterministically instead of waiting on popularity-driven refresh. DeepWiki stays a secondary, acknowledged-stale channel. `llms.txt` for the repo is **not** added — that decision is recorded below, not re-litigated.

The two outward-facing legs — submitting the repo to Context7 and creating the `CONTEXT7_API_KEY` secret — are **maintainer-only** (kickoff §2 D4) and are NOT performed here. Their ready-to-run package is in «Maintainer legs» below, and the honest consequence is stated in «Acceptance», item 4.

## Changes

Four commits: the deliverable, then three corrective commits, one per cold-review finding set. The rework is left in the history on purpose — each fix commit names the finding that produced it.

- **`context7.json`** (new, repo root). Schema fields adopted verbatim from upstream, never invented. `branch: "staging"` per `kickoff-s4.decisions.md` Decision 1. `excludeFolders` drops factory-internal process trees and generated twins; two rows are PARKED rather than guessed (census below). `rules` carries nine imperative POINTERS into `.claude/rules/*`, `CLAUDE.md`, `README.md` and `INSTALL-FOR-AI.md` — no entry carries a threshold, a count, or a definition, so none is a second copy of a rule's substance.
- **`.github/workflows/context7-refresh.yml`** (new). Upstream's documented `curl` step; `on: push: branches: [staging]`; one job, one step; `permissions: contents: read` at both levels; `env:` indirection instead of `${{ … }}` inside `run:`; loud failure on a missing key or a non-2xx refresh.
- **`docs/meta-factory/prior-art-evaluations.md`** — one appended row, id **264**, with `Verdict` / `Rationale` / `Trigger to revisit`. The diff on this file is `1 file changed, 1 insertion(+)`; its first commit carries the `Prior-art:` trailer.

`git diff --name-only origin/staging...HEAD`:

```
.github/workflows/context7-refresh.yml
context7.json
docs/meta-factory/prior-art-evaluations.md
```

No maintainer-owned path and no `.claude/rules/*` path is touched (acceptance item 8).

## Stage gate — the kickoff's literal search is EMPTY, and the gate is still green

The kickoff asks for two searches at entry. Both return `[]`:

```
gh pr list --search "is:merged head:beta-c-s2-skills-probe base:staging" --json number,mergedAt   → []
gh pr list --search "is:merged head:beta-c-s3-selfgen-docs base:staging" --json number,mergedAt   → []
```

That is a **branch-naming artifact, not an open gate**: S2 and S3 were dispatched through the aif runtime, so they landed under aif-generated head names rather than the head names the kickoff predicted. Verified by substance instead:

```
7534fd9 feat(beta-ai-docs-agnosticism): S3 — self-generating docs sweep (C5) (#1550)   ANCESTOR-OF-STAGING: yes
ee0ccfe feat(beta-ai-docs-agnosticism): S2 — skills agnosticism probe (C3) (#1552)     ANCESTOR-OF-STAGING: yes
```

(`git merge-base --is-ancestor <sha> origin/staging` for each.) Actual head names: `feature/beta-ai-docs-agnosticism-fc864f` (#1550) and `feature/beta-ai-docs-agnosticism-5bb3da-s17` (#1552). **Follow-up observation, not fixed here:** the meta-launch §3 gate greps predicted head names, so an aif-dispatched stage can satisfy the gate in substance while failing it literally.

## Entry re-verification (kickoff §1) — measured now, not inherited

| # | Kickoff's claim at authoring | Re-verified 2026-09-02 | Verdict |
|---|---|---|---|
| 1 | remote is `artyhoo/getff`, PUBLIC, default `staging` | `gh repo view` → `{"defaultBranchRef":{"name":"staging"},"isPrivate":false,"name":"getff","visibility":"PUBLIC"}` | HOLDS |
| 2 | repo NOT indexed | `resolve-library-id(libraryName: "getff")` → `/vashongithub/getfamafrenchfactors`, `/live-image-tracking-tools/geff`, `/websites/getfluxy_vercel_app`, `/websites/getfoundry_sh`, `/websites/developer_getfly_vn_6_1` — no `/artyhoo/getff` | HOLDS |
| 3 | no `context7.json`, no `llms.txt` | `ls context7.json llms.txt .llms.txt` → three `No such file or directory` | HOLDS |
| 4 | no marketplace action; upstream ships a `curl` snippet | Re-retrieved at writing time via context7 MCP: `docs/integrations/github-actions.mdx` (path confirmed live, `gh api repos/upstash/context7/contents/docs/integrations`). WebSearch surfaced only the third-party `rennf93/upsert-context7`; no first-party action | HOLDS |
| 5 | `CONTEXT7_API_KEY` does not exist | `grep -rn 'CONTEXT7' .github/` → exit 1, no output | HOLDS |
| 6 | «Every job in a standalone workflow file must declare `# required-context:`» | **CORRECTED.** Principle 37's declarable population is `prTriggeredWorkflows` only — `packages/core/principles/37-required-context-completeness.test.ts:282` (`declarableJobs` iterates it). This workflow has no `pull_request:` trigger, so the gate never parses it. The marker is written anyway as a declaration of intent, and it is well-formed: applying the principle's own regex, extracted from source rather than retyped, to `.github/workflows/context7-refresh.yml:26` yields `required = no`, rationale length 66 (floor is 20) | NARROWER THAN CLAIMED |
| 7 | 12 workflows; workflow-integrity fires on workflow edits; actionlint + zizmor in audit-self | `ls .github/workflows/` → 12 files; `.github/workflows/workflow-integrity.yml:9` (`- '.github/workflows/**'` under its `pull_request:` trigger) | HOLDS |
| 8 | highest SSOT id 263 | `grep -cE '^\| [0-9]+ \|'` → 263 rows, max id 263. New row is **264** | HOLDS |

In-flight probe at entry: `SLUG=beta-ai-docs-agnosticism bash .claude/skills/dispatcher/helpers/probe-inflight.sh` → `VERDICT: DONE-UNHARVESTED`, naming tasks `742d85ba` and `5bb3da8a`. Both **superseded, not loose**: `742d85ba`'s branch head is `4f68ed560a`, a commit already merged to staging (zero own commits ahead), and `5bb3da8a`'s work is PR #1552, harvested under the renamed head `…-5bb3da-s17` which the probe cannot match. No S4 branch, PR, or container branch exists.

## `excludeFolders` — population census BEFORE selection (T10)

Two tables: every tracked **top-level** entry, then the **sub-tree** exclusions. Counts from `git ls-files`. Rows marked **PARKED** are rows I could not verdict from evidence, so the directory stays indexed — kickoff §6's reversible branch.

### Top-level entries

| Top-level entry | files / md | Verdict | Reason |
|---|---|---|---|
| `node_modules` (also `**/node_modules`) | 1 tracked / 0 md | **EXCLUDE** | dependency trees. The single tracked path is a fixture stub, `packages/core/research/fixtures/tier1-single-root/node_modules/drizzle-orm/package.json`. Both the bare name and the depth glob are listed because upstream's two docs disagree on whether a bare name matches at any depth; under either reading nothing with documentation value is lost here, which is why this is the one row where the redundancy is safe |
| `.claude/worktrees` | 0 / 0 | **EXCLUDE** | gitignored operator worktrees (`.gitignore:82`); zero tracked files. Defensive row so a local checkout's worktrees cannot leak into an index |
| `.claude` (rest: `rules` 30, `skills` 94, `hooks` 24, `templates` 1) | — | keep | `.claude/rules/*` is the discipline corpus the `rules` array points AT; excluding it would break every pointer |
| `.github` | 14 / 1 | **EXCLUDE** | CI configuration. Its one markdown file is `.github/pull_request_template.md`, whose guidance is already carried by the indexed `CONTRIBUTING.md`. No nested `.github/` tree exists, so the bare name is unambiguous |
| `.husky` | 3 / 0 | **EXCLUDE** | git hook shims, zero markdown; no nested `.husky/` tree exists |
| `scripts` | 61 / 0 | **EXCLUDE** | shell sources, zero markdown. The one nested `scripts/` tree, `packages/runtime-bridge/scripts/`, is four shell files with zero markdown — so the bare-name ambiguity is verdicted inert here rather than assumed away. Mirrors upstream's own `"excludeFolders": ["src"]` example |
| `plugin/agents` + `plugin/skills/getff` | 9 md of the tree's 13 | **EXCLUDE (narrowed)** | measured by blob equality (`git ls-files -s`), not asserted: only THREE of the 13 markdown files under `plugin/` are byte-identical twins — the `plugin/agents/*` copies of `agents/compliance-verifier.md`, `living-docs-auditor.md`, `review-sidecar.md`. Six under `plugin/skills/getff/` are NEAR-twins of `skills/getff/` that differ in substance, not only link depth, so indexing them would serve agents the stale copy. The row was originally the bare name `plugin`; that hid four documents with no counterpart anywhere in the tree, so it was narrowed |
| `plugin` (the other four files) | 4 md | keep | `plugin/README.md`, `plugin/commands/install-enforcement.md`, `plugin/skills/using-getff/SKILL.md`, `plugin/skills/installing-enforcement/SKILL.md` — no counterpart in the tree, and the last two are consumer-facing skills describing how to activate the plugin and how to wire the hard enforcement layer. Exactly the «how do I use this» content §0 exists to surface |
| `templates` | 9 / 0 | **PARKED — left indexed** | the bare name is dangerous. If Context7's «simple names» mode matches at any depth, `templates` would also drop 13 nested markdown files including `packages/core/templates/shared/AI-USAGE-GUIDE.md` and `tier-home.md` — the shipped consumer docs this stage exists to make findable. Upstream's own docs disagree on the semantics, so the row is parked and the (markdown-free) root `templates/` stays indexed. Cost of parking: nine config files with zero markdown |
| `package-lock.json` | 1 file | **EXCLUDE** (`excludeFiles`) | lockfile |
| `.ai-factory` | 4 / 0 | keep | four small JSON capability/degradation records an agent may legitimately read |
| `.claude-plugin` | 1 / 0 | keep | one manifest; nothing gained by excluding it |
| `.opencode` | 1 / 1 | keep | `INSTALL.md` for a non-CC harness — the agnosticism surface, exactly the audience |
| `agents` | 20 / 20 | keep | consumer-facing agent definitions |
| `demo` | 6 / 1 | keep | small; `demo/README.md` explains the two gate demos README links |
| `docs` | 488 / 448 | keep, minus four sub-trees | see the second table |
| `packages` | 871 / 44 | keep | the shipped consumer docs live here — `packages/core/templates/shared/AI-USAGE-GUIDE.md`, `AGENTS.md.template`, `tier-home.md`. Excluding the tree to drop TypeScript noise would drop those with it |
| `skills` | 9 / 8 | keep | shipped skills |
| `tests` | 180 / 13 | keep, minus `install-sh/baselines` | for a «rules as tests» project the tests are part of the claim |
| root markdown (`README`, `INSTALL`, `INSTALL-FOR-AI`, `CONTRIBUTING`, `AGENTS`, `CLAUDE`, `AUDIT-*`, `LICENSE`) | — | keep | the primary answer to «what is this and how do I use it» |

### Sub-tree exclusions

| Sub-tree | tracked md | Verdict | Reason |
|---|---|---|---|
| `.claude/orchestrator-prompts` | 650 | **EXCLUDE** | per-umbrella internal dispatch kickoffs and closure markers — factory process with no consumer surface, and the largest markdown tree in the repo |
| `docs/meta-factory/research-patches` | 247 | **EXCLUDE** | append-only one-patch-per-gap records; `lychee.toml:33` declares them knowingly stale, «link rot in them is expected archaeology, not showcase drift» |
| `docs/meta-factory/retros` | 26 | **EXCLUDE** | `CLAUDE.md:76` marks them «closed historical artifact post-merge», read-only for all subsequent sessions |
| `docs/meta-factory/generator-forbid-mvp` | 6 | **EXCLUDE** | a closed umbrella's design folder, same lychee declaration |
| `docs/meta-factory/triage-corpus/sources` | 4 | **EXCLUDE** | review reports preserved VERBATIM as blind corpus material; `lychee.toml:37` states editing them would break the preserved-verbatim property |
| `docs/superpowers` | 104 | **PARKED — left indexed** | initially excluded on lychee's grouping, then reverted. Two live rules delegate their own scope INTO it by name: `.claude/rules/language-discipline.md:16` («NOT authoritative for … the i18n pack mechanism — see docs/superpowers/specs/2026-06-01-hook-lang-i18n-design.md») and `.claude/rules/effort-worthiness.md:14`. The `rules` array routes agents into that rule corpus, so excluding this tree would hide the pointer's target |
| `docs/meta-factory/phase-8-research.md` | 1 | **PARKED — left indexed** | one of seven `docs/meta-factory/phase-*-research*.md` files with the identical self-declared transient status, and not the largest. Excluding exactly one of seven was an unrecorded selection |
| `tests/install-sh/baselines` | 0 | **EXCLUDE** | 15 generated snapshot baselines, regenerated by `SNAPSHOT_MODE=capture bash tests/install-sh/snapshot.sh` |

`folders` is left `[]` deliberately: upstream's inclusion logic is «included only if it matches no exclusion **and**, when `folders` is non-empty, sits under a listed folder», so any non-empty `folders` would silently drop every root-level markdown file, `README.md` included.

**Why `lychee.toml` is a partial basis, not a template.** Four of its six declared-archaeology trees are excluded here; two are not. Lychee excludes a tree because its LINKS rot — a claim about link freshness. Indexing asks a different question: is the document still authoritative for something. `docs/superpowers` fails the first test and passes the second, so the two lists legitimately differ, and the difference is recorded rather than silently inherited.

### Adversarial counter-prompt, written and RUN (T7)

> «What indexable surface did I exclude by accident?»

Run mechanically, twice. **First pass** — for each proposed exclusion, count the markdown it removes:

```
.claude/orchestrator-prompts : md=650      docs/meta-factory/retros : md=26
tests/install-sh/baselines   : md=0        plugin (bare, later narrowed) : md=13
.github                      : md=1        .husky                   : md=0
scripts                      : md=0        templates                : md=0
.claude/worktrees            : md=0        node_modules             : md=0
```

Three answers, none of them nothing:

1. **`.claude/orchestrator-prompts/README.md`** is lost with its tree. Accepted: the kickoff-directory convention's authoritative home is `docs/meta-factory/operational-conventions.md`, which stays indexed.
2. **`.github/pull_request_template.md`** is lost. Accepted: `CONTRIBUTING.md` stays indexed and carries the contributor-facing half.
3. **`plugin/` was NOT the uniform generated twin the first-cut reason claimed.** Re-measured by blob equality: 3 of its 13 markdown files are byte-identical twins, 6 are near-twins that differ in SUBSTANCE (the plugin copy of the getff skill still describes `/aif-verify` as the pre-PR gate and omits the `/rule-research` and `/rule-tests` lines), and **4 have no counterpart at all**. The wholesale row would therefore have hidden `plugin/skills/using-getff/SKILL.md` and `plugin/skills/installing-enforcement/SKILL.md` — consumer-facing skills, the exact content §0 names. The row was narrowed to the two duplicated sub-trees. The substance drift in the near-twins is a real defect on an out-of-scope surface — surfaced under «Follow-up observations», not fixed here.

**Second pass**, added after the cold reviews sharpened the question — «does any exclusion hide a document that a LIVE rule points at?» Run as: does the excluded path appear inside a `NOT authoritative for:` delegation clause in `.claude/rules/*.md`, `CLAUDE.md`, `README.md`, `AGENTS.md` or `INSTALL-FOR-AI.md`?

```
.claude/orchestrator-prompts               delegated-to=0
docs/meta-factory/research-patches         delegated-to=0
docs/meta-factory/retros                   delegated-to=0
docs/meta-factory/generator-forbid-mvp     delegated-to=0
docs/meta-factory/triage-corpus/sources    delegated-to=0
docs/superpowers                           delegated-to=2   ← REMOVED from the exclusion list
plugin / .github / .husky / templates / tests/install-sh/baselines   delegated-to=0
```

One answer, and it was a real self-inflicted defect: the config would have routed agents into `.claude/rules/*` and then hidden two trees those rules delegate to. Fixed by dropping the row. The raw first-cut count (grep the path anywhere) returns non-zero for almost every row, but nearly all of those are `globs:` front-matter naming the paths a rule FIRES on, not delegations of authority to a document — the precise test is the `NOT authoritative for:` clause, and it separates the two cleanly.

**Coverage honesty (T14):** this census enumerates every *tracked top-level* entry plus every sub-tree exclusion, and verdicts each. It does **not** claim a per-file audit of the ~1,900 files inside the kept trees. The exclusion list is «verdicted at directory granularity», not «indexing proven correct». Two matching-semantics questions remain open upstream and are handled by parking rather than by guessing (see the `templates` row).

## T16 — where the upstream transfer stops

**Upstream problem class:** a library owner declaring what an agent-facing indexer ingests from their repository. **Our problem class:** the same. Evidence: upstream's own example is `{"folders": [], "excludeFolders": ["src"], "rules": [...]}` — an owner dropping implementation noise and handing agents guidance, which is exactly this change.

**Where it stops, stated rather than cargo-culted:** this repository is simultaneously an operator workspace and a shipped framework. A normal library has no equivalent of `.claude/orchestrator-prompts` — 650 markdown files of internal dispatch process that would otherwise dominate every retrieval. So the exclusion list is *longer and differently shaped* than upstream's example, and the `rules` array points at a rule corpus that ships to consumers rather than describing an importable API. The schema and the refresh mechanism transfer unchanged; the *content* of both fields is ours to derive.

## Recorded decisions (D3)

- **DeepWiki is a SECONDARY, acknowledged-stale channel.** It auto-indexes and refreshes rarely (spec `docs/superpowers/specs/2026-07-23-beta-program-design.md:373-374`). It may be used for orientation snapshots and **never** for a freshness-critical claim. No gate and no doc claim is wired to it by this PR.
- **`llms.txt` for this repo is NOT added.** Rejected in the spec on crawler-log evidence (`:374-375`); llms routes live on the docs site under D5 / umbrella B (`docs/superpowers/specs/2026-07-23-beta-program-design.md:375`). Not re-litigated here, and not added «for completeness».
- **No doc home was used for the DeepWiki note; it lives in this PR body only.** Kickoff §5 permits a one-sentence note in S1's landed AI-facing docs *only if a natural home exists*. Measured: `AGENTS.md` is partly generated (`AGENTS.md:26` opens a `<!-- getff:begin section=rule-index plan=scripts/render-rule-index.mjs -->` block) and its declared authority is «off-CC session context for contributors» (`AGENTS.md:3`), not discovery channels; `packages/core/templates/shared/AI-USAGE-GUIDE.md` is a template shipped INTO a consumer's project, whose subject is that project rather than this repo. Neither is a natural home, so the conditional does not fire.

### PROPOSAL for the spec §8 integration checklist (owner artefact — not applied here)

Decision 1 owes a follow-through. Proposed line for `docs/superpowers/specs/2026-07-23-beta-program-design.md` §8:

> Flip the Context7 index branch `staging` → `main` at the Phase-2 promote: `context7.json`'s `branch` field and `.github/workflows/context7-refresh.yml`'s `on: push: branches:` list, in one commit. **If the promote does not also make `main` the repository's default branch, the same commit must add a `"branch": "main"` key to the refresh POST body** — upstream documents that the refresh endpoint targets the default-branch library unless the body names a branch.

The two cold rounds disagreed on whether that third place is needed, and the disagreement is real rather than resolvable from here: it depends on a future choice about the default branch that nobody has made yet. Both readings are therefore written into the proposal rather than one being asserted. The spec is a separate owner artefact, so this lands as a spec-owner commit, never inside this stage PR.

## Maintainer legs (D4) — prepared, deliberately NOT performed

Neither action below was taken. Both are outward-facing or credential-creating, and the worker must not perform them.

**D4a — submit the repository.** Open `https://context7.com/add-library`, select the GitHub tab, paste:

```
https://github.com/artyhoo/getff
```

Optionally leave the folder settings empty — the committed `context7.json` already carries them. The resulting library ID will be `/artyhoo/getff` (format `/org/project`), which is exactly what `{"libraryName": "/${{ github.repository }}"}` resolves to in the workflow, by construction.

**D4b — create the secret.** Obtain the API key from the Context7 dashboard, then add it at **Settings → Secrets and variables → Actions**, named exactly:

```
CONTEXT7_API_KEY
```

Both steps are documented upstream in `docs/integrations/github-actions.mdx` («Get your API key», «Add the API key as a repository secret») and `docs/adding-libraries.mdx`, retrieved 2026-09-02.

**The workflow's own request, for reference — do not run it by hand; the workflow issues it:**

```bash
curl --fail-with-body -sS -X POST https://context7.com/api/v1/refresh \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${CONTEXT7_API_KEY}" \
  -d '{"libraryName": "/artyhoo/getff"}'
```

## Failure posture (D2) — resolved, not parked

A failed refresh **fails the workflow loudly**. Kickoff §6 says park this if a red workflow on `staging` would block unrelated merges. It cannot: the workflow carries no `pull_request:` trigger at all, so its result never reports on a pull request and it is not a registered required context (`.github/workflows/workflow-integrity.yml:90` lists the six declared-required contexts; this job is not among them and declares `required-context: no`). A swallowed refresh would be `#warning-nobody-reads` (`.claude/rules/attention-is-not-a-mechanism.md:29`), so the step exits non-zero on a missing key and uses `--fail-with-body` on a non-2xx response.

**Zero paid-LLM calls** (`.claude/rules/no-paid-llm-in-ci.md`): the step issues one HTTP POST to a documentation-indexing service. That is not model inference. Stated rather than left to inference, per kickoff §2 D2.

## Acceptance (kickoff §4)

1. **`context7.json` parses**, and carries `$schema`:

```
$ node -e "JSON.parse(require('fs').readFileSync('context7.json','utf8')); console.log('JSON parse: OK')"
JSON parse: OK
$ head -2 context7.json
{
  "$schema": "https://context7.com/schema/context7.json",
```

2. **Population census + counter-prompt** — above, enumeration first, then selection, counter-prompt written and run with three non-empty answers.

3. **`host-verify` block** — see «Verification» below. Three principle/hook suites green; the sweep has two pre-existing reds and one pre-existing flake, each proven against a clean `origin/staging` worktree.

4. **The live-green claim is a DEGRADATION, not a green.** `INCONCLUSIVE — blocked on maintainer legs D4a/D4b.` The workflow **cannot** run green until the maintainer submits the library and creates the secret: with no key the step exits 1 by design, and with no library there is nothing to refresh. The umbrella AC «the Action runs green» is satisfied at the *maintainer's* action, not at this merge. No workflow run URL and no 2xx body is quoted here, because none was obtained. This PR does not claim the AC is met.

5. **`resolve-library-id` probe** — run and reported as not-yet-indexed; full output in the entry table, row 2. This is the expected pre-submission state.

6. **SSOT row 264 appended**, `Prior-art:` trailer on the commit. The row:

> `| 264 | **Context7 `context7.json` + the upstream `POST /api/v1/refresh` GitHub Actions snippet** … | agent-facing discoverability — a library owner controlling what an AI documentation indexer ingests from the repo, and re-indexing it deterministically instead of on popularity | 2026-09-02 | 2026-09-02 | ADOPT | Upstream problem class … is OUR class exactly (T16); the transfer stops at one point … third-party `rennf93/upsert-context7` is REJECTED — it adds a supply-chain dependency for what upstream documents as one HTTP call, with no capability gain. Coverage honesty (T14): three context7 phrasings + one WebSearch + one WebFetch; the WebFetch of the raw `schema/context7.json` 404'd, so the schema comes from the `library-owners` doc via MCP, not from the schema file itself. | Upstash publishes a first-party marketplace action, or the refresh API changes shape → re-evaluate … |`

7. **Both recorded decisions present** — DeepWiki-as-secondary and llms.txt-not-added, each with its spec citation. Above.

8. **No maintainer-owned or `.claude/rules/*` path in the diff** — file list quoted under «Changes».

## Verification

`bash scripts/host-verify.sh` block, run on the host:

```
$ npx vitest run packages/core/principles/37-required-context-completeness.test.ts
 Test Files  1 passed (1)      Tests  11 passed (11)
$ npx vitest run packages/core/principles/17-no-paid-llm-in-ci.test.ts
 Test Files  1 passed (1)      Tests   7 passed (7)
$ npx vitest run packages/core/hooks/unpinned-tool-install.test.ts
 Test Files  1 passed (1)      Tests  34 passed (34)
```

`bash scripts/run-local-ci-sweep.sh` escalated to `--full` (`unmapped path 'context7.json'`). Of its 38 gates, **34 PASS**, `md-ci-only` WARN-SKIPs as CI-only, and three reds are **pre-existing, each proven against a throwaway worktree at `origin/staging` with an identical failure**:

| Gate | Failure | Proof it is not branch-introduced |
|---|---|---|
| `byte-identical` | `cargo/greenfield` and `cargo/brownfield-clippy` differ by a missing `.ai-factory/refresh-baseline.json` | same two cells fail on a clean `origin/staging` worktree, `13 pass / 2 fail` both sides |
| `install-sh-suite` | contains `byte-identical.test.sh` **and** `cargo-entry-lane.test.sh` | `cargo-entry-lane.test.sh` reproduces the same six `✗` lines on the clean baseline. The rest of the battery was then run to completion with exactly those two skipped: **102 PASS / 0 FAIL / 2 SKIP** out of the 104 files in `tests/install-sh/`, so no other test in the suite is red |
| `vitest-skills` | `skills/dispatcher/probe-inflight.test.ts > (b) git-call failure surfaces its cause` — `Test timed out in 5000ms` | flaky on the clean baseline too: 3 consecutive baseline runs gave red, red, green. Green in isolation on this branch as well |

The three reds are cargo-toolchain and timeout conditions on this host. This branch adds no cargo file, no test, and no code — its whole diff is one JSON file, one workflow, and one table row.

**Sweep observation (not fixed here):** on a gate failure `scripts/run-local-ci-sweep.sh:330` and `:340` prints `[sweep] FAIL <name>` and exits without ever printing the captured `$out`, so the operator gets a gate name and no cause. The output is captured into `$out` two lines earlier and then discarded on the failure path.

## Follow-up observations (surfaced, NOT fixed — CLAUDE.md «PR strategy»)

The cold backward sweep returned five GAP-FOUND rows. Two were inside this stage's permitted files and are fixed in the commits above. The remaining three need a gate in a file kickoff §5 does not allow this stage to touch, so they are recorded here with where the gate belongs:

1. **A push-only workflow can write `# required-context: yes` and nothing will notice.** Measured by the sweep: flipping this workflow's marker to `yes` in a temp copy leaves `declaredRequiredContexts` byte-identical, because `declarableJobs` iterates `prTriggeredWorkflows` only (`packages/core/principles/37-required-context-completeness.test.ts:282`). Today's value is `no` and correct, so this is a latent hole, not a live defect. The gate belongs as a new arm in principle 37 asserting that a non-declarable workflow does not claim `yes`.
2. **The `rules` array is a hand-maintained selection of 9 from a generated population of 29** (`.claude/rules/00-rule-index.md`), with no anti-drift test — and no link gate reaches it, since `lychee.toml:2` scopes to markdown and a `.json` never enters that channel. Precedent for the missing gate is dense in-repo: principles 26, 27, 35, 36, 37. The gate belongs as a principle test.
3. **`context7.json`'s `branch` and the workflow's `on: push: branches:` are coupled by a comment, not an assertion.** That is `#warning-nobody-reads` (`.claude/rules/attention-is-not-a-mechanism.md:29`) — the very rule this PR cites elsewhere. A gate would need either a principle test or an `actions/checkout` step added purely to read one JSON field on every staging push; both are outside §5, and the second buys a Type-1 mechanism for a single planned Type-2 event. Recorded rather than silently accepted.

Four more, found in passing and unrelated to the gates above:

4. **`README.md` is now the tree's stale outlier on toolchain coverage.** `README.md:8` names only npm and cargo, and `README.md:258` states «This is a roadmap, not shipped — no Rust rule-pack exists yet» — contradicted by `packages/core/backends/cargo/` (37 tracked files, including a demo crate with `clippy.toml`) and by `install.sh:289`. Kickoff §2 D1 asks the description to stay consistent with README's framing; where the two diverge this PR follows the repository, not the README, and says so. README is maintainer-owned (§3, §9), so the correction is surfaced, never applied here.
5. **`plugin/skills/getff/*` is an ungenerated stale fork, not a generated twin.** `scripts/generate-plugin-twins.sh:4` and `:5` declare its whole scope as `plugin/hooks/` and `plugin/agents/` only. `plugin/skills/getff/SKILL.md` last moved at the 2026-07-11 rename while `skills/getff/SKILL.md` was rewritten by this umbrella's own S1 (#1311) on 2026-08-08, so the shipped copy still calls `/aif-verify` the pre-PR gate where the source now names `audit-ai-docs.sh`. The exclusion row keeps it out of the index; the shipped staleness itself is a sibling-surface gap for a later stage.
6. **The meta-launch §3 umbrella-closure gate greps predicted head branch names**, which an aif-dispatched stage does not use (see «Stage gate» above).
7. **`scripts/run-local-ci-sweep.sh` swallows the failing gate's output.** It captures the section output into `$out` at `scripts/run-local-ci-sweep.sh:330`, then on failure prints only `[sweep] FAIL <name>` at `:340` and exits — the operator gets a gate name and no cause. Diagnosing the three reds in this run meant re-running each gate by hand.

## Prior-art consult

- [x] The commit carries `Prior-art: prior-art-evaluations.md#264 (Context7 context7.json + upstream refresh snippet, verdict ADOPT — upstream problem class «a library owner declaring what an agent-facing indexer ingests» matches ours exactly; third-party `rennf93/upsert-context7` REJECTED as a supply-chain dependency for one documented HTTP call).`
- [x] New capability area surfaced → new SSOT entry **264** added in the same commit as the artefact, with `Verdict` / `Rationale` / `Trigger to revisit`.
- [x] No existing entry matched. `grep -niE 'context7|deepwiki|llms.txt|discoverab'` over the pre-change register (`git show HEAD~1:docs/meta-factory/prior-art-evaluations.md`) returns context7 only in the shape «context7 lookup / query / sweep» — the tool used to RUN a consult — the §3 method prose at `docs/meta-factory/prior-art-evaluations.md:53`, and rows **1** and **78**, which cite a context7 lookup as their evidence. The nearest neighbour is **row 42, «Devin/Cognition DeepWiki MCP»**, evaluated as a research instrument for architectural understanding, not as a channel this repo is published INTO. No row treats an agent-facing indexer as a shipped target, and there is no `llms.txt` row at all.
- [x] context7 queries re-run at writing time (T12), not inherited: `resolve-library-id("getff")`, `resolve-library-id("Context7")`, `query-docs(/upstash/context7, schema fields)`, `query-docs(/upstash/context7, GitHub Actions refresh)`, `query-docs(/upstash/context7, adding libraries + API key)`, plus two WebSearches and one WebFetch.

## Test plan

- [x] `host-verify` block green (three suites above)
- [x] `bash scripts/run-local-ci-sweep.sh` — 34/38 PASS, 1 CI-only WARN-SKIP, 3 pre-existing reds proven against a clean `origin/staging` baseline
- [x] `context7.json` parses; `$schema` present
- [x] Marker well-formedness checked with principle 37's own regex, extracted from its source file rather than retyped

## Provenance

Stage PR — `beta-ai-docs-agnosticism` S4 (discoverability, spec C4). Kickoff: `.claude/orchestrator-prompts/beta-ai-docs-agnosticism/kickoff-s4.md`; decisions log: `kickoff-s4.decisions.md`. Base SHA `37942d24e5f73f1eba4787ebd2fdcb154bb994fa`. Substrate: **in-session** — the kickoff header declares `DISPATCH CHANNEL: maintainer-paste tab — SOLO / Mode-A`, so no aif task was enqueued. Model: Fable 5.1 (implementation and cold audits, each dispatched to a fresh cold seat). Fidelity Round 4.

## Review findings

**Cold backward sweep (T21).** `agents/backward-sweep-auditor.md`, dispatched PR-blind with the change CLASS only — «a new standalone push-triggered workflow calling an external HTTP API with a repository secret, plus a new root-level config that an external service consumes to decide what repository content it ingests and republishes». It enumerated five surface groups (workflow population, the two restatement lists, automatic-coverage surfaces, root configs, content-egress authorities) and returned **REVISE, five GAP-FOUND rows**. Two were inside this stage's permitted files and are fixed in the commits above; three need a gate in a file §5 does not allow this stage to touch and are recorded under «Follow-up observations».

**Cold fidelity rounds.** Four rounds, each on the then-current head; every REVISE landed on scope the previous round had not seen, because each fix added or changed rows.

| Round | Audited-SHA | Verdict | What it caught |
|---|---|---|---|
| 1 | `3534e681ff` | REVISE | **W-1** the build-vs-reuse `rules` entry inlined CLAUDE.md's capability-commit definition, dropping one of three triggers and paraphrasing the threshold, and pointed at a rule whose own header disclaims that scope. **W-2** bare-name exclusions mixed grammars; `templates` would plausibly have dropped 13 nested markdown files including the shipped `AI-USAGE-GUIDE.md` |
| 2 | `49a6fea109` | REVISE | **W-6 (new)** excluding `docs/superpowers` was self-defeating — two live rules delegate their own scope INTO that tree by name, and the `rules` array routes agents into those rules. Round 1's fix had over-applied `lychee.toml`'s grouping |
| 3 | `f57d13183a` | GO | two MINOR in the notes lane: the stated reason for the `plugin` row was wrong, and the description named two toolchain lanes as if exhaustive |
| 4 | `c374940efc` | **GO** | all seven watch-list items CLEAN, verified by blob measurement. Noted that narrowing the `plugin` row also returned `plugin/hooks/**` to the index — a tree `.claude/rules/ci-tool-pinning.md:9` and `.claude/rules/zcode-parity-doctrine.md:5` both name as their gate population |

Round 4's `### Watch-list`, carried forward unedited:

| id | criterion | round-4 status |
|---|---|---|
| W-1 | no `rules` entry carries a threshold, a count, or a definition | CLEAN — the only digits in any `rules` string are the `00` of the `00-rule-index.md` filename |
| W-2 | an `excludeFolders` row that cannot be verdicted from evidence is PARKED, not guessed | CLEAN — the delta moves toward the reversible branch: 9 markdown files excluded where 13 were before |
| W-3 | the Phase-2 index-branch flip must touch every place the index actually reads | CLEAN (preventive) — the index branch has exactly two readers repo-wide |
| W-4 | the worker never submits the library and never creates `CONTEXT7_API_KEY` | CLEAN (preventive) |
| W-5 | index branch stays `staging` in BOTH places until the spec-owner Phase-2 commit | CLEAN |
| W-6 | an exclusion must not remove a tree a live rule header delegates authority INTO | CLEAN — repaired in round 2, re-tested across all remaining rows in rounds 3 and 4 |
| W-7 | a stated exclusion reason must be a MEASURED one; a false reason is worse than none | CLEAN — measured by blob equality, not asserted |

**On the round count.** `.claude/skills/dispatcher/SKILL.md` §2.4 caps two CONSECUTIVE REVISE rounds on unchanged scope, and resets the counter «on any GO or scope addition». Rounds 1 and 2 both returned REVISE, but round 2's finding was on rows added by round 1's own fix — scope round 1 never saw — and round 3 then returned GO, which resets the counter outright. The cap did not fire. Flagging the reading explicitly so it can be overruled rather than discovered.

## Fidelity verdict

FIDELITY: GO
Basis: .claude/orchestrator-prompts/beta-ai-docs-agnosticism/kickoff-s4.md
Round: 4
Audited-SHA: c374940
Evidence: context7.json:17 — the wholesale `plugin` row is replaced by `plugin/agents` + `plugin/skills/getff`, restoring `plugin/hooks/**` to the index
Evidence: install.sh:289 — each of the four lanes named by the description has its own non-npm entry point and backend directory

## Parked questions

**none.** The one author-time park (which branch Context7 indexes) was decided before this run — `kickoff-s4.decisions.md` Decision 1, `staging` now with a Phase-2 flip to `main`, applied at `context7.json:5` and `.github/workflows/context7-refresh.yml:15`. The two conditionally-parkable spots resolved from evidence rather than by guess, both recorded above: the failure posture (a push-only workflow reports on no PR, so failing loudly cannot block a merge) and every `excludeFolders` row (each carries a measured reason; rows that could not be verdicted from evidence were left indexed, the reversible branch). No new fork fired.

## §1.7 Self-discipline check

### §1.7 Forward-check applied

This PR appends to `docs/meta-factory/prior-art-evaluations.md`, which the PR template names explicitly as a discipline-bearing artefact, so the Skipped default does not apply. Existing disciplines checked before writing anything:

- `doc-authority-hierarchy.md` — the SSOT register declares itself append-only and forbids editing existing rows in place. Checked and obeyed: `docs/meta-factory/prior-art-evaluations.md:72` («Entries are appended below this line. Do not edit existing rows in place…»); the diff is `1 file changed, 1 insertion(+)`. An earlier `npx prettier --write` on that file was reverted precisely because it rewrote 94 existing rows; no formatter is wired to this path (`package.json` has no `lint-staged` block, and `.husky/pre-commit` runs markdownlint only).
- `build-first-reuse-default.md` — verdict **ADOPT upstream, REJECT the third-party action**. The re-index mechanism is upstream's documented `curl` step, not a hand-rolled one and not `rennf93/upsert-context7`, which would add a supply-chain dependency for a single HTTP call. Recorded as SSOT row 264, with the commit trailer. file:line evidence: `docs/meta-factory/prior-art-evaluations.md:337`.
- `phase-research-coverage.md §1.12` — every verdict in this body carries command output or a file:line citation, and the negative-existence claim («no first-party marketplace action») was searched rather than remembered: two WebSearch phrasings plus the live upstream `docs/integrations/` listing. file:line evidence: `.github/workflows/context7-refresh.yml:5`.
- `no-paid-llm-in-ci.md` — verdict **compliant**. The new workflow's one step is an HTTP POST to an indexing service; no model inference, no LLM API. Gate re-run green: `packages/core/principles/17-no-paid-llm-in-ci.test.ts:1`, 7 passed.
- `ci-tool-pinning.md` — verdict **no surface**. The workflow installs nothing and uses no third-party action, so there is no version to pin; the gate was run anyway to prove the absence rather than assert it. file:line evidence: `packages/core/hooks/unpinned-tool-install.test.ts:1`, 34 passed.
- `attention-is-not-a-mechanism.md` — checked against the failure posture. A warn-and-pass refresh would be `#warning-nobody-reads`; the step fails loudly instead. file:line evidence: `.claude/rules/attention-is-not-a-mechanism.md:29`.
- `language-discipline.md` — all shipped strings are English, including the error message naming the two maintainer actions. file:line evidence: `.github/workflows/context7-refresh.yml:58`.

### §1.7 Backward-check applied

Sweep of existing artefacts under this change's scope, delegated cold and PR-blind to `agents/backward-sweep-auditor.md` per T21 (its findings are in «Review findings»), and independently verified here:

- `packages/core/principles/37-required-context-completeness.test.ts` — **orthogonal, and the kickoff's claim about it was too broad.** Its declarable population is `prTriggeredWorkflows` only, so a push-only workflow is outside it by construction. The marker is written regardless, and validated with the principle's own regex extracted from source. file:line evidence: `packages/core/principles/37-required-context-completeness.test.ts:282`.
- `.github/workflows/workflow-integrity.yml` — **orthogonal.** Its `required_contexts=` list must equal the declared-`yes` set; this job declares `no`, so the list is unchanged and principle 37 stays green. file:line evidence: `.github/workflows/workflow-integrity.yml:90`.
- `scripts/run-local-ci-sweep.sh` `# REQUIRED_CONTEXTS:` — **orthogonal**, same reason; no entry added. file:line evidence: `scripts/run-local-ci-sweep.sh:21`.
- `.github/workflows/audit-self.yml` actionlint + zizmor — **extends, no list to update.** Both lint the whole `.github/workflows/` tree, so the new file is covered automatically; `actionlint` PASSes in the sweep run above. file:line evidence: `scripts/run-local-ci-sweep.sh:159`.
- The other 12 workflows' `# required-context:` markers — **CLEAN.** The declared population is unchanged; principle 37 re-run green, 11 passed.
- Root-level configs a fresh clone carries (`.markdownlint.json`, `.mcp.json`, `.prettierrc.json`, `lychee.toml`, `package.json`, `extension.json`, `vitest.config.ts`, `Makefile`, `install.sh`, `setup`) — **no collision.** None of them names a `context7` key or claims authority over what an external indexer ingests; `grep -rn 'CONTEXT7' .github/` was empty before this change. file:line evidence: `context7.json:2`.
- `lychee.toml` — the nearest existing artefact that governs an external-facing surface (link auditing). **Orthogonal:** it decides which links are *checked*, never what content is *exposed*. file:line evidence: `.github/workflows/link-checker.yml:39`.
- **`setup.d/05-mcp.sh` and `setup.d/45-python.sh` — the OTHER context7 surface in this repo. Orthogonal, and worth naming so the two are never conflated.** The installer already wires context7 into a consumer's `.mcp.json` as a doc-fetching **MCP client** (`setup.d/45-python.sh:1009` guards on `grep -q '"context7"'`). This PR makes this repo a context7 **library**, the other end of the same service. No collision: `grep -rn 'context7' setup.d/ install.sh setup` returns only the MCP-client wiring, never the root config.
- **Consumer leakage checked: `context7.json` does NOT ship.** It appears in no installer copy list, and the installers name every JSON file explicitly rather than globbing the repo root, so a consumer's project cannot inherit this repo's index configuration. file:line evidence: `setup.d/45-python.sh:1003`.
- S2's and S3's landed surfaces (`tests/agnosticism/probes/*`, principle 21, skill declarations, `agents/claims-conformance-auditor.md`, generated sections) — **consumed, not amended.** No file of theirs appears in this diff.
artyhoo added a commit that referenced this pull request Sep 2, 2026
…merge (#1569) (#1570)

## Summary

Closes the `beta-ai-docs-agnosticism` umbrella. S4 merged as #1569 (squash `1d382d4783`) and was the last stage, so this adds the `done.md` closure marker — the load-bearing Layer-C3 signal `priority-score.sh` reads as `basis=done-md` (`docs/meta-factory/operational-conventions.md` §1, umbrella closure convention).

One new file, no code, no behaviour change.

## Changes

- **`.claude/orchestrator-prompts/beta-ai-docs-agnosticism/done.md`** (new, 79 lines) — the closure marker, plus two things worth carrying out of the umbrella:
  - **A stage table with the REAL head branch names.** S2 and S3 ran through the aif runtime, which mints `feature/<slug>-<id>` and exposes no branch override in `dispatch.ts` or `harvest.ts`. The meta-launch Stage-2→3 entry gate greps the kickoff's *predicted* names, so `gh pr list --search "is:merged head:beta-c-s2-skills-probe base:staging"` returns `[]` for both stages even though both landed. The marker says so explicitly, so the next reader does not re-run that grep and conclude the stages never merged. Landing was verified by substance: `git merge-base --is-ancestor 7534fd9 origin/staging` and the same for `ee0ccfe593`.
  - **The owner-parked residue**, copied out of the three stage PRs' `## Parked questions` sections rather than left to rot there: S3's `aif-version` fork and the `claims-conformance-auditor` skip-list follow-up, S2's drifted `tier-home.md` citation and census boundary, and S4's two maintainer-only Context7 legs, its Phase-2 flip proposal, and the three couplings that still need a gate in files those stages were not permitted to touch.

Also synced to the coordination canon at `~/.claude-coordination/rules-as-tests-aif/beta-ai-docs-agnosticism/done.md` (`/dispatcher` §2.8). That path is machine-local and not part of this diff.

## Umbrella stages

| Stage | PR | Squash |
|---|---|---|
| S1 — AGENTS.md layer + AI Usage Guide (C1) | #1311 | `744bb06e35` |
| S1b — Phase -1 BLOCKER fixes | #1329 | `501af27ea5` |
| S1c — refresh-claim repair | #1332 | `ebb974afde` |
| S2 — skills agnosticism probe (C3) | #1552 | `ee0ccfe593` |
| S3 — self-generating docs sweep (C5) | #1550 | `7534fd9a48` |
| S4 — discoverability (C4) | #1569 | `1d382d4783` |

## Verification

```
$ git ls-files -s .claude/orchestrator-prompts/beta-ai-docs-agnosticism/done.md
100644 0435de2 0	.claude/orchestrator-prompts/beta-ai-docs-agnosticism/done.md
```

Mode `100644`, not `120000` — the coordination hook adopts new untracked files under that directory and replaces them with symlinks within about two minutes, so the file was written and staged in one step and the mode checked afterwards.

```
$ wc -l .claude/orchestrator-prompts/beta-ai-docs-agnosticism/done.md
      79
```

Under the 600-line markdown gate. `markdownlint-cli2` at pre-commit: `Summary: 0 error(s)`. Pre-push gates green on the push of this branch.

## Prior-art consult

- [x] Not a capability commit — one markdown file, no dependency, nothing under `packages/`. The commit carries `Prior-art: skipped — closure marker for a completed umbrella, no capability and no code.`
- [x] No new capability area surfaced; no SSOT entry needed. S4's own capability entry is row **264**, added in #1569.

## Test plan

- [x] `git ls-files -s` confirms mode 100644
- [x] `markdownlint-cli2` green at pre-commit
- [x] Pre-push gate battery green
- [x] Every PR number and squash SHA in the table read from `gh pr view --json mergeCommit`, not from memory

## Provenance

n/a — not a stage PR. This is the closure marker written by the session that merged the umbrella's final stage, per the umbrella closure convention.

## Review findings

n/a — docs-only closure marker. Its factual content (six PR numbers, six squash SHAs, six head branch names) was read from `gh pr view --json number,title,mergedAt,mergeCommit,headRefName` for each PR, and the two ancestry claims from `git merge-base --is-ancestor`.

## Fidelity verdict

FIDELITY: skipped — closure marker for an already-merged umbrella; no kickoff governs it, no deliverable to audit against, and the diff is one new markdown file with no code and no behaviour change.

## Parked questions

n/a — this PR resolves nothing and decides nothing. The umbrella's open items are recorded IN the new file as owner-parked residue, deliberately carried forward rather than closed.

## §1.7 Self-discipline check

### §1.7 Skipped: mechanical closure marker for a merged umbrella — one new markdown file under .claude/orchestrator-prompts/, no discipline rule introduced or extended, no rules/principles/EXECUTION-PLAN/prior-art/CLAUDE.md path touched, and no behaviour change anywhere in the tree.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant