# Circe merged implementation audit

Five confirmed defect groups fixed in PR #8; semantic product remains incomplete.

PR: https://github.com/Absterrg0/circe/pull/8

Baseline: a685f92bede7523193c62616e03dd62b3f7b537c
Fix: 1f21302cf7783b5eaa0017c1328b31f750047e6b

The architecture is credible for a contract-focused runtime. Core owns authorization, intent revisions, effects and recovery. Context owns observations, materialized frames and evidence dependencies. Perception produces accepted decisions and propositions; the compiler routes both public entry points through the same evaluation. The injected Jev adapter stays outside the mutation kernel. These boundaries solve real ownership problems and should be kept.

The implementation is becoming difficult to reason about inside those boundaries. runtime.ts is 2,723 lines, core/types.ts is 1,231, and the accepted-turn compiler is 883. Repeated fixes have concentrated around shared state, completion ordering, evidence ownership and alternate entry points. Those are concrete maintenance risks. A line-count-driven rewrite would not improve correctness by itself; future changes should make transaction/effect transitions and their durable records easier to inspect together.

The new fixes use existing contracts and add no runtime dependencies, queues, database layers or orchestration framework. The optional completion identity is the only journal shape addition. Whole-frame invalidation costs more recomputation than subject-only invalidation, but correctly represents what the model read. Narrowing it later requires recorded selective dependencies, not an assumption that the subject tuple is the entire input.

I would continue from this implementation after the fixes are reviewed. I would not treat passing regression suites as proof that Circe already delivers its semantic product thesis. The next useful work is one real continuing interaction with restart and held-out language evaluation, rather than more abstractions around the scripted A/B demo.

## F72 — Complete a command atomically with its recovered discourse state (fixed)

On merged main, finalize wrote command-applied before discourse-snapshot. Recovery treated the command as complete even when a crash left only the previous discourse snapshot. This is a completion-order defect, not an executor retry issue.

The retained test selects A and then selects B or clears the selection. It restarts after every journal prefix and redelivers the second input. At the old applied-marker cut, recovery keeps A and suppresses the second input. Merely reversing two writes creates another gap: a new selection could be applied twice if its snapshot survived but its completion marker did not.

The fix records the reservation key inside the discourse snapshot, so recovery sees the state and its completion together. The legacy command-applied record follows for format compatibility, and the in-memory result cache is populated afterward. Existing older journals still load; the change cannot recover state that an older writer never persisted.

Validation: postmerge-kernel.test.ts: both select and clear-selection across every crash prefix; file-journal-durability.test.ts: completion identity round trip and invalid identity rejection.

## F73 — Invalidate beliefs when another candidate in their evidence frame changes (fixed)

Annotations were linked to the current generations of their subject refs, although a semantic judgment had received an entire recorded frame. A belief about A could depend on comparing A with B while naming only A as its subject. Updating B left that belief current.

The same hole existed when an asynchronous result arrived after B had already changed: the freshness check only compared the annotation subjects. The retained regressions exercise both publication orders, with controls for a ref outside the frame and an annotation subject absent from the frame.

The fix links every candidate generation captured by the recorded frame and checks the whole candidate read set at publication. Subject membership checks remain intact. This is intentionally conservative: until selective semantic dependencies exist, a frame-based judgment may require recomputation when any candidate it saw changes.

Validation: postmerge-context.test.ts: changed peer invalidation, late arrival, unrelated-ref control, and outside-frame subject rejection.

## F74 — Decode backend values once and require actual probability evidence (fixed)

The shared decoder claimed to read untrusted output once, but read status and answer identities multiple times. A changing status getter could be AMBIGUOUS during validation and RESOLVED in the returned result. Earlier independent PR #5 probes exposed this inherited limitation; the whole-product pass closes it.

Throwing accessors also escaped the public analysis API. Score-array entries were inspected and then copied through a second read. Probability copying mishandled __proto__ option IDs, and a missing chosen probability could be mistaken for an inherited object property. These are boundary defects even though ordinary JSON responses rarely exercise changing getters.

The fix snapshots each value before checking it, contains unreadable responses as structured failures, preserves own probability entries, and checks chosen-option ownership explicitly. The workflow regression verifies that an ambiguous response cannot enter accepted state. This adds no alternate decoder or vendor-specific path.

Validation: postmerge-perception.test.ts: six decoder cases; previous external Jev probes N2 and N3 now pass.

## F75 — Return the same immutable frame contract that the store records (fixed)

Assembly persisted an immutable frame copy but returned a mutable frame to its caller. A caller could change candidate attributes or coverage while retaining the original frame ID and hash. The returned object would then disagree with the stored evidence.

Assembly now returns a detached, deeply frozen snapshot. The regression checks nested candidate attributes and equality with the stored frame. One existing adversarial Jev test intentionally modifies a fixture; it now makes a detached copy first. Consumers that construct alternate frames must likewise construct a new value rather than mutate an assembled one.

Validation: postmerge-context.test.ts: nested returned frame immutability and stored evidence consistency.

## F76 — Do not expose the in-memory journal’s backing records (fixed)

The in-memory journal cloned appended entries but returned its backing array from entries(). TypeScript readonly protected only the type surface: JavaScript callers or nested object mutations could rewrite accepted history.

The regression mutates an input ID through the returned history and appends another entry. Both changes previously affected the journal itself. Returning a structured clone preserves the reference journal’s ownership boundary and keeps recovery dependent on recorded history.

Validation: postmerge-kernel.test.ts: returned array and nested entry mutations do not rewrite journal history.

## Remaining product work

Semantic durability: Kernel interactions have a file journal. The semantic store is still an in-memory implementation: observations, relations, frames, decision traces and beliefs do not survive a host restart through that store. A persistent semantic-store adapter remains product work.

Continuing interaction: runInteractionPipeline creates a fresh context store and starts frame assembly with empty recentReferents on every call. It is useful integration scaffolding, not a continuing conversation host with durable semantic history.

Real interpretation: The inspector uses scripted responses for a fixed scenario. The Jev adapter accepts an injected client; a live SDK/transport host, representative held-out evaluation and outcome-calibrated policy thresholds are still absent.

Operational scope: The file journal is suitable for its current single-process contract. Multi-process coordination and compaction remain deferred. No load benchmark, live-model accuracy study or formal verification was performed in this pass.

411 repository tests, 147 external checks, typecheck, boundary checks, inspector CLI and diff check pass. New eval regressions: 12 failed and two passed on baseline; all 14 pass after fixes. One additional disk-format regression also passes.
