Repository navigation
🐛 Explain joined REPL entry failures in Journal reads - #1104
Conversation
PR #1104: 🐛 Explain joined REPL entry failures in Journal reads12 files, +1368 / -39 Scope🔴 PR has 1407 lines changed. Split into focused PRs. 🟡 1407 lines changed. PRs under 400 receive more thorough review. StructuralOxlint structural signals:
Slop✅ Slop indicators look low. Static AnalysisOxlint: 70 diagnostics across 5 files (14 rules) no-shadow (23): packages/cli/src/repl/sidekick/requests.ts, packages/cli/src/repl/session.ts, packages/core/src/execute.ts CorrectnessNo extraneous code patterns detected. |
taras
left a comment
There was a problem hiding this comment.
Independent implementation review by Claude Fable 5.1 at f4c7ea04a4b2bcf27c4df4b39e789bd87069403f.
Verdict: PASS — no blocking findings.
Reviewed the full #1059 diff and real Journal, task/cleanup, Stop and disclosure consumers at f4c7ea0. The diagnostic stays session-owned, preserves retained history and original errors, distinguishes active cleanup from joined work, and is unknown after host loss. Existing focused evidence supports the five acceptance clauses. No blocking defect found; three nonblocking observations remain below.
The coordinator shortened the summary; the reviewer’s verdict, acceptance coverage and all findings are preserved.
Nonblocking observations:
-
packages/cli/src/repl/session.ts ~L1791-1800: the observer computes failure from started.output() (the raw finalOutput) plus started.stopped only for the interrupted test, whereas direct submit (server.ts settlement) reads exact.output(), i.e. submissionOf().output(), which returns a failed Stop settlement before the output. A Stop that answers Err while the entry outcome and output are both Ok would therefore be reported completed here and failed by direct submit. Per core execute.ts stop() contract a failed append/cleanup is also the execution's completion, and the remaining stopEntry Err branches (slot replaced, projection failure, Ok canonical with no terminal) are not reachable while the slot is held, so the divergence is currently unreachable; reusing submissionOf(started).output() would make the claimed 'same precedence' structural rather than incidental.
-
packages/cli/src/repl/session.ts ~L1786: the observation task is unobserved (owner.run without a result consumer). Everything that can suspend or throw is inside try/catch, and executions.set/Object.freeze/changes.send are effectively non-throwing, so no defect follows; noting only that an exception escaping there would surface through the session owner rather than through any caller, matching the existing stopEntry pattern.
-
packages/cli/src/repl/sidekick/entry-inspection.ts L50 imports ReplEntryExecution (type-only) from ../session.ts, creating a sidekick->session type dependency that did not exist before. Harmless at runtime; defining the detached shape beside InspectedHistory and having session.ts conform to it would keep the inspection module independent of the session owner.
Covered acceptance: controlled-reproduction, repository-authority, joined-lifecycle-disposition, active-negative-no-duplicates, focused-regressions-and-docs.
Required CI and the test setup correction remain pending. This review is anchored to the commit above.
Why
A headless entry can join with a fatal repository-admission refusal while its journal honestly remains unfinished. A later reader needs the known execution outcome beside that retained history. The diagnostic must also protect values entered through Main’s protected-input support.
What changes
Both Journal readers include
execution: {joined, outcome, error}beside the existing fields. A joined fatal refusal can showstatus: "unfinished",failure: null, and a failed execution observation together. Work or cleanup still running hasjoined: false; absent host knowledge has null fields.Useful error details pass through the original execution’s complete disclosure policy. A protected entered value receives its existing replacement before scanning. Unavailable or refused clearance produces the specified withholding object.
How it works
The owned
HostExecution.discloseentry point selects the exact execution and dispatches the existing contextualExecutionAPI. Middleware may replace the candidate without delegating or transform the returned Result. The final candidate then crosses the original private policy. Policy readiness and revocation remain with that owner. Retaining the handle extends no owner lifetime.The CLI associates the cleared copy with the actual caught failure while the entry is live, then releases the temporary association. Canonical errors, failure precedence and retained terminals keep their meaning.
Review guide
Inspect the complete-policy holder in
packages/core/src/computed-bindings.ts, the contextual/owned assembly inpackages/core/src/execute.ts, and the real consumer inpackages/cli/src/repl/session.ts. The two existing Journal readers still sharesidekick/entry-inspection.tsandsidekick/requests.ts.The focused witnesses are
packages/core/tests/protected-input.test.tsandpackages/cli/tests/repl-unfinished-entry.test.ts. Check contextual replacement and outer transformation, final clearance ordering, readiness/revocation, detached data and original error identity.What must stay true
{value,next,prev,last}.How to verify it
Signed current head
5d1fde4853913117dda439a1d8aeca6e2ad848fcis a clean child offe17c0e4, which integrates published Mainc128b655. Its two changed files are the explicit API inventory and unfinished-entry fixture. Core and CLI session implementation are byte-identical to the Architect-reviewed parent.repl-unfinished-entry,repl-execution,repl-boundaries) passed 76 steps.The single Deno repository test runs the genuine canonical subdirectory completion control and the complete fatal-refusal witness in separate fresh scopes. Node/Bun delegate that one test; nine diagnostic cases remain native. The child has a separate 240-second startup/graph/test budget, exact normalized one-test/one-step success checks, preserved channel output and joined resource teardown.
Claude Fable 5.1’s full implementation review returned PASS at
f4c7ea04, with three nonblocking observations retained. The original Architect passed the later contextual disclosure boundary atfe17c0e4; its implementation is unchanged in the current head. Affected Planner feedback is in progress. The later Main/privacy interaction still needs independent affected closeout.CI 2427, attempt 1 failed at the parent; its complete first evidence is retained. The current commit corrects the inventory omission, canonical fixture placement, colored summary assertion and delegated startup budget.
Delivery pending: CI 2428, attempt 1 on exact
5d1fde48, affected Planner feedback, independent affected closeout, and a complete official runner-weight measurement/assembly. The qualified weight bytes must be committed and required CI must pass on the resulting exact head. This PR is not merge-ready.Scope
Included: session-owned joined diagnostics, the two existing Journal consumers, the necessary original-execution disclosure capability, focused regression evidence and affected documentation.
The original incident is preserved. No recovery command, durable diagnostic record, dependency, task, workflow or installed-runtime change is introduced. The protected-input integration uses exact published Main.
New abstractions
ReplEntryExecutioncarries detached host knowledge for existing readers. The added contextualExecution.disclosemember and ownedHostExecution.discloseentry point reuse the existing private disclosure owner. They grant no execution or recovery permission.Risks and limitations
node:sqlitegraph. That first limitation is preserved; supported Bun 1.4.0 qualification belongs to required CI.Scope confirmation
Closes #1059.