Skip to content

Pin the agent instructions, and fix the drift the pin finds - #11210

Merged
MarkusNeusinger merged 6 commits into
mainfrom
test/pin-agent-instructions
Sep 2, 2026
Merged

Pin the agent instructions, and fix the drift the pin finds#11210
MarkusNeusinger merged 6 commits into
mainfrom
test/pin-agent-instructions

Conversation

@MarkusNeusinger

@MarkusNeusinger MarkusNeusinger commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Summary

  • CLAUDE.md and .github/copilot-instructions.md both open with the claim that they stay in sync, and both are read as binding shorthand — one is loaded into every Claude Code session, the other into every Copilot review. Nothing checked either claim.
  • tests/unit/test_agent_instructions.py adds four pins that need no database, no network and no fixtures.
  • The pin found one real gap and one dead link. Both are fixed in this PR (listed below) — nothing was pinned that the guides did not already say.
  • Transferred from the sibling repo kurrentschrift (its tests/test_agent_instructions.py, PR [line-basic] matplotlib implementation #484), adapted to this repository's file layout and its own sync claim.

What is pinned

Pin Scope
Every backticked repo path resolves 55 paths across CLAUDE.md, .github/copilot-instructions.md, agentic/docs/project-guide.md, agentic/commands/prime.md
Every relative link and same-page anchor resolves 5 links; anchors are matched against the file's own headings
Every skill the routing table names exists 8 skills as .claude/skills/<name>/SKILL.md; /update-config is excluded by name because CLAUDE.md itself says it is a harness skill, and slash names that are agentic/commands/*.md resolve there
Rules that must reach both audiences are on both sides 7 rules

A path is only checked when it is multi-segment and file- or directory-shaped, so prose shorthand (CHANGELOG.md, conftest.py) is not forced to carry a full path — pinning those would make the guides harder to read, which is the opposite of the point.

Anchors are matched against real headings: fenced blocks are stripped first, because these guides are full of shell snippets whose # comments would otherwise pass as headings and let a dead link through (63 such phantoms across the four files).

The mirroring pin is keywords, not a text diff. The two files address different readers and paraphrase each other; requiring byte equality would force false uniformity. What it catches is a rule silently living in only one of them. The keywords carry the prohibition, not just its subject — ["never manually merge", "never bypass"], not ["manually merge"] — so a guide cannot be rewritten to permit what the pin claims to forbid while staying green.

The drift it found

1. copilot-instructions.md never stated the rule the pipeline exists to protect. It documents the specification and implementation lifecycles, the label taxonomy and the quality-threshold cascade — but nowhere says: never merge a spec or implementation PR by hand, never write specification.md / metadata/*.yaml by hand, and put the approved label on the issue, not the PR. CLAUDE.md carries all of that in a "CRITICAL: Mandatory Workflow" section with a DON'T/DO table. That is the repository's most consequential rule and the one an agent that opens and edits PRs is most able to break, so a compact form of it now sits in copilot-instructions.md's Important Rules, pointing at the full table.

2. agentic/docs/project-guide.md linked to /CLAUDE.md. A leading slash reads as repo-root-relative to a human but as site-root to GitHub's renderer, where it 404s. Now ../../CLAUDE.md.

3. (review round) CLAUDE.md step 3 said "DO NOT manually merge PRs!" while copilot-instructions.md says "never" — normalised on "never" so the pin can match the negative phrase itself rather than the bare subject.

Nothing else moved. The seven mirrored rules are the ones already present in both files (English output, Google style, the changelog rule, the condensed-release rule, never echoing secrets, structural over symptomatic fix) plus the one added above.

What this test is not

It is not a place to introduce a rule. Adding an entry to MIRRORED_RULES for something only one guide says makes the suite red until someone writes the rule into both — which is the intended order: write it in both guides first, then pin it.

Test plan

  • uv run pytest tests/unit/test_agent_instructions.py — 21 passed.
  • The mirroring pin was verified to bite: with copilot-instructions.md unchanged it failed with rule 'never merge a pipeline PR by hand' is missing from: copilot-instructions.md, and the link pin reported /CLAUDE.md before the fix.
  • The fence stripping was verified to remove only phantoms: the anchor set drops from 178 raw candidates to 115 across the four files, and no real heading is lost.
  • uv run pytest tests/unit — 1768 passed, 1 skipped (pre-existing local skip: MonoLisa italic not cached).
  • uv run ruff check . / ruff format --check . — clean.

Checklist

  • CHANGELOG.md updated under [Unreleased].
  • The two guides remain each other's companion; the change to copilot-instructions.md mirrors a rule CLAUDE.md already had, so no rule moved out of sync.

🤖 Generated with Claude Code

https://claude.ai/code/session_01PBQdMbboxo59sSThGSbfke

CLAUDE.md and .github/copilot-instructions.md both open with the claim that
they stay in sync, and both are read as binding shorthand - CLAUDE.md is
loaded into every Claude Code session, copilot-instructions.md into every
Copilot review. Nothing checked either claim.

tests/unit/test_agent_instructions.py adds four pins that need no database,
no network and no fixtures: every backticked repo path in the four
agent-facing files resolves (55 of them), every relative link and same-page
anchor resolves, every skill the routing table names exists as
.claude/skills/<name>/SKILL.md, and the rules that must reach both audiences
are present on both sides. The mirroring pin is keywords rather than a text
diff, because the two files address different readers and paraphrase each
other; requiring byte equality would force false uniformity.

It found two things. copilot-instructions.md described the specification and
implementation lifecycles but nowhere stated the rule they exist to protect:
never merge a pipeline PR by hand, never write the pipeline's files by hand,
and put the 'approved' label on the issue rather than the PR. That is the
repository's most consequential rule and the one an agent that opens and
edits PRs is most able to break. And agentic/docs/project-guide.md linked to
/CLAUDE.md, which GitHub resolves as a site-root URL and answers with a 404.

Transferred from the sibling repo kurrentschrift.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PBQdMbboxo59sSThGSbfke
Copilot AI balanced review requested due to automatic review settings September 2, 2026 21:24
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PBQdMbboxo59sSThGSbfke

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Multiple instruction pins can pass despite invalid anchors, removed companion claims, or reversed workflow rules.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds regression tests to keep agent instructions synchronized and valid.

Changes:

  • Pins referenced paths, links, skills, and mirrored rules.
  • Adds mandatory pipeline safeguards to Copilot instructions.
  • Fixes a project-guide link and updates the changelog.

Review findings:

  • Strip fenced code blocks before extracting Markdown headings.
  • Match the explicit companion wording rather than filename occurrences.
  • Require negative wording for the manual-merge prohibition.
  • Align the project guide’s release instructions with the companion guides.
File summaries
File Description
tests/unit/test_agent_instructions.py Adds instruction-integrity tests; several assertions require strengthening.
CHANGELOG.md Records the changes.
agentic/docs/project-guide.md Fixes the CLAUDE.md link; release guidance remains inconsistent.
.github/copilot-instructions.md Adds mandatory pipeline safeguards.
Review details

Suppressed comments (1)

tests/unit/test_agent_instructions.py:209

  • This rule pin passes while another file classified above as an agent instruction still says the opposite: agentic/docs/project-guide.md:1064-1067 instructs gh release create to publish the changelog section “verbatim,” whereas both companion guides require a condensed release and also now require bumping app/package.json. Because CLAUDE.md links agents to that guide, the instructions remain materially inconsistent. Update the project guide to the current release flow (and consider pinning that wording too).
    "a release is condensed, never copied": ["condensed, never copied", "agentic/commands/release.md"],
  • Files reviewed: 4/4 changed files
  • Comments generated: 3
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread tests/unit/test_agent_instructions.py Outdated
Comment thread tests/unit/test_agent_instructions.py Outdated
Comment thread tests/unit/test_agent_instructions.py Outdated
@codecov

codecov Bot commented Sep 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copilot review, all three applied.

1. _HEADING ran over raw Markdown, so a '# Install uv' comment inside a
   fenced shell block counted as a heading - a dead same-page anchor could
   pass by matching a line GitHub renders as code. Fenced blocks are stripped
   first; that drops 12 fake anchors in CLAUDE.md, 11 in
   copilot-instructions.md and 40 in project-guide.md, and no real one.

2. The pipeline rule was pinned on the bare substring 'manually merge', which
   carries no polarity: both guides could be rewritten to say an agent may do
   it and the pin would stay green while naming the rule it no longer
   protects. Both guides are normalised on 'never' (CLAUDE.md's step 3 said
   'DO NOT'), and the keywords are now the negative phrases themselves,
   'never manually merge' and 'never bypass'.

3. The companion-claim test matched the bare filenames, which appear in both
   guides in other sections - so it stayed green with both opening claims
   deleted. It now matches the companion sentence and requires 'Both files
   MUST stay in sync' on each side.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PBQdMbboxo59sSThGSbfke
Copilot AI review requested due to automatic review settings September 2, 2026 21:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The path heuristic misses extensionless Dockerfiles, and two prose-style nits remain.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

tests/unit/test_agent_instructions.py:12

  • Add the serial comma required by the repository documentation style.
Four cheap pins, none of which needs the database, the network or a checkout of
anything but this repository:
  • Files reviewed: 5/5 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment thread tests/unit/test_agent_instructions.py Outdated
Comment thread CHANGELOG.md Outdated
Copilot review, both applied.

The file-shape heuristic required a known suffix or a trailing slash, so
extensionless files fell through it silently: agentic/docs/project-guide.md
names api/Dockerfile and app/Dockerfile, and deleting or renaming either
would have left the path pin green. A small allowlist of extensionless
basenames covers them - matched on the basename, so prose tokens like
'prism/r' and the 'app/app/src' anti-example stay out. The checked-path count
goes from 55 to 57.

The changelog entry was missing the serial comma the repository's prose style
requires.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PBQdMbboxo59sSThGSbfke
Copilot AI review requested due to automatic review settings September 2, 2026 21:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The path check misses documented paths contained in multi-path code spans.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

CLAUDE.md:128

  • This edited instruction still uses all-caps and exclamation-mark emphasis, which the repository prose rules prohibit (.claude/skills/write-docs/SKILL.md:79-80). Use sentence case while retaining the negative phrase required by the pin.
3. NEVER manually merge PRs!
  • Files reviewed: 5/5 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread tests/unit/test_agent_instructions.py Outdated
Merge resolves the CHANGELOG conflict by keeping both Added entries (#11205
and #11206 landed on main while this branch was open).

Copilot review: _candidate_paths treated a whole code span as one token, so
'.claude/commands/ -> ../agentic/commands/' - a sentence about two paths -
was not path-shaped and went unchecked as a whole. Spans are now split on
whitespace before the shape test; fragments that are not path-shaped (the
arrow, a command word, a flag) drop out, which is what makes the split safe.
A '../'-relative fragment is skipped rather than resolved against the
repository root, where it would mean something else entirely.

That leaves the arrow's meaning unpinned, and the sharper failure is the one
where somebody replaces the symlink with a real directory: both ends still
exist, the guide still reads true, and commands written on either side
quietly stop matching the other. So the symlink gets its own test, which
follows the link instead of matching its text.

(The specific example was in fact already covered, because
'.claude/commands/' appears standalone later in the same sentence - but the
hole in the heuristic was real.)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PBQdMbboxo59sSThGSbfke
Copilot AI review requested due to automatic review settings September 2, 2026 22:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The mirrored changelog pin does not currently protect the required action.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

tests/unit/test_agent_instructions.py:218

  • The test plan in the PR description is stale after this additional test was added: the current parametrization produces 22 tests, not the stated 21. The same description still reports 55 checked paths while the updated changelog reports 57; refresh both verification figures so the PR metadata matches this revision.
def test_the_commands_symlink_points_where_it_says() -> None:
  • Files reviewed: 5/5 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread tests/unit/test_agent_instructions.py Outdated
Copilot review, same class as the pipeline-rule finding one round earlier:
the changelog entry was pinned on '[unreleased]' plus 'keep-a-changelog',
which is the rule's subject matter. Both guides could be rewritten to merely
mention the file and the format while dropping the requirement, and the pin
would stay green - reporting a mirrored rule when what is mirrored is a
topic.

It now requires 'every pr updates' as well. The Google-style entry had the
same weakness ('google style' plus a path) and now requires the full 'prose
follows the Google developer documentation style guide'. The dict carries the
rule that keywords must include the obligation, so the next entry added does
not repeat this.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PBQdMbboxo59sSThGSbfke
Copilot AI review requested due to automatic review settings September 2, 2026 22:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The only unresolved comment is a non-blocking documentation-style nit.

Review details

Suppressed comments (1)

CLAUDE.md:128

  • Use sentence case here. The repository documentation contract explicitly disallows all-caps and exclamation-mark emphasis; the mirror check is case-insensitive, so this keeps the required negative phrase without violating that rule.
3. NEVER manually merge PRs!
  • Files reviewed: 5/5 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

@MarkusNeusinger
MarkusNeusinger merged commit 9c85763 into main Sep 2, 2026
13 checks passed
@MarkusNeusinger
MarkusNeusinger deleted the test/pin-agent-instructions branch September 2, 2026 22:54
MarkusNeusinger added a commit that referenced this pull request Sep 2, 2026
CHANGELOG only, resolved as a union: every bullet from both sides kept, main's
own order untouched. Added gains this branch's origin-gate entry above the
agent-instruction pin; Changed keeps the two gate entries alongside the Node
pin; the new Security section is carried over unchanged.

The agent-instruction pin test that arrived with #11210 passes against this
branch, including the infra/ entries this PR adds to both repository maps.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PBQdMbboxo59sSThGSbfke
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants