Skip to content

feat(skill-drift): multi-channel drift detection from D-AuditC-5 - #65

Merged
artyhoo merged 3 commits into
mainfrom
feat/skill-drift-detection-wave-3-2026-05-16
May 16, 2026
Merged

feat(skill-drift): multi-channel drift detection from D-AuditC-5#65
artyhoo merged 3 commits into
mainfrom
feat/skill-drift-detection-wave-3-2026-05-16

Conversation

@artyhoo

@artyhoo artyhoo commented May 16, 2026

Copy link
Copy Markdown
Owner

Summary

Implements D-AuditC-5 verdict A+B multi-channel skill-drift detection across three channels per README invariant «every rule fails at earliest reachable channel; CI = last resort»:

Detects: (a) broken internal markdown refs in .claude/skills/**/*.md, agents/**/*.md, skills/**/*.md; (b) missing name: / description: YAML frontmatter on skill+agent files; (c) trigger-overlap inventory (WARN-only). Repo-local scope ONLY — does NOT scan ~/.claude/skills/** (non-portable for pre-push / CI).

3 atomic commits:

  • C1feat(skill-drift): bash drift detector for skill/agent files (D-AuditC-5 channel 1) (b4ed685)
  • C2feat(skill-drift): pre-push hook wires skill-drift detector (D-AuditC-5 channel 2) (a110318)
  • C3feat(skill-drift): principle test as CI last-resort gate (D-AuditC-5 channel 3) (1845a96)

Slot 14 rationale (NOT slot 11)

1A workstream reserves slots 11-13 for the BFR-default / ai-laziness-traps / phase-research-coverage cascade (per 2026-05-16-1a-drafts-substantive-review.md + decisions.md §D-AuditC-5 Known parallel work). This PR takes slot 14 to avoid cascading renumbering onto 1A. Temporary gap at 12-13 closes when 1A ships. Vitest enumerates principles via glob — non-contiguous slot numbers are fine.

Test plan

  • Pre-push hooks all pass (no --no-verify)
    • 16 pass / 0 fail on substance gates (substance, Prior-art, §1.7, body-prose)
    • hook-stub-completeness.test.sh: ✅ (scripts/check-skill-drift.sh is bypass-by-design — outside packages/core/audit-self/ scope)
    • render-rules.ts --check: rules-table region up-to-date
    • test:principles: 11 files / 58 tests pass (was 10/56 pre-PR; +1 file +2 tests)
  • Standalone scripts/check-skill-drift.sh returns exit 0 on current repo state (0 broken refs, 0 missing frontmatter, 0 trigger-overlaps)
  • Slot 14 verified free at execution time (ls packages/core/principles/14-* → absent before commit)
  • Capability-commit status verified per commit: none triggered (no new dep, no new packages/core/<dir>/, all new files < 80 LOC or outside packages/)

ATTN

  • Trigger-overlap inventory ran during pre-push (channel 2) and currently reports 0 overlaps — that may shift as new skills land; the WARN-only channel surfaces this proactively without blocking.

§1.7 Forward-check applied

Existing disciplines checked against this PR's new rule (skill-drift detection):

§1.7 Backward-check applied

Sweep of existing artefacts under the new rule's scope (skill+agent files):

🤖 Generated with Claude Code (orchestrator session, Wave 3 of 2026-05-16 D-items execution)

artyhoo added 3 commits May 16, 2026 23:48
…C-5 channel 1)

Implement edit-time channel of D-AuditC-5 multi-channel skill-drift detection
per README invariant 'every rule fails at earliest reachable channel'.

Script scans .claude/skills/, agents/, and skills/ for:
- Broken internal markdown refs (file existence verification)
- Missing 'name:' or 'description:' YAML frontmatter on skill+agent files
- Trigger-overlap inventory (WARN-only, does not fail)

Repo-local scope ONLY — does not scan ~/.claude/skills/ (per Phase -1
amendment: user-home is non-portable for pre-push / CI). User-home drift
is a separate session-bound concern.

T16 problem-class statement in the script's top comment block — ADAPT
of audit-ai-docs.test.sh pattern, not ADOPT (different problem class).

Per decisions.md D-AuditC-5 verdict A+B (2026-05-16).
…-5 channel 2)

Wire scripts/check-skill-drift.sh into .husky/pre-push as new section 3b,
positioned between hook-stub-completeness (section 3a) and manifest render
drift (section 4).

Uses [ -x ] guard so missing/non-executable script = silent pass.
Intentional bypass-by-design: scripts/check-skill-drift.sh lives outside
packages/core/audit-self/ so the hook-stub-completeness audit does not
require stub entries for it. The guard makes 'absent script' benign for
contributors who haven't pulled the script.

Hook smoke-test (§1.8) confirmed:
- hook-stub-completeness.test.sh still passes post-wire.
- scripts/check-skill-drift.sh runs cleanly on current repo state.

Per decisions.md D-AuditC-5 verdict A+B (2026-05-16).
…channel 3)

Slot 14 (NOT 11) — respect 1A workstream's reservation of 11-13 for the
BFR-default / ai-laziness-traps / phase-research-coverage cascade. Vitest
enumerates principles/**/*.test.ts via glob; non-contiguous slot numbers
are fine. Temporary gap at 12-13 closes when 1A ships.

Test delegates to scripts/check-skill-drift.sh (channel 1) — minimum-LOC
path. Does not re-implement check logic in TypeScript. Stays under
80 LOC capability-commit threshold (45 LOC); no Prior-art trailer required.

Per decisions.md D-AuditC-5 verdict A+B (2026-05-16).
@artyhoo
artyhoo merged commit be348ea into main May 16, 2026
23 checks passed
artyhoo added a commit that referenced this pull request May 22, 2026
#165)

* docs(meta-factory): N8 A-phase gate — list D1/D2/D3 explicitly in Track-1 row + dep diagram (§7 link)

Track-1 row 1.3 and the dependency diagram showed only Depends-on 1.1;
the D1/D2/D3 maintainer gate lived only in the §0 prose snapshot. An
orchestrator picking work from the operational table/diagram could start
A-phase impl before the cost-lever / bench / priority decisions are made.
Now both operational touchpoints name D1·D2·D3 + link findings §7.

Prior-art: skipped — doc-only edit, no new capability (sequencing-plan prose, no code/dep/artifact added).

* docs(meta-factory): clarify N5/N6b readiness + SSOT-ID collision in §0 (anti-confusion)

Sessions kept reading 🔲 as 'blocked' regardless of cause. Disambiguate §0:
- N5: 🔲 **BLOCKED** — gated on N7 live-dogfood trial (decision=C done, repo-side applied, live trial pending) + N2; can't give back before dogfooding reveals what's unique.
- N6b: 🔲 **NOT blocked** — deps met (N3 portable TS-core = packages/core/hooks/pre-push.ts+checks/; the 7 .claude/hooks/*.sh are thin CC-event glue, not engine; + N6a ✅). Sequenced 'last' by choice, startable anytime.
- 🔲 legend added: blocked (unmet dep) vs deprioritized (deps met, startable) — the exact distinction sessions confuse.
- ⚠ SSOT-ID collision flagged: N7 took #64/#65; N8 findings §7 proposed #64#68 → N8 A-phase renumbers to #66+ at admission.

N7 row left untouched (freshly applied by its owning session). Status reconciled against origin/staging + Wave-10 TS file inventory.
@artyhoo
artyhoo deleted the feat/skill-drift-detection-wave-3-2026-05-16 branch May 22, 2026 18:10
artyhoo added a commit that referenced this pull request May 22, 2026
…E Superpowers + SSOT #64/#65 + retention=A coexist (#166)

N7 (DECISION=C) repo-side application. Source-verified the Superpowers
adoption against shipped SKILL.md (dual-channel DeepWiki + raw WebFetch,
2026-05-22) instead of assuming from name.

- .claude/rules/parallel-subwave-isolation.md §4: drop the homegrown
  AST-detection build-target; REFERENCE Superpowers `using-git-worktrees`
  (Step 0 GIT_DIR!=GIT_COMMON skip → compatible with isolation:"worktree").
  Stays Class C; new §5 §1.7 forward/backward note.
- prior-art-evaluations.md: append SSOT #64 (SDD, ADOPT process-layer) +
  #65 (using-git-worktrees, ADOPT + REFERENCE). NOT #60/#61 — those were
  taken by the parallel channel-selection wave (the exact ID-collision §6
  warned about). "#27 = Git-Isolation" was a misattribution (#27 is
  HANDOFF_MODE) — corrected, void #27-update skipped.
- N7 patch §9 closure: source-verification findings, retention verdict
  A (coexist), ID corrections, classifier-blocked items.
- roadmap banner reconciled (DECISION=C set, original framing preserved
  append-only); sequencing-plan N7 status updated.

Retention=A: SDD review is post-implementation, orchestrator Phase -1 is
pre-dispatch + owns quota/Mode/bootstrap meta-layer SDD lacks → coexist.

Blocked (maintainer-applied): global Superpowers install + orchestrator-
skill annotation — both denied by the auto-mode classifier (untrusted
external code / self-modification). Live-dogfood trial pending those.

§1.7: Forward — demotion complies with build-first-reuse-default.md (REFERENCE-over-BUILD) + no-paid-llm-in-ci.md (using-git-worktrees pure-git); Backward — scope-reducing, only edited bullet is parallel-subwave-isolation.md:37 (§4), SSOT cross-ref at prior-art-evaluations.md row #65, full self-reflexive note at parallel-subwave-isolation.md:46
Prior-art: skipped — N7 process-layer dogfood adoption; SSOT #64/#65 appended documenting ADOPT verdicts, no new dependency or capability code added
artyhoo added a commit that referenced this pull request May 24, 2026
…p-3 (#202)

* docs(ssot): add row #71 — delegation-vs-decision discipline (round-1 BUILD evidence trail)

ATTN-1 follow-up from round-2 audit (PR #201, commit d212dae Sub-wave B
Invariant 1). Documents the external-prior-art check that justified
round-1's BUILD verdict over ADOPT for the problem class
«delegation-vs-decision discipline in skill priority-tie resolution».

Row #71 records:
- Candidate: Superpowers `using-superpowers` Red Flags table (13-entry
  skill-invocation rationalisation tracker)
- Verdict: REJECT (T16 problem-class non-match — match score ~5%)
- T16 evidence: upstream addresses *whether* to invoke a skill; ours
  addresses *who decides* among ranked priority candidates
- ADAPT credit (internal, no SSOT row per §1 scope): reviewer-discipline
  §2 «Surface-as-decision-needed» 4-step protocol

Format follows the §3 entry template + existing row precedent (#67-#70).
Last reviewed 2026-05-24. Trigger to revisit: Superpowers ships a
delegation-vs-decision skill; OR /meta-orchestrator §2 scope expands to
autonomous-pick-without-confirmation.

Not a capability commit (docs-only — §4 entry table append; no new dep,
no ≥80 LOC under packages/, no ≥50 LOC under packages/core/<new-dir>/).

Prior-art: skipped — append to existing SSOT register (one row, no new
upstream-tool adoption); the row itself IS the prior-art evidence trail
for an already-shipped BUILD decision.

§1.7: forward-check applied — row format complies with
prior-art-evaluations.md §3 entry template (next-ID 71, all 8 columns
populated, rationale cites round-2 commit d212dae + reviewer-discipline
§2 with file:line); T16 problem-class check explicit per
ai-laziness-traps.md §2 T16 (upstream-class vs our-class enumerated with
match-score). Backward-check sweep — extends existing append-only
register; does not edit prior rows; reviewer-discipline.md §2 path
verified (.claude/rules/reviewer-discipline.md exists, §2 «Surface-as-
decision-needed pattern» at line 17 of that file).

* feat(meta-orchestrator): add globs+inject markers per round-2 Invariant 4

ATTN-2 follow-up from round-2 audit (PR #201, commit d212dae Sub-wave B
Invariant 4 «recommend path-scoped injection via inject-matching-rule.sh
+ globs marker. Follow-up annotation»).

Adds <!-- globs: --> and <!-- inject: --> markers to both SKILL.md copies
(.claude/skills/ runtime + skills/ shipped), targeting:
- .claude/orchestrator-prompts/** (kickoff authoring)
- docs/meta-factory/wave-sequencing-plan.md (wave plan edits)

When extended to scan .claude/skills/*/SKILL.md, the existing
inject-matching-rule.sh hook (today scans .claude/rules/*.md per
rule-enforcement-channel-selection.md §4) will JIT-inject the
meta-orchestrator one-liner reminder on the matched edits — narrowing
discoverability from manual recall to per-edit deterministic injection.

Forward-going annotation: the hook does NOT yet scan skills/ — that is
a separate scope expansion (out of round-2 follow-up scope). Markers are
honest annotation pending that extension; the inject summary itself
carries this status note.

Marker format follows the dogfood precedent in
.claude/rules/rule-enforcement-channel-selection.md (the first repo file
to carry <!-- globs: --> / <!-- inject: --> markers).

500-line gate respected: markers placed without surrounding blank lines
(2-line net addition) so .claude/skills/meta-orchestrator/SKILL.md stays
at 500 lines (the gate limit).

Dual-file annotation per dual-implementation-discipline §7: both copies
get markers so consumer installations (via install.sh) inherit them
unchanged when the consumer-side hook supports skills/ scanning.

Not a capability commit (annotations + comments only — no new dep,
no ≥80 LOC under packages/, no ≥50 LOC under packages/core/<new-dir>/).

Prior-art: skipped — annotation-only addition implementing an already-
shipped round-2 audit recommendation (Invariant 4); no new upstream-tool
adoption (the hook itself is the existing ADAPT of OhMyOpencode
`rulesInjector` per SSOT #61).

§1.7: forward-check applied — markers conform to
rule-enforcement-channel-selection.md §4 grammar (globs subset:
prefix/**, exact path; inject summary self-documenting) verified by
re-reading .claude/hooks/inject-matching-rule.sh:53,69 parsing regex;
dual-file addition complies with dual-implementation-discipline.md §3
(consumer-facing artefact, both copies updated atomically); forward-
going annotation discipline follows rule-enforcement-channel-selection.md
§6 «Existing rules — forward-going, not retroactive». Backward-check
sweep — inline note in inject summary prevents future readers from
assuming markers are active (they activate only on hook extension); does
not modify existing § content, See also entries, or section ordering;
extends but does not supersede prior round-2 Sub-wave B Invariant 4
finding.

* fix(meta-orchestrator): plan-currency-check fetches + cross-checks origin/staging

Gap-2 follow-up from round-2 audit (PR #201, §1.5 «plan-currency-check.sh
не cross-check'ит git log origin/<branch> против локального — пропускает
свежие PR'ы»).

Before this fix the helper relied on whatever local copy of
origin/staging the user happened to have — days stale in long sessions
or after a fresh worktree, making fresh merges since last sync
invisible to the §1 plan-currency check that consumes this output.

Adds a fail-soft `git fetch --quiet origin staging` before the JSON
PR-list queries, then surfaces the count of remote-only commits via
`git rev-list HEAD..origin/staging`. If non-zero, the oneline log of
those commits is printed (capped to 10) as «likely merged PRs since
last local sync» — the explicit fresh-PR detector.

Fail-soft contract: offline / auth-failure / no-network → echoed
warning, helper continues to exit 0 (matches existing graceful-
unavailability pattern for `gh` and `git status` blocks at lines 18 /
30 / 38).

Dual-file: both `skills/meta-orchestrator/helpers/plan-currency-check.sh`
(authoring) and `.claude/skills/meta-orchestrator/helpers/plan-currency-check.sh`
(runtime) updated atomically per dual-implementation-discipline §3.

Smoke test verified: helper runs clean (exit 0), new section integrates
between branch + PR-list blocks, current-branch behaviour confirmed
(0 remote-only when synced, lists oneline when stale).

Not a capability commit (helper enhancement — no new dep, no ≥80 LOC
under packages/, no ≥50 LOC under packages/core/<new-dir>/).

Prior-art: skipped — fix to existing helper (shipped #186, audited
#192/#201) addressing a specific stale-data gap; no new upstream-tool
adoption (git rev-list + git fetch are existing capabilities).

§1.7: forward-check applied — fail-soft fetch complies with
no-paid-llm-in-ci.md §1 (deterministic git ops, no API-billed calls),
dual-implementation-discipline.md §3 (both copies updated atomically;
diff -q reports identical post-patch), ai-laziness-traps.md §2 T3
(no-prose-only findings — smoke test verifies exit 0 + correct output
on current branch state above). Backward-check sweep — addition is
between existing sections (not modifying them); the existing left-right
ahead/behind block at lines 22-23 stays unchanged (it benefits from the
fetch immediately above when re-run); does not modify §1 SKILL.md
consumer logic (helper output remains a superset of prior output —
purely additive section), so SKILL.md §1 read of this helper output is
backward-compatible.

* feat(meta-orchestrator): meta-kickoff template ships worktree setup boilerplate

Gap-3 follow-up from round-2 audit (PR #201, §1.5 «worktree symlink slot
в template — каждый worker re-discovers packages/core/node_modules
symlink discipline»).

Adds §4a «Worker worktree setup» between §4 (dispatch instructions) and
§5 (AI-traps). The slot ships the boilerplate every worker dispatched
into a `git worktree add`-created directory needs as the first session
step, otherwise the worker rediscovers (burning Opus) the workspaces /
remark requirement that `git worktree add` does NOT copy from the
primary workdir.

Detection contract uses `git rev-parse --git-dir != --git-common-dir`
(absolute path vs relative `.git`) — the same probe Superpowers
`using-git-worktrees` uses for its nested-worktree skip, per
`parallel-subwave-isolation.md §4`. Idempotent: the `if` body is a
no-op in the primary workdir; symlinks are created only when missing.

Plumbing reconstituted:
- `node_modules` → symlink to primary's `node_modules` (saves an
  `npm install` cycle inside the worktree)
- `packages/core/node_modules` → symlink to `../../node_modules`
  (workspaces hoisting marker — empirically the load-bearing one)

Dual-file: both `skills/meta-orchestrator/templates/meta-kickoff.template.md`
(authoring) and `.claude/skills/meta-orchestrator/templates/meta-kickoff.template.md`
(runtime) updated atomically per dual-implementation-discipline §3;
diff -q reports identical post-patch.

The slot lives in the template (not the helper), so it travels with
every meta-kickoff generated by `/meta-orchestrator` automatically —
the dispatch instructions {{DISPATCH_INSTRUCTIONS}} are sub-wave-
specific, this is universal worker boilerplate that precedes them.

Not a capability commit (template enhancement — no new dep, no ≥80 LOC
under packages/, no ≥50 LOC under packages/core/<new-dir>/).

Prior-art: skipped — template enhancement closing a §1.5-surfaced gap
in an already-shipped artefact (#186 + #192 + #201); no new upstream-
tool adoption (the worktree-detection probe is ADAPT from upstream
Superpowers `using-git-worktrees`, SSOT #65, already in the register).

§1.7: forward-check applied — slot complies with
no-paid-llm-in-ci.md §1 (pure-git deterministic ops, no API-billed
calls), parallel-subwave-isolation.md §4 (REFERENCE — uses the same
GIT_DIR/GIT_COMMON_DIR worktree-detection pattern Superpowers ships),
dual-implementation-discipline.md §3 (both copies updated atomically),
ai-laziness-traps.md §2 T15 (the slot itself self-applies — it codifies
the boilerplate workers were re-discovering; recursive). Backward-check
sweep — addition is purely additive (new §4a section between existing
§4 and §5; no edits to existing sections); meta-kickoff.template.md
consumers (the launch-table-generator + downstream workers reading the
generated kickoff) see the slot as static text post-template-substitution
— no placeholder logic depends on the slot's absence.
artyhoo added a commit that referenced this pull request May 29, 2026
….6 antipattern bug #39886 backstop + template §4a removal (PR #271 §8 item 4)

Extension of commit 193758a per amended kickoff scope. PR #279 hook
(WorktreeCreate `.claude/hooks/worktree-setup.sh`) shipped on its own
branch → unblocks PR #271 §8 item 4 «DELETE template §4a IFF D2 hook
lands first». §4a content is replaced with a brief migration note
pointing to PR #279 + parallel-subwave-isolation.md §1 fallback for
unwired-hook / non-CC harness setups (forward-going annotation per
dual-implementation-discipline.md §9 — not silent deletion).

* SKILL.md §7.6 antipattern (line 353, `#worker-dispatch-via-subagent`):
  add empirical-backstop reference to bug #39886
  (anthropics/claude-code#39886, closed-as-
  duplicate; Agent tool + isolation:"worktree" for WRITE tasks silently
  fails; read-only Agent dispatch remains OK). Applied via
  /tmp/iphase-skill-edit.py (idempotent + reversible recipe; state in
  /tmp/iphase-skill-revert-state.json; revert via
  /tmp/iphase-skill-revert.py).
* meta-kickoff.template.md §4a (was lines 126-148): REMOVED. Replaced
  with one-paragraph migration note: PR #279 hook handles symlinks when
  registered; unwired-hook / non-CC consumers fall back to
  parallel-subwave-isolation.md §1.

Stays out of scope (separate batches per PR #271 §8):
* item 6: parallel-subwave-isolation.md §1 rule edit (add `claude -w`
  preferred channel) — Class-A rule, separate atomic per Artifact
  Ownership Contract.
* item 7: .gitignore for .claude/worktrees/ — separate trivial atomic.
* item 8: 3 new SSOT entries in prior-art-evaluations.md — separate
  append-only batch.

Prior-art: skipped — prose migration following on the capability commit
in PR #279 (which already cited SSOT #65 Superpowers using-git-worktrees
ADOPT + tfriedel ADAPT); no new dep, no new ≥80 LOC file, no new
packages/core subdir. Bug-#39886 is an external evidence citation, not
a new SSOT entry.
artyhoo added a commit that referenced this pull request May 30, 2026
… base-ref fix (#300)

Implements the dual-channel worktree-create capability (verdict combo b+c) from
the 2026-05-30 R-phase. Two delivery channels share the `worktree-create-setup`
dual-pair anchor:

(b) BUILD scripts/create-worktree.sh — portable CLI/CI/agent-callable worktree
    setup. Accepts <name> [<project-dir>] [<base-ref>]; mirrors the hook's
    semantic check but reads CLI args instead of JSON stdin. No jq dependency.
    Base-ref is configurable (explicit arg → $WORKTREE_BASE_REF → refreshed
    origin/HEAD → fallback chain) — no hardcoded trunk name, per cold-QA
    Finding 1.

Bug 1 fix (.claude/hooks/worktree-setup.sh): `git remote set-head origin --auto`
before the base-ref candidate loop. A stale local origin/HEAD (frozen at main,
pre the 2026-05-22 staging migration) was silently basing new worktrees on the
wrong branch. Reproduced empirically this session: origin/HEAD pointed at
origin/main; --auto corrected it to origin/staging.

Marker: swapped the hook's @cc-only-rationale → @dual-pair worktree-create-setup
(a portable equivalent now exists; dual-implementation-discipline.md §6 + patch
§6.3 / cold-QA Finding 2). First dual-channel pair in the repo.

Tests (paired-negative discipline, principle 02): create-worktree.test.ts (11
cases incl. configurable base-ref + 2 paired-negatives); worktree-setup.test.ts
gains a BUG-1 regression that fails on the unfixed hook (stale origin/HEAD →
main) and passes on the fix (→ staging).

(c) REFERENCE Superpowers `using-git-worktrees` (SSOT #65) for the AI-session
    axis — unchanged; this BUILD serves the orthogonal human/CI axis.

Prior-art: docs/meta-factory/research-patches/2026-05-30-worktree-create-dual-channel.md (BUILD verdict for scripts/create-worktree.sh — BFR §3 6-layer survey, 4 candidates surveyed, no portable bash equivalent upstream) + SSOT #65 (Superpowers using-git-worktrees, ADOPT — AI-session axis only, REFERENCE here).
artyhoo added a commit that referenced this pull request May 30, 2026
…te + SSOT #87 (#301)

Follow-up to PR #300 (worktree-create dual-channel I-phase core). Wires the
shipped capability into the discipline surfaces that point at it:

- parallel-subwave-isolation.md §1: replace the raw `git worktree add ... main`
  block (a stale-base footgun since the 2026-05-22 staging migration — Bug 1's
  class) with `bash scripts/create-worktree.sh <name>`, plus a Bug 1 note on why
  base-ref must come from refreshed origin/HEAD, never a hard-coded branch.
- meta-kickoff.template.md §4: non-CC / unwired-hook fallback now points at the
  portable script instead of the manual git-worktree path.
- prior-art-evaluations.md: new SSOT row #87 (worktree-create dual-channel,
  verdict BUILD + REFERENCE #65; 4-candidate adversarial survey, T16 check,
  first dual-channel pair → dual-implementation-discipline.md §9 counter = 1).

Closes I-phase items 4/5/7 from the worktree-create-dual-channel umbrella.

Prior-art: skipped — doc-wiring only (rule/template/SSOT pointers to PR #300's already-evaluated capability), no new capability artifact in this commit.
artyhoo added a commit that referenced this pull request May 31, 2026
…и версии) (#309)

Продолжение хроники с места обрыва (v1/v3 ~22 мая, v2 до «большого переезда»):
- Чужой меч в руке: мост к рантайму aif-handoff (#289/290/293/296/298/299) +
  superset REJECT/KEEP-NARROW/REFERENCE (SSOT #86) + N7-догфуд worktree (SSOT #65)
- Распорядитель над распорядителями: /meta-orchestrator (#239-245) + inflight-check (#303)
- Застава, что не выдержала испытания: recommendation-laziness — FP=84.2% → снято,
  оставлены H1 + ловушка T20 (#206/207/210/211/212/215)
- Сторожа стерегут сторожей: Stryker-порча (#183), git.ts 0 тестов → 486 строк
- v1: догоняющие главы (Wave 10, staging-ствол, аудит памяти, worktree dual-channel #297/300/301)
  со сносками [^6]-[^13] на первоисточники; v2: догоняющая Часть XIV (переезд+двор+память)

Все falsifiable-утверждения сверены с git/research-patches/SSOT (T3-протокол).
Примечание: ~468 строк pre-push верны для .husky/pre-push (bash, до миграции, история 468/476) —
не путать с pre-push.ts (TS-порт, 447); строки 6/439 — историч. факт-чек, оставлены как есть.

Prior-art: skipped — docs/narrative chronicle edit, no new capability
artyhoo added a commit that referenced this pull request Jul 23, 2026
… pre-push preflight (#1101)

* fix(worktree): SSOT provisioning helper + doctor sweep + self-healing pre-push preflight

.claude/hooks/worktree-setup.sh has NEVER been registered: `git log -S'WorktreeCreate' --
.claude/settings.json` is empty and `jq '.hooks.WorktreeCreate'` is null in both the repo and
the user-global settings. The hook shipped in PR #279 with its registration delivered as a
PR-body HEREDOC for manual application; it was never applied, and .claude/settings.json is
agent-uncommittable, so no agent could close the gap. CLAUDE.md:182 nevertheless stated the
hook "auto-creates the worktree + node_modules symlinks". PR #1072 later added a self-heal
block INSIDE that hook for this same incident class — it cannot help, because the hook it
lives in never runs.

Live census: 63 of 125 registered worktrees under .claude/worktrees/ are unprovisioned; 32 of
them hold a real node_modules directory containing nothing but vitest's .vite caches.

Root cause of the unrecoverable state: the principles section of this very hook shells out to
vitest, which materialises node_modules/.vite inside the worktree. The path then EXISTS, so
both channels' `[[ ! -e … ]]` guards are permanently false, and `ln -sfn TARGET node_modules`
against that directory creates node_modules/node_modules — a link nested INSIDE the cache.

Changes:
- scripts/worktree-node-modules.sh (new) — single source of truth. Separates "free to
  replace" (absent | symlink | dir holding only .vite* caches) from "already provisioned"
  (conflating them was a real bug: a correct symlink is both). --check never writes.
- .claude/hooks/worktree-setup.sh + scripts/create-worktree.sh — both now call the helper
  instead of carrying byte-identical copies of the block, which was #sync-by-copy-paste under
  a shared @dual-pair anchor (dual-implementation-discipline.md §7-§8). The hook's early
  "worktree exists → reuse" return now re-provisions before returning.
- scripts/worktree-doctor.sh (new) — operator sweep over `git worktree list`; --fix applies.
- packages/core/hooks/pre-push.ts — `worktree-provisioning` section, FIRST in ALL_SECTIONS so
  the symlinks land before any section can invoke vitest. Self-heals; blocks only when the
  primary itself has no node_modules, and then names the remediation.
- CLAUDE.md — states what is actually true, including that the hook is not registered and how
  to verify it.
- worktree-setup.test.ts + create-worktree.test.ts — fixtures now ship the helper the hooks
  depend on; without it both silently no-op on `|| true` and every symlink assertion fails.

Paired fixture: packages/core/hooks/worktree-node-modules.test.ts. Verified red->green — 4 of
8 arms fail against the pre-fix inline logic (cache-poison heal, dangling-symlink re-point,
unfixable-exit-2, --check-never-writes), 8/8 with the fix. Live: a real vite-poisoned worktree
went cache-dirs -> symlinks with no nesting and tsx reachable again.

Prior-art: prior-art-evaluations.md#87 (portable worktree-creation CLI landscape, verdict BUILD — unchanged). This commit extracts the shared provisioning block of that entry's own dual pair into one home and adds a sweep over it; no new capability area, no new dependency. Last reviewed updated in this commit. Superpowers `using-git-worktrees` (#65, ADOPT) remains the AI-session axis and is untouched.

* chore(install-sh): regenerate npm-stack fingerprints after pre-push.ts edit

The 8 npm-stack baselines carry a content hash of packages/core/hooks/pre-push.ts, which
ships to consumers; adding the worktree-provisioning section changed it. Diff is exactly one
hash line per baseline — the new scripts/worktree-*.sh are maintainer tooling and are NOT in
the shipped fingerprint, which is why the section guards on existsSync(helper) and is tagged
owner: 'maintainer' (composeSections filters it out of a consumer layout entirely).

Pre-push runs test:principles, not the install-sh bash battery, so this surfaced only in CI
shard C — the known regen path (SNAPSHOT_MODE=capture bash tests/install-sh/snapshot.sh).

Prior-art: skipped — mechanical baseline regeneration after a shipped-file edit, no new capability and no new dependency.
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