Repository navigation
fix: land the two P1 interview-path blockers — claude adapter permission rules (#498) and the pinned score snapshot (#500) - #501
Merged
Conversation
…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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 —
a9c560ainternal/adapters/claude: absolute permission rules are written with two slashes, soWrite(<output>/**)is honoured and a movement withoutshellcan write its result envelope. Without this, arepo_read-only interview part cannot return a result at all.#500 —
dfa3eb1internal/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 onmissing pinned score snapshot, andresumecan carry the run past the approval.Closes #498
Closes #500
🤖 Generated with Claude Code