Skip to content

/refactor: reviewers should receive the diff by path — inlining it routes a byte-exact artifact through the model's output channel #3

Description

@Danglebary

Summary

/refactor step 4 requires every reviewer brief to carry the diff inlined as content, and forbids handing a reviewer the .pirr/diff.patch path:

  • The diff itself, inlined as content — not .pirr/diff.patch's path. Reviewers hold no path to it by contract: exactly two agent bodies name that artifact and DIFF-MATERIALIZATION.md's two-agent contract is published, so handing a reviewer the path both widens that contract and hands a Read-only agent a file it was never promised.

skills/engineering/refactor/SKILL.md:68, reinforced as an anti-pattern at :164.

At real diff sizes this is unexecutable, and the way it fails is silent.

Where it bites

A single-ticket diff of ~129 KB (2532 lines, 8 files) against a Reviewers manifest of 8 lenses. The orchestrator must emit ~43k tokens of diff per lens — ~344k tokens of generated output, and more than a single message's output budget can carry even once.

The workarounds available to the orchestrator are all defects:

  1. Abbreviate hunks to fit. This is what happens in practice, and it is invisible downstream — the reviewer returns confident findings against a diff that differs from the real one. Observed directly: on a first dispatch the orchestrator silently collapsed two doc comments to ... and compressed several context hunks.
  2. Reduce the diff per lens. Produces reviewers reading different material, which makes the convergence count /refactor step 5 asks for uninterpretable — the skill's own ranking input is destroyed by the accommodation.
  3. Hand-transcribe faithfully across many messages. No mechanism verifies the transcription, so it trades a visible departure for an invisible one.

The underlying defect

The diff is a relay, not a composition. Routing a byte-exact artifact through the model's output channel asks the one component in the system that cannot guarantee fidelity to act as a copy mechanism.

The rest of the brief — ticket contract, Glossary vocabulary, settled-ADR list, deferrals, the planning-artifact hunk label — is genuine synthesis, and inlining is correct for all of it, because the orchestrator is the only thing that can produce it.

The seam: inline what you composed; reference what you copied.

The stated rationale is self-referential

The justification is a count: "exactly two agent bodies name that artifact." But the two-agent contract in skills/_shared/DIFF-MATERIALIZATION.md:68 says two because only two were written — and then that tally becomes the reason a third consumer may not join. It is a constraint that rots on first growth.

This is the same failure mode ADR 0100's Population rule already fixes for briefs: membership is declared, never inferred from a tally.

The plugin already contradicts itself

Three diff-consuming dispatch sites, two rules:

Site What reviewers get
skills/engineering/done/SKILL.md:58 "The diff artifact path (.pirr/diff.patch)"
skills/engineering/retro/SKILL.md:51 "The diff artifact path (.pirr/diff.patch)"
skills/engineering/refactor/SKILL.md:68 path forbidden, inlining mandated

/done states the reason plainly at :28 — "the close-out agents have no git access; this artifact is their only view of the diff." That reasoning applies verbatim to reviewer agents, which hold the same Read/Grep/Glob toolset and the same absence of git access.

A downstream fork of this plugin already resolved it the other way: its DIFF-MATERIALIZATION.md names "the diff-operating reviewer agents parse it" as a first-class consumer of the artifact, and its /refactor hands reviewers "the diff (or scope)" with no inline mandate. Nothing broke.

This is not fixed by keeping diffs small

Worth stating because it is the tempting read. The wall is O(1) in the design rather than O(n) in the repo:

  • Ticket diffs are already scoped — the size comes from the files one ticket touched, not from repo size.
  • At 8 lenses, even a 30 KB diff costs ~240 KB of generated output and still carries transcription risk.
  • Shrinking diffs lowers how often the wall is hit. It does not remove it.

Proposed change

  1. skills/_shared/DIFF-MATERIALIZATION.md ("The artifact") — replace the enumerated two-agent contract with a named consumer population: the close-out pair plus every reviewer /refactor dispatches. Keep "never move or rename it" and the ephemeral-scratch status unchanged.

  2. skills/engineering/refactor/SKILL.md step 4 — reviewers receive the artifact path; the composed planning context stays inlined. The ad-hoc files-or-tree arm keeps inlining its scope description, which is small by construction.

  3. skills/engineering/refactor/SKILL.md anti-patterns — invert the bullet into the general rule it was reaching for: don't route through the model an artifact the model would have to reproduce. The genuine prohibition — never hand-roll a git diff — already lives at step 3 and is untouched.

  4. (Optional, and the one that makes it a contract rather than a convention) — give the shipped reviewer bodies the artifact line the two close-out bodies already carry, so the consumer states its own input.

Note on what does not change

The anti-substitution and pinned-subagent_type rules are unaffected, as is the exit-code discipline at step 3. This changes how the diff reaches a reviewer, not which reviewers run or how their absence is recorded.

Version

Observed on pirr 1.4.0.


🤖 Filed with Claude Code

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions