Graduated from the friction-log inbox (entry dated 2026-09-07). Severity M as logged.
What happened
PR #711's panel was assembled after PR #709 merged. Its prompts named ec750753eff1a645c64163b61a2b511e3adf71d4 as the base. origin/main was 6f2cc2470c62ca4aa16793e0e20252341ba48b24 at launch — one commit ahead.
Diffing against the named base attributed PR #709's already-merged hook, tests and manifest to PR #711, a docs-only change. That is a large, non-empty, wrong diff: the exact shape the panel contract's Right revision item warns about, because it satisfies every other check a lens runs.
Both lenses detected it independently against the remote, re-derived the correct three-file diff, and said so in their reports before reviewing. The contract worked.
Why it is worth filing anyway
The cockpit had no signal. panel_prompt.py reported the base as "resolved from the remote at assembly time, not supplied by the author" — which is true, and which reads as a currency guarantee it does not give. Nothing in the rendered prompt distinguishes a base resolved a second ago from one resolved before an intervening merge.
A lens that skipped the Right revision check would have reviewed the wrong diff and reported it clean. That check is the last line of defence and it is a lens-side behavioural rule, not a mechanism — the same asymmetry #570 and #578 are filed about elsewhere in this tool.
The window is not exotic: assemble prompts, merge a sibling PR, launch. That is an ordinary sequence when several PRs are in flight, and it is exactly what happened here.
Options
- Re-resolve at render time. Removes the window for the common case, and does not close it — a merge can still land between render and launch.
- Stamp the resolution. Print when the base was resolved, so a stale one is visible in the prompt rather than inferred. Does not prevent it; makes it detectable by the cockpit as well as the lens.
- Both. Narrow the window and make the remainder visible.
- Have the tool verify at launch rather than render — closest to closing it, and the largest change, since
panel_prompt.py renders text and does not own the launch.
Option 2 is worth having regardless of the others: the failure here was not that the base went stale, it was that nothing said so.
Reproduction
Render a prompt, merge anything to the protected branch, then compare the rendered base against git ls-remote origin main. In this occurrence the drift was visible by diffstat alone — the prompt announced a docs-only PR and the diff carried a hook, a test module and a manifest.
Cross-references #642 (a lens asserting a base-currency relationship its command did not establish) — related but distinct: there the lens's own check was unsound, here the lens's check was sound and caught the tool.
https://claude.ai/code/session_019VqvhqHbSiZaLJjUnoy3nY
Graduated from the friction-log inbox (entry dated 2026-09-07). Severity M as logged.
What happened
PR #711's panel was assembled after PR #709 merged. Its prompts named
ec750753eff1a645c64163b61a2b511e3adf71d4as the base.origin/mainwas6f2cc2470c62ca4aa16793e0e20252341ba48b24at launch — one commit ahead.Diffing against the named base attributed PR #709's already-merged hook, tests and manifest to PR #711, a docs-only change. That is a large, non-empty, wrong diff: the exact shape the panel contract's Right revision item warns about, because it satisfies every other check a lens runs.
Both lenses detected it independently against the remote, re-derived the correct three-file diff, and said so in their reports before reviewing. The contract worked.
Why it is worth filing anyway
The cockpit had no signal.
panel_prompt.pyreported the base as "resolved from the remote at assembly time, not supplied by the author" — which is true, and which reads as a currency guarantee it does not give. Nothing in the rendered prompt distinguishes a base resolved a second ago from one resolved before an intervening merge.A lens that skipped the Right revision check would have reviewed the wrong diff and reported it clean. That check is the last line of defence and it is a lens-side behavioural rule, not a mechanism — the same asymmetry
#570and#578are filed about elsewhere in this tool.The window is not exotic: assemble prompts, merge a sibling PR, launch. That is an ordinary sequence when several PRs are in flight, and it is exactly what happened here.
Options
panel_prompt.pyrenders text and does not own the launch.Option 2 is worth having regardless of the others: the failure here was not that the base went stale, it was that nothing said so.
Reproduction
Render a prompt, merge anything to the protected branch, then compare the rendered base against
git ls-remote origin main. In this occurrence the drift was visible by diffstat alone — the prompt announced a docs-only PR and the diff carried a hook, a test module and a manifest.Cross-references
#642(a lens asserting a base-currency relationship its command did not establish) — related but distinct: there the lens's own check was unsound, here the lens's check was sound and caught the tool.https://claude.ai/code/session_019VqvhqHbSiZaLJjUnoy3nY