Circe PR #11: fixes verified
The correction blockers are fixed. This integration milestone is ready within its stated scope.
The two round-5 blockers are fixed on PR #11 at 6a89cc9. Two GPT-6 Luna agents implemented bounded fixes; a third audited recovery. The integrated implementation was reviewed and verified independently. All 525 repository tests, 22 strengthened probes and the retained 19-probe suite pass. PR #11 remains open and unmerged.
+5416 −160 6a89cc90 findings open. No merge performed. Reviewed 24 September 2026.
Current architectural judgment
The corrections now use the proposal binding checks, and intent identity stays explicit from the persisted frame through the kernel. The implementation reuses the existing evaluator and normalizer. It does not introduce another compiler or orchestration layer.
The real service and restart tests support this milestone. They do not establish live model quality or complete the remaining product capabilities.
Round 6: correction fixes implemented and verified
The two round-5 blockers are fixed on PR #11 at 6a89cc9. Two GPT-6 Luna agents implemented bounded fixes; a third audited recovery. The integrated implementation was reviewed and verified independently. All 525 repository tests, 22 strengthened probes and the retained 19-probe suite pass. PR #11 remains open and unmerged.
- F101: one shared binding normalizer now governs proposals and corrections; the failing exclusion and contradictory-binding probes pass with valid destination identity.
- F102: intent identity survives frame persistence, is paired with the revision at compilation, and is checked again by the kernel before a revision.
- Current-version correction recovery is tested against the real HTTP service. Replaying a correction does not create a new revision, changed content under the same command ID is rejected, and redelivering confirmation invokes only the replacement target once.
- 525 repository tests, typecheck, static and deletion boundary checks, real and continuing demos, and held-out fixtures pass. The 22-probe and 19-probe suites overlap and are not an additive test count.
- Upgrade limit: older accepted-turn logs containing corrections may fail replay validation because they lack the newly pinned identity. Old context frames still decode. No automatic migration is provided; preserve old logs and finish outstanding interactions with their original version before starting fresh interactions.
- This increment is ready within its stated scope. Live language quality and risk calibration remain unverified, with belief reuse, deliberation, general language controls and retrieval scale still pending. No whole-product completion claim.
Round 5: shared evaluation improved, two correction gaps remain
Independent review of 4db47a0: 519 repository tests and the retained 19-probe suite pass. Two positive continuation checks also pass. Three new compiler-contract probes expose two remaining correction-boundary findings, so the implementation agent’s round-4 approval is superseded.
- The evaluator now genuinely shares ordered dependency validity across proposals and continuations. Frame-certified correction versions, explicit clarification answers and the complete-write service changes are substantive improvements.
- The previous six findings’ retained reproductions all pass. Additional positive checks confirm retargeting revokes authorization and later completes only the new target, and an explicit clarification answer stays resolved across restart.
- Two correction checks remain incomplete: binding normalization ignores unresolved exclusions and contradictory summary refs; destination selection ignores a supplied targetIntentId. These are public compiler contract tests. The built-in normal correction flow passed.
- Verified 519 repository tests, typecheck, static boundary check, demo:real and the retained 19 probes. The new suite contains 3 failures and 19 passes: 17 repeated host checks plus 2 new positive controls. These counts overlap and must not be added together.
- No product source changes, GitHub comments or merge. No model credentials were needed. The author reports the deletion check; this pass independently reran the static boundary check only.
Round 4: one ordered evaluation, explicit answers, complete durability
This section preserves the implementation agent’s reported verification. The later independent review and round-6 verification supersede that earlier approval.
All six round-3 findings are fixed at 4db47a0 and independently verified. The round-3 probes (8 new failures + 11 repeated controls) all pass; no new findings were introduced.
- F95/F96/F97: evaluateTurn now evaluates proposal, confirmation, cancellation, correction and grounded answer in one ordered pass. A confirmation executes the frozen obligation target set — any accepted or unvalidated adjustment to it becomes a revision or a clarification, never a confirmation of the old revision; a dependency is valid only when the predecessor passed that same evaluation; corrections must bind frame-certified refs and carry their frozen versions into the revision.
- F98: only a proposition that explicitly names a pending question (an explicit clarify answer, or a rejection that abandons it) closes it, and only when the answering commands were not rejected at runtime. Unrelated requests preserve the question.
- F99: the durable writer completes short writes, fails on zero progress, fsyncs the file, renames, then fsyncs the directory; a post-rename directory-sync failure is 5xx with the operation recorded, so the caller reconciles instead of retrying. Injected short-write and directory-EIO faults are covered by tests.
- F100: the adapter requires the service's refusal payload on 404; an unreadable, mismatched or unrecognized 404 stays UNKNOWN with the reconciliation receipt.
- Verification at 4db47a0: 519 repository tests, 19/19 extended probes, typecheck, static and deletion boundary checks, demo:real.
Round 3: original probes green, contracts still incomplete
Independent re-review of bb7a46b: the original 13 probes and 507 repository tests pass, but eight additional probes expose six remaining findings. The implementation agent’s round-2 approval is superseded by this review.
- The thin inspector wrapper and full-plan command replay validation are improvements. The original F85-F94 reproductions all pass. Those statuses record the tested fixes, not a claim that the surrounding contracts have no remaining gaps.
- planTurnCommands remains two evaluations inside one module: proposals use evaluateTurn, while continuationIssue and the continuation loop repeat a subset. Partial exclusions, invalid prerequisites and missing correction evidence still escape.
- Explicit pinned obligation transitions fix the interrupted append and interaction leak probes. Resolution still infers an answer from any emitted command, so unrelated work can consume the question.
- The staged service write and malformed-success handling are better. Short-write handling, directory-sync errors, and the unconditional 404 refusal branch remain incorrect.
- Verified 507 repository tests, typecheck, static boundary check, demo:real, all 13 original probes. The extended suite contains 8 new failures and 11 repeated passing controls, so its passes are not additional unique tests.
- No live model call, product source edits, merge, or GitHub review comments. The deletion boundary check was reported by the author; this pass independently ran the static check only.
Round 2: one compiler, durable obligation transitions, honest HTTP outcomes
This section preserves the implementation agent’s reported verification. The later independent review and round-6 verification supersede that earlier approval.
All ten findings are addressed at bb7a46b and independently verified. No new findings were introduced by the fixes.
- F85/F86/F87/F94: planTurnCommands is now the single whole-turn compiler; proposal, confirmation, cancellation, correction and grounded answer are evaluated over the same frame identity, structural, exclusion, dependency and citation checks, and the accepted-turn codec recomputes the complete command plan. An accepted adjustment that cannot become a revision clarifies instead of confirming the adjusted-away targets; a request with an accepted capability is a new proposal, never a revision.
- F88/F89: the service stages the task and operation, persists both (write, fsync, rename, directory fsync) and only then publishes them; internal faults are 5xx, never a refusal. The adapter confirms only contract-valid refusals; malformed or unrecognized outcomes throw so the kernel records UNKNOWN and reconciles.
- F90/F91/F92: obligation transitions are pinned with the turn and applied idempotently on first delivery and replay; lookup is interaction-scoped before paging; only a consequence command resolves a question.
- F93: relation observation travels through the declared RelationObservationProvider contract on the authority, and relation edges deduplicate by identity so re-observation no longer inflates the frame.
- Verification at bb7a46b: 507 repository tests, 13/13 independent probes (11 reproductions + 2 controls), typecheck, static and deletion boundary checks, demo:real.
Final verification evidence
Final run instructionsImplemented fixes525 repository testsTypecheckStrengthened probes22 strengthened probes pass19 retained probes passCurrent-version restart testsBoundary checksReal demoContinuing demoHeld-out fixtures
Historical round-5 evidence
Full sidecarReview textRun instructionsHost probesConfig3 failing probes + positive controls19 retained probes pass519 testsTypecheckStatic boundariesReal demoIncremental diff
F85–F100 retain passing reproductions. F101 and F102 are now fixed at 6a89cc9. Original finding bodies and evidence remain below.
Round 5 findings, now fixed
P1 F102. A correction ignores the intent it explicitly names fixedpackages/perception/src/proposals.ts:679-687 · logic · correctness
Verified at 6a89cc9. Frames now associate the live transaction with its intent ID, and context-file decoding preserves that field. Corrections check the pending intent identity and revision against that association and emit expectedIntentId. The kernel checks expectedIntentId before changing bindings. Restart coverage verifies persisted identity, exact-command replay, changed-payload rejection, and one invocation of only the replacement target.
The correction evaluator requires targetIntentRevision but never checks targetIntentId. Command construction at lines 723-726 always targets the frame’s current obligation, so a proposition explicitly naming a different intent can be silently redirected to this transaction. Matching revision numbers do not identify an intent.
Q3 gives a correction a targetIntentId that differs from the pending intent while keeping a valid revision and certified replacement target. The compiler emits revise for the current transaction. The reproduction proves the compiler accepts the wrong destination; it does not claim the built-in graph currently emits that inconsistent proposition.
The original proposal path already treats expected intent identity as meaningful. A correction should either match the intended pending object or fail closed, especially when applications can supply their own proposition builders.
Fix direction. Validate the named intent and revision together against the exact pending intent/obligation association before constructing the revision. If the frame cannot establish the association, reject or clarify rather than defaulting to the current transaction. Carry explicit destination identity through the command boundary as needed.
Evidence. Q3 fails in evidence/round5/host-review.test.ts. Keep Q4 as the valid-retarget control and add matching-intent, mismatched-intent and stale-revision coverage.
Source at finding commitRelevant source
679: if (proposition.operation === "correction") {
680: if (proposition.targetIntentRevision === undefined) {
681: return fail("correction does not name the revision it replaces");
682: }
683: if (!pending) return fail("no pending intent to correct");
684: const capability = pendingIntent?.capability;
685: const offered = capability
686: ? frame.capabilities.find((entry) => entry.capabilityId === capability)
687: : undefined;Prompt for AI Agents
Original findings, preserved with passing reproductions
P1 F85. Excluding every pending target falls through to confirmation fixedpackages/perception/src/interpret.ts:365-388 · logic · correctness
correctionProposition returns undefined for both an unchanged target set and an empty result. The affirmation branch treats either result as permission to fall through to commit. An accepted exclusion can therefore disappear precisely when it excludes everything.
R1 first gates completion of auth rotation, then supplies accepted affirmation and exclusion decisions for "Yes, except auth rotation. Leave that alone." The host emits confirm and the real service completes that excluded task. This fails even with correct model decisions; a better prompt or API key cannot repair the deterministic translation.
Fix direction. Distinguish no adjustment, a valid revision, and an empty or invalid revision. An accepted adjustment must never fall through to confirmation of the original targets; empty selection should cancel or clarify under an explicit policy.
Evidence. R1 in host-review.test.ts asserts both absence of confirm and unchanged service task status.
Source at finding commitRelevant source
365: if (act === "affirm" || act === "reject") {
366: const hasRoles = includes.length > 0 || excludes.length > 0;
367: if (pending && hasRoles) {
368: const correction = correctionProposition({
369: frame,
370: act,
371: base: includes.length > 0 ? includes.map((entry) => entry.ref) : pending.targets,
372: excluded: excludes,
373: pending,
374: decisions: decisionsFor([
375: ...includes.map((entry) => entry.specId),
376: ...excludes.map((entry) => entry.specId),
377: ]),
378: });
379: if (correction) return [correction];
380: }
381: if (!obligation) return [];
382: return [
383: {
384: act,
385: operation: act === "affirm" ? "commit" : "cancel",
386: refs: obligation.targets.map(cloneRef),
387: polarity: "include",
388: decisions: [actTrace],Prompt for AI Agents
P1 F86. An exclusion converts a new capability into the old operation fixedpackages/perception/src/interpret.ts:395-412 · logic · correctness
The request branch treats any excluded reference overlapping the pending intent as a correction. That inference ignores the newly accepted capability. It preserves the old capability while replacing its targets with the new request targets.
R2 gates complete(auth rotation), then accepts request, resume, include(Billing export), and exclude(auth rotation). The graph emits revise of the old complete intent to Billing export. The requested resume never happens, and a later confirmation would complete the wrong task. Exclusion overlap does not establish that the user is correcting the old operation.
Fix direction. Represent correction versus a new operation in accepted semantics. Preserve the selected capability, and clarify if the relationship to the pending intent is unresolved. Do not use a target-set overlap heuristic to replace an accepted operation.
Evidence. R2 checks the accepted resume decision and requires a corresponding proposal, with service state as the outcome.
Source at finding commitRelevant source
395: const pendingHit =
396: pending !== undefined &&
397: excludes.some((entry) =>
398: pending.targets.some((target) => entityRefKey(target) === entityRefKey(entry.ref)),
399: );
400: if (pending && (includes.length > 0 || excludes.length > 0) && (act === "correction" || pendingHit)) {
401: const correction = correctionProposition({
402: frame,
403: act: "request",
404: base: includes.length > 0 ? includes.map((entry) => entry.ref) : pending.targets,
405: excluded: excludes,
406: pending,
407: decisions: decisionsFor([
408: ...includes.map((entry) => entry.specId),
409: ...excludes.map((entry) => entry.specId),
410: ]),
411: });
412: if (correction) return [correction];Prompt for AI Agents
P1 F87. Continuation commands bypass whole-turn safety checks fixedapps/inspector/src/language-plan.ts:110-127 · logic · correctness
planLanguageCommands adds confirm, cancel, and revise commands independently of compileSemanticTurn. Its new verifyPropositionEvidence helper checks citations only. It does not apply the whole-turn structural, exclusion, dependency, frame identity, and evidence checks already centralized for proposals.
R3 supplies a valid confirmation with an accepted sibling exclusion for its target; the planner still emits confirm. R4 supplies a mismatched frame ID; compilation rejects that frame, yet the planner again emits confirm. These exercise the exported planner with caller-supplied semantic turns. The built-in demo need not generate the malformed combination for this entry-point contract to matter. This repeats the earlier alternate-writer safety drift.
Fix direction. Extend one evaluated whole-turn representation to cover all consequence-bearing operations, and make every command come from that result. Do not add another partial validator in the inspector or assume accepted citations imply a valid complete turn.
Evidence. R3 and R4 in host-review.test.ts cover exclusion and frame-identity bypasses. Add matching dependency and malformed-sibling preservation controls.
Source at finding commitRelevant source
110: turn.propositions.forEach((proposition, index) => {
111: const commandId = commandIdFor(proposition, index);
112: const evidence = verifyPropositionEvidence(turn, proposition, {
113: traces: turn.traces,
114: });
115: const reject = (reason: string): void => {
116: rejected.push({ index, reason });
117: };
118: if (proposition.operation === "commit") {
119: const obligation = frame.interaction.liveObligation;
120: if (!evidence.ok) return reject(evidence.reason ?? "unverified evidence");
121: if (!obligation) return reject("no live obligation to confirm");
122: commands.push({
123: kind: "confirm",
124: commandId,
125: transactionId: obligation.transactionId,
126: intentRevision: obligation.revision,
127: });Prompt for AI Agents
P1 F88. A failed file write reports refusal after changing the service fixedapps/task-service/src/service.ts:315-328 · logic · data-integrity
The action handler mutates the task and inserts a SUCCEEDED operation before persist succeeds. The outer catch at lines 380-383 converts every exception, including a storage error, into HTTP 400 bad-request. The adapter treats that response as a confirmed execution failure.
R8 makes the temporary persistence path unwritable by placing a directory there. The service task changes to paused in memory, while the adapter returns ok:false. The idempotency map also claims success before durable commit. The kernel receives a definitive failure even though the live service applied the operation; a restart can then produce another history.
Fix direction. Stage the task and operation together, persist them before publishing the new in-memory state, and distinguish validated request refusals from internal or uncertain outcomes. Define and test the durability boundary; write-and-rename alone does not establish power-loss durability.
Evidence. R8 in boundary-review.test.ts injects a real filesystem write failure and checks the service snapshot alongside the adapter outcome.
Source at finding commitRelevant source
315: task.status = transitionStatus(action, task.status);
316: task.version = before + 1;
317: task.updatedAt = clock();
318: operations.set(operationKey, {
319: key: operationKey,
320: fingerprint,
321: action,
322: taskId: task.id,
323: status: "SUCCEEDED",
324: versionBefore: before,
325: versionAfter: task.version,
326: at: task.updatedAt,
327: });
328: persist();Prompt for AI Agents
P1 F89. Malformed success responses become terminal failure fixedpackages/adapter-http-tasks/src/adapter.ts:380-414 · logic · correctness
The adapter turns an undecodable or unexpected response into EXECUTION_ERROR unless the HTTP status is at least 500. A 200 response with invalid JSON is not evidence that the service refused the mutation. The current fallback nevertheless returns ok:false and makes the kernel mark the effect FAILED.
R7 lets the real service apply a pause, then replaces its successful response with malformed JSON while preserving HTTP 200. The task is paused but the effect is FAILED instead of UNKNOWN. The existing lost-response test covers a thrown fetch, so it misses this equivalent loss of authoritative outcome evidence.
Fix direction. Only recognized, contract-valid refusal responses should become definitive failures. Treat missing or malformed outcome evidence as unknown, preserve the operation receipt, and reconcile without reinvoking. Validate success and reconciliation identity fields as part of the protocol.
Evidence. R7 in host-review.test.ts requires UNKNOWN after the applied action loses a decodable response.
Source at finding commitRelevant source
380: const body = (await response.json().catch(() => undefined)) as unknown;
381: if (response.ok && isRecord(body) && body.ok === true) {
382: return {
383: ok: true,
384: status: "SUCCEEDED",
385: result: isRecord(body.task) ? { task: body.task, replayed: body.replayed === true } : undefined,
386: receipt: {
387: effectId: requestBody.effectId,
388: executor: `${authorityId}-executor`,
389: externalOperationId: requestBody.idempotencyKey,
390: idempotencyKey: requestBody.idempotencyKey,
391: dispatchedAt: clock(),
392: },
393: };
394: }
395: const code = isRecord(body) && typeof body.error === "string" ? body.error : undefined;
396: const failureFor = (): InvokeResult["failure"] => {
397: switch (response.status) {
398: case 404:
399: return { kind: "TARGET_INVALIDATED", detail: `task ${target.id} no longer exists` };
400: case 409:
401: if (code === "version-mismatch") return { kind: "STALE_REFERENCE" };
402: if (code === "invalid-transition") return { kind: "PRECONDITION_FAILED" };
403: return { kind: "EXECUTION_ERROR", detail: code ?? "conflict" };
404: case 400:
405: return { kind: "EXECUTION_ERROR", detail: code ?? "bad request" };
406: default:
407: return { kind: "EXECUTION_ERROR", detail: `task service responded ${response.status}` };
408: }
409: };
410: // A 5xx is not a confirmed refusal: the action may have been applied.
411: if (response.status >= 500) {
412: throw new Error(`task service responded ${response.status} for ${requestBody.capability}`);
413: }
414: return { ok: false, failure: failureFor() };Prompt for AI Agents
P1 F90. Pinned replay skips unfinished clarification writes fixedapps/inspector/src/host.ts:539-566 · logic · data-integrity
The host pins the interpreted turn before dispatch, but writes the clarification event afterward only when !pinned. A crash or append failure between those writes leaves a durable question in the turn record without a corresponding pending obligation in context. Redelivery reuses the turn and permanently skips the missing write.
R5 interrupts recordEvent on obligation-opened, reopens the file host, and redelivers the same observation. The returned turn still contains its question, but the next frame has no pendingQuestion. This loses the interaction exactly at the restart boundary the milestone claims to cover. The same ordering also leaves a gap for interrupted resolution events.
Fix direction. Persist deterministic obligation transitions with the pinned plan, including prior question identity, then idempotently complete those transitions on both first delivery and replay. Do not call the model again to reconstruct the missing transition.
Evidence. R5 in host-review.test.ts injects the append failure after pinning and checks the following frame after restart and redelivery.
Source at finding commitRelevant source
539: if (!pinned) {
540: // Record the obligation this turn leaves open, or close the one it
541: // answered. The event is durable evidence; the frame carries it back
542: // to perception on the next turn.
543: if (question !== undefined) {
544: recordObligationEvent(
545: config.context,
546: "obligation-opened",
547: config.interactionId,
548: input.now,
549: {
550: questionId: `${config.interactionId}:question:${input.observationId}`,
551: awaiting: "disambiguation",
552: question,
553: candidates: frame.candidates.map((candidate) => cloneRef(candidate.ref)),
554: },
555: knownRefs(runtime.state(), input.refs ?? []),
556: );
557: } else if (previousQuestion && (commands.length > 0 || answer !== undefined)) {
558: recordObligationEvent(
559: config.context,
560: "obligation-resolved",
561: config.interactionId,
562: input.now,
563: previousQuestion,
564: knownRefs(runtime.state(), input.refs ?? []),
565: );
566: }Prompt for AI Agents
P1 F91. Shared context imports another interaction’s clarification fixedapps/inspector/src/host.ts:278-295 · logic · correctness
findPendingQuestion looks up events by entity references but never filters evidence.interactionId. Its signature does not even accept the current interaction. Entity overlap is not interaction identity, and the shared semantic store can contain history for more than one interaction.
R9 records another interaction’s open question for a shared task, then runs the current host with that task in context. The current frame receives "Other user secret request" as its pendingQuestion. This mixes discourse and can disclose unrelated interaction content to the model. Per-host file paths in the demo conceal the shared-store case.
Fix direction. Make obligation lookup explicitly interaction-scoped. Apply that scope before bounded paging so unrelated events cannot crowd out the current interaction’s state. Preserve shared entity knowledge without borrowing another interaction’s discourse.
Evidence. R9 in boundary-review.test.ts uses the supported in-memory shared context store and two distinct interaction identities.
Source at finding commitRelevant source
278: export function findPendingQuestion(
279: store: SemanticContextStoreContract,
280: refs: EntityRef[],
281: ): FramePendingQuestion | undefined {
282: if (refs.length === 0) return undefined;
283: const events = store.eventsFor(refs, { limit: 128 });
284: const resolved = new Set<string>();
285: for (const event of events) {
286: const detail = event.detail;
287: const questionId =
288: isRecord(detail) && typeof detail.questionId === "string" ? detail.questionId : undefined;
289: if (!questionId) continue;
290: if (event.kind === "obligation-resolved") {
291: resolved.add(questionId);
292: continue;
293: }
294: if (event.kind !== "obligation-opened" || resolved.has(questionId)) continue;
295: const awaiting =Prompt for AI Agents
P2 F92. An unrelated query silently consumes an open question fixedapps/inspector/src/host.ts:557-565 · logic · correctness
The host resolves previousQuestion whenever the current turn emits any command or an answer. It has no accepted semantic relationship establishing that this turn answered, rejected, or superseded that particular obligation.
R10 opens an ambiguous completion request and then asks a separate status query about Docs refresh. The query is answered, but the following frame has lost the original unresolved clarification. Ordinary conversation cannot safely interleave with a pending question under this rule.
Fix direction. Resolve only an explicitly identified obligation through an accepted answer, rejection, or supersession transition. Preserve pending clarification across unrelated queries and requests; use the same typed transition plan for persistence and replay.
Evidence. R10 in host-review.test.ts verifies the unrelated query does not consume the earlier question.
Source at finding commitRelevant source
557: } else if (previousQuestion && (commands.length > 0 || answer !== undefined)) {
558: recordObligationEvent(
559: config.context,
560: "obligation-resolved",
561: config.interactionId,
562: input.now,
563: previousQuestion,
564: knownRefs(runtime.state(), input.refs ?? []),
565: );Prompt for AI Agents
P2 F93. Relation observations never reach the configured host fixedapps/inspector/src/host.ts:397-404 · logic · correctness
The host reads observeRelations by casting each authority to a shape with an optional method. The HTTP adapter instead returns observeRelations beside authority and executor at adapter.ts:472. The demo and tests pass only adapter.authority, so the method the host probes is absent.
R6 asks about a task with blockedBy data and inspects its actual frame. The task attributes contain the raw blocker IDs, but candidate.relations is empty. The demo’s grounded answer reads the attribute fallback, making the output look correct while the promised relation evidence channel remains disconnected.
Fix direction. Wire relation observation through an explicit typed provider contract or a declared authority extension used consistently at both ends. Test the frame’s relation evidence, source authority and version provenance, not only the rendered answer.
Evidence. R6 in host-review.test.ts requires the blockedBy relation in the actual host-built frame.
Source at finding commitRelevant source
397: const relations = (
398: authority as {
399: observeRelations?: (refs: EntityRef[]) => Promise<RelationObservation[]>;
400: }
401: ).observeRelations;
402: if (typeof relations === "function") {
403: const observations = await relations.call(authority, [ref]);
404: if (observations.length > 0) ingestRelationObservations(config.context, observations);Prompt for AI Agents
P2 F94. Stored continuation commands escape semantic replay validation fixedapps/inspector/src/turn-store.ts:126-134 · logic · data-integrity
The accepted-turn decoder recompiles the stored semantic turn but compares only the propose subset of record.commands. Other command kinds need only a string kind. A confirm, cancel, or revise command can therefore disagree with the stored interpretation and still be accepted for replay.
R11 records a no-op "Thanks" turn while a transaction awaits confirmation, appends a structurally valid confirm command to that turn’s JSONL record, and reopens the host. The decoder accepts the inconsistent record. This is a codec and replay-consistency finding, not a claim that the application must withstand an attacker with arbitrary filesystem control. The existing recompilation guarantee now covers only part of the durable execution plan.
Fix direction. Recompute and compare the complete deterministic command plan from the saved frame and semantic turn, including continuation commands and ordering. Reuse the unified compiler from F87 and reject inconsistent stored commands; cryptographic signatures are unnecessary for this consistency check.
Evidence. R11 in host-review.test.ts expects reopening to reject the injected continuation. The reproduction checks decoder acceptance, not execution of the altered command.
Source at finding commitRelevant source
126: if (record.commands !== undefined) {
127: if (!Array.isArray(record.commands) || record.commands.some((command) =>
128: !command || typeof command !== "object" || typeof (command as { kind?: unknown }).kind !== "string")) {
129: throw new Error("accepted turn commands are malformed");
130: }
131: const propose = record.commands.filter((command) => command.kind === "propose");
132: if (encodeValue(propose) !== encodeValue(expected.commands)) {
133: throw new Error("accepted turn typed commands do not carry the compiled proposals");
134: }Prompt for AI Agents
P1 F95. Confirmation still ignores partial and unverified exclusions fixedpackages/perception/src/proposals.ts:1057-1072 · logic · correctness
The replacement compiler checks only whether subtracting accepted exclusions leaves zero refs. If any ref remains, it emits confirm for the original transaction and revision. A confirm command cannot carry the smaller target set, so this still authorizes the excluded frozen target. The branch also never checks unvalidatedExclusionRefs.
N1 constructs a confirmation for two gated targets with an accepted sibling exclusion for one; the planner returns confirm. N2 uses a sibling exclusion whose decision is not accepted; the planner again returns confirm. These are exported compiler contract tests with supplied semantic turns, not claims that the current built-in graph emits these exact combinations. The original one-target exclusion probe passes, but it covered only the empty-set case.
Fix direction. Compare against the complete frozen obligation target set. If an accepted adjustment changes it, revise and require the new authorization or clarify; never confirm the old revision. Reject confirmation when an unvalidated exclusion affects any frozen target, and verify summary refs agree with what confirmation will actually execute.
Evidence. N1 and N2 in round3/host-review.test.ts. Follow-up to F87; the original exclusion and frame-identity reproductions pass.
Source at finding commitRelevant source
1057: // A sibling exclusion constrains a confirmation exactly as it
1058: // constrains a proposal.
1059: const remaining = proposition.refs.filter(
1060: (ref) => !analysis.excludedRefs.has(entityRefKey(ref)),
1061: );
1062: if (remaining.length === 0) {
1063: rejected.push({ index, reason: "an accepted adjustment leaves no targets to confirm" });
1064: adjustmentWithoutTargets = true;
1065: return;
1066: }
1067: commands.push({
1068: kind: "confirm",
1069: commandId: commandIdFor(proposition, index),
1070: transactionId: obligation.transactionId,
1071: intentRevision: obligation.revision,
1072: });Prompt for AI Agents
P1 F96. Accepted citations still substitute for a valid prerequisite fixedpackages/perception/src/proposals.ts:902-911 · logic · correctness
continuationIssue checks whether a dependsOn predecessor has accepted citations, but never checks whether the predecessor itself passed command evaluation. evaluateTurn already records rejected prerequisites for proposals; the new continuation loop ignores those results.
N3 supplies a structurally valid prerequisite that compileSemanticTurn rejects for lacking an executable capability, then a confirmation depending on it. The whole-turn planner nevertheless emits confirm. A dependency can therefore be rejected by one part of the supposedly shared compiler and accepted by another. This is the same distinction between accepted evidence and a valid executable proposition that earlier reviews required.
Fix direction. Use one ordered validity result for every operation kind. A continuation must depend on a valid predecessor, including its structural, prohibition, evidence and operation checks. Do not infer prerequisite validity from citations or rerun a smaller dependency checker.
Evidence. N3 in round3/host-review.test.ts proves the predecessor is rejected before asserting that its dependent must not be emitted.
Source at finding commitRelevant source
902: for (const relation of proposition.relations ?? []) {
903: if (relation.kind !== "dependsOn") continue;
904: if (relation.targetIndex >= index) return "forward dependencies are not an executable form";
905: const related = turn.propositions[relation.targetIndex];
906: if (!related) return "malformed proposition: relation target is missing";
907: const relatedAccepted =
908: decisionsAccepted(related, acceptedDecisions) &&
909: citationIssue(related, turn, acceptedDecisions, tracesById, tracesAvailable) === undefined;
910: if (!relatedAccepted) return "a dependency proposition was not accepted";
911: }Prompt for AI Agents
P1 F97. Corrections bypass certified frame evidence fixedpackages/perception/src/proposals.ts:1084-1105 · logic · correctness
The correction branch constructs slots and emits revise after citation checks without applying expectedVersionsFromFrame or verifying that every binding ref has frame evidence. The evaluated proposal results above this branch are not used for corrections. Moving the code into proposals.ts has not made the evidence rule shared.
N4 supplies a correction with an accepted citation and a target absent from the certified frame. The planner emits revise for that target. A downstream authority or kernel may reject an unknown entity, but that is not proof that the semantic selection was grounded in this frame. The public compiler should reject this before issuing any command.
Fix direction. Apply shared binding validation and frame coverage to correction slots and argument refs, including exclusion and slot consistency checks. Carry the certified versions through the revision path where required rather than substituting later observations. Keep kernel validation as a second boundary.
Evidence. N4 in round3/host-review.test.ts expects no command for a correction target missing from the frame. This is a compiler-contract reproduction, not a demonstrated execution of a nonexistent service task.
Source at finding commitRelevant source
1084: const declaredSlots =
1085: proposition.slots && proposition.slots.length > 0
1086: ? proposition.slots
1087: : [{ slot: "targets", refs: proposition.refs }];
1088: const slots = declaredSlots
1089: .map((slot) => ({
1090: slot: slot.slot,
1091: refs: slot.refs.filter((ref) => !analysis.excludedRefs.has(entityRefKey(ref))),
1092: }))
1093: .filter((slot) => slot.refs.length > 0);
1094: if (slots.length === 0) {
1095: rejected.push({ index, reason: "an accepted adjustment leaves no targets to correct" });
1096: adjustmentWithoutTargets = true;
1097: return;
1098: }
1099: commands.push({
1100: kind: "revise",
1101: commandId: commandIdFor(proposition, index),
1102: ...(obligation !== undefined ? { transactionId: obligation.transactionId } : {}),
1103: expectedIntentRevision: proposition.targetIntentRevision,
1104: slots,
1105: });Prompt for AI Agents
P2 F98. Unrelated commands still consume a clarification fixedapps/inspector/src/host.ts:559-563 · logic · correctness
The fix preserves pending questions across queries, but still resolves previousQuestion whenever commands.length is nonzero. Emitting a command does not establish that the current turn answers or supersedes the pending question. The new durable transition faithfully persists that incorrect inference.
N5 opens "Complete the failing one", then submits a separate accepted request to pause Docs refresh. The pause succeeds, but the following frame has lost the unresolved completion question. The original query probe passes; the broader obligation lifecycle remains incomplete.
Fix direction. Have the accepted turn explicitly name the obligation it answers, rejects or supersedes. Derive and pin a resolved transition only from that relationship; preserve the question across independent work. Apply the same rule when a command is rejected at runtime.
Evidence. N5 in round3/host-review.test.ts checks a successful unrelated request and then the next frame. Follow-up to F92, whose query-specific reproduction is fixed.
Source at finding commitRelevant source
559: if (previousQuestion) {
560: obligations.push({ kind: "resolved", question: previousQuestion });
561: }
562: } else if (previousQuestion && commands.length > 0) {
563: obligations.push({ kind: "resolved", question: previousQuestion });Prompt for AI Agents
P1 F99. The replacement durable writer can acknowledge corrupt or unsynced state fixedapps/task-service/src/service.ts:280-299 · logic · data-integrity
The new writeDurable calls writeSync once and ignores its returned byte count. A partial write is then fsynced and renamed over the state file, and the service returns success. Its directory-sync catch also suppresses every error, including real I/O failures, while the module claims successful responses are durable against power loss.
N6 injects a legal short write at the filesystem boundary. The action returns HTTP 200 and the persisted file is truncated invalid JSON. N7 injects EIO specifically for directory fsync; the service still returns 200. These are deterministic fault-injection tests, not an assertion that an actual power failure was exercised. Staging in-memory state fixes the earlier pre-write fault but does not make this replacement writer complete.
Fix direction. Write all encoded bytes with a full-write loop or a suitable complete-write API before rename. Handle zero progress and failures explicitly. Do not swallow genuine directory I/O errors; define supported durability semantics and keep post-rename uncertainty from being mistaken for a clean rollback or a durable success. Reuse the repository’s established file persistence patterns where applicable.
Evidence. N6 and N7 in round3/durability-review.test.ts use a real temporary file while injecting partial write and directory EIO behavior. Preserve the earlier failed-write staging control.
Source at finding commitRelevant source
280: const temporary = `${file}.tmp`;
281: const fd = openSync(temporary, "w");
282: try {
283: writeSync(fd, content);
284: fsyncSync(fd);
285: } finally {
286: closeSync(fd);
287: }
288: renameSync(temporary, file);
289: try {
290: const directoryFd = openSync(directory, "r");
291: try {
292: fsyncSync(directoryFd);
293: } finally {
294: closeSync(directoryFd);
295: }
296: } catch {
297: // Directory fsync is not available everywhere; the file fsync above
298: // still establishes the operation boundary for process crashes.
299: }Prompt for AI Agents
P1 F100. The 404 path still accepts an unverified refusal fixedpackages/adapter-http-tasks/src/adapter.ts:423-430 · logic · correctness
The stricter response decoder handles malformed 2xx and most unrecognized errors correctly, but its 404 branch returns TARGET_INVALIDATED without validating the response body. An arbitrary proxy or malformed 404 therefore becomes a definitive failure despite the stated requirement for contract-valid refusals.
N8 lets the real service apply a pause and replaces the reply with plain-text HTTP 404. The service task is paused while the kernel marks its effect FAILED. This is the same uncertain-outcome failure mode as the original malformed-success reproduction, now isolated to the remaining unchecked status branch.
Fix direction. Require the service’s expected refusal payload on 404 as on other statuses. An unreadable, mismatched or unrecognized response must preserve UNKNOWN and the reconciliation receipt. Add controls for genuine task-not-found and malformed/proxy responses.
Evidence. N8 in round3/host-review.test.ts checks both applied service state and the expected UNKNOWN effect. Follow-up to F89; the original malformed-200 probe passes.
Source at finding commitRelevant source
423: // Only a recognized, contract-valid refusal is a confirmed failure.
424: // Any other status or body (5xx, unknown codes, unreadable payload) is
425: // an unconfirmed outcome and must not be reported as a refusal.
426: const code = isRecord(body) && typeof body.error === "string" ? body.error : undefined;
427: if (response.status === 404) {
428: return {
429: ok: false,
430: failure: { kind: "TARGET_INVALIDATED", detail: `task ${target.id} no longer exists` },Prompt for AI Agents
Original baseline walkthrough
Useful integration milestone with reproduced correctness and recovery failures.
Review of implementation and architecture against the original semantic-runtime requirements.
- Reviewed the actual current PR #11 diff and implementation at 364b3ab831f061f3a8dbbf82d3fe07c808bf46c3. Base 1f73383773bb6c0089850f045b2a44e734d4fcdc already includes merged PRs #9 and #10.
- 28 changed files, +3566 −33. Read the changed paths and their compiler, runtime, context-store and replay callers.
- Used a detached worktree for verification. No product files were edited, no PR comments posted, and nothing merged.
- Repository suite: 494 passed. Typecheck, static anti-corruption check and demo:real passed. The deletion check, demo:continuing and eval:heldout were reported by the author but not independently rerun in this pass.
- Independent review suite: 11 expected-behavior failures and 2 passing original integration controls. The 11 failures map to 10 findings; R3 and R4 share F87.
- The external probes executed under Vitest; they were not separately typechecked. No real model call was made.
Authority observations → immutable frame → bounded interpretation → semantic turn proposal → whole-turn compiler → kernel continuation → inspector language planner → kernel [F87: divergent checks] Pinned turn → commands → obligation event [F90: interrupted replay gap] Kernel → HTTP adapter → service state + operation record → file malformed response / failed persistence [F88, F89: false certainty]
Original architecture assessment and scope limits
The direction is right. A service-owned task version, conditional action, idempotent operation key, and reconciliation endpoint are a useful real boundary. The service remains independent of Circe; the adapter translates its protocol. The interpretation graph asks bounded questions over the frame and adds no English clause parser. Keep those choices.
The implementation is not ready to merge. The largest architectural regression is language-plan.ts becoming a second compiler with a smaller safety contract. The correction and continuation paths bypass or discard constraints that the proposal path already enforces. Consolidating these paths will remove complexity and defects together.
Clarification state also needs a firmer owner. Scanning entity-indexed events to infer a pending question makes persistence order, interaction identity, and resolution meaning implicit. A small typed obligation transition in the durable host plan is enough. This does not call for a new orchestration framework or a rewrite of the kernel.
The service and adapter need a precise distinction between confirmed refusal and missing outcome evidence. An HTTP reply is not automatically a confirmed outcome. Stage durable state changes together and preserve UNKNOWN whenever application cannot be established. These are ordinary integration contracts, not semantic-model problems.
The demo is useful integration coverage, but both sides of its HTTP protocol were authored together and its semantic answers are scripted. The 494-test total proves the existing suite passes. It does not establish general language understanding, fault tolerance at all append boundaries, or production readiness. The independent probes deliberately provide correct accepted decisions and still expose implementation failures.
P1 and P2 are only partially covered. The graph selects one capability for all included candidates; it does not represent multiple distinct operations in a compound request. Unsupported mixtures need safe abstention or clarification until that scope is implemented.
Transaction pause/resume in language and non-reference argument filling remain deferred, as the author states. Task.resume is a domain capability and is not transaction resumption.
Queries currently render selected task facts. This is grounded output, but it is a narrow query facility. Durable clarification exists on the successful scripted path, with the lifecycle gaps documented above.
P3 reusable belief publication, P4 deliberation and P7 scale remain open. P6 live semantic evaluation and outcome calibration remain future evidence. Missing TypeSafe credentials are not a blocker for this code review and are not counted as a finding.
The real task adapter is a useful P5 reference integration. This review does not establish independent third-party interoperability or production durability. Retain its narrow service boundary and add adversarial protocol and restart tests before expanding scope.
Original changed files
| ARCHITECTURE.md | +6 −4 |
| README.md | +32 −5 |
| apps/inspector/package.json | +3 −0 |
| apps/inspector/src/host.ts | +216 −15 |
| apps/inspector/src/language-plan.ts | +176 −0 |
| apps/inspector/src/real-cli.ts | +266 −0 |
| apps/inspector/src/real-integration.test.ts | +334 −0 |
| apps/inspector/src/turn-store.ts | +28 −0 |
| apps/task-service/package.json | +23 −0 |
| apps/task-service/src/index.ts | +2 −0 |
| apps/task-service/src/main.ts | +46 −0 |
| apps/task-service/src/seed.ts | +38 −0 |
| apps/task-service/src/service.test.ts | +165 −0 |
| apps/task-service/src/service.ts | +417 −0 |
| apps/task-service/tsconfig.json | +8 −0 |
| docs/SEMANTIC-CONTEXT-MODEL.md | +2 −0 |
| docs/SEMANTIC-PERCEPTION.md | +39 −9 |
| packages/adapter-http-tasks/package.json | +25 −0 |
| packages/adapter-http-tasks/src/adapter.test.ts | +251 −0 |
| packages/adapter-http-tasks/src/adapter.ts | +473 −0 |
| packages/adapter-http-tasks/src/index.ts | +1 −0 |
| packages/adapter-http-tasks/tsconfig.json | +8 −0 |
| packages/context/src/types.ts | +14 −0 |
| packages/perception/src/index.ts | +1 −0 |
| packages/perception/src/interpret.test.ts | +463 −0 |
| packages/perception/src/interpret.ts | +466 −0 |
| packages/perception/src/proposals.ts | +23 −0 |
| pnpm-lock.yaml | +40 −0 |
Copy verified-state handoff · Ctrl+`
Copy re-review · Ctrl+Space
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `packages/perception/src/proposals.ts` around lines 699-717, The ordered evaluator now shares dependency checks and verifies correction evidence, but its correction branch still applies fewer binding checks than proposals. It removes accepted exclusions only. It never rejects a correction target covered by unvalidatedExclusionRefs, and never checks that summary refs agree with executable slot refs. Apply the same binding normalization and safety checks to proposal and revision inputs: unresolved exclusions, summary/slot agreement, declared slot constraints and frame coverage. Reject or clarify the unsafe correction before issuing revise. Preserve certified expectations and the passing retarget control; avoid copying another partial check list into the correction branch. Q1 and Q2 fail in evidence/round5/host-review.test.ts. Q4 passes: an ordinary certified retarget revokes authorization, then confirmation completes only the new target. Follow-up to the binding contract in F97. Keep the passing original controls and avoid another parallel validator. Validate the whole contract around the failing example, not only the exact test input.
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `packages/perception/src/proposals.ts` around lines 679-687, The correction evaluator requires targetIntentRevision but never checks targetIntentId. Command construction at lines 723-726 always targets the frame’s current obligation, so a proposition explicitly naming a different intent can be silently redirected to this transaction. Matching revision numbers do not identify an intent. Validate the named intent and revision together against the exact pending intent/obligation association before constructing the revision. If the frame cannot establish the association, reject or clarify rather than defaulting to the current transaction. Carry explicit destination identity through the command boundary as needed. Q3 fails in evidence/round5/host-review.test.ts. Keep Q4 as the valid-retarget control and add matching-intent, mismatched-intent and stale-revision coverage. Keep the passing original controls and avoid another parallel validator. Validate the whole contract around the failing example, not only the exact test input.
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `packages/perception/src/interpret.ts` around lines 365-388, correctionProposition returns undefined for both an unchanged target set and an empty result. The affirmation branch treats either result as permission to fall through to commit. An accepted exclusion can therefore disappear precisely when it excludes everything. Distinguish no adjustment, a valid revision, and an empty or invalid revision. An accepted adjustment must never fall through to confirmation of the original targets; empty selection should cancel or clarify under an explicit policy. R1 in host-review.test.ts asserts both absence of confirm and unchanged service task status. Keep the kernel as the owner of authorization and effects. Retain the existing passing controls and add the failing reproduction to the appropriate package tests.
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `packages/perception/src/interpret.ts` around lines 395-412, The request branch treats any excluded reference overlapping the pending intent as a correction. That inference ignores the newly accepted capability. It preserves the old capability while replacing its targets with the new request targets. Represent correction versus a new operation in accepted semantics. Preserve the selected capability, and clarify if the relationship to the pending intent is unresolved. Do not use a target-set overlap heuristic to replace an accepted operation. R2 checks the accepted resume decision and requires a corresponding proposal, with service state as the outcome. Keep the kernel as the owner of authorization and effects. Retain the existing passing controls and add the failing reproduction to the appropriate package tests.
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `apps/inspector/src/language-plan.ts` around lines 110-127, planLanguageCommands adds confirm, cancel, and revise commands independently of compileSemanticTurn. Its new verifyPropositionEvidence helper checks citations only. It does not apply the whole-turn structural, exclusion, dependency, frame identity, and evidence checks already centralized for proposals. Extend one evaluated whole-turn representation to cover all consequence-bearing operations, and make every command come from that result. Do not add another partial validator in the inspector or assume accepted citations imply a valid complete turn. R3 and R4 in host-review.test.ts cover exclusion and frame-identity bypasses. Add matching dependency and malformed-sibling preservation controls. Keep the kernel as the owner of authorization and effects. Retain the existing passing controls and add the failing reproduction to the appropriate package tests.
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `apps/task-service/src/service.ts` around lines 315-328, The action handler mutates the task and inserts a SUCCEEDED operation before persist succeeds. The outer catch at lines 380-383 converts every exception, including a storage error, into HTTP 400 bad-request. The adapter treats that response as a confirmed execution failure. Stage the task and operation together, persist them before publishing the new in-memory state, and distinguish validated request refusals from internal or uncertain outcomes. Define and test the durability boundary; write-and-rename alone does not establish power-loss durability. R8 in boundary-review.test.ts injects a real filesystem write failure and checks the service snapshot alongside the adapter outcome. Keep the kernel as the owner of authorization and effects. Retain the existing passing controls and add the failing reproduction to the appropriate package tests.
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `packages/adapter-http-tasks/src/adapter.ts` around lines 380-414, The adapter turns an undecodable or unexpected response into EXECUTION_ERROR unless the HTTP status is at least 500. A 200 response with invalid JSON is not evidence that the service refused the mutation. The current fallback nevertheless returns ok:false and makes the kernel mark the effect FAILED. Only recognized, contract-valid refusal responses should become definitive failures. Treat missing or malformed outcome evidence as unknown, preserve the operation receipt, and reconcile without reinvoking. Validate success and reconciliation identity fields as part of the protocol. R7 in host-review.test.ts requires UNKNOWN after the applied action loses a decodable response. Keep the kernel as the owner of authorization and effects. Retain the existing passing controls and add the failing reproduction to the appropriate package tests.
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `apps/inspector/src/host.ts` around lines 539-566, The host pins the interpreted turn before dispatch, but writes the clarification event afterward only when !pinned. A crash or append failure between those writes leaves a durable question in the turn record without a corresponding pending obligation in context. Redelivery reuses the turn and permanently skips the missing write. Persist deterministic obligation transitions with the pinned plan, including prior question identity, then idempotently complete those transitions on both first delivery and replay. Do not call the model again to reconstruct the missing transition. R5 in host-review.test.ts injects the append failure after pinning and checks the following frame after restart and redelivery. Keep the kernel as the owner of authorization and effects. Retain the existing passing controls and add the failing reproduction to the appropriate package tests.
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `apps/inspector/src/host.ts` around lines 278-295, findPendingQuestion looks up events by entity references but never filters evidence.interactionId. Its signature does not even accept the current interaction. Entity overlap is not interaction identity, and the shared semantic store can contain history for more than one interaction. Make obligation lookup explicitly interaction-scoped. Apply that scope before bounded paging so unrelated events cannot crowd out the current interaction’s state. Preserve shared entity knowledge without borrowing another interaction’s discourse. R9 in boundary-review.test.ts uses the supported in-memory shared context store and two distinct interaction identities. Keep the kernel as the owner of authorization and effects. Retain the existing passing controls and add the failing reproduction to the appropriate package tests.
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `apps/inspector/src/host.ts` around lines 557-565, The host resolves previousQuestion whenever the current turn emits any command or an answer. It has no accepted semantic relationship establishing that this turn answered, rejected, or superseded that particular obligation. Resolve only an explicitly identified obligation through an accepted answer, rejection, or supersession transition. Preserve pending clarification across unrelated queries and requests; use the same typed transition plan for persistence and replay. R10 in host-review.test.ts verifies the unrelated query does not consume the earlier question. Keep the kernel as the owner of authorization and effects. Retain the existing passing controls and add the failing reproduction to the appropriate package tests.
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `apps/inspector/src/host.ts` around lines 397-404, The host reads observeRelations by casting each authority to a shape with an optional method. The HTTP adapter instead returns observeRelations beside authority and executor at adapter.ts:472. The demo and tests pass only adapter.authority, so the method the host probes is absent. Wire relation observation through an explicit typed provider contract or a declared authority extension used consistently at both ends. Test the frame’s relation evidence, source authority and version provenance, not only the rendered answer. R6 in host-review.test.ts requires the blockedBy relation in the actual host-built frame. Keep the kernel as the owner of authorization and effects. Retain the existing passing controls and add the failing reproduction to the appropriate package tests.
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `apps/inspector/src/turn-store.ts` around lines 126-134, The accepted-turn decoder recompiles the stored semantic turn but compares only the propose subset of record.commands. Other command kinds need only a string kind. A confirm, cancel, or revise command can therefore disagree with the stored interpretation and still be accepted for replay. Recompute and compare the complete deterministic command plan from the saved frame and semantic turn, including continuation commands and ordering. Reuse the unified compiler from F87 and reject inconsistent stored commands; cryptographic signatures are unnecessary for this consistency check. R11 in host-review.test.ts expects reopening to reject the injected continuation. The reproduction checks decoder acceptance, not execution of the altered command. Keep the kernel as the owner of authorization and effects. Retain the existing passing controls and add the failing reproduction to the appropriate package tests.
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `packages/perception/src/proposals.ts` around lines 1057-1072, The replacement compiler checks only whether subtracting accepted exclusions leaves zero refs. If any ref remains, it emits confirm for the original transaction and revision. A confirm command cannot carry the smaller target set, so this still authorizes the excluded frozen target. The branch also never checks unvalidatedExclusionRefs. Compare against the complete frozen obligation target set. If an accepted adjustment changes it, revise and require the new authorization or clarify; never confirm the old revision. Reject confirmation when an unvalidated exclusion affects any frozen target, and verify summary refs agree with what confirmation will actually execute. N1 and N2 in round3/host-review.test.ts. Follow-up to F87; the original exclusion and frame-identity reproductions pass. Keep the passing original controls and avoid another parallel validator. Validate the whole contract around the failing example, not only the exact test input.
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `packages/perception/src/proposals.ts` around lines 902-911, continuationIssue checks whether a dependsOn predecessor has accepted citations, but never checks whether the predecessor itself passed command evaluation. evaluateTurn already records rejected prerequisites for proposals; the new continuation loop ignores those results. Use one ordered validity result for every operation kind. A continuation must depend on a valid predecessor, including its structural, prohibition, evidence and operation checks. Do not infer prerequisite validity from citations or rerun a smaller dependency checker. N3 in round3/host-review.test.ts proves the predecessor is rejected before asserting that its dependent must not be emitted. Keep the passing original controls and avoid another parallel validator. Validate the whole contract around the failing example, not only the exact test input.
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `packages/perception/src/proposals.ts` around lines 1084-1105, The correction branch constructs slots and emits revise after citation checks without applying expectedVersionsFromFrame or verifying that every binding ref has frame evidence. The evaluated proposal results above this branch are not used for corrections. Moving the code into proposals.ts has not made the evidence rule shared. Apply shared binding validation and frame coverage to correction slots and argument refs, including exclusion and slot consistency checks. Carry the certified versions through the revision path where required rather than substituting later observations. Keep kernel validation as a second boundary. N4 in round3/host-review.test.ts expects no command for a correction target missing from the frame. This is a compiler-contract reproduction, not a demonstrated execution of a nonexistent service task. Keep the passing original controls and avoid another parallel validator. Validate the whole contract around the failing example, not only the exact test input.
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `apps/inspector/src/host.ts` around lines 559-563, The fix preserves pending questions across queries, but still resolves previousQuestion whenever commands.length is nonzero. Emitting a command does not establish that the current turn answers or supersedes the pending question. The new durable transition faithfully persists that incorrect inference. Have the accepted turn explicitly name the obligation it answers, rejects or supersedes. Derive and pin a resolved transition only from that relationship; preserve the question across independent work. Apply the same rule when a command is rejected at runtime. N5 in round3/host-review.test.ts checks a successful unrelated request and then the next frame. Follow-up to F92, whose query-specific reproduction is fixed. Keep the passing original controls and avoid another parallel validator. Validate the whole contract around the failing example, not only the exact test input.
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `apps/task-service/src/service.ts` around lines 280-299, The new writeDurable calls writeSync once and ignores its returned byte count. A partial write is then fsynced and renamed over the state file, and the service returns success. Its directory-sync catch also suppresses every error, including real I/O failures, while the module claims successful responses are durable against power loss. Write all encoded bytes with a full-write loop or a suitable complete-write API before rename. Handle zero progress and failures explicitly. Do not swallow genuine directory I/O errors; define supported durability semantics and keep post-rename uncertainty from being mistaken for a clean rollback or a durable success. Reuse the repository’s established file persistence patterns where applicable. N6 and N7 in round3/durability-review.test.ts use a real temporary file while injecting partial write and directory EIO behavior. Preserve the earlier failed-write staging control. Keep the passing original controls and avoid another parallel validator. Validate the whole contract around the failing example, not only the exact test input.
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `packages/adapter-http-tasks/src/adapter.ts` around lines 423-430, The stricter response decoder handles malformed 2xx and most unrecognized errors correctly, but its 404 branch returns TARGET_INVALIDATED without validating the response body. An arbitrary proxy or malformed 404 therefore becomes a definitive failure despite the stated requirement for contract-valid refusals. Require the service’s expected refusal payload on 404 as on other statuses. An unreadable, mismatched or unrecognized response must preserve UNKNOWN and the reconciliation receipt. Add controls for genuine task-not-found and malformed/proxy responses. N8 in round3/host-review.test.ts checks both applied service state and the expected UNKNOWN effect. Follow-up to F89; the original malformed-200 probe passes. Keep the passing original controls and avoid another parallel validator. Validate the whole contract around the failing example, not only the exact test input.
PR #11 fixes are verified at 6a89cc944e0b5cb76166401bdcc38aee601d0057. Read the round-6 report and compatibility notes before merging. F85-F102 are fixed; do not reimplement historical findings. Product work still pending includes live evaluation, belief reuse, deliberation, language controls and retrieval scale. Do not merge without explicit authorization.
/abbyview PR #11, incremental review from 6a89cc944e0b5cb76166401bdcc38aee601d0057. Read /home/abstergo/Documents/reviews/Circe-pr11-real-integration-abbyview.json. Preserve prior finding bodies and baseline. Verify shared binding checks, destination identity, persistence and replay with positive controls; append only reproduced findings. No numeric scores.
Copied.
P1 F101. Corrections still skip exclusion and binding-consistency checks fixedpackages/perception/src/proposals.ts:699-717 · logic · correctness
Verified at 6a89cc9. Proposals and corrections now call the same binding normalizer. It rejects unresolved exclusions, contradictory summary refs and invalid slot cardinality, using the pending capability for corrections. Corrections retain certified versions; unsupported correction constraints and entity-ref-valued arguments fail closed. The strengthened Q1/Q2 probes include valid identity, so an identity failure cannot mask these checks.
The ordered evaluator now shares dependency checks and verifies correction evidence, but its correction branch still applies fewer binding checks than proposals. It removes accepted exclusions only. It never rejects a correction target covered by unvalidatedExclusionRefs, and never checks that summary refs agree with executable slot refs.
Q1 supplies a frame-certified correction target and a sibling exclusion whose citation is unaccepted. The planner still emits revise for that target. Q2 supplies summary refs naming one task and a slot naming another; the planner silently revises the slot target. Both are public compiler-contract tests with supplied semantic turns. The current built-in graph’s normal retarget path passes the positive control.
These failures do not mean the ordered evaluator refactor should be undone. They show that common binding validation must also be shared. A valid version token proves which entity snapshot was seen; it does not erase an unresolved exclusion or reconcile contradictory target declarations.
Fix direction. Apply the same binding normalization and safety checks to proposal and revision inputs: unresolved exclusions, summary/slot agreement, declared slot constraints and frame coverage. Reject or clarify the unsafe correction before issuing revise. Preserve certified expectations and the passing retarget control; avoid copying another partial check list into the correction branch.
Evidence. Q1 and Q2 fail in evidence/round5/host-review.test.ts. Q4 passes: an ordinary certified retarget revokes authorization, then confirmation completes only the new target. Follow-up to the binding contract in F97.
Source at finding commitRelevant source
699: const slots = declaredSlots 700: .map((slot) => ({ 701: slot: slot.slot, 702: refs: slot.refs.filter((ref) => !analysis.excludedRefs.has(entityRefKey(ref))), 703: })) 704: .filter((slot) => slot.refs.length > 0); 705: if (slots.length === 0) { 706: return clarify("an accepted adjustment leaves no targets to correct", pending.targets); 707: } 708: const refs = [...slots.flatMap((slot) => slot.refs), ...argumentRefsOf(proposition)]; 709: const evidence = expectedVersionsFromFrame(frame, refs); 710: for (const ref of refs) { 711: if ( 712: !evidence.some( 713: (precondition) => entityRefKey(precondition.ref) === entityRefKey(ref), 714: ) 715: ) { 716: return fail(`no frame observation for ${entityRefKey(ref)}`); 717: }Prompt for AI Agents