fix(kernel,router): rehydrate by CAS content hash (F-021) + narration budget

rehydrate() now scans ArtifactContentStoredEvent (the durable slot->CAS-hash
bridge) and fetches stored bytes by content hash, keying the cache by the
logical slot name. The slot name is never passed to the hash-keyed CAS, so the
odd-length-hex crash is gone and artifact content is restored on cold-start
resume. RehydrateTest reworked to use a content-addressed fake store (slot name
!= content hash) so it actually exercises the bug. Replay (#8) is unaffected —
rehydrate is live-resume-only.

Also bump router narration maxTokens 1024 -> 4096: reasoning models were
spending the whole budget thinking and emitting empty content (finishReason=
length), so narrations never reached the TUI.

Removes the stale TUI-refactor progress doc.
This commit is contained in:
2026-06-09 10:14:04 +04:00
parent b407b47503
commit 89487db72a
5 changed files with 42 additions and 156 deletions
+9 -5
View File
@@ -52,7 +52,8 @@ Patches applied this session (rebuild + restart server to load):
- F-020: `FileEditTool` — model-correctable failures (bad patch, target-not-found, bad params,
unknown op) now `recoverable=true` (feed back, don't abort); tool/`operation` descriptions +
implementer prompt steer toward `replace`/`file_write` over the fragile `patch` op.
- F-021: OPEN (not patched) — resume `rehydrate()` slot-name-vs-CAS-hash bug; see finding.
- F-021: FIXED — resume `rehydrate()` now consumes `ArtifactContentStoredEvent` (slot→hash)
and fetches CAS bytes by content hash instead of passing the slot name to the hash-keyed store.
**Key reproducibility note:** the live config the server reads is `~/.config/correx/`
(`configDir = ConfigLoader.configPath().parent`), NOT the repo. Code fixes load via repo
@@ -426,10 +427,13 @@ repo `docs/schemas/` were stale relative to live — a clean-checkout reproducti
- **fix direction:** rehydrate from `ArtifactContentStoredEvent` — `artifactStore.get(contentHash)`
then `artifactContentCache["sessionId:slot"] = content`. The F-007/F-015 events already record
the needed slot→hash mapping; this just consumes it on cold start.
- **status:** OPEN (found by code inspection while answering "is resume actually implemented?").
Replay (`ReplayOrchestrator` + `testing/replay/` suite) is implemented and unit-tested; resume's
wiring exists (`POST /sessions/{id}/resume`, `resume()`, `rehydrate()`) but this bug means it
almost certainly does not restore content correctly — needs a live #1/#8 probe to confirm.
- **status:** FIXED — `rehydrate` now scans `ArtifactContentStoredEvent` (the durable slot→CAS-hash
bridge added in F-007) and calls `artifactStore.get(p.contentHash)`, keying the cache by the
logical slot name (`p.artifactId`). The slot name is never passed to the hash-keyed CAS, so the
odd-length-hex crash is gone and content is restored on cold start. `RehydrateTest` reworked to
use a content-addressed fake store (slot name ≠ content hash) so it actually exercises the bug;
both cases green. Replay (#8) unaffected — rehydrate is live-resume-only. Still wants a live
#1/#8 resume probe to confirm end-to-end restoration.
### Steering (functional contract) — partially exercised live
- During the live operator sessions, approval-with-steering was informally validated: the operator