Skip to content

Wave 10.6 — port hook-stub-completeness audit to principle 16 - #127

Merged
artyhoo merged 1 commit into
mainfrom
feat/wave-10.6-hook-stub-principle
May 21, 2026
Merged

Wave 10.6 — port hook-stub-completeness audit to principle 16#127
artyhoo merged 1 commit into
mainfrom
feat/wave-10.6-hook-stub-principle

Conversation

@artyhoo

@artyhoo artyhoo commented May 21, 2026

Copy link
Copy Markdown
Owner

What was done

  • Ported packages/core/audit-self/hook-stub-completeness.test.sh (bash self-test) → packages/core/principles/16-hook-stub-completeness.test.ts (vitest principle, slot 16).
  • Deleted the bash; removed its §3a invocation from packages/core/hooks/pre-push.ts and the now-dead requireSelfTest() helper (zero remaining call sites).
  • TS port reproduces the bash violation semantics exactly (same make_test_repo() scope gate, per-hard-fail-script stub matching, identical ❌ <file>: missing stub for <name> message).

§1.7 Forward-check applied

This port makes the hook-stub invariant an executable principle test (earliest-channel upgrade: bash-in-pre-push → CI principle suite). Forward sweep for analogous surfaces: hook-stub-completeness.test.sh was the last .test.sh hard-fail invoked from the orchestrator — after removal packages/core/hooks/pre-push.ts contains zero .test.sh refs (verified empty grep). The extractor at packages/core/principles/16-hook-stub-completeness.test.ts:45 plus the vacuous-pass guard at packages/core/principles/16-hook-stub-completeness.test.ts:102 keep the now-empty invariant green while still guarding any future re-introduction of an unstubbed hard-fail.

§1.7 Backward-check applied

The deleted bash was the regression-fixture spec; the TS port reproduces its exact violation message. Backward citation: the §3a invocation was replaced by the migration-note comment now at packages/core/hooks/pre-push.ts:236, and the new test's header (packages/core/principles/16-hook-stub-completeness.test.ts:4) records the deleted source. This closes the 3-place tracker place #2 in docs/meta-factory/research-patches/2026-05-13-memory-to-docs-codification-audit.md §10.A.

How to verify

  • Principle suite green (16 files, 95 passed | 4 skipped) — verified: npm --prefix packages/core run test:principles (worker VERIFY + pre-push + independent QA)
  • Paired-negative actually fails on a missing-stub fixture (not a tautology) — verified: independent QA arm (b), exact message text asserted
  • Principle 16 introduces zero new typecheck errors — verified: QA grep of tsc --noEmit output (principles/16 = empty)
  • Bash deleted, §3a invocation + dead requireSelfTest helper removed, dispatcher intact — verified: QA grep empty, downstream sections intact
  • Phantom stub in tests/hooks/prior-art-trailer-hook.test.sh left intact (out of scope; one-directional check) — verified: QA, untouched

Notes

  • Commit carries escape-hatch Prior-art: skipped — bash→TS port of existing hook-stub-completeness audit, no new capability. The ≥80-LOC mechanical gate triggers a warn-only PA-substance notice (calibration window → 2026-06-10); kept as escape-hatch because a port introduces no new capability per CLAUDE.md (forcing an SSOT cite would be inaccurate).
  • Wave 10 sub-wave; depends on 10.4 (Wave 10.4 — port audit-ai-docs.sh → TS (remark D1–D5 hardening) #120, merged). Independent of 10.5 (parallel PR) — pre-push.ts overlap avoided (10.5 makes zero pre-push.ts edits).

Scope-out

  • Pre-existing audit-ai-docs.test.ts TS2345 on main (from Wave 10.4) — not touched here.

…inciple 16

- Add packages/core/principles/16-hook-stub-completeness.test.ts (7 tests):
  (a) real-tree vacuous pass: empty hard-fail set post-migration → passes, not dies
  (b) paired-negative: make_test_repo() test file missing stub → ❌ violation detected + message text asserted
  (c) non-empty happy path: stub present → no violation
  + scope gate, multi-script, dedup, T15 self-application arms
- Delete packages/core/audit-self/hook-stub-completeness.test.sh (bash predecessor)
- Remove requireSelfTest('…hook-stub-completeness.test.sh') invocation from pre-push.ts §3a
- Remove requireSelfTest() helper (zero call sites remaining → genuinely dead)
- Leave phantom stub in tests/hooks/prior-art-trailer-hook.test.sh (harmless; out of scope)

Prior-art: skipped — bash→TS port of existing hook-stub-completeness audit (Wave 10.6), no new capability
@artyhoo
artyhoo merged commit 7f80f62 into main May 21, 2026
24 of 25 checks passed
@artyhoo
artyhoo deleted the feat/wave-10.6-hook-stub-principle branch May 21, 2026 23:33
artyhoo added a commit that referenced this pull request May 22, 2026
…ive-test] (#132)

* docs(research): memory coverage audit (memory → docs → tests) 2026-05-22 (#126)

R-phase report: triages all 51 project-memory files against the project
goal (rule = executable test), builds a 30-row coverage matrix by pipeline
stage (0 memory-only / 1 prose / 2 executable), and proposes a forward-going
memory-codification discipline (write-time + local-audit + periodic re-audit).
No implementation — gap-closure + new rule are a separate PR after maintainer GO.

Successor to 2026-05-13 memory-to-docs codification audit (extends memory→docs
for 6 entries to memory→docs→tests over all 51 files). Surfaces T16 stale-header
finding (principle tests 11/12/13 shipped but rule headers say "pending").

Prior-art: skipped — research-patch doc only, no new capability/dependency; reuses 2026-05-13 §7 REUSE verdict (Cline Memory Bank + CC scope hierarchy).

* feat(principles): Wave 10.6 — port hook-stub-completeness audit to principle 16 (#127)

- Add packages/core/principles/16-hook-stub-completeness.test.ts (7 tests):
  (a) real-tree vacuous pass: empty hard-fail set post-migration → passes, not dies
  (b) paired-negative: make_test_repo() test file missing stub → ❌ violation detected + message text asserted
  (c) non-empty happy path: stub present → no violation
  + scope gate, multi-script, dedup, T15 self-application arms
- Delete packages/core/audit-self/hook-stub-completeness.test.sh (bash predecessor)
- Remove requireSelfTest('…hook-stub-completeness.test.sh') invocation from pre-push.ts §3a
- Remove requireSelfTest() helper (zero call sites remaining → genuinely dead)
- Leave phantom stub in tests/hooks/prior-art-trailer-hook.test.sh (harmless; out of scope)

Prior-art: skipped — bash→TS port of existing hook-stub-completeness audit (Wave 10.6), no new capability

* docs(automerge): codify branch-from-main staging flow + resync discipline (#128)

* docs(automerge): codify branch-from-main→staging flow + resync discipline; sync doc to LIVE state

main's copy was stale (still called ci-success a placeholder). Updates: status LIVE (settings applied 2026-05-22); new §2.1 branching flow — always branch FROM main, auto-merge INTO staging, with the load-bearing RESYNC discipline (ff staging→main after each promotion) that keeps staging a disposable buffer not a divergent develop; §5 recipe marked APPLIED with the real ci-success+actionlint+zizmor contexts + main owner-only protection; §6 #2 RESOLVED (#125).

Prior-art: skipped — doc codification of an already-decided flow, no new capability/dependency/subdir.

* docs(§2.1): drop trunk-based exception — everything routine → staging (0 clicks)

Maintainer's point: direct-to-main is owner-only → forces a manual merge
click per PR, the exact toil being removed. staging auto-merges (0 clicks).
So all routine work → staging; direct-to-main only for owner hotfixes.

Added dependency note: for true zero-click walk-away the agent must set
auto-merge on staging-targeted PRs, currently blocked by the git-safety
hook (allows only feat→epic). Relaxing it (permit auto-merge --base staging)
is the actual zero-click lever, and is a maintainer-side hook edit.

Prior-art: skipped — doc refinement of the codified flow, no new capability.

* feat(hooks): Wave 10.5 — bash-fallback + install.sh feature detection (#129)

Ships the critical-only bash fallback for the pre-push hook and updates
the consumer-facing dispatcher template to runtime feature detection.

Artifacts:
- packages/core/hooks/checks/registry.ts (~114 LOC): declarative
  check-registry ({ id, criticalForFallback, runner }[]) decoupling
  check-set selection from execution (ADAPT from Aider §4.8.X.2).
  Critical entries: prior-art-presence + s17-presence (both runner: 'bash'),
  per D2 + research patch §7.2.
- packages/core/hooks/checks/registry.test.ts: unit tests asserting
  bash-expressible invariant (every criticalForFallback entry → runner: 'bash')
  AND presence of both required critical entries.
- packages/core/hooks/pre-push.fallback.sh (~63 LOC): critical-only bash gate.
  Runs §7 Prior-art presence + §1.7 presence checks on origin/main..HEAD commits.
  Historical cutoff (2026-05-12) respected. bash 3.2-compatible. exit 1 if either
  required trailer is absent; exit 0 when both present or no discipline files touched.
- packages/core/templates/shared/husky-pre-push.sh: updated from OLD consumer
  pre-push to runtime dispatcher (per research patch §7.4). Node ≥20 + pre-push.ts
  present → TS-core; otherwise → bash fallback. Capability-check, NOT brand-name.
- install.sh: also copies pre-push.fallback.sh to consumer project so the
  runtime dispatcher can find it at $REPO_ROOT/packages/core/hooks/pre-push.fallback.sh.
- docs/meta-factory/prior-art-evaluations.md: SSOT entry #59 added in-commit
  (registry.ts ≥80 LOC under packages/ → capability commit gate fires).

T15 self-application: the registry invariant (every criticalForFallback check is
bash-expressible) is itself unit-tested in registry.test.ts — the rule applies to
itself. Zero edits to pre-push.ts (parallel-overlap avoidance; 10.6 owns that file).

Prior-art: prior-art-evaluations.md#59 (Aider parse_lint_cmds / self.languages, verdict ADAPT — structural pattern of decoupling selection-table from execution-runner transfers; semantic axis differs: file-language vs project-stack. Wave 10.5 registry.ts is 114 LOC ≥80 threshold, capability commit gate fires, SSOT entry added in same commit per CLAUDE.md discipline).

* fix(ci): make ci-success the sole required gate; fold actionlint+zizmor under it (#130)

Branch protection on main/staging required ci-success + actionlint + zizmor, but
actionlint/zizmor lived in workflow-integrity.yml path-filtered to
.github/workflows/** — so PRs not touching workflows (docs, packages) never
triggered them, their required contexts never reported, and the PR deadlocked
(auto-merge could never fire). PR #126 hit this exact wall.

Fix: cross-workflow `needs:` is impossible, so move actionlint + zizmor into
audit-self.yml (no path filter → runs every PR) and add them to ci-success's
`needs:`. ci-success now transitively gates the linters and always reports, so
branch protection can require ONLY ci-success. workflow-integrity.yml keeps just
the R11 branch-protection-assertion. Checks are stricter, not weaker: a broken
workflow YAML on a docs PR is now caught (previously it wasn't).

Synced: rules-manifest R11 check.command + re-rendered RULES.md table + snapshot;
RULES.md R11 prose; ci-success-gate.sh comment; automerge-staging-plan.md §5
recipe (was telling the maintainer to re-add the deadlocking contexts).

Maintainer-side follow-up: re-run the branch-protection PUT with single-context
payload {"contexts":["ci-success"]} per automerge-staging-plan.md §5.

Prior-art: skipped — moves existing CI jobs between workflow files + doc sync; no new capability, dependency, or ≥80-LOC file.

* feat(principles): principle 17 — no paid LLM in CI (DN-6 stage-1→2 promotion)

Promotes .claude/rules/no-paid-llm-in-ci.md from "Class A, grep mechanism
ready, test pending" to a real executable gate (memory-coverage-audit §10
DN-6 — the one clean stage-1→2 win in-repo). Scans .github/workflows/*.yml
for paid-LLM *usage* (ANTHROPIC/OPENAI api-key assignment or secret ref,
api.{anthropic,openai}.com hostnames, paid SDK imports) and fails CI if any
is present.

Usage-precise, not mention-counting: full-line comments are stripped first,
so the project's own negation mention (framework-self-template-render.yml:
"NO ANTHROPIC_API_KEY reference") does NOT false-positive. Negative-controls
in the test prove that, plus session/MCP tooling (claude CLI, context7) is
out of scope per rule §2.

Slot 17 (01-16 occupied). Runs in CI via principles-meta-tests → gated by
ci-success. 7/7 local; full suite 17 files / 106 tests green.

§1.7: forward-check applied — principle 17 IS the executable artifact for an existing prose rule (no-paid-llm-in-ci.md §1/§6 "pre-merge grep" counter); paired-negatives at packages/core/principles/17-no-paid-llm-in-ci.test.ts:91 (api-key assignment), :96 (hostname), :101 (SDK) prove detection, negative-controls at :107/:112 prevent false-positives. Backward-check sweep — reviewed principle slots 01-16 (17 next free) + prior-art-evaluations.md; no overlap (secret-scanners detect leaked creds, this bans a paid-LLM dependency surface — inverse problem class).
Prior-art: skipped — principle test for the existing no-paid-llm-in-ci.md rule (DN-6 promotion); no new capability/dependency/subdir, mirrors principle 15/16 precedent.
artyhoo added a commit that referenced this pull request May 22, 2026
…ive-test] (#132) (#133)

* docs(research): memory coverage audit (memory → docs → tests) 2026-05-22 (#126)

R-phase report: triages all 51 project-memory files against the project
goal (rule = executable test), builds a 30-row coverage matrix by pipeline
stage (0 memory-only / 1 prose / 2 executable), and proposes a forward-going
memory-codification discipline (write-time + local-audit + periodic re-audit).
No implementation — gap-closure + new rule are a separate PR after maintainer GO.

Successor to 2026-05-13 memory-to-docs codification audit (extends memory→docs
for 6 entries to memory→docs→tests over all 51 files). Surfaces T16 stale-header
finding (principle tests 11/12/13 shipped but rule headers say "pending").

Prior-art: skipped — research-patch doc only, no new capability/dependency; reuses 2026-05-13 §7 REUSE verdict (Cline Memory Bank + CC scope hierarchy).

* feat(principles): Wave 10.6 — port hook-stub-completeness audit to principle 16 (#127)

- Add packages/core/principles/16-hook-stub-completeness.test.ts (7 tests):
  (a) real-tree vacuous pass: empty hard-fail set post-migration → passes, not dies
  (b) paired-negative: make_test_repo() test file missing stub → ❌ violation detected + message text asserted
  (c) non-empty happy path: stub present → no violation
  + scope gate, multi-script, dedup, T15 self-application arms
- Delete packages/core/audit-self/hook-stub-completeness.test.sh (bash predecessor)
- Remove requireSelfTest('…hook-stub-completeness.test.sh') invocation from pre-push.ts §3a
- Remove requireSelfTest() helper (zero call sites remaining → genuinely dead)
- Leave phantom stub in tests/hooks/prior-art-trailer-hook.test.sh (harmless; out of scope)

Prior-art: skipped — bash→TS port of existing hook-stub-completeness audit (Wave 10.6), no new capability

* docs(automerge): codify branch-from-main staging flow + resync discipline (#128)

* docs(automerge): codify branch-from-main→staging flow + resync discipline; sync doc to LIVE state

main's copy was stale (still called ci-success a placeholder). Updates: status LIVE (settings applied 2026-05-22); new §2.1 branching flow — always branch FROM main, auto-merge INTO staging, with the load-bearing RESYNC discipline (ff staging→main after each promotion) that keeps staging a disposable buffer not a divergent develop; §5 recipe marked APPLIED with the real ci-success+actionlint+zizmor contexts + main owner-only protection; §6 #2 RESOLVED (#125).

Prior-art: skipped — doc codification of an already-decided flow, no new capability/dependency/subdir.

* docs(§2.1): drop trunk-based exception — everything routine → staging (0 clicks)

Maintainer's point: direct-to-main is owner-only → forces a manual merge
click per PR, the exact toil being removed. staging auto-merges (0 clicks).
So all routine work → staging; direct-to-main only for owner hotfixes.

Added dependency note: for true zero-click walk-away the agent must set
auto-merge on staging-targeted PRs, currently blocked by the git-safety
hook (allows only feat→epic). Relaxing it (permit auto-merge --base staging)
is the actual zero-click lever, and is a maintainer-side hook edit.

Prior-art: skipped — doc refinement of the codified flow, no new capability.

* feat(hooks): Wave 10.5 — bash-fallback + install.sh feature detection (#129)

Ships the critical-only bash fallback for the pre-push hook and updates
the consumer-facing dispatcher template to runtime feature detection.

Artifacts:
- packages/core/hooks/checks/registry.ts (~114 LOC): declarative
  check-registry ({ id, criticalForFallback, runner }[]) decoupling
  check-set selection from execution (ADAPT from Aider §4.8.X.2).
  Critical entries: prior-art-presence + s17-presence (both runner: 'bash'),
  per D2 + research patch §7.2.
- packages/core/hooks/checks/registry.test.ts: unit tests asserting
  bash-expressible invariant (every criticalForFallback entry → runner: 'bash')
  AND presence of both required critical entries.
- packages/core/hooks/pre-push.fallback.sh (~63 LOC): critical-only bash gate.
  Runs §7 Prior-art presence + §1.7 presence checks on origin/main..HEAD commits.
  Historical cutoff (2026-05-12) respected. bash 3.2-compatible. exit 1 if either
  required trailer is absent; exit 0 when both present or no discipline files touched.
- packages/core/templates/shared/husky-pre-push.sh: updated from OLD consumer
  pre-push to runtime dispatcher (per research patch §7.4). Node ≥20 + pre-push.ts
  present → TS-core; otherwise → bash fallback. Capability-check, NOT brand-name.
- install.sh: also copies pre-push.fallback.sh to consumer project so the
  runtime dispatcher can find it at $REPO_ROOT/packages/core/hooks/pre-push.fallback.sh.
- docs/meta-factory/prior-art-evaluations.md: SSOT entry #59 added in-commit
  (registry.ts ≥80 LOC under packages/ → capability commit gate fires).

T15 self-application: the registry invariant (every criticalForFallback check is
bash-expressible) is itself unit-tested in registry.test.ts — the rule applies to
itself. Zero edits to pre-push.ts (parallel-overlap avoidance; 10.6 owns that file).

Prior-art: prior-art-evaluations.md#59 (Aider parse_lint_cmds / self.languages, verdict ADAPT — structural pattern of decoupling selection-table from execution-runner transfers; semantic axis differs: file-language vs project-stack. Wave 10.5 registry.ts is 114 LOC ≥80 threshold, capability commit gate fires, SSOT entry added in same commit per CLAUDE.md discipline).

* fix(ci): make ci-success the sole required gate; fold actionlint+zizmor under it (#130)

Branch protection on main/staging required ci-success + actionlint + zizmor, but
actionlint/zizmor lived in workflow-integrity.yml path-filtered to
.github/workflows/** — so PRs not touching workflows (docs, packages) never
triggered them, their required contexts never reported, and the PR deadlocked
(auto-merge could never fire). PR #126 hit this exact wall.

Fix: cross-workflow `needs:` is impossible, so move actionlint + zizmor into
audit-self.yml (no path filter → runs every PR) and add them to ci-success's
`needs:`. ci-success now transitively gates the linters and always reports, so
branch protection can require ONLY ci-success. workflow-integrity.yml keeps just
the R11 branch-protection-assertion. Checks are stricter, not weaker: a broken
workflow YAML on a docs PR is now caught (previously it wasn't).

Synced: rules-manifest R11 check.command + re-rendered RULES.md table + snapshot;
RULES.md R11 prose; ci-success-gate.sh comment; automerge-staging-plan.md §5
recipe (was telling the maintainer to re-add the deadlocking contexts).

Maintainer-side follow-up: re-run the branch-protection PUT with single-context
payload {"contexts":["ci-success"]} per automerge-staging-plan.md §5.

Prior-art: skipped — moves existing CI jobs between workflow files + doc sync; no new capability, dependency, or ≥80-LOC file.

* feat(principles): principle 17 — no paid LLM in CI (DN-6 stage-1→2 promotion)

Promotes .claude/rules/no-paid-llm-in-ci.md from "Class A, grep mechanism
ready, test pending" to a real executable gate (memory-coverage-audit §10
DN-6 — the one clean stage-1→2 win in-repo). Scans .github/workflows/*.yml
for paid-LLM *usage* (ANTHROPIC/OPENAI api-key assignment or secret ref,
api.{anthropic,openai}.com hostnames, paid SDK imports) and fails CI if any
is present.

Usage-precise, not mention-counting: full-line comments are stripped first,
so the project's own negation mention (framework-self-template-render.yml:
"NO ANTHROPIC_API_KEY reference") does NOT false-positive. Negative-controls
in the test prove that, plus session/MCP tooling (claude CLI, context7) is
out of scope per rule §2.

Slot 17 (01-16 occupied). Runs in CI via principles-meta-tests → gated by
ci-success. 7/7 local; full suite 17 files / 106 tests green.

§1.7: forward-check applied — principle 17 IS the executable artifact for an existing prose rule (no-paid-llm-in-ci.md §1/§6 "pre-merge grep" counter); paired-negatives at packages/core/principles/17-no-paid-llm-in-ci.test.ts:91 (api-key assignment), :96 (hostname), :101 (SDK) prove detection, negative-controls at :107/:112 prevent false-positives. Backward-check sweep — reviewed principle slots 01-16 (17 next free) + prior-art-evaluations.md; no overlap (secret-scanners detect leaked creds, this bans a paid-LLM dependency surface — inverse problem class).
Prior-art: skipped — principle test for the existing no-paid-llm-in-ci.md rule (DN-6 promotion); no new capability/dependency/subdir, mirrors principle 15/16 precedent.
artyhoo added a commit that referenced this pull request May 22, 2026
…plan (DECISION=C) (#135)

* feat(principles): principle 17 — no paid LLM in CI (DN-6) [→staging live-test] (#132) (#133)

* docs(research): memory coverage audit (memory → docs → tests) 2026-05-22 (#126)

R-phase report: triages all 51 project-memory files against the project
goal (rule = executable test), builds a 30-row coverage matrix by pipeline
stage (0 memory-only / 1 prose / 2 executable), and proposes a forward-going
memory-codification discipline (write-time + local-audit + periodic re-audit).
No implementation — gap-closure + new rule are a separate PR after maintainer GO.

Successor to 2026-05-13 memory-to-docs codification audit (extends memory→docs
for 6 entries to memory→docs→tests over all 51 files). Surfaces T16 stale-header
finding (principle tests 11/12/13 shipped but rule headers say "pending").

Prior-art: skipped — research-patch doc only, no new capability/dependency; reuses 2026-05-13 §7 REUSE verdict (Cline Memory Bank + CC scope hierarchy).

* feat(principles): Wave 10.6 — port hook-stub-completeness audit to principle 16 (#127)

- Add packages/core/principles/16-hook-stub-completeness.test.ts (7 tests):
  (a) real-tree vacuous pass: empty hard-fail set post-migration → passes, not dies
  (b) paired-negative: make_test_repo() test file missing stub → ❌ violation detected + message text asserted
  (c) non-empty happy path: stub present → no violation
  + scope gate, multi-script, dedup, T15 self-application arms
- Delete packages/core/audit-self/hook-stub-completeness.test.sh (bash predecessor)
- Remove requireSelfTest('…hook-stub-completeness.test.sh') invocation from pre-push.ts §3a
- Remove requireSelfTest() helper (zero call sites remaining → genuinely dead)
- Leave phantom stub in tests/hooks/prior-art-trailer-hook.test.sh (harmless; out of scope)

Prior-art: skipped — bash→TS port of existing hook-stub-completeness audit (Wave 10.6), no new capability

* docs(automerge): codify branch-from-main staging flow + resync discipline (#128)

* docs(automerge): codify branch-from-main→staging flow + resync discipline; sync doc to LIVE state

main's copy was stale (still called ci-success a placeholder). Updates: status LIVE (settings applied 2026-05-22); new §2.1 branching flow — always branch FROM main, auto-merge INTO staging, with the load-bearing RESYNC discipline (ff staging→main after each promotion) that keeps staging a disposable buffer not a divergent develop; §5 recipe marked APPLIED with the real ci-success+actionlint+zizmor contexts + main owner-only protection; §6 #2 RESOLVED (#125).

Prior-art: skipped — doc codification of an already-decided flow, no new capability/dependency/subdir.

* docs(§2.1): drop trunk-based exception — everything routine → staging (0 clicks)

Maintainer's point: direct-to-main is owner-only → forces a manual merge
click per PR, the exact toil being removed. staging auto-merges (0 clicks).
So all routine work → staging; direct-to-main only for owner hotfixes.

Added dependency note: for true zero-click walk-away the agent must set
auto-merge on staging-targeted PRs, currently blocked by the git-safety
hook (allows only feat→epic). Relaxing it (permit auto-merge --base staging)
is the actual zero-click lever, and is a maintainer-side hook edit.

Prior-art: skipped — doc refinement of the codified flow, no new capability.

* feat(hooks): Wave 10.5 — bash-fallback + install.sh feature detection (#129)

Ships the critical-only bash fallback for the pre-push hook and updates
the consumer-facing dispatcher template to runtime feature detection.

Artifacts:
- packages/core/hooks/checks/registry.ts (~114 LOC): declarative
  check-registry ({ id, criticalForFallback, runner }[]) decoupling
  check-set selection from execution (ADAPT from Aider §4.8.X.2).
  Critical entries: prior-art-presence + s17-presence (both runner: 'bash'),
  per D2 + research patch §7.2.
- packages/core/hooks/checks/registry.test.ts: unit tests asserting
  bash-expressible invariant (every criticalForFallback entry → runner: 'bash')
  AND presence of both required critical entries.
- packages/core/hooks/pre-push.fallback.sh (~63 LOC): critical-only bash gate.
  Runs §7 Prior-art presence + §1.7 presence checks on origin/main..HEAD commits.
  Historical cutoff (2026-05-12) respected. bash 3.2-compatible. exit 1 if either
  required trailer is absent; exit 0 when both present or no discipline files touched.
- packages/core/templates/shared/husky-pre-push.sh: updated from OLD consumer
  pre-push to runtime dispatcher (per research patch §7.4). Node ≥20 + pre-push.ts
  present → TS-core; otherwise → bash fallback. Capability-check, NOT brand-name.
- install.sh: also copies pre-push.fallback.sh to consumer project so the
  runtime dispatcher can find it at $REPO_ROOT/packages/core/hooks/pre-push.fallback.sh.
- docs/meta-factory/prior-art-evaluations.md: SSOT entry #59 added in-commit
  (registry.ts ≥80 LOC under packages/ → capability commit gate fires).

T15 self-application: the registry invariant (every criticalForFallback check is
bash-expressible) is itself unit-tested in registry.test.ts — the rule applies to
itself. Zero edits to pre-push.ts (parallel-overlap avoidance; 10.6 owns that file).

Prior-art: prior-art-evaluations.md#59 (Aider parse_lint_cmds / self.languages, verdict ADAPT — structural pattern of decoupling selection-table from execution-runner transfers; semantic axis differs: file-language vs project-stack. Wave 10.5 registry.ts is 114 LOC ≥80 threshold, capability commit gate fires, SSOT entry added in same commit per CLAUDE.md discipline).

* fix(ci): make ci-success the sole required gate; fold actionlint+zizmor under it (#130)

Branch protection on main/staging required ci-success + actionlint + zizmor, but
actionlint/zizmor lived in workflow-integrity.yml path-filtered to
.github/workflows/** — so PRs not touching workflows (docs, packages) never
triggered them, their required contexts never reported, and the PR deadlocked
(auto-merge could never fire). PR #126 hit this exact wall.

Fix: cross-workflow `needs:` is impossible, so move actionlint + zizmor into
audit-self.yml (no path filter → runs every PR) and add them to ci-success's
`needs:`. ci-success now transitively gates the linters and always reports, so
branch protection can require ONLY ci-success. workflow-integrity.yml keeps just
the R11 branch-protection-assertion. Checks are stricter, not weaker: a broken
workflow YAML on a docs PR is now caught (previously it wasn't).

Synced: rules-manifest R11 check.command + re-rendered RULES.md table + snapshot;
RULES.md R11 prose; ci-success-gate.sh comment; automerge-staging-plan.md §5
recipe (was telling the maintainer to re-add the deadlocking contexts).

Maintainer-side follow-up: re-run the branch-protection PUT with single-context
payload {"contexts":["ci-success"]} per automerge-staging-plan.md §5.

Prior-art: skipped — moves existing CI jobs between workflow files + doc sync; no new capability, dependency, or ≥80-LOC file.

* feat(principles): principle 17 — no paid LLM in CI (DN-6 stage-1→2 promotion)

Promotes .claude/rules/no-paid-llm-in-ci.md from "Class A, grep mechanism
ready, test pending" to a real executable gate (memory-coverage-audit §10
DN-6 — the one clean stage-1→2 win in-repo). Scans .github/workflows/*.yml
for paid-LLM *usage* (ANTHROPIC/OPENAI api-key assignment or secret ref,
api.{anthropic,openai}.com hostnames, paid SDK imports) and fails CI if any
is present.

Usage-precise, not mention-counting: full-line comments are stripped first,
so the project's own negation mention (framework-self-template-render.yml:
"NO ANTHROPIC_API_KEY reference") does NOT false-positive. Negative-controls
in the test prove that, plus session/MCP tooling (claude CLI, context7) is
out of scope per rule §2.

Slot 17 (01-16 occupied). Runs in CI via principles-meta-tests → gated by
ci-success. 7/7 local; full suite 17 files / 106 tests green.

§1.7: forward-check applied — principle 17 IS the executable artifact for an existing prose rule (no-paid-llm-in-ci.md §1/§6 "pre-merge grep" counter); paired-negatives at packages/core/principles/17-no-paid-llm-in-ci.test.ts:91 (api-key assignment), :96 (hostname), :101 (SDK) prove detection, negative-controls at :107/:112 prevent false-positives. Backward-check sweep — reviewed principle slots 01-16 (17 next free) + prior-art-evaluations.md; no overlap (secret-scanners detect leaked creds, this bans a paid-LLM dependency surface — inverse problem class).
Prior-art: skipped — principle test for the existing no-paid-llm-in-ci.md rule (DN-6 promotion); no new capability/dependency/subdir, mirrors principle 15/16 precedent.

* docs(research-patches): N7 dogfood-companions process-layer adoption plan (DECISION=C, axis B)

Read-only research deliverable for roadmap Wave N7. Inventories Superpowers process-layer
artefacts (SDD skill, using-git-worktrees) dogfoodable in our own dev under DECISION=C;
ADOPT both at process layer with explicit substrate-purity boundary (axis A never coupled).
Verifies isolation:"worktree" compatibility (DeepWiki, not name-assumed). Proposes SSOT
#60/#61 in-text (not written — surfaced for maintainer application after the §4-step-5
empirical trial). N0-storm overlap noted. §7 carries the §1.7 forward/backward self-review.

Prior-art: skipped — research-patch doc only, no capability artefact (DeepWiki ×3 + WebSearch ×3 evidence in §2; SSOT rows proposed not written).
artyhoo added a commit that referenced this pull request May 22, 2026
…dation (#136)

* feat(principles): principle 17 — no paid LLM in CI (DN-6) [→staging live-test] (#132) (#133)

* docs(research): memory coverage audit (memory → docs → tests) 2026-05-22 (#126)

R-phase report: triages all 51 project-memory files against the project
goal (rule = executable test), builds a 30-row coverage matrix by pipeline
stage (0 memory-only / 1 prose / 2 executable), and proposes a forward-going
memory-codification discipline (write-time + local-audit + periodic re-audit).
No implementation — gap-closure + new rule are a separate PR after maintainer GO.

Successor to 2026-05-13 memory-to-docs codification audit (extends memory→docs
for 6 entries to memory→docs→tests over all 51 files). Surfaces T16 stale-header
finding (principle tests 11/12/13 shipped but rule headers say "pending").

Prior-art: skipped — research-patch doc only, no new capability/dependency; reuses 2026-05-13 §7 REUSE verdict (Cline Memory Bank + CC scope hierarchy).

* feat(principles): Wave 10.6 — port hook-stub-completeness audit to principle 16 (#127)

- Add packages/core/principles/16-hook-stub-completeness.test.ts (7 tests):
  (a) real-tree vacuous pass: empty hard-fail set post-migration → passes, not dies
  (b) paired-negative: make_test_repo() test file missing stub → ❌ violation detected + message text asserted
  (c) non-empty happy path: stub present → no violation
  + scope gate, multi-script, dedup, T15 self-application arms
- Delete packages/core/audit-self/hook-stub-completeness.test.sh (bash predecessor)
- Remove requireSelfTest('…hook-stub-completeness.test.sh') invocation from pre-push.ts §3a
- Remove requireSelfTest() helper (zero call sites remaining → genuinely dead)
- Leave phantom stub in tests/hooks/prior-art-trailer-hook.test.sh (harmless; out of scope)

Prior-art: skipped — bash→TS port of existing hook-stub-completeness audit (Wave 10.6), no new capability

* docs(automerge): codify branch-from-main staging flow + resync discipline (#128)

* docs(automerge): codify branch-from-main→staging flow + resync discipline; sync doc to LIVE state

main's copy was stale (still called ci-success a placeholder). Updates: status LIVE (settings applied 2026-05-22); new §2.1 branching flow — always branch FROM main, auto-merge INTO staging, with the load-bearing RESYNC discipline (ff staging→main after each promotion) that keeps staging a disposable buffer not a divergent develop; §5 recipe marked APPLIED with the real ci-success+actionlint+zizmor contexts + main owner-only protection; §6 #2 RESOLVED (#125).

Prior-art: skipped — doc codification of an already-decided flow, no new capability/dependency/subdir.

* docs(§2.1): drop trunk-based exception — everything routine → staging (0 clicks)

Maintainer's point: direct-to-main is owner-only → forces a manual merge
click per PR, the exact toil being removed. staging auto-merges (0 clicks).
So all routine work → staging; direct-to-main only for owner hotfixes.

Added dependency note: for true zero-click walk-away the agent must set
auto-merge on staging-targeted PRs, currently blocked by the git-safety
hook (allows only feat→epic). Relaxing it (permit auto-merge --base staging)
is the actual zero-click lever, and is a maintainer-side hook edit.

Prior-art: skipped — doc refinement of the codified flow, no new capability.

* feat(hooks): Wave 10.5 — bash-fallback + install.sh feature detection (#129)

Ships the critical-only bash fallback for the pre-push hook and updates
the consumer-facing dispatcher template to runtime feature detection.

Artifacts:
- packages/core/hooks/checks/registry.ts (~114 LOC): declarative
  check-registry ({ id, criticalForFallback, runner }[]) decoupling
  check-set selection from execution (ADAPT from Aider §4.8.X.2).
  Critical entries: prior-art-presence + s17-presence (both runner: 'bash'),
  per D2 + research patch §7.2.
- packages/core/hooks/checks/registry.test.ts: unit tests asserting
  bash-expressible invariant (every criticalForFallback entry → runner: 'bash')
  AND presence of both required critical entries.
- packages/core/hooks/pre-push.fallback.sh (~63 LOC): critical-only bash gate.
  Runs §7 Prior-art presence + §1.7 presence checks on origin/main..HEAD commits.
  Historical cutoff (2026-05-12) respected. bash 3.2-compatible. exit 1 if either
  required trailer is absent; exit 0 when both present or no discipline files touched.
- packages/core/templates/shared/husky-pre-push.sh: updated from OLD consumer
  pre-push to runtime dispatcher (per research patch §7.4). Node ≥20 + pre-push.ts
  present → TS-core; otherwise → bash fallback. Capability-check, NOT brand-name.
- install.sh: also copies pre-push.fallback.sh to consumer project so the
  runtime dispatcher can find it at $REPO_ROOT/packages/core/hooks/pre-push.fallback.sh.
- docs/meta-factory/prior-art-evaluations.md: SSOT entry #59 added in-commit
  (registry.ts ≥80 LOC under packages/ → capability commit gate fires).

T15 self-application: the registry invariant (every criticalForFallback check is
bash-expressible) is itself unit-tested in registry.test.ts — the rule applies to
itself. Zero edits to pre-push.ts (parallel-overlap avoidance; 10.6 owns that file).

Prior-art: prior-art-evaluations.md#59 (Aider parse_lint_cmds / self.languages, verdict ADAPT — structural pattern of decoupling selection-table from execution-runner transfers; semantic axis differs: file-language vs project-stack. Wave 10.5 registry.ts is 114 LOC ≥80 threshold, capability commit gate fires, SSOT entry added in same commit per CLAUDE.md discipline).

* fix(ci): make ci-success the sole required gate; fold actionlint+zizmor under it (#130)

Branch protection on main/staging required ci-success + actionlint + zizmor, but
actionlint/zizmor lived in workflow-integrity.yml path-filtered to
.github/workflows/** — so PRs not touching workflows (docs, packages) never
triggered them, their required contexts never reported, and the PR deadlocked
(auto-merge could never fire). PR #126 hit this exact wall.

Fix: cross-workflow `needs:` is impossible, so move actionlint + zizmor into
audit-self.yml (no path filter → runs every PR) and add them to ci-success's
`needs:`. ci-success now transitively gates the linters and always reports, so
branch protection can require ONLY ci-success. workflow-integrity.yml keeps just
the R11 branch-protection-assertion. Checks are stricter, not weaker: a broken
workflow YAML on a docs PR is now caught (previously it wasn't).

Synced: rules-manifest R11 check.command + re-rendered RULES.md table + snapshot;
RULES.md R11 prose; ci-success-gate.sh comment; automerge-staging-plan.md §5
recipe (was telling the maintainer to re-add the deadlocking contexts).

Maintainer-side follow-up: re-run the branch-protection PUT with single-context
payload {"contexts":["ci-success"]} per automerge-staging-plan.md §5.

Prior-art: skipped — moves existing CI jobs between workflow files + doc sync; no new capability, dependency, or ≥80-LOC file.

* feat(principles): principle 17 — no paid LLM in CI (DN-6 stage-1→2 promotion)

Promotes .claude/rules/no-paid-llm-in-ci.md from "Class A, grep mechanism
ready, test pending" to a real executable gate (memory-coverage-audit §10
DN-6 — the one clean stage-1→2 win in-repo). Scans .github/workflows/*.yml
for paid-LLM *usage* (ANTHROPIC/OPENAI api-key assignment or secret ref,
api.{anthropic,openai}.com hostnames, paid SDK imports) and fails CI if any
is present.

Usage-precise, not mention-counting: full-line comments are stripped first,
so the project's own negation mention (framework-self-template-render.yml:
"NO ANTHROPIC_API_KEY reference") does NOT false-positive. Negative-controls
in the test prove that, plus session/MCP tooling (claude CLI, context7) is
out of scope per rule §2.

Slot 17 (01-16 occupied). Runs in CI via principles-meta-tests → gated by
ci-success. 7/7 local; full suite 17 files / 106 tests green.

§1.7: forward-check applied — principle 17 IS the executable artifact for an existing prose rule (no-paid-llm-in-ci.md §1/§6 "pre-merge grep" counter); paired-negatives at packages/core/principles/17-no-paid-llm-in-ci.test.ts:91 (api-key assignment), :96 (hostname), :101 (SDK) prove detection, negative-controls at :107/:112 prevent false-positives. Backward-check sweep — reviewed principle slots 01-16 (17 next free) + prior-art-evaluations.md; no overlap (secret-scanners detect leaked creds, this bans a paid-LLM dependency surface — inverse problem class).
Prior-art: skipped — principle test for the existing no-paid-llm-in-ci.md rule (DN-6 promotion); no new capability/dependency/subdir, mirrors principle 15/16 precedent.

* docs(research-patches): N4b recommendation-moment gate design consolidation

Read-only research deliverable for roadmap Wave N4b. Consolidates iterative rounds 1–5 +
a fresh prior-art re-verification (DeepWiki ×4 + WebSearch ×3, 2026-05-22) sustaining the
BUILD verdict for H10; ADOPT-VOCABULARY for AgentSpec trigger→check→enforce. Does NOT
re-open D6 (H1 shipped / H2 rejected / H10 trigger-gated, §13.39). Advances within D6 by
surfacing two not-yet-shipped low-cost mechanisms (W1 §1.7-allowlist tightening; Option B
compliance-verifier extension) as recommended follow-up — surfaced, not applied (both touch
maintainer-owned enforcement/agent files). §8 carries the §1.7 forward/backward self-review.

Prior-art: skipped — research-patch doc only, no capability artefact (DeepWiki ×4 + WebSearch ×3 evidence in §2; SSOT #62 proposed not written, to ship only with H10).
artyhoo added a commit that referenced this pull request May 22, 2026
…le (#139)

* feat(principles): principle 17 — no paid LLM in CI (DN-6) [→staging live-test] (#132) (#133)

* docs(research): memory coverage audit (memory → docs → tests) 2026-05-22 (#126)

R-phase report: triages all 51 project-memory files against the project
goal (rule = executable test), builds a 30-row coverage matrix by pipeline
stage (0 memory-only / 1 prose / 2 executable), and proposes a forward-going
memory-codification discipline (write-time + local-audit + periodic re-audit).
No implementation — gap-closure + new rule are a separate PR after maintainer GO.

Successor to 2026-05-13 memory-to-docs codification audit (extends memory→docs
for 6 entries to memory→docs→tests over all 51 files). Surfaces T16 stale-header
finding (principle tests 11/12/13 shipped but rule headers say "pending").

Prior-art: skipped — research-patch doc only, no new capability/dependency; reuses 2026-05-13 §7 REUSE verdict (Cline Memory Bank + CC scope hierarchy).

* feat(principles): Wave 10.6 — port hook-stub-completeness audit to principle 16 (#127)

- Add packages/core/principles/16-hook-stub-completeness.test.ts (7 tests):
  (a) real-tree vacuous pass: empty hard-fail set post-migration → passes, not dies
  (b) paired-negative: make_test_repo() test file missing stub → ❌ violation detected + message text asserted
  (c) non-empty happy path: stub present → no violation
  + scope gate, multi-script, dedup, T15 self-application arms
- Delete packages/core/audit-self/hook-stub-completeness.test.sh (bash predecessor)
- Remove requireSelfTest('…hook-stub-completeness.test.sh') invocation from pre-push.ts §3a
- Remove requireSelfTest() helper (zero call sites remaining → genuinely dead)
- Leave phantom stub in tests/hooks/prior-art-trailer-hook.test.sh (harmless; out of scope)

Prior-art: skipped — bash→TS port of existing hook-stub-completeness audit (Wave 10.6), no new capability

* docs(automerge): codify branch-from-main staging flow + resync discipline (#128)

* docs(automerge): codify branch-from-main→staging flow + resync discipline; sync doc to LIVE state

main's copy was stale (still called ci-success a placeholder). Updates: status LIVE (settings applied 2026-05-22); new §2.1 branching flow — always branch FROM main, auto-merge INTO staging, with the load-bearing RESYNC discipline (ff staging→main after each promotion) that keeps staging a disposable buffer not a divergent develop; §5 recipe marked APPLIED with the real ci-success+actionlint+zizmor contexts + main owner-only protection; §6 #2 RESOLVED (#125).

Prior-art: skipped — doc codification of an already-decided flow, no new capability/dependency/subdir.

* docs(§2.1): drop trunk-based exception — everything routine → staging (0 clicks)

Maintainer's point: direct-to-main is owner-only → forces a manual merge
click per PR, the exact toil being removed. staging auto-merges (0 clicks).
So all routine work → staging; direct-to-main only for owner hotfixes.

Added dependency note: for true zero-click walk-away the agent must set
auto-merge on staging-targeted PRs, currently blocked by the git-safety
hook (allows only feat→epic). Relaxing it (permit auto-merge --base staging)
is the actual zero-click lever, and is a maintainer-side hook edit.

Prior-art: skipped — doc refinement of the codified flow, no new capability.

* feat(hooks): Wave 10.5 — bash-fallback + install.sh feature detection (#129)

Ships the critical-only bash fallback for the pre-push hook and updates
the consumer-facing dispatcher template to runtime feature detection.

Artifacts:
- packages/core/hooks/checks/registry.ts (~114 LOC): declarative
  check-registry ({ id, criticalForFallback, runner }[]) decoupling
  check-set selection from execution (ADAPT from Aider §4.8.X.2).
  Critical entries: prior-art-presence + s17-presence (both runner: 'bash'),
  per D2 + research patch §7.2.
- packages/core/hooks/checks/registry.test.ts: unit tests asserting
  bash-expressible invariant (every criticalForFallback entry → runner: 'bash')
  AND presence of both required critical entries.
- packages/core/hooks/pre-push.fallback.sh (~63 LOC): critical-only bash gate.
  Runs §7 Prior-art presence + §1.7 presence checks on origin/main..HEAD commits.
  Historical cutoff (2026-05-12) respected. bash 3.2-compatible. exit 1 if either
  required trailer is absent; exit 0 when both present or no discipline files touched.
- packages/core/templates/shared/husky-pre-push.sh: updated from OLD consumer
  pre-push to runtime dispatcher (per research patch §7.4). Node ≥20 + pre-push.ts
  present → TS-core; otherwise → bash fallback. Capability-check, NOT brand-name.
- install.sh: also copies pre-push.fallback.sh to consumer project so the
  runtime dispatcher can find it at $REPO_ROOT/packages/core/hooks/pre-push.fallback.sh.
- docs/meta-factory/prior-art-evaluations.md: SSOT entry #59 added in-commit
  (registry.ts ≥80 LOC under packages/ → capability commit gate fires).

T15 self-application: the registry invariant (every criticalForFallback check is
bash-expressible) is itself unit-tested in registry.test.ts — the rule applies to
itself. Zero edits to pre-push.ts (parallel-overlap avoidance; 10.6 owns that file).

Prior-art: prior-art-evaluations.md#59 (Aider parse_lint_cmds / self.languages, verdict ADAPT — structural pattern of decoupling selection-table from execution-runner transfers; semantic axis differs: file-language vs project-stack. Wave 10.5 registry.ts is 114 LOC ≥80 threshold, capability commit gate fires, SSOT entry added in same commit per CLAUDE.md discipline).

* fix(ci): make ci-success the sole required gate; fold actionlint+zizmor under it (#130)

Branch protection on main/staging required ci-success + actionlint + zizmor, but
actionlint/zizmor lived in workflow-integrity.yml path-filtered to
.github/workflows/** — so PRs not touching workflows (docs, packages) never
triggered them, their required contexts never reported, and the PR deadlocked
(auto-merge could never fire). PR #126 hit this exact wall.

Fix: cross-workflow `needs:` is impossible, so move actionlint + zizmor into
audit-self.yml (no path filter → runs every PR) and add them to ci-success's
`needs:`. ci-success now transitively gates the linters and always reports, so
branch protection can require ONLY ci-success. workflow-integrity.yml keeps just
the R11 branch-protection-assertion. Checks are stricter, not weaker: a broken
workflow YAML on a docs PR is now caught (previously it wasn't).

Synced: rules-manifest R11 check.command + re-rendered RULES.md table + snapshot;
RULES.md R11 prose; ci-success-gate.sh comment; automerge-staging-plan.md §5
recipe (was telling the maintainer to re-add the deadlocking contexts).

Maintainer-side follow-up: re-run the branch-protection PUT with single-context
payload {"contexts":["ci-success"]} per automerge-staging-plan.md §5.

Prior-art: skipped — moves existing CI jobs between workflow files + doc sync; no new capability, dependency, or ≥80-LOC file.

* feat(principles): principle 17 — no paid LLM in CI (DN-6 stage-1→2 promotion)

Promotes .claude/rules/no-paid-llm-in-ci.md from "Class A, grep mechanism
ready, test pending" to a real executable gate (memory-coverage-audit §10
DN-6 — the one clean stage-1→2 win in-repo). Scans .github/workflows/*.yml
for paid-LLM *usage* (ANTHROPIC/OPENAI api-key assignment or secret ref,
api.{anthropic,openai}.com hostnames, paid SDK imports) and fails CI if any
is present.

Usage-precise, not mention-counting: full-line comments are stripped first,
so the project's own negation mention (framework-self-template-render.yml:
"NO ANTHROPIC_API_KEY reference") does NOT false-positive. Negative-controls
in the test prove that, plus session/MCP tooling (claude CLI, context7) is
out of scope per rule §2.

Slot 17 (01-16 occupied). Runs in CI via principles-meta-tests → gated by
ci-success. 7/7 local; full suite 17 files / 106 tests green.

§1.7: forward-check applied — principle 17 IS the executable artifact for an existing prose rule (no-paid-llm-in-ci.md §1/§6 "pre-merge grep" counter); paired-negatives at packages/core/principles/17-no-paid-llm-in-ci.test.ts:91 (api-key assignment), :96 (hostname), :101 (SDK) prove detection, negative-controls at :107/:112 prevent false-positives. Backward-check sweep — reviewed principle slots 01-16 (17 next free) + prior-art-evaluations.md; no overlap (secret-scanners detect leaked creds, this bans a paid-LLM dependency surface — inverse problem class).
Prior-art: skipped — principle test for the existing no-paid-llm-in-ci.md rule (DN-6 promotion); no new capability/dependency/subdir, mirrors principle 15/16 precedent.

* docs(research): rule-enforcement channel-selection prior-art survey

Survey of just-in-time rule delivery to AI agents (companion-first:
Superpowers/aif-handoff/AIF/OhMyOpencode -> CC-native -> ecosystem).
Validates+refines the narrowest-reachable-channel principle into a
two-axis model (detectability->gate/inject; relevance->breadth).
Proposes SSOT rows #60-#63; codification home deferred to maintainer (Option A).

* feat(rules): rule-enforcement channel-selection (Class C)

Codify the narrowest-reachable-channel principle from the 2026-05-22
prior-art survey: deliver each rule by two axes (detectability->gate/inject;
relevance->breadth), reliability-ordered (deterministic matcher >= always-on
> semantic > memory). Reserve always-on for 3-4 invariants; never memory for
load-bearing rules. Register the rule in principle 09 REQUIRED_HEADER_DOCS so
its authority header is enforced. Class C (mechanism deferred: ADAPT
rule-injector hook per patch section 4).

Prior-art: research-patches/2026-05-22-rule-enforcement-channel-selection.md — prior-art survey (Superpowers / aif-handoff / AIF / OhMyOpencode / Cursor / Agent RuleZ). Verdict: the meta-discipline (which-channel selection) is BUILD — no upstream rule-selection discipline to adopt verbatim; delivery mechanisms are REFERENCE (CC hooks native, SSOT #20). Proposed SSOT rows #60-#63 surfaced for maintainer, not written.

§1.7: forward-check applied — rule complies with no-paid-llm-in-ci (deferred ADAPT hook is deterministic bash, not an LLM call), doc-authority-hierarchy (Class + Authoritative-for header present; registered at packages/core/principles/09-doc-authority-hierarchy.ts:43 so principle 09 enforces its header — verified test 17/17), and README earliest-reachable-channel (delivery-scope companion on a separate axis, not a conflicting goal claim); backward-check sweep — the channel-declaration obligation (rule §3 step 5) is forward-going per the §6 'Existing rules' note, parallel to dual-implementation-discipline §9; no retroactive sweep of the existing .claude/rules/*.md required, no CI gate checks channel declaration (Class C).
artyhoo added a commit that referenced this pull request May 22, 2026
…0) (#140)

* feat(principles): principle 17 — no paid LLM in CI (DN-6) [→staging live-test] (#132) (#133)

* docs(research): memory coverage audit (memory → docs → tests) 2026-05-22 (#126)

R-phase report: triages all 51 project-memory files against the project
goal (rule = executable test), builds a 30-row coverage matrix by pipeline
stage (0 memory-only / 1 prose / 2 executable), and proposes a forward-going
memory-codification discipline (write-time + local-audit + periodic re-audit).
No implementation — gap-closure + new rule are a separate PR after maintainer GO.

Successor to 2026-05-13 memory-to-docs codification audit (extends memory→docs
for 6 entries to memory→docs→tests over all 51 files). Surfaces T16 stale-header
finding (principle tests 11/12/13 shipped but rule headers say "pending").

Prior-art: skipped — research-patch doc only, no new capability/dependency; reuses 2026-05-13 §7 REUSE verdict (Cline Memory Bank + CC scope hierarchy).

* feat(principles): Wave 10.6 — port hook-stub-completeness audit to principle 16 (#127)

- Add packages/core/principles/16-hook-stub-completeness.test.ts (7 tests):
  (a) real-tree vacuous pass: empty hard-fail set post-migration → passes, not dies
  (b) paired-negative: make_test_repo() test file missing stub → ❌ violation detected + message text asserted
  (c) non-empty happy path: stub present → no violation
  + scope gate, multi-script, dedup, T15 self-application arms
- Delete packages/core/audit-self/hook-stub-completeness.test.sh (bash predecessor)
- Remove requireSelfTest('…hook-stub-completeness.test.sh') invocation from pre-push.ts §3a
- Remove requireSelfTest() helper (zero call sites remaining → genuinely dead)
- Leave phantom stub in tests/hooks/prior-art-trailer-hook.test.sh (harmless; out of scope)

Prior-art: skipped — bash→TS port of existing hook-stub-completeness audit (Wave 10.6), no new capability

* docs(automerge): codify branch-from-main staging flow + resync discipline (#128)

* docs(automerge): codify branch-from-main→staging flow + resync discipline; sync doc to LIVE state

main's copy was stale (still called ci-success a placeholder). Updates: status LIVE (settings applied 2026-05-22); new §2.1 branching flow — always branch FROM main, auto-merge INTO staging, with the load-bearing RESYNC discipline (ff staging→main after each promotion) that keeps staging a disposable buffer not a divergent develop; §5 recipe marked APPLIED with the real ci-success+actionlint+zizmor contexts + main owner-only protection; §6 #2 RESOLVED (#125).

Prior-art: skipped — doc codification of an already-decided flow, no new capability/dependency/subdir.

* docs(§2.1): drop trunk-based exception — everything routine → staging (0 clicks)

Maintainer's point: direct-to-main is owner-only → forces a manual merge
click per PR, the exact toil being removed. staging auto-merges (0 clicks).
So all routine work → staging; direct-to-main only for owner hotfixes.

Added dependency note: for true zero-click walk-away the agent must set
auto-merge on staging-targeted PRs, currently blocked by the git-safety
hook (allows only feat→epic). Relaxing it (permit auto-merge --base staging)
is the actual zero-click lever, and is a maintainer-side hook edit.

Prior-art: skipped — doc refinement of the codified flow, no new capability.

* feat(hooks): Wave 10.5 — bash-fallback + install.sh feature detection (#129)

Ships the critical-only bash fallback for the pre-push hook and updates
the consumer-facing dispatcher template to runtime feature detection.

Artifacts:
- packages/core/hooks/checks/registry.ts (~114 LOC): declarative
  check-registry ({ id, criticalForFallback, runner }[]) decoupling
  check-set selection from execution (ADAPT from Aider §4.8.X.2).
  Critical entries: prior-art-presence + s17-presence (both runner: 'bash'),
  per D2 + research patch §7.2.
- packages/core/hooks/checks/registry.test.ts: unit tests asserting
  bash-expressible invariant (every criticalForFallback entry → runner: 'bash')
  AND presence of both required critical entries.
- packages/core/hooks/pre-push.fallback.sh (~63 LOC): critical-only bash gate.
  Runs §7 Prior-art presence + §1.7 presence checks on origin/main..HEAD commits.
  Historical cutoff (2026-05-12) respected. bash 3.2-compatible. exit 1 if either
  required trailer is absent; exit 0 when both present or no discipline files touched.
- packages/core/templates/shared/husky-pre-push.sh: updated from OLD consumer
  pre-push to runtime dispatcher (per research patch §7.4). Node ≥20 + pre-push.ts
  present → TS-core; otherwise → bash fallback. Capability-check, NOT brand-name.
- install.sh: also copies pre-push.fallback.sh to consumer project so the
  runtime dispatcher can find it at $REPO_ROOT/packages/core/hooks/pre-push.fallback.sh.
- docs/meta-factory/prior-art-evaluations.md: SSOT entry #59 added in-commit
  (registry.ts ≥80 LOC under packages/ → capability commit gate fires).

T15 self-application: the registry invariant (every criticalForFallback check is
bash-expressible) is itself unit-tested in registry.test.ts — the rule applies to
itself. Zero edits to pre-push.ts (parallel-overlap avoidance; 10.6 owns that file).

Prior-art: prior-art-evaluations.md#59 (Aider parse_lint_cmds / self.languages, verdict ADAPT — structural pattern of decoupling selection-table from execution-runner transfers; semantic axis differs: file-language vs project-stack. Wave 10.5 registry.ts is 114 LOC ≥80 threshold, capability commit gate fires, SSOT entry added in same commit per CLAUDE.md discipline).

* fix(ci): make ci-success the sole required gate; fold actionlint+zizmor under it (#130)

Branch protection on main/staging required ci-success + actionlint + zizmor, but
actionlint/zizmor lived in workflow-integrity.yml path-filtered to
.github/workflows/** — so PRs not touching workflows (docs, packages) never
triggered them, their required contexts never reported, and the PR deadlocked
(auto-merge could never fire). PR #126 hit this exact wall.

Fix: cross-workflow `needs:` is impossible, so move actionlint + zizmor into
audit-self.yml (no path filter → runs every PR) and add them to ci-success's
`needs:`. ci-success now transitively gates the linters and always reports, so
branch protection can require ONLY ci-success. workflow-integrity.yml keeps just
the R11 branch-protection-assertion. Checks are stricter, not weaker: a broken
workflow YAML on a docs PR is now caught (previously it wasn't).

Synced: rules-manifest R11 check.command + re-rendered RULES.md table + snapshot;
RULES.md R11 prose; ci-success-gate.sh comment; automerge-staging-plan.md §5
recipe (was telling the maintainer to re-add the deadlocking contexts).

Maintainer-side follow-up: re-run the branch-protection PUT with single-context
payload {"contexts":["ci-success"]} per automerge-staging-plan.md §5.

Prior-art: skipped — moves existing CI jobs between workflow files + doc sync; no new capability, dependency, or ≥80-LOC file.

* feat(principles): principle 17 — no paid LLM in CI (DN-6 stage-1→2 promotion)

Promotes .claude/rules/no-paid-llm-in-ci.md from "Class A, grep mechanism
ready, test pending" to a real executable gate (memory-coverage-audit §10
DN-6 — the one clean stage-1→2 win in-repo). Scans .github/workflows/*.yml
for paid-LLM *usage* (ANTHROPIC/OPENAI api-key assignment or secret ref,
api.{anthropic,openai}.com hostnames, paid SDK imports) and fails CI if any
is present.

Usage-precise, not mention-counting: full-line comments are stripped first,
so the project's own negation mention (framework-self-template-render.yml:
"NO ANTHROPIC_API_KEY reference") does NOT false-positive. Negative-controls
in the test prove that, plus session/MCP tooling (claude CLI, context7) is
out of scope per rule §2.

Slot 17 (01-16 occupied). Runs in CI via principles-meta-tests → gated by
ci-success. 7/7 local; full suite 17 files / 106 tests green.

§1.7: forward-check applied — principle 17 IS the executable artifact for an existing prose rule (no-paid-llm-in-ci.md §1/§6 "pre-merge grep" counter); paired-negatives at packages/core/principles/17-no-paid-llm-in-ci.test.ts:91 (api-key assignment), :96 (hostname), :101 (SDK) prove detection, negative-controls at :107/:112 prevent false-positives. Backward-check sweep — reviewed principle slots 01-16 (17 next free) + prior-art-evaluations.md; no overlap (secret-scanners detect leaked creds, this bans a paid-LLM dependency surface — inverse problem class).
Prior-art: skipped — principle test for the existing no-paid-llm-in-ci.md rule (DN-6 promotion); no new capability/dependency/subdir, mirrors principle 15/16 precedent.

* docs(meta-factory): DN-4 — memory-codification gap tracker (15 stage-0)

Dedicated tracker for the 15 stage-0 (memory-only) conventions from the
2026-05-22 memory coverage audit; close incrementally as-touched per
memory-codification.md §3 (not big-bang — open-questions was at the 500-line cap).

§1.7: Forward — complies with memory-codification.md:1 (operationalises its §3 codify-then-pointer at corpus level) + doc-authority-hierarchy.md:1 (carries Authoritative-for header). Backward — implements DN-4 from docs/meta-factory/research-patches/2026-05-22-memory-coverage-audit.md:168; rows sourced from §4 matrix rows 16-30; no existing doc superseded.
Prior-art: skipped — in-repo tracker doc, no new capability/dependency/packages ≥80 LOC.
artyhoo added a commit that referenced this pull request May 29, 2026
…eep evaluation (#268)

Variant scored: MCP-consumer bridge (handoff_create_task + accept_existing_plan +
WebSocket tail + handoff_sync_status). 7 DeepWiki probes + 2 WebSearch queries +
SSOT #27/#28/#30/#43/#44/#46/#67/#80 consult + SKILL.md:404/429 disambiguation.

Verdict: REFERENCE (not ADOPT). Body-format falsifier PASSES — description field
accepts arbitrary markdown (z.string().optional(), no .max()). Minimum call =
{projectId, title}. BUT full pipeline bridge blocked by three structural issues:
(1) accept_existing_plan requires physical PLAN.md on disk in .ai-factory/ —
filesystem coupling beyond MCP boundary; (2) WebSocket broadcast channel has no
topic filter — client must filter by taskId; (3) aif-handoff Reviewer (autoMode)
conflicts with reviewer-discipline.md §2 strategy-fork-surface gate.

Admission gate §2.4: PR #127/#128 touch packages/runtime/ only — no packages/mcp/
or apps/coordinator/ changes. Gate CLEAR.

SKILL.md:404 vs :429 inconsistency resolved analytically (both consistent — BFR
verdict = REFERENCE for SP skill; operational action = ADOPT SP dispatch template).

Prior-art: prior-art-evaluations.md#44 (DEFER, body-format now confirmed compatible);
prior-art-evaluations.md#30 (DEFER, accept_existing_plan bypass documented);
prior-art-evaluations.md#67 (REJECT unchanged — Variant A is optional layer, not
replacement). Sub-wave D proposes new SSOT row for Variant A bridge vocabulary.
artyhoo added a commit that referenced this pull request May 29, 2026
#269)

Mechanical corrections to merged SW-A (#268) + SW-B (#267) research-patches per
Phase -1 Stage 1→2 cold-review. No verdict changes — SW-A REFERENCE and SW-B
REJECT both unaffected.

- B1: SW-B :39, :117 — PR #128 IS merged. Original record used jq camelCase
  '.mergedAt' which returns null; the actual snake_case '.merged_at' returns
  2026-05-26T08:07:12Z (merge SHA 51ce96a). Verified 2026-05-29 via
  'gh api repos/lee-to/aif-handoff/pulls/128 --jq .merged_at'.
- M1: SW-A :343 — gate-4 evidence said "all are from PR #128" but BOTH
  PR #127 (e1ffa70, merged 2026-05-15) AND PR #128 (51ce96a, merged
  2026-05-26) are in the 30-day window. Both touch packages/runtime/ only.
- m1: SW-A :392 — Probe 6 URL hash typo ae7472a9 -> ae7072a9 (aligned to
  line 119 body-text canonical version; inferred from internal consistency,
  not externally re-verified due to DeepWiki client-side rendering).
- m2: SW-B :210 — overclaim "≥4 distinct phrasings on dir-watch" corrected
  to actual breakdown: 2 direct + 2 adjacent DeepWiki + 1 file-tree +
  1 gh + 3 WebSearch = 9 channels. Multi-channel triangulation noted.
- m3: SW-B §0 falsifier (:17) — aligned to §5 specificity ("…and creates
  tasks via the internal createTask function — re-evaluate as ADAPT with
  three criteria 1/2/4 re-scored…").

Phase -1 Stage 1→2 cold-review verdict was REVISE; this patch closes
B1+M1+m1/m2/m3 dispositions per state.md §3.4. DN-1 and DN-2 remain
maintainer-call; SW-C dispatch still blocked on those answers.

Prior-art: skipped — mechanical text correction, no capability commit, no
new dependency, no new file ≥50 LOC. Per CLAUDE.md capability-commit
definition, this is a refactor/typo-fix grade change to existing artifacts.
artyhoo added a commit that referenced this pull request May 29, 2026
… Implementer-equivalent only) value-add audit (#276)

R-phase patch for Sub-wave C of the aif-handoff-as-runtime-bridge umbrella.
Evaluates Variant C (kickoff §3 lines 124-145): aif-handoff as Implementer-
equivalent only, bypass Planner+Reviewer cycle, thin CLI wrapper for kickoff
dispatch + kanban status tracking.

Verdict: REJECT (BFR-default §1 ladder). Rationale:
- The kickoff-framed "aif-handoff exec --kickoff <path>" CLI does not exist
  in lee-to/aif-handoff (DeepWiki probes 1+5, 2026-05-29).
- No first-class Implementer-only mode; skipReview:true bypasses Reviewer but
  Planner is mandatory unless accept_existing_plan with on-disk PLAN.md
  (same disk coupling SW-A flagged for Variant A).
- BEFORE/AFTER maintainer-action count: 25% literal / 0% cognitive reduction
  (T-AIF-BRIDGE-C table §4) — below kickoff §8 STOP 30% threshold → verdict
  "Variant C value-add insufficient".
- Pure-tracker pattern (paused:true + autoMode:false + manual state-machine
  transitions) IS shipped but adds zero automation beyond UI tracking;
  Docker+SQLite infra unjustified.

Cites:
- SW-A merged PR #268 (Variant A REFERENCE, 28% match, 3 ADOPT-blockers)
- SW-B merged PR #267 (Variant B REJECT, ~5% match, no dir-watch capability)
- PR #269 follow-up (mechanical corrections, no verdict changes)
- DN-1=B-constrained input consumed in criterion 5 (mooted for Variant C
  which bypasses aif-handoff Reviewer entirely)
- Gate-4 admission re-sweep: PR #127+#128 touch packages/runtime/ only
  (no MCP/coordinator drift in 30-day window)

5 distinct DeepWiki probes + 2 WebSearches + cross-ref to SW-A/SW-B/PR #269
= 19+ evidence channels (T1 floor exceeded 3.8x). §1.7 forward+backward +
§self-application + T-trap walk per ai-laziness-traps.md §3.

Single output file under docs/meta-factory/research-patches/. No code, skill,
agent, install.sh, or .claude/rules/ modifications.

### §1.7 Forward-check applied

build-first-reuse-default.md §1 verdict ladder applied; BFR §3 6-layer search
performed (SSOT rows #27/#28/#29/#30/#43/#44/#46/#67/#80 reviewed at
prior-art-evaluations.md:95-148; DeepWiki >=5 probes; WebSearch >=2 phrasings;
own-stack sweep at .claude/skills/meta-orchestrator/SKILL.md:441 anti-scope +
:404+:429 SP requesting-code-review). no-paid-llm-in-ci.md §1 enforced (all
evidence via subscription-bundled DeepWiki/WebSearch + free gh CLI + bash).
reviewer-discipline.md §2 respected (DN-1=B-constrained consumed as fact, not
re-litigated; verdict is research finding against §8 STOP, not strategy
choice). ai-laziness-traps.md §3 active T-traps applied (T1, T3, T7, T11,
T12, T13, T15, T16, T17, T19, T20, T-AIF-BRIDGE-C MANDATORY BEFORE/AFTER
table at patch §4). Evidence: see patch §8 file:line citations.

### §1.7 Backward-check applied

SSOT #27/#28/#67 receive additive notes (additive-only; no verdict changes).
Original DEFER/DEFER/REJECT rationales reviewed at prior-art-evaluations.md:
95, 96, 135 — consistent with Sub-wave C findings (reinforce existing
classifications, do not re-litigate). No .claude/rules/* modified; no
.claude/skills/* modified; no agents/* modified; no packages/* modified;
no install.sh modified; no kickoff.md modified. Single output file in
docs/meta-factory/research-patches/. Scope strictly bounded to Variant C;
SW-A/SW-B/SW-B2/SW-D out of scope. T15 self-application confirmed in
patch §10. Memory not written (Sub-wave D synthesis is the natural
codification surface). Evidence: see patch §9 file:line citations.
artyhoo added a commit that referenced this pull request Jun 17, 2026
…24-128→126-130 (collision with #607 cruft/Copier 124/125)

Append-only register collision from parallel work: #607 took SSOT 124 (cruft)
+ 125 (Copier) while aif's branch also used 124-128. Renumbered aif's rows to
126-130 and updated self-refs in passport.ts + principle 23 (#124#126 CC/init,
#126#128 Repomix). Bridge-patch #127/#128 refs untouched (upstream PR numbers,
different namespace).
artyhoo added a commit that referenced this pull request Jun 17, 2026
…#547 P1) (#610)

* docs(aif-init-passport-gen): R-phase prior-art consult + parked design forks (#547 P1)

Design-first task dispatched under the LIVE park-don't-guess contract. Did the
deterministic work the contract authorizes — prior-art consult (own-stack-first
CC /init + tool-bootstrapping; WebSearch/WebFetch x3 phrasings; DeepWiki MCP
unavailable in container, substituted per #121/#123) — and PARKED the 4 genuine
design forks (delivery channel / run-timing / det-vs-LLM split / review gate)
as DECISION-NEEDED rather than guessing them. No generator code (T5, R-phase).

- SSOT #124 ADAPT (CC /init, own-stack — reuse mechanism, build schema residue)
- SSOT #125 DEFER (ai-doc-gen + human-curation research finding)
- SSOT #126 DEFER (Repomix/gitingest/StackSync — own detector covers detection)
- SSOT #127 DEFER (Cursor generators — parallel-evolution, harness-specific)
- SSOT #128 REJECT (Aider repo-map — T16 name-trap, in-context ranking != gen)
- Plan: design/R-phase output, status blocked_external/manualReviewRequired.

Prior-art: prior-art-evaluations.md#124 (CC /init ADAPT, own-stack-first), #125 (ai-doc-gen DEFER), #126 (Repomix family DEFER), #127 (Cursor generators DEFER), #128 (Aider repo-map REJECT, T16 problem-class mismatch). New SSOT entries landed in this commit.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(aif-init-passport-gen): implement AI-driven passport generation (I-phase, GH #547 P1)

Deliver the aif-init I-phase: portable agents/aif-init.md agent +
deterministic detector/passport.ts + principle 23 (2-fixture acceptance test).

Design forks resolved with evidence-backed defaults (park-don't-guess R-phase
evidence → sensible-defaults in HANDOFF_MODE=1):
- Delivery channel: agents/aif-init.md (portable markdown, ships to consumer
  .claude/agents/ via install.sh glob — same path as existing review-sidecar.md)
- Run-timing: explicit post-install AI-session step (install has no AI; #548 seam)
- Det-vs-LLM split: thin deterministic detectPassportFields() core (all null-safe,
  tested on 2+ fixtures) + agent instructs LLM to fill prose (SSOT #125 empirical:
  deterministic-inspect-first then ground LLM in that evidence)
- Review gate: explicit DRAFT banner + required human edit before removing

Files:
- agents/aif-init.md: 5-step portable agent (detect → generate DESCRIPTION.md
  → generate ARCHITECTURE.md → write DRAFT → review gate). Ships to consumers.
- packages/core/detector/passport.ts: detectPassportFields() reads root +
  workspace package.jsons, maps deps to passport fields (framework/db/orm/
  observability/testRunner/mobile/uiLayer/dbSchemaPath). All-null on unknown.
- packages/core/detector/fixtures/hono-drizzle-monorepo/: Fixture A
  (apps/api workspace: Hono + Drizzle + pg + Honeycomb + Vitest)
- packages/core/detector/fixtures/nextjs-prisma-flat/: Fixture B
  (Next.js + Prisma + Vitest flat repo)
- packages/core/principles/23-aif-init-passport-gen.test.ts: principle 23,
  13 tests - no-placeholder assertion on both fixtures + T-Passport-A counter
  (different fixtures yield different stacks, proves detection is not hardcoded)
- install.sh: add agents/aif-init.md to SHIPPED_DOCS (count 18 to 19)
- 09-doc-authority-hierarchy.ts/.test.ts: add agents/aif-init.md to
  REQUIRED_HEADER_DOCS; update install count sentinel 18 to 19

Acceptance criteria met:
1. detectPassportFields on each fixture produces zero <...> placeholders, stack-correct
2. 2 differently-shaped fixtures proved (Hono+Drizzle monorepo vs Next.js+Prisma flat)
3. AI-agnostic: agents/aif-init.md runs on operator session only; degrades to
   template copy when no AI present (see Degradation section in agent)

Prior-art: prior-art-evaluations.md#124 (CC /init ADAPT - mechanism reused:
AI session reads repo, drafts, human curates; AIF passport schema is the only
build residue), prior-art-evaluations.md#126 (Repomix/StackSync DEFER - own-stack
detectPassportFields reuses readPkgDeps pattern from read-manifest.ts, no new dep).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(aif-init): remove Bash-tool mkdir from agent — Write creates parent dir automatically (rework)

The agent prompt at agents/aif-init.md:183 previously instructed the AI to
run `Bash: mkdir -p .ai-factory` before writing output files. The Write tool
creates parent directories automatically, so this Bash invocation is incorrect
and inconsistent with the declared tool list (Read, Glob, Write only).

Prior-art: skipped — refactor only, no new capability

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant