Skip to content

refactor(git-agent): move the 8 PR/review op bodies to references/pr and collapse the git.md ceilings (#326, #328) - #353

Open
dean0x wants to merge 9 commits into
mainfrom
feat/326-pr-host-references
Open

dean0x wants to merge 9 commits into
mainfrom
feat/326-pr-host-references

Conversation

@dean0x

@dean0x dean0x commented Sep 22, 2026

Copy link
Copy Markdown
Owner

refactor(git-agent): move the 8 PR/review op bodies to references/pr and collapse the git.md ceilings (#326, #328)

Summary

Moves the 8 PR/review **Process:** bodies out of src/assets/agents/git.mds into a new,
provider-independent reference module (src/assets/mds/git/_pr.mds → installed at
references/pr/), then spends the recovered headroom by collapsing the phase-named git.md
byte ceilings onto one live gate per shape and regenerating the golden.

Why references/pr/ and not a fourth provider tree. ensure-pr-ready, validate-branch,
post-review-summary, check-ci-status, fetch-review-threads, resolve-review-threads,
post-resolution-summary and check-merge-readiness are PR mechanics, not issue-tracker
mechanics — PRs stay on GitHub under every tracker provider (github, jira, linear all
open PRs on GitHub; only the issue side of tracker mechanics is pluggable). So the module is
installed unconditionally, once, converged the same way references/tracker/ is, rather than
duplicated per provider.

What stayed in git.md. Every operation keeps its ## Operation: heading and
**Process:** label — pointing at **PR mechanics:** load references/pr/{op}.md — plus:

  • resolve-review-threads step 3, applying the D9 gate, stays in the agent (it is an action,
    not documentation — see the Known trade-off note below);
  • both summary ops' D10 sentence naming references/publication-gate.md;
  • post-resolution-summary's op-local non-reproduction clause.

The ## Comment-sink scrub (D11) section is byte-identical to main — SG-8 forbade moving it,
and it didn't move.

#328 folded in. Commit 9af9764 (fix(git-agent): state the comment-posting non-reproduction rule once in Principles) landed first: the cross-op non-reproduction sentence
that used to live inside post-resolution-summary step 5 — invisible to a
post-review-summary spawn that never reads that section — is now a Principle 8 sub-bullet
every spawn reads, with the op-local half restated at post-resolution-summary itself. Folding
it in first meant the SG-8 move (commit decf75f) carried a settled cross-op rule rather than
inventing one mid-split.

Numbers

before (main) after
dist/agents/git.md 58,100 ch / 917 L / 58,549 B 45,068 ch / 801 L / 45,400 B
references/pr/** 8 files, 16,408 B
Installed generated refs — github 13 21
Installed generated refs — jira / linear 24 32
Packed generated-reference manifest 34 42

Ceilings — before → after

Registered ceiling before after measured headroom
budget-git-md 55,750 45,150 45,068 82
budget-git-md-p3 58,870 retired
budget-loaded-set (GitHub) 80,200 67,200 67,123 77
budget-loaded-set-jira 89,500 76,500 76,427 73
budget-loaded-set-linear 91,700 78,700 78,610 90
budget-loaded-set-pr-host 59,100 (new, gated) 59,033 67
preamble-max-lines 36 36 (unchanged) 35 lines 1

Supersession note. budget-git-md-p3 (58,870) was the live git.md gate and budget-git-md
(55,750) its declared base, kept apart so a Phase-3 preamble revision could be read as a delta
from an unraised number. #326 cut 13,032 characters out of the always-loaded agent, which makes
the split pointless: one number now gates the whole artifact. The pair is recorded as superseded
once, in budget-git-md's manifest description; nothing in the source says "P3 removed"
(ADR-003, and ADR-027's condition is met).

Every provider row now sits below the value its 2026-09-20 re-baseline raised it from (GitHub
below the pre-split 77,824, jira below 88,660, linear below 91,000) — that authorisation is
fully spent back.

The new PR-host row. BUDGET_LOADED_SET_PR_HOST = PRELOADED + max over PR_HOST_OPS of (chars(pr/{op}.md) + every reference that op's own git.md section names). No max_op term of
its own — an op's PR-host file is already inside its one-spawn load. Gate = 54,591 + 4,442
(post-review-summary, the max) = 59,033. references/github-api.md (21,166 ch) is a
written exclusion (LOADED_SET_WRITTEN_EXCLUSIONS in budget-model.ts) — without it,
fetch-review-threads/resolve-review-threads would push the gate to 77,674, recorded as shape
2c-ex rather than gated. Non-vacuity is asserted twice: a named-set arm pinning that exactly
fetch-review-threads and resolve-review-threads reach the excluded file, and an arm asserting
the unexcluded figure would exceed the ceiling — so the exclusion is load-bearing, not a rounding
convenience.

Byte-budget recorded tables, verbatim at the branch tip:

┌─────────┬────────────────────────────────────────────────────────────────────────────────┬───────┬───────┐
│ (index) │ row                                                                            │ chars │ bytes │
├─────────┼────────────────────────────────────────────────────────────────────────────────┼───────┼───────┤
│ 0       │ 'dist/agents/git.md'                                                           │ 45068 │ 45400 │
│ 1       │ 'skills/git/SKILL.md'                                                          │ 6581  │ 6601  │
│ 2       │ 'skills/worktree-support/SKILL.md'                                             │ 2942  │ 2950  │
│ 3       │ 'references/learn-conventions.md'                                              │ 3627  │ 3647  │
│ 4       │ 'references/publication-gate.md'                                               │ 1114  │ 1132  │
│ 5       │ 'references/decision-markers.md'                                               │ 1681  │ 1701  │
│ 6       │ 'references/github-api.md  (excluded from the gate — pinned, not budgeted)'    │ 21166 │ 21216 │
│ 7       │ 'max_op tracker reference (manage-debt)'                                       │ 5007  │ NaN   │
│ 8       │ 'worst-case one-spawn load, TRACKER ops (setup-task)'                          │ 7525  │ NaN   │
│ 9       │ 'worst-case one-spawn load, NON-tracker ops (fetch-review-threads)'            │ 23083 │ NaN   │
│ 10      │ 'sum of all GitHub tracker references'                                         │ 25223 │ NaN   │
│ 11      │ 'references/tracker/_mcp.md  (0 on the GitHub path, per-spawn elsewhere)'      │ 7963  │ NaN   │
│ 12      │ 'max_op jira reference (backlink-shipped-issues)'                              │ 6058  │ NaN   │
│ 13      │ 'worst-case one-spawn load, jira ops (setup-task)'                             │ 7815  │ NaN   │
│ 14      │ 'max_op linear reference (backlink-shipped-issues)'                            │ 7480  │ NaN   │
│ 15      │ 'worst-case one-spawn load, linear ops (setup-task)'                           │ 8576  │ NaN   │
│ 16      │ 'cross-cutting glossary named in the always-loaded part (decision-markers.md)' │ 1681  │ NaN   │
└─────────┴────────────────────────────────────────────────────────────────────────────────┴───────┴───────┘
┌─────────┬────────────────────────────────────────────────────────────────────────────────────────┬───────┬────────────────────────────┬────────────────────────────────┐
│ (index) │ shape                                                                                  │ chars │ vs shape 1 (preloaded set) │ vs shape 2 (per-op loaded set) │
├─────────┼────────────────────────────────────────────────────────────────────────────────────────┼───────┼────────────────────────────┼────────────────────────────────┤
│ 0       │ '1. baseline — the always-loaded preloaded set'                                        │ 54591 │ '0.0%'                     │ '-18.7%'                       │
│ 1       │ '2. per-op split, GitHub path (the worst-case formula)'                                │ 67123 │ '23.0%'                    │ '0.0%'                         │
│ 2       │ '3. per-provider single file (DISQUALIFIED — margin over shape 2, see both % columns)' │ 79814 │ '46.2%'                    │ '18.9%'                        │
│ 3       │ '4. per-op without _mcp.md (GitHub path — identical to 2 in Phase 2)'                  │ 67123 │ '23.0%'                    │ '0.0%'                         │
│ 4       │ '2-jira. per-op split, jira path (loads the tool-call contract)'                       │ 76427 │ '40.0%'                    │ '13.9%'                        │
│ 5       │ '2-linear. per-op split, linear path (loads the tool-call contract)'                   │ 78610 │ '44.0%'                    │ '17.1%'                        │
│ 6       │ '2c. PR-host spawn (the eight pr/ ops — same cost under every tracker)'                │ 59033 │ '8.1%'                     │ '-12.1%'                       │
│ 7       │ '2c-ex. PR-host spawn + the written exclusion charged (RECORDED, not gated)'           │ 77674 │ '42.3%'                    │ '15.7%'                        │
│ 8       │ '2b. shape 2 + cross-cutting glossary as if mandatory (RECORDED, not gated)'           │ 68804 │ '26.0%'                    │ '2.5%'                         │
└─────────┴────────────────────────────────────────────────────────────────────────────────────────┴───────┴─────────┘
┌─────────┬─────────────────────────────────────────────────────────────────────────────────┬───────┬─────────┐
│ (index) │ term                                                                            │ value │ unit    │
├─────────┼─────────────────────────────────────────────────────────────────────────────────┼───────┼─────────┤
│ 0       │ '`**Mechanics:**` pointer sites in the agent (1 extra sequential Read each)'    │ 11    │ 'sites' │
│ 1       │ '`**PR mechanics:**` pointer sites in the agent (1 extra sequential Read each)' │ 8     │ 'sites' │
│ 2       │ 'mechanics Reads added per spawn, max over TRACKER ops (setup-task)'            │ 2     │ 'Reads' │
│ 3       │ 'smallest generated reference #1 (tracker/github/create-release.md)'            │ 563   │ 'ch'    │
│ 4       │ 'smallest generated reference #2 (tracker/github/fetch-issues-batch.md)'        │ 1179  │ 'ch'    │
│ 5       │ 'smallest generated reference #3 (tracker/github/post-wave-report.md)'          │ 1243  │ 'ch'    │
└─────────┴─────────────────────────────────────────────────────────────────────────────────┴───────┴─────────┘

SG-8 discharge

SG-8 forbade moving post-review-summary / post-resolution-summary mechanics unless the D10
and D11 guards move in the same PR. They did:

  • D10 block (the publication gate — visibility probe, FULL/STUB/OFF, fail-closed) is
    repointed to gitPlusPrHostCorpus()git.md ∪ references/pr/** — via a single named
    predicate, d10Reaches(corpus, op, literal) (tests/git-agent.test.ts:1547), called by both
    the live guard (:1550) and the known-bad probe (:1561), and the fail-closed literal itself
    is named once, D10_FAIL_CLOSED_LITERAL = 'treat as PUBLIC' (:1518).
  • D11 forward and reverse guards are repointed the same way through
    isPostingSection(sec) (tests/git-agent.test.ts:1769) — one predicate, called by the ≥8
    forward guard (:1772) and the SG-8 known-bad probe (:1827).
  • Posting floor unchanged: d11-posting-ops stays >= 8 — the posting SET is still the
    same 8 operations before and after the move.

Non-vacuity proof. The floor of 8 alone can't show the union corpus is load-bearing (the
forward guard stayed green through the whole move). Driving isPostingSection over the sink
corpus with references/pr/** dropped narrows the posting set from 8 to exactly 5, named
(not counted, so losing one op and gaining an unrelated one can't pass as agreement):

[backlink-shipped-issues, ensure-pr-ready, ensure-traceable-issue, manage-debt, post-wave-report]

Three of the eight vanish entirely (post-review-summary, post-resolution-summary,
resolve-review-threads post only from pr/); ensure-pr-ready survives at a reduced surface
because it sits in both rosters — step 4a's create moved to pr/, step 4b's edit stayed in
tracker/{provider}/.

Mutation proof on isPostingSection. Narrowing the predicate (e.g. dropping the
-F body=@ arm) takes both the forward guard and the SG-8 probe red together, because both now
read the same function — there is no longer a second, frozen copy of the rule that could stay
green after the live one is weakened.

Containment proof

Transient script (never committed): for every non-blank line of the 8 **Process:** bodies at
main:src/assets/agents/git.mds, asserts the line is verbatim in _pr.mds or a declared
RETAINED / REWORDED / DELETED exception; for every non-blank line git.mds gained vs main,
asserts it matches a declared insertion.

OUT: 126 non-blank Process-body lines checked across 8 ops
IN : 15 non-blank lines gained by git.mds checked

Declared exceptions, all exercised:
  RETAINED  **Mechanics:** load this operation's provider reference.
  RETAINED  3. Apply the D9 gate above: resolve via `resolveReviewThread` if VERIFICATION_STATUS == PASS AND verdict FIXED
  REWORDED       The resolution summary describes external review threads and issue content.…
            → op-local non-reproduction clause RETAINED in git.mds at column 0, rephrased; cross-op half DELETED in commit 1 (#328) and restated in Principle 8
  REWORDED  2. Resolve `REVIEW_PUBLICATION` through the publication gate named above; `off` …
            → MOVED to _pr.mds with "the publication gate named above" → "`references/publication-gate.md`" (deixis)
  REWORDED  The publication gate this operation applies is the `devflow:git` skill's `refere…
            → D10 naming sentence RETAINED in git.mds, "below" → "in those mechanics" (deixis)
  INSERTED     - **Never reproduced in a posted body**: no comment-posting operation (`post-…
            → commit 1: Principle 8 sub-bullet (#328)
  INSERTED  **Mechanics:** load this operation's provider reference.…
            → commit 2: ensure-pr-ready's provider pointer — RETAINED, re-emitted by the diff (moved down one stanza)
  INSERTED  **PR mechanics:** load `references/pr/check-ci-status.md`…
            → commit 2: check-ci-status PR-host pointer
  INSERTED  **PR mechanics:** load `references/pr/check-merge-readiness.md`…
            → commit 2: check-merge-readiness PR-host pointer
  INSERTED  **PR mechanics:** load `references/pr/ensure-pr-ready.md`…
            → commit 2: ensure-pr-ready PR-host pointer
  INSERTED  **PR mechanics:** load `references/pr/fetch-review-threads.md`…
            → commit 2: fetch-review-threads PR-host pointer
  INSERTED  **PR mechanics:** load `references/pr/post-resolution-summary.md`…
            → commit 2: post-resolution-summary PR-host pointer
  INSERTED  **PR mechanics:** load `references/pr/post-review-summary.md`…
            → commit 2: post-review-summary PR-host pointer
  INSERTED  **PR mechanics:** load `references/pr/resolve-review-threads.md`…
            → commit 2: resolve-review-threads PR-host pointer
  INSERTED  **PR mechanics:** load `references/pr/validate-branch.md`…
            → commit 2: validate-branch PR-host pointer
  INSERTED  - **Load the mechanics:** an operation whose section carries a `**Mechanics:**` …
            → commit 2: load rule gains the PR-mechanics arm
  INSERTED  - **Merged step order:** every loaded reference's steps carry this operation's o…
            → commit 2: merged-step rule generalised to two references
  INSERTED  The body those mechanics compose MUST NOT reproduce verbatim content from any `<…
            → commit 2: post-resolution-summary op-local non-reproduction clause, rephrased
  INSERTED  The publication gate this operation applies is the `devflow:git` skill's `refere…
            → commit 2: D10 naming sentence, deixis fixed

PROOF: OK

Frozen fixture

tests/fixtures/golden/github-status-lines.txt is byte-identical to main
(cmp: IDENTICAL); extractStatusLines() was retargeted instead (six new pr/ entries in
STATUS_LINE_REFERENCE_FILES, plus two more straddle splits). No re-capture authorisation was
requested or spent — the three prior authorisations on this fixture remain fully spent, and this
branch adds none.

Red-proof table

Guard File:line Known-bad sample How proven red
gitPlusPrHostCorpus detection scope (AC-0.6b remote-I/O sweep) tests/git-agent.test.ts:101 widening the corpus to the full sink corpus (all providers) setup-task gets detected as remote-I/O through PROVIDER mechanics it never touched — a subject change the guard must not tolerate; kept scoped to git.md ∪ pr/ deliberately (deviation 3)
D10 per-op containment, d10Reaches tests/git-agent.test.ts:1547 (predicate), :1550 (live), :1561 (probe) seedPrHostFile('post-review-summary', …) deletes 'treat as PUBLIC' from one pr/ file probe drives the SAME d10Reaches the live guard calls; reports exactly post-review-summary, not the sibling op that still carries the sentence
D11 forward/reverse posting guard, isPostingSection tests/git-agent.test.ts:1769 (predicate), :1772 (forward, ≥8), :1827 (SG-8 probe) sinkCorpusWithoutPrHost() — drop references/pr/** from the corpus posting set narrows from 8 to the named 5 [backlink-shipped-issues, ensure-pr-ready, ensure-traceable-issue, manage-debt, post-wave-report]; mutation of isPostingSection (e.g. dropping the -F body=@ arm) takes both the guard and the probe red together
Reachability anchor, anchorsOnLineOne tests/tracker/reference-reachability.test.ts:328 (predicate), :538 (probe) displaced = "Load this first.\n\n## Operation: {op}\n…" (anchor not on line 1) probe calls the SAME anchorsOnLineOne the live arm calls; fails on the displaced body AND asserts the positive direction (wellFormed) so a predicate gone constant-false is also caught (mutation: startsWithincludes takes it red)
Containment negative arm, REMOTE_PLACEHOLDER_RE tests/git-agent.test.ts:2406 (shared regex), :2408 (live arm), :2471 (probe) seed a pr/ compose template with Echo the thread {title} verbatim. probe seeds the placeholder into the PR-host half specifically — proves the negative arm isn't only reading the half that stayed in git.md; mutation: narrowing the regex to /\{body\}/ takes the probe red
Installer prune scope, pruneTrackerSubtreeOnly (frozen pre-#326 rule) vs. live overlayGeneratedReferences tests/installer/reference-overlay.test.ts:733 (frozen rule), :803/:815 (live), known-bad it immediately following :803 a stale pr/retired-op.md left by an older build live prune removes it and reports it root-relative (pr/retired-op.md); the frozen pruneTrackerSubtreeOnly probe leaves the SAME file standing and never names it — proving the old rule really was tracker-scoped, not merely undertested
Budget-model cross-cutting reachability, nameableFrom seeded reader tests/tracker/budget-model.ts:220; probe at tests/tracker/byte-budget.test.ts:1064 inject a reader returning Then read \references/smuggled.md` for the rest.` only for the PR-host op's own file nameableFrom(op, injectedReader) reports [op → smuggled.md] — proves the PR-host hop is reachable through the injected reader without writing into dist/ mid-suite (PF-055)
Provider-scope literal guard, FORBIDDEN_SCOPES tests/guards/provider-scope.test.ts:420 (list), :432 (loop) dist/skills/git/references/pr/ seeded with a jira/linear token in its header prose scope asserted non-vacuous (inScope.length > 0) and provider-token-free the same as the github tree — a pr/ file naming a provider is flagged exactly like one under tracker/github/ would be; this caught the real "jira user" phrase in _pr.mds's header during this branch (deviation 6)

Two commits made these probes trustworthy rather than merely present: 538da24 hoisted
anchorsOnLineOne and REMOTE_PLACEHOLDER_RE to describe-scope so the live arm and its
known-bad probe read the same predicate/regex instead of two independently hand-spelled copies
(proven by mutation: startsWithincludes and narrowing the regex each now take the
probe red, which they did not before); 83f6c2f did the same for isPostingSection and
d10Reaches/D10_FAIL_CLOSED_LITERAL, and retitled the SG-8 probe (the narrowing is 8→5, not a
halving).

Deviations from the plan

  1. AC-0.6b's detection corpus is scoped to git.md ∪ pr/, not the full sink corpus. Over
    the full union, setup-task is detected as remote-I/O through its provider mechanics — text
    an earlier phase moved, for an op this commit never touched — changing the guard's subject.
    Widened to exactly what git.md: second size cut — move the 8 PR/review op bodies to references (SG-7) #326 moved (gitPlusPrHostCorpus()), the ADR-025-correct reading.
  2. The D11 SG-8 probe asserts a named set of 5, not a count of 4. ensure-pr-ready survives
    the narrowing (it's in both rosters), so the correct assertion is a named set — a bare count
    of 5 is equally satisfied by losing ensure-pr-ready and gaining an unrelated op.
  3. [DR-20](ii)'s distinctness assertion is scoped to the three expected basenames, not
    corpus-wide.
    ensure-pr-ready.md now legitimately exists at four paths (pr/ + three
    providers), so a corpus-wide distinctness check is false on its face. Scoped instead to: each
    of the three expected labels names exactly one file.
  4. Commit 1 (fix(git.md): cross-op containment rule sited inside post-resolution-summary where post-review-summary agents never read it #328) alone transiently exceeded all three loaded-set ceilings by ~240 characters
    before commit 2 (decf75f) returned 13,400. The Principle-8 bullet costs more than the
    sentence it replaced; kept the settled wording verbatim rather than shrinking it to buy back
    200 bytes commit 2 returns 60× over. All three ceilings are green at the tip with large
    margins — squash-merge makes the transient breach moot, noted here for the record.
  5. manage-debt-archive-cap occurrences 4 → 6. Two new summary-cap known-bad probes are
    counted sites under the existing toContain('60000') pattern; left at 4, the non-vacuity
    probe stops discriminating. The floor itself is untouched.
  6. Sweep names are references-root-relative (pr/stale.md), not sub-root-relative
    (stale.md)
    — plain concatenation would make a stale.md removed from pr/ and one
    removed from tracker/ render as the same user-facing string.
  7. Row 2c split into gated 2c and recorded 2c-ex. Two rows were added, not two
    replacing five: 2c is the gated PR-host figure (54,591 + 4,442 = 59,033), 2c-ex is the
    same maximum with the github-api.md exclusion charged (54,591 + 23,083 = 77,674) —
    recorded, not gated, so a reader can always tell which number the ceiling actually enforces.

Known trade-off

resolve-review-threads is a three-part straddle: pr/ holds the loop preamble plus steps 1,
2 and 4; git.md keeps step 3 — applying the D9 gate — because it is an action, not
documentation. This is the first PR-host split where the retained git.md half is executable
rather than a pointer or a naming sentence. Mitigated by the merged-step rule (generalised in
this branch to cover two references): every loaded reference's steps carry this operation's own
ordering, so step 3 interleaves correctly with the moved steps by number regardless of which
file it physically lives in.

Verification

  • Full suite: npm run build && npx vitest run --exclude 'tests/eager-memory-refresh.test.ts'
    155 files / 5,537 tests, 0 failures, 48.9s. Known flakes named and shown not to be this
    branch: model-discovery T1 (passed first time this run), decisions-usage-scan lock timing,
    and redact-secrets adversarial backtracking-budget (Phase A observed it once; proven
    pre-existing by stashing all changes and re-running the same file, which failed on a
    different test) — each green standalone / on later runs.
  • Integration: npm run test:integration5 files / 50 tests, 0 failures, 38s.
    git status --porcelain empty afterwards.
  • npm pack --dry-run: 434 files, 1.2 MB; 42 files under dist/skills/git/references/
    (floor packed-reference-manifest-size = 42, exact), 8 under pr/.
  • Install shape, HOME forced to a scratch dir (real ~/.claude verified untouched
    throughout):
    $ node dist/cli.js init --recommended --tracker github
       total 26   pr/ 8   tracker/ 10          (21 generated + 5 hand-authored)
    
    $ echo '# junk' > $REFS/pr/stale.md ; node dist/cli.js init --recommended --tracker github
       Removed 1 orphaned asset(s) no longer in the registry: reference pr/stale.md
       total 26   pr/ 8   stale.md present: NO
    
    $ node dist/cli.js tracker --set jira
       total 37   pr/ 8
    
    $ node dist/cli.js tracker --set github
       total 26   pr/ 8   (the 8 generated names, unchanged through both switches)
    
    A seeded pr/stale.md is pruned on the very next init — the installer prune now converges
    references/pr/ the same way it converges references/tracker/ (D-CONVERGED-SUBTREES).

Follow-ups

Related Issues

Closes #326
Closes #328
Refs #289 — this PR does not meet #289's own acceptance criterion of git.md under 300 lines
(now 801, down from 917); substantial progress, not full closure.
Refs #342 — this PR completes item 1 of #342's scope (the git.md PR-host cut); the remaining
prose pass and the rest of the devflow-wide diet are still open.

…in Principles (#328)

The cross-op sentence "This applies to all comment-posting operations
(…)" lived inside post-resolution-summary's compose step, where a
reader of any OTHER comment-posting operation's section never reaches
it. Move the cross-op scope to Principle 8 as its own sub-bullet, and
leave post-resolution-summary's op-local clause stating only what that
operation's own body must not reproduce.

Principle 8 is where the containment contract is already stated once
for the whole agent; naming the four posting operations there makes the
rule reachable from the principle rather than from one operation's
step 5.

Refs #328
…rence module (#326, SG-8)

git.md is billed on every Git spawn (PF-026), and half its operation
roster was never a tracker fact: pull requests, PR reviews and PR
checks stay on GitHub under every issue-tracker provider. Those eight
operations' `**Process:**` bodies move to a new generated module,
src/assets/mds/git/_pr.mds -> references/pr/{op}.md — one file set for
everyone, installed unconditionally, named by a fixed literal path that
composes nothing from the provider token.

dist/agents/git.md: 58,803 -> 45,400 ch (920 -> 801 L).

What deliberately STAYED, each for a guard that reads git.md alone:
  - both summary ops' sentence naming references/publication-gate.md
    ([DR-20](i) reads the agent alone);
  - post-resolution-summary's op-local non-reproduction clause
    (Principle 8 must be readable from the op's OWN section);
  - resolve-review-threads' step 3, the D9 gate application (D9 has
    one authority, and the frozen fixture samples that exact line);
  - every `**Input:**`, `**Degradation (D4):**` and `**Output:**`.

SG-8 is satisfied as a condition, not waived: the two summary ops move
in the same commit as their guards, every repointed guard carries a
known-bad probe, and `## Comment-sink scrub (D11)` never leaves the
agent. The non-vacuity proof SG-8 actually asks for is the new D11
probe — the posting SET is the same 8 ops before and after, so green
alone proved nothing; dropping references/pr/ must take it to a named
set of 5.

Guard classification is per literal, at the call site, per ADR-025 —
'union' only where the text provably moved, 'sole' everywhere else.
Two corpora are deliberately narrower than the full sink corpus:
AC-0.6b's remote-I/O detection reads git.md union pr/ (the full union
would detect setup-task through its PROVIDER mechanics, changing the
guard's subject), and its D4-evidence half stays git.md-only (PF-027).

The frozen fixture tests/fixtures/golden/github-status-lines.txt is
BYTE-UNCHANGED: six entries joined STATUS_LINE_REFERENCE_FILES and two
samples became straddle splits, but every sampled byte still exists in
the same order. No re-capture authorisation was spent. Verified by cmp
against main and by an --unfreeze --out-dir re-derivation.

Floors raised (never lowered): installed-reference-count-github 13->21,
installed-reference-count-provider 24->32, generated/packed manifest
34->42, capability-hoist-block-floor 49->57. New floor
git-agent-remote-io-ops = 14, replacing a bare > 0 that one detected op
satisfies.

tests/fixtures/golden/git-agent.md is expected red until its own
fixture-only commit (PF-057).

Refs #326
The PR-host reference tree landed in the previous commit but nothing pruned
it: `references/pr/` was overlaid and preserved whole by the full-install
pre-clean, so a retired op's document, a shadow-supplied file, or a stale
copy from an older build stayed inside the installed skill indefinitely.

Parameterise the prune by subtree and drive it from one list:

- D-CONVERGED-SUBTREES names `tracker/` and `pr/` — the directories whose
  every file is generated. The references ROOT stays exempt for the inverse
  reason (hand-authored documents beside the generated ones, no manifest of
  which is which — D-OVERLAY-FLAT-UNIT).
- `prunePreservingRecoveryCopies` takes the subtree instead of hard-coding
  `tracker/` in three places, so a recovery copy stranded under one subtree
  skips THAT subtree only rather than refusing to converge the other.
- `pruneConvergedSubtrees` merges the sweeps into the one SweepResult
  `ReferenceOverlayResult.pruned` and `recordSweep` already carry; no caller
  changes.

Sweep names are now relative to the references ROOT (`pr/stale.md`,
`tracker/probe-provider`). Merging two sweeps that each named paths relative
to their own root would report `stale.md` for a file in either of them — an
install-report line naming a file the user cannot find. It also matches the
stranded-skip failure, which has always named its subtree from the root.

`devflow tracker --set` needs no change: `pr/` is wanted under every provider
(ADR-026), so a switch converges its contents and never adds or removes it.

Tests: a `pr/` arm mirroring the tracker convergence arms — stale file
removed and named, a deleted generated document put back, and the
stranded-recovery scoping. Non-vacuity per ADR-024/PF-018: the replaced
tracker-only rule is spelled out in the test and shown to leave the same
seeded orphan standing. Verified RED by narrowing CONVERGED_SUBTREES to
`[TRACKER_SUBTREE]` — the two convergence arms fail, the probe stays green.

Refs #326
…he PR-host row (#326)

The two phase-named git.md ceilings become one. BUDGET_GIT_MD is re-derived
downward 55_750 -> 45_150 against a measured 45_068, and is now the live gate
on dist/agents/git.md; the Phase-3 companion and the preamble-allowance
arithmetic that split the file into two gated halves are gone, since a single
number gates the whole artifact again.

The three loaded-set rows fall with it, every character of the fall being
git.md's: GitHub 80_200 -> 67_200 (measured 67_123), jira 89_500 -> 76_500
(76_427), linear 91_700 -> 78_700 (78_610). Each now sits below the value it
was re-baselined from in September, so that authorisation is fully spent back.

A fourth row is added. references/pr/ is installed under every tracker, so a
PR operation costs the same bytes on all three paths and belongs on a row of
its own rather than folded into the per-provider ones or onto the GitHub row,
which is scoped to tracker ops. BUDGET_LOADED_SET_PR_HOST = 59_100 against a
measured 59_033, with references/github-api.md as a written exclusion
(LOADED_SET_WRITTEN_EXCLUSIONS): two of these ops loaded that file long before
any split existed and #326 moved only the line that names it. What the
exclusion owes in return is recorded row 2c-ex, which prints the same maximum
with the file charged, plus an arm asserting the unexcluded figure would NOT
fit under the ceiling -- so the exclusion is load-bearing, not a rounding
convenience.

The round-trip table's collector is generalised over the pointer prefix and
now prints both vocabularies: 11 `**Mechanics:**` sites and 8 `**PR
mechanics:**` sites. Both stay recorded, never asserted.

Refs #326
…lit (#326)

Fixture-only. `npm run test:golden:update -- git-agent` plus the equality
baselines that pin it, all re-set from the updater's own output:

  GIT_AGENT_BYTES  58_549 -> 45_400
  GIT_MD_CHARS     58_100 -> 45_068
  GIT_MD_LINES        917 -> 801
  TOTAL_CHARS      67_623 -> 54_591
  TOTAL_LINES       1_222 -> 1_106

The SKILL_* pins do not move — neither skill file was touched — and
tests/fixtures/golden/github-status-lines.txt stays byte-identical to main;
its updater still refuses without --unfreeze, and no authorisation was spent.

Reviewed as a text diff: the fixture loses the eight PR/review operations'
step bodies and gains their `**PR mechanics:**` pointers, the load rule's
PR-mechanics arm, the merged-step rule generalised to two references, the two
reworded D10 naming sentences, post-resolution-summary's op-local
non-reproduction clause, and Principle 8's #328 sub-bullet. All eighteen
`## Operation:` sections and all eighteen `**Process:**` headings survive.

Refs #326
…326)

- Move the sinkCorpusWithoutPrHost JSDoc off gitPlusPrHostCorpus (it had
  landed on the wrong function during the split) and give
  gitPlusPrHostCorpus its own correct doc comment.
- Factor the two known-bad probes that seed a defect into a single
  references/pr/{op}.md corpus entry into a shared seedPrHostFile helper,
  removing duplicated corpus-mapping scaffolding while keeping each
  probe's assertion and defect untouched.
Both probes restated their live arm's predicate inline instead of calling
it, so each stayed green after the arm it guards was weakened — the PF-018
shape every other probe in this branch avoids by driving a shared collector.

- reference-reachability: extract `anchorsOnLineOne(body, op)` and call it
  from the PR-host parity arm and its probe; the probe also asserts the
  positive direction, so a predicate gone constant-false is caught too.
- git-agent: hoist `REMOTE_PLACEHOLDER_RE` to describe scope so the
  containment negative arm and its probe share one regex.

Proven by mutation: `startsWith` -> `includes` and narrowing the regex to
`/\{body\}/` each take the corresponding probe red, and neither did before.
- git-agent.test.ts: drop the unused PR_HOST_OPS import.
- Hoist the D11 posting predicate into one isPostingSection() the live
  forward guard and its SG-8 known-bad probe both call, so narrowing it
  takes the guard (and the probe's named set) red instead of leaving a
  frozen copy of the old spelling behind.
- Hoist the D10 per-op containment check into d10Reaches() and name the
  fail-closed literal once, so the known-bad probe reads the table it
  freezes rather than re-spelling its literal and its predicate.
- Retitle the SG-8 probe: the narrowing is 8 -> 5, not a halving.
- numeric-floors.json: restore the literal em-dashes and arrows that a
  whole-file re-serialization turned into \u escapes, cutting the diff
  against main from 18 hunks to the 5 that carry real entry changes.
  No floor or ceiling value changed.

Refs #326
…D-INSTALL-SET

The D-INSTALL-SET docblock said the build emits 34 reference files. It
emits 42 since the eight PR-host operations gained their own module.

Refs #326
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant