From 7402956c92ffb9525fac945820af3b3307915b8e Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 28 Aug 2026 16:02:50 +0000 Subject: [PATCH 1/3] fix(docs): correct nine false claims in the L4 closure record, and fix three citations its derivation could not see MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A seventh review round audited dd6c11fe (#3477) and e7e3a368 (#3478). Their adjudications hold: the twelve citations are keep-correct, the eight L4 Group 2 rows really were already closed, the dometrain note does not over-claim. Nine surrounding statements are wrong, and one of them installed a rule describing an event that did not happen. The worst: both specs and #3478's message call 6c7a1032 (#3380) "the same commit that wrote the roster", and the roster's own closure stamp said its summary sentence "was never true". git log --diff-filter=A on docs-hygiene-sweep-unapplied-remediations.md returns 3fbe9789 (#3362), git blame puts the sentence and the whole L4 section on 3fbe97898, and #3380's only hunks in that file are in "Status at the stamp", L2, L6 and L7 -- never L4. #3362 wrote the sentence while all 34 rows were open, so it went stale rather than starting false. The rule drawn from the false version -- "a record that fixes findings and updates its own summary in the same commit must update the summary" -- is replaced by the near-inverse the evidence supports: a commit that closes findings inventoried in a record it did not author still owes that record's summary an update. The second derivation claimed "52 tokens, 0 clause 3 failures" over every citation token in the plugin-level reference/, context/ and agents/ trees. A third expression -- every skills/ path token ending in a real file extension, resolved against the base its form implies -- returns 119 tokens and 3 failures, each the exact defect class ADR 0018's correction 1 names. The first derivation's regex requires a (reference|context|actions|evals|templates)/ tail and all three end in SKILL.md, so both prior passes were blind the same way; reporting them as independent overstated the evidence. One sits 65 lines above V-sc-01 in a file a pass had verified. All three are rewritten to ${CLAUDE_PLUGIN_ROOT}/skills//…, the form each file already uses elsewhere; re-running the third expression returns 0 failures. V-review-13 and V-review-14 closed in #3468 (c66f26ce), which rewrote all three native-references sites to slash invocations, not in #3475, which touched only that convention's CHANGELOG. Fixed in both specs. Four claims live only in merged messages, which cannot be edited, so they are corrected in the spec where a reader following the refs meets them. #3477's subject says "a fired security re-trigger" while the note it adds correctly says the condition cannot be settled by reading the page. Its :943 re-anchoring credit is false: the hunk is @@ -944,0 +945,7 @@, a pure insertion that does not move 943 -- good practice, wrong justification. Its "which the note says" is false about the note. And "every one of #3468's fixes wrote a CHANGELOG entry" is false: PLUGIN-PHILOSOPHY.md and pre-pr-ordering/README.md got fixes with no entry, and pre-pr-ordering ships no CHANGELOG at all. Two precision fixes: the twelve name their replacing invocation in a later sentence of the same bullet, not the same sentence, and detector-findings :57 names none; the nine cover eight distinct targets, not eleven, which is the count across all twelve. And the absolute that the fetched-contract problem "cannot occur" for intra-plugin citations is softened, with the counter-instance named: work-items' work/SKILL.md:208 sends a reader to fetch source-control's config-resolution.md, for whom ${CLAUDE_PLUGIN_ROOT} resolves to work-items. The roster's inventory rows are untouched, per its own decay rule; only the attribution about the roster is corrected. Three plugins bumped for their own diffs. Refs #3478, refs #3477, refs #3475, refs #3468, refs #3380, refs #3362. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01UmrZGdp1dgbZuPCy7tcRJo --- ...cs-hygiene-sweep-unapplied-remediations.md | 31 ++- docs/specs/extract-ssot-sweep-2026-08-28.md | 194 ++++++++++++++++-- .../songwriting/.claude-plugin/plugin.json | 2 +- plugins/songwriting/CHANGELOG.md | 14 ++ .../research/lyric-melodic-roadmaps.md | 2 +- .../source-control/.claude-plugin/plugin.json | 2 +- plugins/source-control/CHANGELOG.md | 17 ++ .../reference/config-resolution.md | 3 +- plugins/work-items/.claude-plugin/plugin.json | 2 +- plugins/work-items/CHANGELOG.md | 12 ++ .../reference/permission-preflight.md | 3 +- 11 files changed, 247 insertions(+), 35 deletions(-) diff --git a/docs/specs/docs-hygiene-sweep-unapplied-remediations.md b/docs/specs/docs-hygiene-sweep-unapplied-remediations.md index 9f50a61e5..c7849fe71 100644 --- a/docs/specs/docs-hygiene-sweep-unapplied-remediations.md +++ b/docs/specs/docs-hygiene-sweep-unapplied-remediations.md @@ -344,13 +344,30 @@ citing text the audit quoted. > **Closure stamp, 2026-08-28. All 34 rows below are closed. The tables are left verbatim as the > inventory this record exists to preserve; only this note is added.** The sentence directly above -> is the one thing in this section that was never true: #3380 wrote it and fixed 32 of the 34 in the -> same commit, so it asserts a re-verification of citing text it had already deleted. Three separate -> later passes each re-derived this roster from scratch because of it. Rows closed by -> [#3380](https://github.com/melodic-software/claude-code-plugins/pull/3380) (`6c7a1032`): 22 of -> Group 1, **all 8 of Group 2**, and both of Group 3. `V-review-13` and `V-review-14` closed later, -> in [#3475](https://github.com/melodic-software/claude-code-plugins/pull/3475). Group 2's eight -> were rewritten from the bare `skills//` form to the anchored +> went stale rather than starting false. It was written on 2026-08-26 by +> [#3362](https://github.com/melodic-software/claude-code-plugins/pull/3362) (`3fbe9789`), the +> commit that created this file and this whole section, while all 34 rows were open; it was true +> then. Rows closed by [#3380](https://github.com/melodic-software/claude-code-plugins/pull/3380) +> (`6c7a1032`): 22 of Group 1, **all 8 of Group 2**, and both of Group 3. #3380 fixed those 32 in +> the citing files and never touched this section — `git show 6c7a1032 -- ` has hunks +> only in "Status at the stamp", L2 structure, L6 and L7 — so the summary above kept asserting a +> re-verification of citing text that no longer stood. Three separate later passes each re-derived +> this roster from scratch because of it. +> +> **Correction, 2026-08-28 (seventh review round).** An earlier version of this stamp said the +> sentence "was never true" and that "#3380 wrote it … in the same commit". Both are false, and the +> generalizable rule the sweep spec drew from them was drawn from something that did not happen. +> `git log --diff-filter=A -- docs/specs/docs-hygiene-sweep-unapplied-remediations.md` returns +> `3fbe9789` (#3362), and `git blame -L 340,343` puts the sentence on `3fbe97898`. The corrected +> rule is in the sweep spec's "The L4 roster is closed" section. +> +> `V-review-13` and `V-review-14` closed later, in +> [#3468](https://github.com/melodic-software/claude-code-plugins/pull/3468) (`c66f26ce`), which +> rewrote all three `docs/conventions/native-references/README.md` sites to slash invocations. An +> earlier version of this stamp credited #3475; that PR touched only that convention's CHANGELOG. +> The 34-closed total is unaffected either way. +> +> Group 2's eight were rewritten from the bare `skills//` form to the anchored > `${CLAUDE_PLUGIN_ROOT}/skills//` form clause 3 requires, and all seven distinct targets > resolve on disk. Group 3's two anchors were dropped to file-level links. **Do not re-derive this > roster again; verify against the sweep spec's closure section instead.** diff --git a/docs/specs/extract-ssot-sweep-2026-08-28.md b/docs/specs/extract-ssot-sweep-2026-08-28.md index 115037a6c..1306681e4 100644 --- a/docs/specs/extract-ssot-sweep-2026-08-28.md +++ b/docs/specs/extract-ssot-sweep-2026-08-28.md @@ -378,20 +378,35 @@ kept set. Every one of the twelve above was written by the fix commit itself, so individually against the test now written into [ADR 0018](../adr/0018-treat-the-plugin-as-the-encapsulation-boundary-for-skill-citation.md)'s amendment, not accepted as a class. Every one sits inside a dated entry whose claim is what a named -file contained on that date, and each is quoted as the string the entry removed, with the public -invocation that replaced it named in the same sentence. No reader is sent to any of them to get a -rule, so none is an address. Three sub-rulings the class needed: +file contained on that date, and each is quoted as the string the entry removed. No reader is sent +to any of them to get a rule, so none is an address. Three sub-rulings the class needed: - The three `config-cascade` rows quote plugin-relative forms (`skills/audit/scripts/detect.sh`, `skills/setup/SKILL.md`, `run-e2e/context/e2e-config.md`) that resolve against nothing from that - file, and the entry says so in the same sentence. Clause 3 does not fire on them: the entry - asserts their non-resolution rather than offering them as addresses, so requiring them to resolve - would delete the finding. + file, and the entry says so. Clause 3 does not fire on them: the entry asserts their + non-resolution rather than offering them as addresses, so requiring them to resolve would delete + the finding. - The other nine all resolve on disk today from the base their own form implies, checked one at a - time, so clause 3 is satisfied where it does apply. + time, so clause 3 is satisfied where it does apply. They cover **eight** distinct targets, not + eleven: `plugins/review/skills/fanout/SKILL.md` is cited by both `detector-findings` `:44` and + `native-references` `:17`. Eleven is the distinct-target count across all twelve rows, the nine + plus `config-cascade`'s three; #3477's merged message applied it to the nine, where it cannot + hold. - None of the twelve carries a line pin or a step pin, which is the part the amendment says rots first. Nothing to drop. +**Two wording corrections, seventh review round.** This section previously said each of the twelve +names "the public invocation that replaced it **in the same sentence**", and that `config-cascade`'s +entry asserts non-resolution "in the same sentence" as the quoted forms. Neither is accurate as +written, and the rulings do not depend on it. +`docs/conventions/detector-findings/CHANGELOG.md:57` names **no** invocation at all — the row "now +says 'its shape library' and 'the scanner'", which is a rename to the row's own terms rather than a +routing fix — and the other eleven name the invocation in a **later sentence of the same bullet**. +`config-cascade`'s non-resolution assertion is likewise the next sentence, at `:13-14`, after the +quotes at `:11-13`. The unit that carries the evidence claim is the bullet, not the sentence, and +the substance holds at that unit: every row states what it removed and why, and `:57` states the +replacement terms even though it names no slash invocation. Read the ruling as scoped to the bullet. + The judgment is what was missing, and it is now recorded so a pass that re-derives this shape reads a ruling instead of buying twelve fresh ones. The general lesson is worth more than the twelve rows: **a sweep that documents each fix by quoting the citation it removed manufactures new instances of @@ -452,21 +467,107 @@ because the encapsulation pass kept that record's five file-and-frontmatter cita strength of* its re-trigger clause, which means the clause was read and its own condition was not checked. Whoever re-runs the review owns the record; the citations are fine either way. +### Corrections to the merged messages of #3477 and #3478 + +A merged commit subject and body cannot be edited, so four claims those two messages make are +corrected here, where a reader who follows the refs will meet them. None changes an adjudication; +all four are the record misdescribing itself. + +**The `dometrain` subject over-claims, and the file it added does not.** `dd6c11fe`'s subject is +"…and flag a **fired** security re-trigger". Nothing in the change establishes that the re-trigger +fired. The note it added says the opposite, correctly: whether any of the eleven releases added a +trust surface "cannot be settled either way by reading this page", and the re-review is logged as +owed rather than performed. What is established is a stale review record and an unadjudicated +condition. **Read the subject as "flag a possibly-fired security re-trigger"**; the playbook text is +the accurate statement and needs no edit. Recorded rather than left, because a security claim +reading stronger in the log than in the artifact is the direction that misleads. + +**The `:943` re-anchoring was good practice for a reason that was not true.** `dd6c11fe`'s message +says the spec's `dometrain` entry pinned `MIGRATION-PLAYBOOK.md:943`, "a line this change's own edit +would have invalidated", and claims the decay rule was for the first time "caught before landing". +The insertion lands below that line: + +```console +$ git show dd6c11fe --unified=0 --format='' -- docs/MIGRATION-PLAYBOOK.md | grep '^@@' +@@ -944,0 +945,7 @@ ### Review record — `dometrain` (ACCEPT, 2026-07-22) +``` + +A pure insertion after 944 does not move 943. Re-anchoring a pin onto heading text instead of a line +number is still the right call and the entry keeps it, but the justification and the credit both go. +No violation was caught; a hazard was avoided that was not present on this diff. + +**"Two checks were run … which the note says" is false about the note.** `dd6c11fe`'s message says +two checks were run to avoid claiming a trust surface was added, "which the note says". The note +says nothing about any checks — it states the reviewed version, the shipping version, that the +question is unadjudicated, and that the re-review is owed. Whether the two checks ran is not +recoverable from the diff either. Treat the note's own text as the whole of what this pass +established. + +**"Every one of #3468's ADR-0018 citation fixes wrote a CHANGELOG entry" is false, in the +harmless direction.** `c66f26ce` also fixed two sites that produced no changelog entry: the +Convention registry row in `docs/PLUGIN-PHILOSOPHY.md`, and a `skills/confirm/SKILL.md` parenthetical +in `docs/conventions/pre-pr-ordering/README.md` — a convention that ships no `CHANGELOG.md` at all +(`ls docs/conventions/pre-pr-ordering/` returns `README.md` alone). Both were resolved by deleting +the path rather than by quoting it, so neither manufactured a new citation. The twelve-row count and +the "16 fixed and 35 kept" arithmetic are unaffected; only the universal is wrong. It matters +because the sweep's own lesson — that documenting a fix by quoting the citation it removed +manufactures the shape being swept — is a tendency of the changelog form, not a law of the pass, and +these two are the counter-examples that show the tendency is escapable. + ## The L4 roster is closed, all 34 rows, and Group 2 was never open A pass dispatched to fix the predecessor roster's eight Group 2 rows found **nothing to fix**. All eight were closed on 2026-08-26 by -[#3380](https://github.com/melodic-software/claude-code-plugins/pull/3380) (`6c7a1032`) — the same -commit that wrote the roster. Its own message says so in a clause nobody carried forward: "eight -citations written with an implied base of the plugin root while the real base was `reference/` — -none of them resolved for any reader". It fixed them and left the roster's summary line asserting -that all 34 still resolved to the citing text the audit quoted. +[#3380](https://github.com/melodic-software/claude-code-plugins/pull/3380) (`6c7a1032`). Its own +message says so in a clause nobody carried forward: "eight citations written with an implied base of +the plugin root while the real base was `reference/` — none of them resolved for any reader". It +fixed them in the citing files and left the roster's summary line asserting that all 34 still +resolved to the citing text the audit quoted. + +**#3380 did not write the roster, and that is the whole point.** An earlier version of this section, +and the merged message of +[#3478](https://github.com/melodic-software/claude-code-plugins/pull/3478) (`e7e3a368`), both called +`6c7a1032` "the same commit that wrote the roster". Both are false. The roster was created two +hours earlier the same night, by +[#3362](https://github.com/melodic-software/claude-code-plugins/pull/3362) (`3fbe9789`, 01:28), the +commit that also wrote the summary sentence, at a time when all 34 rows were open and the sentence +was true. #3380 (03:36) never touched the roster's L4 section at all: + +```console +$ git log --diff-filter=A --format='%h %s' -- docs/specs/docs-hygiene-sweep-unapplied-remediations.md +3fbe9789 docs: run all eight docs-hygiene audits repo-wide, ... (#3362) +$ git blame -L 340,343 -- docs/specs/docs-hygiene-sweep-unapplied-remediations.md # all four lines: 3fbe97898 +$ git show 6c7a1032 --unified=0 -- docs/specs/docs-hygiene-sweep-unapplied-remediations.md | grep '^@@' +@@ -75 +75 @@ ## Status at the stamp +@@ -223 +223 @@ ### `blind-pointer`, 22 +@@ -229,0 +230,31 @@ ### `blind-pointer`, 22 +@@ -577,0 +609,18 @@ ## L6 compression: 1 finding +@@ -603 +652 @@ ### P3, a pointer opens on the routing verb ... +@@ -635,0 +685,118 @@ ### P3, a pointer opens on the routing verb ... +``` + +L4 sat at 307–403 in that revision. Every hunk is outside it. **That one stale sentence has now caused four passes to re-derive the same roster**, this one included. It is the most expensive line in the sweep record, and it is expensive precisely because -it sits above an inventory whose own decay rule says the status column is its weakest part. The -lesson is not about these eight rows: **a record that fixes findings and updates its own summary in -the same commit must update the summary, or the summary outranks the fix for every later reader.** +it sits above an inventory whose own decay rule says the status column is its weakest part. + +**Corrected lesson (seventh review round).** This section previously drew the rule *"a record that +fixes findings and updates its own summary in the same commit must update the summary, or the +summary outranks the fix for every later reader."* That rule describes an event that did not happen: +no commit here both fixed the findings and touched the summary. It is also close to backwards, since +it lets a commit off the hook whenever it happens not to author the record. The rule the evidence +actually supports is the near-inverse: + +> **A commit that closes findings inventoried in a record it did not author still owes that record's +> summary an update.** Cross-file staleness is the default outcome, not the exception: the fix and +> the record live in different files, nothing in the toolchain links them, and the commit has no +> reason of its own to open the record. #3380 closed 32 of 34 rows in three plugins' files and left +> a two-hour-old roster in `docs/specs/` asserting the opposite, and four later passes paid for it. + +The operational form is: when a change closes something a spec has rostered, edit the spec's status +line in the same PR, even when the spec is somebody else's and the diff would otherwise touch no +`docs/specs/` file at all. ### The eight, verified against the live tree @@ -488,7 +589,13 @@ rewritten from the bare `skills//` form to the anchored All seven distinct targets exist on disk. Group 3's two heading anchors are closed by the same commit, dropped to file-level links, so **the 34-row roster stands at 34 closed, 0 open**: 22 of Group 1 plus all of Groups 2 and 3 by #3380, and `V-review-13` and `V-review-14` by -[#3475](https://github.com/melodic-software/claude-code-plugins/pull/3475). +[#3468](https://github.com/melodic-software/claude-code-plugins/pull/3468) (`c66f26ce`), which +rewrote all three `docs/conventions/native-references/README.md` sites — the Boundary section's +worked model and both Adopters rows — to `/review:quality-gate`, `/review:fanout` and +`/claude-ops:audit-install-state`. An earlier version of this line, and the merged messages of +both #3477 and #3478, credited #3475; `git show --stat 02e1d8b0` shows that PR touched +only `docs/conventions/native-references/CHANGELOG.md`, never the README the two rows cite. +The 34-closed total is unaffected. Derived twice with unrelated expressions, per this file's own discipline. First by matching the roster's quoted bare-form text at each citing path: zero matches remain, and a regex for any @@ -496,8 +603,38 @@ roster's quoted bare-form text at each citing path: zero matches remain, and a r `${CLAUDE_PLUGIN_ROOT}` returns zero across both plugins' `reference/` trees. Second, without reference to the roster at all, by resolving **every** citation token in every plugin-level `reference/`, `context/` and `agents/` tree and every plugin README against the base its own form -implies: **52 tokens, 0 clause 3 failures.** That population strictly contains the eight, so the -second derivation confirms the first without sharing its search expression. +implies. + +**The second derivation's result was reported as "52 tokens, 0 clause 3 failures". That is false: +the population held three failures, and the first derivation was structurally unable to see them.** +Its regex requires a `(reference|context|actions|evals|templates)/` tail, and all three of these end +in `SKILL.md`. A third derivation, run on 2026-08-28 with a wider expression — every +`skills/…` path token ending in a real file extension, resolved against the base its own form +implies, over the same population — returned **119 tokens and 3 clause-3 failures**, each one the +exact defect class ADR 0018's correction 1 names, an implied base of the plugin root against a real +base of the citing file's directory: + +| Citing `path:line` | Token as written | Resolved against | Fixed to | +|---|---|---|---| +| `plugins/source-control/reference/config-resolution.md:124` | `skills/babysit-prs/SKILL.md` | `plugins/source-control/reference/`, absent | `${CLAUDE_PLUGIN_ROOT}/skills/babysit-prs/SKILL.md` | +| `plugins/work-items/reference/permission-preflight.md:45` | `skills/work/SKILL.md` | `plugins/work-items/reference/`, absent | `${CLAUDE_PLUGIN_ROOT}/skills/work/SKILL.md` | +| `plugins/songwriting/context/pat-pattison/research/lyric-melodic-roadmaps.md:203` | `skills/meter-prosody/SKILL.md` | `…/research/`, absent | `${CLAUDE_PLUGIN_ROOT}/skills/meter-prosody/SKILL.md` | + +All three are fixed in this change, each to the form its own file already uses elsewhere: +`config-resolution.md:189` (which is `V-sc-01`, 65 lines below the defect the pass that verified +that file did not see) and `permission-preflight.md:214` were already anchored, and +`songwriting`'s `research/` tree anchors its script paths the same way. Re-running the third +expression after the fixes returns 119 tokens, 0 failures. + +The token counts differ between derivations because the expressions do — 52 against 119 — and per +this file's own recall-limits discipline neither is a total. The **failure** count is the claim that +matters, and 0 was wrong. The lesson generalises past these three rows: **a second derivation +confirms a first only if it can fail differently.** The first two here shared the assumption that a +cited skill file lives under a `reference/`-shaped subdirectory, so both were blind to citations of +a `SKILL.md` itself, and reporting them as independent overstated the evidence. + +The corrected population still strictly contains the eight Group 2 rows, so the roster's closure +stands unchanged; what does not stand is the claim that the tree around it was clean. ### Judgment: ADR 0018 barely reaches this class, and its encapsulation half does not @@ -507,10 +644,23 @@ clause would have been easy. **Group 2 was never an encapsulation defect.** The roster says so itself: "Legal as citations under ADR 0018, defective as paths." Clause 1 names this exact citing surface — it covers "plugin-level `context/`, `reference/` and `agents/` docs" reaching a sibling skill's private files — and -legalises it. Clause 2 cannot reach them: both files ship inside one plugin, so the runtime absence -that motivates clause 2, and the fetched-contract problem the amendment builds on it, cannot occur. -A consumer enabling `source-control` gets `reference/review-discipline.md` and -`skills/babysit-prs/reference/safety.md` or gets neither. +legalises it. Clause 2 does not reach them: both files ship inside one plugin, so for a reader +inside that plugin the runtime absence motivating clause 2 does not arise. A consumer enabling +`source-control` gets `reference/review-discipline.md` and `skills/babysit-prs/reference/safety.md` +or gets neither. + +**Softened, seventh review round.** An earlier version said the fetched-contract problem the +amendment builds on clause 2 "cannot occur" for intra-plugin citations. It can, by one indirect +route, and the counter-instance is in this repo: +`plugins/work-items/skills/work/SKILL.md:208` sends its reader to +`plugins/source-control/reference/config-resolution.md` over `raw.githubusercontent.com`. That +reader is running `work-items`, so `${CLAUDE_PLUGIN_ROOT}` resolves to `work-items` and the +intra-plugin citations inside the fetched file address paths that are absent for them. The +mechanism is that a *cross*-plugin fetch drags an intra-plugin citation across the boundary its form +assumed. This does not overturn the conclusion: clause 1 still legalises the citation, only clause 3 +has teeth on it, and the remedy is still form rather than routing — a fetched reader cannot follow +`skills/babysit-prs/SKILL.md` either way. It does mean the absolute was too strong, and a pass +auditing intra-plugin citation forms should treat "who fetches this file" as a live question. So **only clause 3 reaches Group 2**, and clause 3 is a resolvability rule, not an encapsulation rule. The amendment's fix-an-address / keep-evidence test does not apply either: that test divides diff --git a/plugins/songwriting/.claude-plugin/plugin.json b/plugins/songwriting/.claude-plugin/plugin.json index 242197f98..d32ae0cf5 100644 --- a/plugins/songwriting/.claude-plugin/plugin.json +++ b/plugins/songwriting/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "songwriting", - "version": "1.4.17", + "version": "1.4.18", "description": "Songwriting craft companion — nine concern-scoped lyric-craft skills (workflow router, rhyme, object-writing, metaphor, meter-prosody, song-form, co-write, diagnose, practice) applying Pat Pattison's methods, with an object-writing agent that performs the sensory exercise itself and per-skill emission boundaries that route generation to the skill that owns it, plus Suno v5.5 prompt engineering (style prompts, tagged lyrics, genre templates, troubleshooting).", "author": { "name": "Melodic Software", diff --git a/plugins/songwriting/CHANGELOG.md b/plugins/songwriting/CHANGELOG.md index d08ca3b07..20077d1ce 100644 --- a/plugins/songwriting/CHANGELOG.md +++ b/plugins/songwriting/CHANGELOG.md @@ -3,6 +3,20 @@ All notable changes to the `songwriting` plugin are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning. +## [1.4.18] + +### Fixed + +- **`lyric-melodic-roadmaps.md` cited `meter-prosody` by an unresolvable path.** The + keep-these-four-consistent sentence named `prosody.md` and `meter.md`, which are siblings and + resolve, alongside `skills/meter-prosody/SKILL.md`, whose implied base is the plugin root while + its real base is `context/pat-pattison/research/`, the defect class + [ADR 0018](../../docs/adr/0018-treat-the-plugin-as-the-encapsulation-boundary-for-skill-citation.md)'s + correction 1 names. It now reads `${CLAUDE_PLUGIN_ROOT}/skills/meter-prosody/SKILL.md`, the + anchored form this `research/` tree already uses for the Datamuse script. The sentence is the + plugin's own prose, not printed Pat Pattison text, so the distilled-corpus exclusion does not + cover it. Intra-plugin citation, legal under clause 1; clause 3 only, so the target is unchanged. + ## [1.4.17] ### Added diff --git a/plugins/songwriting/context/pat-pattison/research/lyric-melodic-roadmaps.md b/plugins/songwriting/context/pat-pattison/research/lyric-melodic-roadmaps.md index e9b31e5f5..c71d2ad48 100644 --- a/plugins/songwriting/context/pat-pattison/research/lyric-melodic-roadmaps.md +++ b/plugins/songwriting/context/pat-pattison/research/lyric-melodic-roadmaps.md @@ -200,7 +200,7 @@ is in the second one. Matching a lyric to a *model lyric* (verse 2 against verse *melody* — the frame of this whole file — a mismatch in **either** direction is a greedy spot, because either one fights the bar. That two-frame split is the plugin's, not Pat's, and it is stated the same way in `prosody.md`, `meter.md` -and `skills/meter-prosody/SKILL.md`; keep the four consistent. +and `${CLAUDE_PLUGIN_ROOT}/skills/meter-prosody/SKILL.md`; keep the four consistent. Pat's printed passage, which is the *model-lyric* frame: diff --git a/plugins/source-control/.claude-plugin/plugin.json b/plugins/source-control/.claude-plugin/plugin.json index d1e9a8a92..84847b64e 100644 --- a/plugins/source-control/.claude-plugin/plugin.json +++ b/plugins/source-control/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "source-control", - "version": "0.55.29", + "version": "0.55.30", "description": "Git and GitHub delivery workflow: /commit (Conventional Commits + Co-authored-by trailer via safe heredoc mechanics), /pull-request (prep, create, CI monitoring, review-comment triage, merge, CI-log fetch), /babysit-prs (self-pacing fleet loop \u2014 safe by default; opt-in worker/autopilot tiers add gate-checked merge and thread resolution behind a deterministic Python engine), /babysit-loop (the loop-lane merge lane: a standing or drain loop that invokes babysit-prs per cycle, configured through repo-scoped babysit_loop_* keys on the layered source-control.md seam, with merge authority human-only until the target repo's tracked config adopts the lane, a gate-proven C2-mechanical baseline once adopted, and standing merge-rung raises binding from the team-tracked layer only \u2014 with one named exception, where an invocation line explicitly typing both the autopilot tier keyword and the dedicated raise argument --merge c3-this-run widens that single invocation's merge authority up to C3 behind a fresh independent frontier-tier resolver, while C4-structural and C5-untrusted-provenance stay unconditionally human-merge), /worktree (create, status, cleanup, audit for parallel-session isolation), /setup (check the effective commit-subject / PR-title convention merged across its config layers and the babysit-prs config, or apply \u2014 interview the repo and write the convention config to a chosen layer), and /resolve-conflicts (intent-first merge/rebase conflict resolution with a semantic-conflict sweep \u2014 never --abort). The commit-subject / PR-title convention is configurable via a source-control.md config written by a re-runnable setup skill, layered across a ~/.claude user-global file, the tracked team file, and a gitignored .claude/source-control.local.md personal overlay merged per key; Conventional Commits is the default when no convention is declared.", "author": { "name": "Melodic Software", diff --git a/plugins/source-control/CHANGELOG.md b/plugins/source-control/CHANGELOG.md index b9b1cf370..dcac2494f 100644 --- a/plugins/source-control/CHANGELOG.md +++ b/plugins/source-control/CHANGELOG.md @@ -3,6 +3,23 @@ All notable changes to the `source-control` plugin are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning. +## [0.55.30] + +### Fixed + +- **`reference/config-resolution.md` cited `babysit-prs` by a path that resolved + against nothing.** The autonomy-table pointer read + `skills/babysit-prs/SKILL.md`, whose implied base is the plugin root while its + real base is `reference/`, the defect class + [ADR 0018](../../docs/adr/0018-treat-the-plugin-as-the-encapsulation-boundary-for-skill-citation.md)'s + correction 1 names. It now reads + `${CLAUDE_PLUGIN_ROOT}/skills/babysit-prs/SKILL.md`, the form the same file + already uses 65 lines below for `babysit-loop`. Intra-plugin citation, legal + under clause 1; this is clause 3 only, so the target is unchanged and no + routing moves. Found by a third derivation over the plugin-level + `reference/`, `context/` and `agents/` trees whose predecessor could not see + citations of a `SKILL.md` itself. + ## [0.55.29] ### Changed diff --git a/plugins/source-control/reference/config-resolution.md b/plugins/source-control/reference/config-resolution.md index b31b4e0c3..6264d7ed3 100644 --- a/plugins/source-control/reference/config-resolution.md +++ b/plugins/source-control/reference/config-resolution.md @@ -121,7 +121,8 @@ binding layer, never unioned). | `babysit_loop_trusted_internal_bot_logins` | flat Markdown bullet list (`- ` per line) of exact GitHub App bot logins the repository attests as its own internal automation — the C5 trust test's reviewed internal-bot trust signal; **honored in the team-tracked layer only** ("the C5 trust test's one reviewed widening" below) | none — empty set: the trust test accepts `OWNER`/`MEMBER` only | Dimension semantics — what each tier value grants per dimension — are owned by the babysit-prs -autonomy table (`skills/babysit-prs/SKILL.md`, "Autonomy tiers (per action class)") and are not +autonomy table (`${CLAUDE_PLUGIN_ROOT}/skills/babysit-prs/SKILL.md`, "Autonomy tiers (per action +class)") and are not restated here. The merge dimension's rung semantics are owned by the loop-lane convention's autonomy ladder (`docs/conventions/loop-lane/README.md` §1 in the marketplace repository). diff --git a/plugins/work-items/.claude-plugin/plugin.json b/plugins/work-items/.claude-plugin/plugin.json index d9850f21a..ac7149954 100644 --- a/plugins/work-items/.claude-plugin/plugin.json +++ b/plugins/work-items/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "work-items", - "version": "0.39.38", + "version": "0.39.39", "description": "Manages development work items through a provider-neutral tracker seam that ships with the plugin (bundled dispatcher plus github, local-markdown, jira, gitea, and linear adapters; seam plugin-dir canonical, adapters consumer-local-first): dashboard, taxonomy-labeled creation, a race-safe assignee-plus-lease claim protocol, recurring-schedule checks, TODO scanning, stale-lease auditing, plan decomposition into vertical-slice items, a macro-journey router over spec containers (rollup, per-container execution shape, next-step routing), raw-intake triage (issues and unsolicited PRs through raw, verified, briefed, autonomous-eligible states), plus the two work-items loop lanes of the loop-lane convention: a self-paced autonomous work-loop drain (work-class admission gate, adaptive item cap, PR-only) and an attended attend-queue escalation lane. The re-runnable setup skill binds the provider (.work-item-tracker.json), seeds the recurring-schedule seam (.github/recurring-schedule.json), and remaps canonical role labels.", "author": { "name": "Melodic Software", diff --git a/plugins/work-items/CHANGELOG.md b/plugins/work-items/CHANGELOG.md index c80c3c2a4..dc66a71af 100644 --- a/plugins/work-items/CHANGELOG.md +++ b/plugins/work-items/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to the `work-items` plugin are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning. +## [0.39.39] + +### Fixed + +- **`reference/permission-preflight.md` cited the `work` skill by an unresolvable path.** The Step 0 + pointer for the `reclaim` classifier-denial mitigation read `skills/work/SKILL.md`, whose implied + base is the plugin root while its real base is `reference/`, the defect class + [ADR 0018](../../docs/adr/0018-treat-the-plugin-as-the-encapsulation-boundary-for-skill-citation.md)'s + correction 1 names. It now reads `${CLAUDE_PLUGIN_ROOT}/skills/work/SKILL.md`, the form the same + file already uses for `preflight.sh`. Intra-plugin citation, legal under clause 1; clause 3 only, + so the target is unchanged and no routing moves. + ## [0.39.38] ### Changed diff --git a/plugins/work-items/reference/permission-preflight.md b/plugins/work-items/reference/permission-preflight.md index 2ed276e27..c183b0cac 100644 --- a/plugins/work-items/reference/permission-preflight.md +++ b/plugins/work-items/reference/permission-preflight.md @@ -42,7 +42,8 @@ matching "arbitrary-code-execution patterns" as routed through the classifier re defining that pattern set precisely enough to say which side a script invocation (`work-item-tracker.sh reclaim `) falls on. Do not write a rule into the standards floor on the strength of this doc alone; confirm the carve-out first. `/work-items:work`'s Step 0 treats a classifier denial of -`reclaim` as a non-blocking, report-once-and-skip condition (see `skills/work/SKILL.md` "Step 0") — +`reclaim` as a non-blocking, report-once-and-skip condition (see +`${CLAUDE_PLUGIN_ROOT}/skills/work/SKILL.md` "Step 0") — that is the current mitigation; a permission-rule fix, if one applies, still lives operator-side per the pattern above. From 3032f8d1579ac7025531fae0df33c2fad9ae8804 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 28 Aug 2026 16:13:39 +0000 Subject: [PATCH 2/3] fix(docs): route the autonomy pointer through the invocation, not an anchor the fetching plugin redefines `reference/config-resolution.md` is fetched by `work-items`'s `work` skill over raw.githubusercontent.com. For that reader `${CLAUDE_PLUGIN_ROOT}` denotes the `work-items` installation, so the anchored form this change first shipped named a `babysit-prs` skill that does not exist there. The sentence is the doc's address for the autonomy obligation, which is the case ADR 0018's amendment routes to the public invocation. It now reads `/source-control:babysit-prs`, the form the same file already uses in two other places. The sweep record's own paragraph had established the cross-boundary fetch and then concluded "the remedy is still form rather than routing". That inference was wrong and is corrected in place: the anchored form is unfollowable for the fetched reader too, so clause 3 alone can force the invocation. The blanket claim that a reopened Group 2 row would take the path form "and nothing else" is qualified the same way, and the unchecked question is named rather than assumed. Found by review before merge. --- docs/specs/extract-ssot-sweep-2026-08-28.md | 48 ++++++++++++++----- plugins/source-control/CHANGELOG.md | 22 ++++++--- .../reference/config-resolution.md | 3 +- 3 files changed, 52 insertions(+), 21 deletions(-) diff --git a/docs/specs/extract-ssot-sweep-2026-08-28.md b/docs/specs/extract-ssot-sweep-2026-08-28.md index 1306681e4..06fbe9488 100644 --- a/docs/specs/extract-ssot-sweep-2026-08-28.md +++ b/docs/specs/extract-ssot-sweep-2026-08-28.md @@ -616,15 +616,24 @@ base of the citing file's directory: | Citing `path:line` | Token as written | Resolved against | Fixed to | |---|---|---|---| -| `plugins/source-control/reference/config-resolution.md:124` | `skills/babysit-prs/SKILL.md` | `plugins/source-control/reference/`, absent | `${CLAUDE_PLUGIN_ROOT}/skills/babysit-prs/SKILL.md` | +| `plugins/source-control/reference/config-resolution.md:124` | `skills/babysit-prs/SKILL.md` | `plugins/source-control/reference/`, absent | `/source-control:babysit-prs`, the public invocation | | `plugins/work-items/reference/permission-preflight.md:45` | `skills/work/SKILL.md` | `plugins/work-items/reference/`, absent | `${CLAUDE_PLUGIN_ROOT}/skills/work/SKILL.md` | | `plugins/songwriting/context/pat-pattison/research/lyric-melodic-roadmaps.md:203` | `skills/meter-prosody/SKILL.md` | `…/research/`, absent | `${CLAUDE_PLUGIN_ROOT}/skills/meter-prosody/SKILL.md` | -All three are fixed in this change, each to the form its own file already uses elsewhere: -`config-resolution.md:189` (which is `V-sc-01`, 65 lines below the defect the pass that verified -that file did not see) and `permission-preflight.md:214` were already anchored, and -`songwriting`'s `research/` tree anchors its script paths the same way. Re-running the third -expression after the fixes returns 119 tokens, 0 failures. +**Two** are fixed to the form their own file already uses elsewhere: `permission-preflight.md:214` +was already anchored, and `songwriting`'s `research/` tree anchors its script paths the same way. +Neither file is fetched from outside its plugin, so `${CLAUDE_PLUGIN_ROOT}` denotes the right +installation for every reader either has. + +**The third is fixed to the public invocation instead**, and the reason is the subsection below. +`config-resolution.md` is fetched across the plugin boundary, so the anchored form would have named +a `babysit-prs` skill that does not exist in the fetching plugin. The anchored form was what this +change first shipped; a review pass caught it before merge. Recorded rather than quietly amended, +because the wrong remedy was chosen by reasoning this same document had already written down and +then failed to apply to its own fix. + +Re-running the third expression after the fixes leaves no clause-3 failure in the three files. The +`config-resolution.md` row leaves the path population altogether, since an invocation is not a path. The token counts differ between derivations because the expressions do — 52 against 119 — and per this file's own recall-limits discipline neither is a total. The **failure** count is the claim that @@ -657,16 +666,31 @@ route, and the counter-instance is in this repo: reader is running `work-items`, so `${CLAUDE_PLUGIN_ROOT}` resolves to `work-items` and the intra-plugin citations inside the fetched file address paths that are absent for them. The mechanism is that a *cross*-plugin fetch drags an intra-plugin citation across the boundary its form -assumed. This does not overturn the conclusion: clause 1 still legalises the citation, only clause 3 -has teeth on it, and the remedy is still form rather than routing — a fetched reader cannot follow -`skills/babysit-prs/SKILL.md` either way. It does mean the absolute was too strong, and a pass -auditing intra-plugin citation forms should treat "who fetches this file" as a live question. +assumed. + +**And that does change the remedy, which the first version of this paragraph denied.** It claimed +"the remedy is still form rather than routing", on the ground that a fetched reader cannot follow +`skills/babysit-prs/SKILL.md` either way. True of the bare form, false of the choice it was used to +justify: the anchored `${CLAUDE_PLUGIN_ROOT}/skills/babysit-prs/SKILL.md` is *also* unfollowable for +that reader, because the variable denotes their plugin and not this one, while +`/source-control:babysit-prs` is followable by every reader regardless of which plugin fetched the +document. So this row went to the invocation. The paragraph reasoned its way to the exposure and +then declined to draw the consequence for the fix sitting in the same commit; a review pass drew it. + +Clause 1 still legalises the citation and only clause 3 has teeth on it — that much stands. What +does not is the inference from "clause 3 only" to "path form only". Where a file is fetched across +the boundary, clause 3 alone can force the invocation, because for the fetched reader no path form +resolves. A pass auditing intra-plugin citation forms must treat "who fetches this file" as a live +question, and must treat it as bearing on the remedy, not only on the diagnosis. So **only clause 3 reaches Group 2**, and clause 3 is a resolvability rule, not an encapsulation rule. The amendment's fix-an-address / keep-evidence test does not apply either: that test divides clause 2 applications, and these are not clause 2 matters. Had the eight still been open, the remedy -would have been the path form and nothing else — no routing to a slash invocation, no promotion of -content to a shared location. **Intra-plugin genuinely is a different case, and the file that says +would have been the path form for any of them whose file is read only from inside its own plugin, +and the invocation for any that is fetched across the boundary — never a promotion of content to a +shared location. **Which of the eight are fetched was not checked**, because all eight were already +closed; a pass that reopens one owes that check first, on the evidence of the row above, where +exactly that question decided the remedy. **Intra-plugin genuinely is a different case, and the file that says so is the ADR's own correction 1**, which withdrew the bare-relative breakage claim as a category error and named this narrower shape as the real defect: an implied base of the plugin root against a real base of the citing file's directory. diff --git a/plugins/source-control/CHANGELOG.md b/plugins/source-control/CHANGELOG.md index dcac2494f..5d2e7bc1d 100644 --- a/plugins/source-control/CHANGELOG.md +++ b/plugins/source-control/CHANGELOG.md @@ -12,13 +12,21 @@ All notable changes to the `source-control` plugin are documented here. Format f `skills/babysit-prs/SKILL.md`, whose implied base is the plugin root while its real base is `reference/`, the defect class [ADR 0018](../../docs/adr/0018-treat-the-plugin-as-the-encapsulation-boundary-for-skill-citation.md)'s - correction 1 names. It now reads - `${CLAUDE_PLUGIN_ROOT}/skills/babysit-prs/SKILL.md`, the form the same file - already uses 65 lines below for `babysit-loop`. Intra-plugin citation, legal - under clause 1; this is clause 3 only, so the target is unchanged and no - routing moves. Found by a third derivation over the plugin-level - `reference/`, `context/` and `agents/` trees whose predecessor could not see - citations of a `SKILL.md` itself. + correction 1 names. It now names the public invocation, + `/source-control:babysit-prs`, keeping the section name. + + **The `${CLAUDE_PLUGIN_ROOT}` form this fix first took was wrong for the reader + that most needs it.** `work-items`'s `work` skill fetches this file over + `raw.githubusercontent.com`, and for that reader `${CLAUDE_PLUGIN_ROOT}` denotes + the `work-items` installation, so the anchor resolved to a `babysit-prs` skill + that does not exist there. This sentence is the doc's address for the autonomy + obligation, which is the case + [ADR 0018](../../docs/adr/0018-treat-the-plugin-as-the-encapsulation-boundary-for-skill-citation.md)'s + 2026-08-28 amendment routes to the invocation rather than to a path whose + meaning depends on which plugin fetched the document. Found by a third + derivation over the plugin-level `reference/`, `context/` and `agents/` trees + whose predecessor could not see citations of a `SKILL.md` itself; the remedy + corrected by review before merge. ## [0.55.29] diff --git a/plugins/source-control/reference/config-resolution.md b/plugins/source-control/reference/config-resolution.md index 6264d7ed3..0f9c8b246 100644 --- a/plugins/source-control/reference/config-resolution.md +++ b/plugins/source-control/reference/config-resolution.md @@ -121,8 +121,7 @@ binding layer, never unioned). | `babysit_loop_trusted_internal_bot_logins` | flat Markdown bullet list (`- ` per line) of exact GitHub App bot logins the repository attests as its own internal automation — the C5 trust test's reviewed internal-bot trust signal; **honored in the team-tracked layer only** ("the C5 trust test's one reviewed widening" below) | none — empty set: the trust test accepts `OWNER`/`MEMBER` only | Dimension semantics — what each tier value grants per dimension — are owned by the babysit-prs -autonomy table (`${CLAUDE_PLUGIN_ROOT}/skills/babysit-prs/SKILL.md`, "Autonomy tiers (per action -class)") and are not +autonomy table (`/source-control:babysit-prs`, "Autonomy tiers (per action class)") and are not restated here. The merge dimension's rung semantics are owned by the loop-lane convention's autonomy ladder (`docs/conventions/loop-lane/README.md` §1 in the marketplace repository). From fec9b6aba49e79575dafa740f306898a9d3386d9 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 28 Aug 2026 16:21:05 +0000 Subject: [PATCH 3/3] docs: correct three false statements this round introduced, and fix the citations its derivation could not see A fresh-context verifier reproduced the F3 derivation independently (119 tokens, 3 failures pre-fix, 0 post-fix, same three sites) and found three new false statements in the round that produced it. - "#3380 closed 32 of 34 rows in three plugins' files" is refuted by `git show --stat 6c7a1032`: the rows span a `.claude/rules/` file, `docs/PLUGIN-PHILOSOPHY.md`, four convention READMEs and several plugins' trees, and the majority are not plugin files at all. - The `config-cascade` sentences were pinned at `:13-14` and `:11-13`; the quoted forms are on 12, 13 and 14 and the assertion runs 14 to 16. A line pin written into the file whose own decay rule says the check is the text. Both re-anchored on text rather than corrected. - "names no invocation at all" is contradicted by the bullet's own text, which names two. It names no invocation as the replacement, which is the claim the ruling actually rests on. The claim that both earlier derivations shared one blind spot is downgraded to what the evidence supports: derivation 1's expression is recorded and does have it, derivation 2's was never written down. An unrecorded expression cannot be audited, only believed, and that is the defect worth carrying forward. The verifier also found three citations the third derivation could not see, because it was `skills/`-scoped and these name no skill. They sit three lines above V-disc-04 through V-disc-06, which this sweep closed: a pass corrected the citations below them and left these standing. Fixed to the anchored form, which is right here because the file is not fetched across the plugin boundary. --- docs/specs/extract-ssot-sweep-2026-08-28.md | 65 ++++++++++++++++---- plugins/discovery/.claude-plugin/plugin.json | 2 +- plugins/discovery/CHANGELOG.md | 19 ++++++ plugins/discovery/reference/topic-docs.md | 5 +- 4 files changed, 75 insertions(+), 16 deletions(-) diff --git a/docs/specs/extract-ssot-sweep-2026-08-28.md b/docs/specs/extract-ssot-sweep-2026-08-28.md index 06fbe9488..faf48055e 100644 --- a/docs/specs/extract-ssot-sweep-2026-08-28.md +++ b/docs/specs/extract-ssot-sweep-2026-08-28.md @@ -399,13 +399,21 @@ to any of them to get a rule, so none is an address. Three sub-rulings the class names "the public invocation that replaced it **in the same sentence**", and that `config-cascade`'s entry asserts non-resolution "in the same sentence" as the quoted forms. Neither is accurate as written, and the rulings do not depend on it. -`docs/conventions/detector-findings/CHANGELOG.md:57` names **no** invocation at all — the row "now -says 'its shape library' and 'the scanner'", which is a rename to the row's own terms rather than a +The `detector-findings` bullet beginning "The `docs-hygiene:audit-noise` adopter row stops +path-citing the producer's shape library" names **no slash invocation as the replacement** — the row +"now says 'its shape library' and 'the scanner'", a rename to the row's own terms rather than a routing fix — and the other eleven name the invocation in a **later sentence of the same bullet**. -`config-cascade`'s non-resolution assertion is likewise the next sentence, at `:13-14`, after the -quotes at `:11-13`. The unit that carries the evidence claim is the bullet, not the sentence, and -the substance holds at that unit: every row states what it removed and why, and `:57` states the -replacement terms even though it names no slash invocation. Read the ruling as scoped to the bullet. +`config-cascade`'s non-resolution assertion ("All three are plugin-relative paths that resolve +against nothing from this file") is likewise the sentence that follows the three quoted forms rather +than the sentence carrying them. The unit that carries the evidence claim is the bullet, not the +sentence, and the substance holds at that unit: every row states what it removed and why. + +A first attempt at this correction said that bullet "names **no** invocation at all", which its own +text refutes: it names `docs-hygiene:audit-noise` and `claude-config:audit-instructions`, just not as +the replacement. That attempt also pinned the `config-cascade` sentences at `:13-14` and `:11-13` +when the quoted forms are on 12, 13 and 14 and the assertion runs 14 to 16 — a line pin written into +the very file whose decay rule says the check is the text. Both are corrected here on text anchors, +and both were caught by the round verifying this one. The judgment is what was missing, and it is now recorded so a pass that re-derives this shape reads a ruling instead of buying twelve fresh ones. The general lesson is worth more than the twelve rows: @@ -562,8 +570,14 @@ actually supports is the near-inverse: > **A commit that closes findings inventoried in a record it did not author still owes that record's > summary an update.** Cross-file staleness is the default outcome, not the exception: the fix and > the record live in different files, nothing in the toolchain links them, and the commit has no -> reason of its own to open the record. #3380 closed 32 of 34 rows in three plugins' files and left -> a two-hour-old roster in `docs/specs/` asserting the opposite, and four later passes paid for it. +> reason of its own to open the record. #3380 closed 32 of 34 rows spread across a `.claude/rules/` +> file, `docs/PLUGIN-PHILOSOPHY.md`, four convention READMEs and several plugins' trees, and left a +> two-hour-old roster in `docs/specs/` asserting the opposite, and four later passes paid for it. +> +> An earlier version of this paragraph said "three plugins' files", which `git show --stat 6c7a1032` +> refutes: the majority of the 32 are not plugin files at all. Corrected by the round that verified +> this one, and left visible because a rule stated over a miscounted example invites the next reader +> to re-derive it. The operational form is: when a change closes something a spec has rostered, edit the spec's status line in the same PR, even when the spec is somebody else's and the diff would otherwise touch no @@ -620,8 +634,9 @@ base of the citing file's directory: | `plugins/work-items/reference/permission-preflight.md:45` | `skills/work/SKILL.md` | `plugins/work-items/reference/`, absent | `${CLAUDE_PLUGIN_ROOT}/skills/work/SKILL.md` | | `plugins/songwriting/context/pat-pattison/research/lyric-melodic-roadmaps.md:203` | `skills/meter-prosody/SKILL.md` | `…/research/`, absent | `${CLAUDE_PLUGIN_ROOT}/skills/meter-prosody/SKILL.md` | -**Two** are fixed to the form their own file already uses elsewhere: `permission-preflight.md:214` -was already anchored, and `songwriting`'s `research/` tree anchors its script paths the same way. +**Two** are fixed to the form their own file already uses elsewhere: `permission-preflight.md` +already anchors its `preflight.sh` invocation line that way, and `songwriting`'s `research/` tree +anchors its script paths the same way. Neither file is fetched from outside its plugin, so `${CLAUDE_PLUGIN_ROOT}` denotes the right installation for every reader either has. @@ -638,9 +653,33 @@ Re-running the third expression after the fixes leaves no clause-3 failure in th The token counts differ between derivations because the expressions do — 52 against 119 — and per this file's own recall-limits discipline neither is a total. The **failure** count is the claim that matters, and 0 was wrong. The lesson generalises past these three rows: **a second derivation -confirms a first only if it can fail differently.** The first two here shared the assumption that a -cited skill file lives under a `reference/`-shaped subdirectory, so both were blind to citations of -a `SKILL.md` itself, and reporting them as independent overstated the evidence. +confirms a first only if it can fail differently.** The first two here missed the same three rows, +each of which cites a `SKILL.md` directly rather than a file beneath a `reference/`-shaped +subdirectory, so reporting them as independent overstated the evidence. + +**What is established and what is inferred.** Derivation 1's expression is recorded verbatim in this +file and does require that subdirectory shape, so its blindness is a fact. Derivation 2's expression +was never written down anywhere; the record describes it as resolving "every citation token", which +would not have that blind spot. All that the evidence settles is that derivation 2 was narrower than +its own description, since it returned 52 tokens and 0 failures where a third expression returns 119 +and 3. The shared *mechanism* is a plausible reconstruction, not a verified one, and an unrecorded +expression is itself the defect worth carrying forward: a derivation nobody can re-run cannot be +audited, only believed. + +**A fourth derivation is owed and not performed here.** The third is `skills/`-scoped, so it is +blind by construction to the same defect class in tokens that name no skill. The verifying round +found three such tokens in `plugins/discovery/reference/topic-docs.md`, whose `agents/explorer.md`, +`agents/researcher.md` and `agents/intent-tracer.md` imply a base of the plugin root against a real +base of `reference/`. Verified against the tree, fixed in this change to the anchored form, and +called out here because of where they sat: **three lines above `V-disc-04` through `V-disc-06`, +which this sweep did close.** A pass looked at that paragraph, corrected the citations below these +three, and left these three standing, because its expression could not see them. + +That is the strongest available argument that the `skills/`-scoped population was never the right +population. The class is "a path whose implied base is the plugin root while its real base is the +citing file's directory", and nothing in that definition mentions skills. Whoever runs the fourth +derivation should build it from the class, not from the token shape the last three happened to +share. The corrected population still strictly contains the eight Group 2 rows, so the roster's closure stands unchanged; what does not stand is the claim that the tree around it was clean. diff --git a/plugins/discovery/.claude-plugin/plugin.json b/plugins/discovery/.claude-plugin/plugin.json index 0006f1cb2..11e9194b5 100644 --- a/plugins/discovery/.claude-plugin/plugin.json +++ b/plugins/discovery/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "discovery", - "version": "0.16.16", + "version": "0.16.17", "description": "Structured discovery before changes: explore the local codebase, run disciplined multi-source external research, and reconstruct why a past decision was made from evidence outside the code — each dispatching a purpose-built subagent by default so the reading stays out of the main conversation, with source tiers, falsification, recency gates, an intent-evidence tier, and a corpus-coverage ledger — persisting EXPLORE.md / RESEARCH.md / INTENT.md index-plus-sidecar handoff artifacts.", "author": { "name": "Melodic Software", diff --git a/plugins/discovery/CHANGELOG.md b/plugins/discovery/CHANGELOG.md index 636db0865..a442890fd 100644 --- a/plugins/discovery/CHANGELOG.md +++ b/plugins/discovery/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog — discovery plugin +## [0.16.17] + +### Fixed + +- **`reference/topic-docs.md` cited its three agent definitions by a path that + resolved against nothing.** The return-payload sentence named `agents/explorer.md`, + `agents/researcher.md` and `agents/intent-tracer.md`, whose implied base is the + plugin root while their real base is `reference/`, the defect class + [ADR 0018](../../docs/adr/0018-treat-the-plugin-as-the-encapsulation-boundary-for-skill-citation.md)'s + correction 1 names. All three now carry `${CLAUDE_PLUGIN_ROOT}/`, the form the + next sentence of the same paragraph already uses for the three dispatch docs. + This file is not fetched from outside the plugin, so the anchored form resolves + for every reader it has and the invocation is not needed. + + Found by the round verifying the sweep's own third derivation. That derivation + was `skills/`-scoped and therefore blind by construction to citations naming no + skill, which is why three defects of the same class survived it three lines + above rows the sweep had already closed. + ## [0.16.16] ### Changed diff --git a/plugins/discovery/reference/topic-docs.md b/plugins/discovery/reference/topic-docs.md index 588e6e443..7bdb7d111 100644 --- a/plugins/discovery/reference/topic-docs.md +++ b/plugins/discovery/reference/topic-docs.md @@ -82,8 +82,9 @@ checkout (worktree or background session) returns findings by value instead, and the memory slice. **Where that rule is reachable from.** A worker does not choose the by-value mode by reading this -file; it is `persistence: by-value` in the return payload (`agents/explorer.md`, -`agents/researcher.md`, `agents/intent-tracer.md`), and the parent acts on it at the +file; it is `persistence: by-value` in the return payload +(`${CLAUDE_PLUGIN_ROOT}/agents/explorer.md`, `${CLAUDE_PLUGIN_ROOT}/agents/researcher.md`, +`${CLAUDE_PLUGIN_ROOT}/agents/intent-tracer.md`), and the parent acts on it at the `persistence: by-value` rung of each family's recovery ladder — `${CLAUDE_PLUGIN_ROOT}/skills/explore/reference/dispatch.md`, `${CLAUDE_PLUGIN_ROOT}/skills/research/context/dispatch.md` and