Skip to content

🐛 Explain joined REPL entry failures in Journal reads - #1104

Merged
taras merged 4 commits into
mainfrom
codex/unfinished-entry-1059
Nov 4, 2026
Merged

taras merged 4 commits into
mainfrom
codex/unfinished-entry-1059

Conversation

@taras

@taras taras commented Nov 4, 2026 •

Copy link
Copy Markdown
Owner

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 show status: "unfinished", failure: null, and a failed execution observation together. Work or cleanup still running has joined: 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

Original caught failure
  -> Execution.disclose middleware replacement/transformation
  -> original execution's protected-input projection and scanner
  -> detached safe diagnostic
Exact task and cleanup join -> selected entry's execution observation
Journal read -> complete data -> yq -> existing pagination

The owned HostExecution.disclose entry point selects the exact execution and dispatches the existing contextual Execution API. 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 in packages/core/src/execute.ts, and the real consumer in packages/cli/src/repl/session.ts. The two existing Journal readers still share sidekick/entry-inspection.ts and sidekick/requests.ts.

The focused witnesses are packages/core/tests/protected-input.test.ts and packages/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

  • Repository selection survives lexical directory changes; actual Git admission refusals remain intact.
  • Joined completion follows the exact task and owned cleanup; idle status or a terminal alone is insufficient.
  • Reads create no terminal, admission, prompt or repeated effect.
  • Explicitly protected values are projected even with heuristic scanning disabled.
  • Contextual results alone establish no security authority or completed disclosure.
  • Both Journal consumers query complete data before pagination and return exactly {value,next,prev,last}.

How to verify it

Signed current head 5d1fde4853913117dda439a1d8aeca6e2ad848fc is a clean child of fe17c0e4, which integrates published Main c128b655. 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.

  • The focused Deno selection (repl-unfinished-entry, repl-execution, repl-boundaries) passed 76 steps.
  • The same Node selection passed 76 tests with no skips, using an initially empty private Deno cache and forced terminal colors. Its real delegated child completed in 8,392 ms.
  • Node project typecheck and bounded cached/manual Deno typing passed.
  • Portable Bun files passed 66 tests. The local unfinished-entry import limitation remains; CI owns supported Bun 1.4.0 qualification.
  • The unchanged parent’s protected-input file passed 21 steps and headless-submit file passed 28 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 at fe17c0e4; 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

ReplEntryExecution carries detached host knowledge for existing readers. The added contextual Execution.disclose member and owned HostExecution.disclose entry point reuse the existing private disclosure owner. They grant no execution or recovery permission.

Risks and limitations

  • After host loss, an unrecorded joined outcome remains unknown.
  • An unfinished segment still refuses a successor. Reopening may execute unrecorded work and is not passive inspection.
  • Clearance before readiness or after policy revocation refuses; the caller uses fixed withholding.
  • Local Bun 1.3.14 cannot load the new CLI fixture’s node:sqlite graph. That first limitation is preserved; supported Bun 1.4.0 qualification belongs to required CI.
  • New/changed tests require fresh runner weights; no local weights or hand-edited milliseconds are used.

Scope confirmation

  • Every feature change supports the accepted diagnostic and privacy behavior.
  • Unrelated optional review polish is excluded.
  • The published Main integration is identified separately from the feature correction.
  • The description distinguishes passed focused evidence from pending delivery gates.

Closes #1059.

@github-actions

github-actions Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

PR #1104: 🐛 Explain joined REPL entry failures in Journal reads

12 files, +1368 / -39

Scope

🔴 PR has 1407 lines changed. Split into focused PRs.

🟡 1407 lines changed. PRs under 400 receive more thorough review.

Structural

Oxlint structural signals:

  • no-unused-vars ×9: packages/cli/src/repl/session.ts, packages/core/src/execute.ts
  • no-unnecessary-type-assertion ×5: packages/core/src/execute.ts
  • no-unnecessary-type-arguments ×3: packages/cli/src/repl/expansion.ts, packages/cli/src/repl/session.ts
  • no-empty-function ×2: packages/cli/src/repl/expansion.ts, packages/core/src/execute.ts

Slop

✅ Slop indicators look low.

Static Analysis

Oxlint: 70 diagnostics across 5 files (14 rules)
Density: 0.051 violations/added-line

no-shadow (23): packages/cli/src/repl/sidekick/requests.ts, packages/cli/src/repl/session.ts, packages/core/src/execute.ts
no-unused-vars (9): packages/cli/src/repl/session.ts, packages/core/src/execute.ts
unbound-method (9): packages/cli/src/repl/sidekick/requests.ts, packages/cli/src/repl/session.ts, packages/core/src/execute.ts
no-floating-promises (5): packages/cli/src/repl/session.ts
no-unsafe-type-assertion (5): packages/core/src/execute.ts
no-unnecessary-type-assertion (5): packages/core/src/execute.ts
no-unnecessary-type-arguments (3): packages/cli/src/repl/expansion.ts, packages/cli/src/repl/session.ts
consistent-function-scoping (2): packages/cli/src/repl/expansion.ts, packages/core/src/execute.ts
no-empty-function (2): packages/cli/src/repl/expansion.ts, packages/core/src/execute.ts
consistent-return (2): packages/core/src/execute.ts
no-duplicate-type-constituents (2): packages/core/src/execute.ts
no-empty-pattern (1): packages/cli/src/repl/expansion.ts
no-array-sort (1): packages/core/src/execute.ts
no-misused-spread (1): packages/cli/src/repl/sidekick/entry-inspection.ts

Correctness

No extraneous code patterns detected.

@taras taras left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

  1. 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.

  2. 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.

  3. 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.

@taras
taras marked this pull request as ready for review November 4, 2026 14:10
@taras
taras merged commit 97d7b44 into main Nov 4, 2026
58 checks passed
@taras
taras deleted the codex/unfinished-entry-1059 branch November 4, 2026 16:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Resolve unfinished headless REPL entries when the host reports idle

1 participant