Skip to content

fix: land the two P1 interview-path blockers — claude adapter permission rules (#498) and the pinned score snapshot (#500) - #501

Merged
BeomSeogKim merged 3 commits into
mainfrom
fix/p1-blockers-498-500
Sep 28, 2026
Merged

BeomSeogKim merged 3 commits into
mainfrom
fix/p1-blockers-498-500

Conversation

@BeomSeogKim

Copy link
Copy Markdown
Owner

Two independent fixes, combined into one PR for a single CI pass under the strict up-to-date rule (same shape as #499). Each was produced and verified by its own Partitur run on 2026-09-22 (build, vet, gofmt, whole-repo tests, a named red-first test, and untouched-surface criteria all VERIFIED; the run trees are byte-identical to the two commits here). Both change disjoint files.

#498 — a9c560a internal/adapters/claude: absolute permission rules are written with two slashes, so Write(<output>/**) is honoured and a movement without shell can write its result envelope. Without this, a repo_read-only interview part cannot return a result at all.

#500 — dfa3eb1 internal/runstore, internal/score: a score snapshot is serialized as exactly the score whose hash was pinned, so approving an adapter-origin amendment in the draft phase no longer halts on missing pinned score snapshot, and resume can carry the run past the approval.

Closes #498
Closes #500

🤖 Generated with Claude Code

BeomSeogKim and others added 3 commits September 22, 2026 09:36
…ashes (#498)

A movement without shell could not write its result envelope: the performer
explored the repository, prepared its answer, and then reported that both Write
and shell redirection into the writable artifact directory were denied. The
attempt ended task_failed with "result envelope missing".

Claude Code reads one leading slash in a permission rule as a path relative to
the working directory. buildSettings built every Edit(...)/Write(...) rule from
absolutePattern, which ends in filepath.Clean and therefore yields exactly one
leading slash, so none of those rules ever matched anything. A bare rule has no
path, which is why Bash was unaffected — and why every earlier claude movement
that wrote into its output directory happened to hold shell and got there by
redirection. The draft interview movement is repo_read by rule, so it was the
first shape with no way through.

Probed outside Partitur with the flags buildCommand passes (claude 2.1.278,
--permission-mode dontAsk --safe-mode --setting-sources ""): Write(/abs/out/**)
is denied, Write(//abs/out/**) succeeds with nothing else changed. Controls:
--allowed-tools with one slash is denied too, and --permission-mode acceptEdits
writes regardless of any rule — including past a deny rule with one slash — so
it is not the fix; it would let a read_only movement edit the repository.

absolutePermissionPattern now prefixes the resolved absolute path for rule use
only. --add-dir still receives a plain absolute directory, the permission mode
is unchanged, and the same defect is fixed for every Grants.PathsRW entry.

Produced by a Partitur run (codex writer, eight acceptance criteria including
go test ./..., read-only codex verifier, human gate approved). The verifier's
whole-repo test item failed inside its sandbox on unix-socket bind and
.partitur/work mkdir denials, the constraint documented in #478; the
authoritative criterion ran outside the sandbox and passed, as did the full
suite on this branch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
)

Approving an adapter-origin amendment in the draft phase stopped with "missing
pinned score snapshot", and resume then halted forever with
missing_snapshot_file: the journal ended at amendment.approval_prepared, the
decision stayed pending, and the run could not be moved.

The snapshot was there and was sound. On the stuck run, scores/revision-3.yaml
matched the pinned file hash, compiled with no diagnostics, and reported
revision 3 — three of the four checks in validatePrepareSnapshot passed. Only
the semantic hash differed, and revision 2 of the same run round-tripped to
exactly the base hash the same prepare recorded, so this was not hash-algorithm
drift.

The serialization side was wrong. CanonicalYAML always wrote multiline scalars
with |-, so a value ending in a newline lost it on the way to disk and
recompiled into a different score than the one the prepare had hashed. The
chomping indicator is now chosen from the value: |- for no trailing newline, |
for one, |+ for more. Validation is unchanged — nothing was relaxed, skipped or
reordered.

validatePrepareSnapshot also collapsed its four failures into one bare
sentinel, which is why diagnosing this run took a hand-computed hash
comparison. Each now carries a distinct detail while still wrapping
ErrMissingPinnedSnapshot, so errors.Is keeps working for the recoveryexec
caller that maps it to HaltMissingSnapshotFile.

This corrects prepares made from here on. A run already parked on a snapshot
written by the old serializer stays parked, because its file on disk is still
missing the newline. The issue's second question — whether recovery may abandon
a prepare whose snapshot does not validate — is left to the owner: cancellation
already shows a durable abandonment shape, but silently reclassifying an
unreadable or hash-mismatched pinned artifact as ordinary plan invalidation
would hide an integrity failure, so it should be an explicit operator action
with its own reason.

Produced by a Partitur run (codex writer, seven acceptance criteria including
go test ./..., read-only codex verifier, human gate approved). The verifier's
whole-repo test item failed inside its sandbox on unix-socket bind and
.partitur/work mkdir denials, the constraint documented in #478; the
authoritative criterion ran outside the sandbox and passed, as did the full
uncached suite on this branch (41 packages).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@BeomSeogKim
BeomSeogKim merged commit 19e1fd7 into main Sep 28, 2026
6 checks passed
@BeomSeogKim
BeomSeogKim deleted the fix/p1-blockers-498-500 branch September 28, 2026 14:14
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