Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions docs/09-reviews/2026-09-02-m5-2-real-effects-live-attempt.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,19 @@ the completed-only persisted turn cannot by itself prove whether the second
callback result was durably completed. The next diagnostic adds only one
aggregate—completed tool actions—to distinguish callback rejection from an
adapter-finalization failure. It does not expose tool arguments or outputs.

## Attempt 13 result and correction

Attempt 13 ran the merged completed-action projection on `3609ce3` under the
same live conditions. It reported the same stage and reconciliation reason,
but distinguished 5 selected actions from 4 completed actions. The first
reviewer read callback completed; the second finding callback was selected and
rejected before completion. Cleanup again completed exactly.

The live finding tool required the reviewer to copy the exact path,
counterexample, and a digest that the trusted coordinator can deterministically
derive from the first two values. Copying that digest from tool output is a
brittle model obligation. The correction makes it a coordinator-bound schema
constant instead, while retaining exact path/counterexample comparison against
the detached checkout, bounded reason validation, wrong-content negative
coverage, and all downstream lifecycle/Git/verifier bindings.
7 changes: 7 additions & 0 deletions docs/09-reviews/2026-09-02-mainline-checkpoint.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ not distinguish a rejected second callback from post-callback adapter failure,
the projection now also includes the bounded completed-action aggregate before
the next run.

Attempt 13 then reported 5 selected versus 4 completed actions, proving that
the second reviewer callback—not adapter finalization—was the failing boundary.
The correction replaces the redundant requirement for the model to copy a
coordinator-derivable digest from tool output with a coordinator-bound schema
constant. Exact path and counterexample matching against the detached checkout,
negative tamper coverage, and the downstream verifier chain remain mandatory.

## Ordered next gates

1. Run the merged real-effects Codex path once with the new partial-stage
Expand Down
13 changes: 8 additions & 5 deletions src/validation/coordinator-driven-no-plan-scenario.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -821,9 +821,13 @@ export async function runCoordinatorDrivenNoPlanScenario({
required: Object.freeze([...Object.keys(staticArguments), "commitSha"]),
}),
});
const realReviewFindingDigest = independentGitFindingDigest({
resourcePath: REAL_EFFECT_RESOURCE,
counterexample: REAL_EFFECT_IMPLEMENTATION.trim(),
});
const realReviewPublish = Object.freeze({
...TOOLS.review,
description: `${TOOLS.review.description} Use only the artifact content returned by the preceding read tool. Copy its candidateFindingDigest and report the exact resourcePath, counterexample, and a bounded reason.`,
description: `${TOOLS.review.description} Use only the artifact content returned by the preceding read tool. Report its exact resourcePath and counterexample with a bounded reason; use the coordinator-bound findingDigest constant from this schema.`,
inputSchema: Object.freeze({
type: "object", additionalProperties: false,
properties: Object.freeze({
Expand All @@ -832,7 +836,7 @@ export async function runCoordinatorDrivenNoPlanScenario({
resourcePath: Object.freeze({ type: "string", minLength: 1, maxLength: 200 }),
counterexample: Object.freeze({ type: "string", minLength: 1, maxLength: 256 }),
reason: Object.freeze({ type: "string", minLength: 1, maxLength: 1000 }),
findingDigest: Object.freeze({ type: "string", pattern: "^sha256:[a-f0-9]{64}$" }),
findingDigest: Object.freeze({ const: realReviewFindingDigest }),
}),
required: Object.freeze([
"sourceEventId", "event", "resourcePath", "counterexample", "reason",
Expand Down Expand Up @@ -1086,7 +1090,7 @@ export async function runCoordinatorDrivenNoPlanScenario({
counterexample: injectRealReviewFindingTamper
? "WRONG_COUNTEREXAMPLE" : read.content.trim(),
reason: "The detached artifact contains the exact blocking counterexample.",
findingDigest: read.candidateFindingDigest,
findingDigest: realReviewFindingDigest,
};
}
return value;
Expand Down Expand Up @@ -1135,7 +1139,7 @@ export async function runCoordinatorDrivenNoPlanScenario({
"receiver-decision": "receiver-decision", "r-review": "admitted-tool",
},
instructions: realEffects
? "Review only coordinator-admitted context. In the admitted review turn, call every offered tool exactly once and in order: read the detached-checkout artifact, then report the exact counterexample found in the returned content and copy candidateFindingDigest. Do not stop after the read result."
? "Review only coordinator-admitted context. In the admitted review turn, call every offered tool exactly once and in order: read the detached-checkout artifact, then report the exact resourcePath and counterexample found in the returned content. Use the coordinator-bound findingDigest constant from the report tool schema; do not derive or copy it from tool output. Do not stop after the read result."
: "Review only coordinator-admitted context.",
scenarioId: "coordinator_driven_no_plan",
});
Expand Down Expand Up @@ -1333,7 +1337,6 @@ export async function runCoordinatorDrivenNoPlanScenario({
resourcePath: REAL_EFFECT_RESOURCE,
content,
commitSha: checkout.subjectSha,
candidateFindingDigest: independentGitFindingDigest(candidate),
};
}
if (realEffects && selectedTool === TOOLS.review.name) {
Expand Down
6 changes: 6 additions & 0 deletions test/coordinator-driven-no-plan-scenario.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,12 @@ test("real-effects path keeps reviewer context blind and binds model finding", a
assert.equal(result.verification.signatureVerified, true);
assert.equal(result.verification.resultDigestBound, true);
assert.equal(result.runtime.modelSelectedToolCalls, 14);
const liveReviewSchema = result.routeHandlerConfigs[0].businessTools[1].inputSchema;
assert.match(liveReviewSchema.properties.findingDigest.const, /^sha256:[a-f0-9]{64}$/u);
assert.deepEqual(liveReviewSchema.required, [
"sourceEventId", "event", "resourcePath", "counterexample", "reason",
"findingDigest",
]);
assert.deepEqual(result.nativeTurnManifest.records.map(({ actions }) =>
actions.map(({ tool }) => tool)), [
["threadmesh_commit_candidate", "threadmesh_publish_artifact"],
Expand Down
Loading