Skip to content

✨ Reuse root JSON across REPL entries and cold reopen (#939) - #943

Merged
taras merged 7 commits into
mainfrom
agent/repl-root-bindings-939-20261017
Oct 18, 2026
Merged

taras merged 7 commits into
mainfrom
agent/repl-root-bindings-939-20261017

Conversation

@taras

@taras taras commented Oct 17, 2026 •

Copy link
Copy Markdown
Owner

Why

Root <Let> and ordinary component captures now reach the next REPL entry, explicit Bindings reads and a cold reopen. Reusing a captured value, such as a Git commit ID, does not repeat completed effects.

Closes #939.

What changes

Entry 1:

<Let as="saved" value={{ answer: 42 }} />

After it settles, <REPL.Bindings /> includes saved: { answer: 42 }, and Entry 2 renders Answer: 42 from Answer: {saved.answer}, including after reopening the journal.

The retained value is the eligible root data when the entry finishes. Each entry receives isolated copies of inherited objects: mutations made before its ordinary result is retained carry forward without re-exporting the name. Earlier entries and historical readings remain unchanged.

How it works

Canonical execution carries computed root JSON on its ordinary document result, without individual binding journal publications or publication modes. Rendered output, typed return values and computed bindings remain distinct. Both ordinary success and authored failure retain their computed data; cold reconstruction reads recorded outcomes without repeating completed work. A valid core <Fail> preserves its authored Error and ordinary recovery; unrelated undescribed errors continue to escape. Each root Close has one selectable checkpoint while its binding rows and data remain available.

Explicit Bindings reads combine retained data with the running entry's safe live root. Historical panes remain limited to their selected prefix. Each host-handle read returns an independent detached map. An Effection resource is acquired before owned work; its own finalizer releases live root/policy references. Halt or fatal completion without an accepted result refuses later reads, while accepted JSON remains readable for the handle's promised lifetime without retaining live resources or rescanning replayed data.

Risks and limitations

  • Functions, live handles and other non-JSON values remain local and are omitted from retained root data. Omission does not delete an earlier ordinary retained fact.
  • A halted run remains unfinished and permits no successor. A recorded cancelled Close adds no computed map, but preserves preceding retained facts such as eval exports.
  • Older ordinary histories expose only their recorded facts. Prototype publication-format histories keep the accepted preserved-runtime route at 7490f014; the fixed 939 runtime remains there for active sessions.

How to verify it

All seven focused groups pass with zero failures:

Group Passed suites / steps
Core Let and owned handles 6 / 24
REPL entries 30 / 86
Sidekick controls 8 / 47
Repository journeys 2 / 11
Guarded journal and secret detection 4 / 52
Output errors, component returns and eval bindings 15 / 169
Execution initialization and protocol 3 / 74

All seven groups ran on the published repair tree b3a65dbc1392d1c7459e6bbbf423ecfbf56a046a. They cover actual capture/successor handoff, cold and unfinished replay without repeated Git effects, joined-halt refusal, returned-map mutation isolation, cancellation facts and secret/append enforcement. The affected Fail/recovery, escaping-error and REPL model/drawer journeys also pass (9/53, 6/67 and 74/179 suites/steps); deno task lint and deno task check exit 0.

Both original reviewers explicitly covered the resource lifetime/detachment requirement and this narrow CI repair on the published head. These are agent verdicts, not GitHub account approvals:

  • Original Architect: PASS, exact 0217795b5cc38c7be6c20e755c28f3850232385e.
  • Original Planner: PASS, exact 0217795b5cc38c7be6c20e755c28f3850232385e.

The complete reviews and focused logs remain in the central #939 delivery records.

CI run 39135245943, attempt 1 completed successfully on exact 0217795b5cc38c7be6c20e755c28f3850232385e: 41 jobs succeeded, and only composability was correctly skipped for this ordinary pull request. Required aggregate green succeeded at 14:26:17 UTC on 2026-10-18.

Stack and dependency scope

#939 -> #940 -> #934 -> #942 -> #932

The healthy, approved corrected parent 0217795b5cc38c7be6c20e755c28f3850232385e is published on this PR and available for future authorized safe integration. All downstream tracks (#940, #934, #942 and #932) remain PARKED. Each delivery still needs its own corrected-parent integration, affected evidence, both original reviewers inspecting one identical final integrated head, and its own Planner title/body APPLY/VERIFY. Earlier-parent reviews do not cover that integrated head. Lexical visibility (#110) and REPL.Entry.{Source,Prompt,Output,Journal} (#932) retain their separate scope.

taras and others added 3 commits October 17, 2026 11:35
A root `<Let>` and an ordinary component capture bound into the environment
they were written in and recorded nothing, so the entry after them could not
read the value: `<Let as="saved" value="alpha" />` in one entry left `{saved}`
undefined in the next, and a cold reopen found nothing either. Only an `eval`
block's exports crossed, because evaluating one is a durable effect and a
capture was not.

Retention is now a second trusted-host input beside the initial bindings,
`rootBindingPublications: "json-v1"`, which the REPL states for each entry it
admits. Core builds the publisher beside the canonical root binding
environment and hands it to expansion as an argument, so what may publish is a
capture whose actual assignment target is that exact object — a component
body, an `<Each>` iteration, a `<Spawn>` and a generated fragment each write a
different environment and none of them acquires root ownership from the file
it was written in. Each successful root capture is one ordinary durable record
whose value is a detached snapshot taken through the one strict JSON parser
the initial bindings are copied through; the binding itself stays the exact
value the producer made, so reference identity, resource lifetime and later
mutation are unchanged and none of them reaches the record.

Values outside that JSON domain stay in the entry that made them. They bind
and remain usable, publish no replacement — so a name keeps the last value
anything did publish under it — and produce one value-free outcome, which
removes nothing and warns about nothing. One record per successful capture
whichever outcome it is, so a partial continuation replays the positions it
recorded.

The mode travels on the root import's own description, and root-history
admission compares it against the invoking execution's before a terminal is
reused, before public replay policy and before authored work. An absent field
is a history written before this existed: it agrees with an execution that
publishes nothing, which is what lets an unfinished entry from such a file
continue in its own mode through its own close with its completed effects
restored rather than repeated. Cold projection applies the same rule
independently. Ordinary `execute()` states nothing and keeps the exact LET11
inventory it had.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Review of 3fc3f29 found that core consumed a retained publication without
parsing it. `publish()` discarded what `retain()` handed back, and `retain()`
returned the durable operation's stored value unread — so on a continuation a
record this version cannot read was accepted as history: the live operand was
bound over it, the suffix no record describes ran, and a completion was
appended on top. The CLI projector parses the same bytes and refuses them,
which is exactly why its parser cannot be the only enforcement: the trusted
host reaches `executeInstalled()` directly.

`publish()` now reads back what the journal holds and parses it before the
caller binds and before any later work. Live, the record parsed is the one just
written and the check is free; on a continuation it is the retained record, and
an unreadable one raises `StaleInputError` — the same classification a stale
loop terminal raises, so it escapes as the run's own durability failure rather
than becoming a document error that a printing boundary could absorb.

One record contract serves both readers. `parseRootBindingRecord()` holds the
version, the binding name, its agreement with the effect name replayed under,
and the closed outcome; the event reader applies it after its own event checks.
Two readings of one persisted shape would be two contracts, and the day they
disagreed is the day a history one of them refused continued through the other.

A recognized retained outcome stays authoritative: parsing reads it and never
refreshes it from today's operand, so an entry whose eligibility changed on
reconstruction still replays the positions it recorded. Ordinary execution,
legacy old-mode continuation and entry-local non-JSON behavior are unchanged.

The review also named four frozen assertions the evidence had not supplied, and
each is completed in the row that already owned it rather than in a new one:

- P3 now writes an ordinary component capture inside the `<Each>` iteration,
  inside two spawned branches and inside an admitted generated fragment. Each
  runs — five retained symbol reads and the fragment's own admission prove it —
  and none publishes, reaches the root binding map or reaches the successor.
- P9 gains the malformed-version representative on the core continuation path,
  a record whose binding disagrees with the effect name it replayed under, and
  the incompatible-retention comparison at core's own owned admission in both
  directions over a history that holds its terminal, each with a sound control.
- P2 mutates a member one level down rather than a scalar, so the retained
  value's detachment is pinned at that depth in the entry's own binding, in the
  next entry and at the position that retained the first publication.
- G2 opens the completed-prefix execution it then asserts is unchanged, so an
  append to the history being inspected would be caught rather than hidden
  behind an untouched copy.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…al (#939)

Review of ceebc74 found F1 closed for an unfinished prefix and still open for
terminal reuse. Parsing the retained record where a capture publishes only
protects a history expansion walks: a history standing behind a recorded
completion reuses that terminal without expanding anything, so the publisher is
never entered. An unreadable publication with its own Close was therefore
accepted as history and its recorded success returned as authoritative — bytes
the CLI projector refuses.

`admitRootHistory()` now collects every retained publication in the walk it
already makes and holds each one to the shared record parser, beside the
retained-mode comparison it already performed. That is inside `readAll`, where
every other root-history admission lives, so the refusal is ahead of terminal
reuse, public replay policy, authored work and any append. It raises
`StaleInputError` with the same diagnostic the publish path raises, so which
boundary discovered the unreadable record does not change what the run reports
or how the failure is classified.

One parser, two boundaries. A record the projector refuses is not a record core
continues through, whether the continuation runs the body or reuses a terminal.

A history holding no publication is unaffected, which is every ordinary run and
every entry admitted before this existed. Recognized retained outcomes stay
authoritative and are not refreshed from today's operand; live assignment still
binds the original operand by reference; ordinary execution, accepted
entry-local behavior and legacy old-mode continuation are unchanged.

The existing P9 version-2 representative now covers both boundaries: the
unfinished prefix refuses as before, the same record with its retained Close
refuses rather than reusing recorded success, and the untouched history remains
as the control that reuses its completion, runs nothing again and appends
nothing. F2–F5 and their evidence are untouched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Found 5 redundant comments. Inline suggestions to remove them below.

Comment thread packages/core/src/expand.ts Outdated
// through the ordinary public Component Api, exactly as it always has.
// through the ordinary public Component Api, exactly as it always has. And
// no root publisher: an expansion with no execution has no root environment
// of an execution's to publish for.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Redundant comment — restates what the code does.

Suggested change
// of an execution's to publish for.

Comment thread packages/core/src/generated-xmd.ts Outdated
environment,
undefined,
// A fragment writes an environment of its own, so it has no root
// capture to publish and no root publisher to be given one.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Redundant comment — restates what the code does.

Suggested change
// capture to publish and no root publisher to be given one.

Comment thread packages/core/src/generated-xmd.ts Outdated
// document execution that admitted it.
undefined,
// And no root publisher: a fragment's locals are its own, and a name it
// binds is not something a later entry inherits.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Redundant comment — restates what the code does.

Suggested change
// binds is not something a later entry inherits.

// defined: `values["__proto__"] = …` reaches `Object.prototype`'s inherited
// setter, and what that does depends on the engine. This is the environment a
// retained name is read back into, so a capture of that name has to be the
// same own data property every runtime.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Redundant comment — restates what the code does.

Suggested change
// same own data property every runtime.

name,
...sourceDescription(position),
},
// deno-lint-ignore require-yield

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Redundant comment — restates what the code does.

Suggested change
// deno-lint-ignore require-yield

@github-actions

github-actions Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

PR #943: ✨ Reuse root JSON across REPL entries and cold reopen (#939)

20 files, +3063 / -78

Scope

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

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

Structural

Oxlint structural signals:

  • no-unused-vars ×8: packages/cli/src/repl/session.ts, packages/core/src/execute.ts
  • no-unnecessary-type-assertion ×6: packages/core/src/execute.ts, packages/cli/src/repl/model.ts
  • no-unnecessary-type-arguments ×2: packages/cli/src/repl/session.ts
  • no-empty-function ×1: packages/core/src/execute.ts

Slop

  • packages/core/src/expand.ts:861 (removed)
  • packages/core/src/generated-xmd.ts:2416 (removed)
  • packages/core/src/generated-xmd.ts:2438 (removed)
  • packages/core/src/root-binding-publications.ts:196 (removed)
  • packages/core/src/root-binding-publications.ts:399 (removed)
  • packages/core/src/execute.ts:3281 (removed)
  • packages/cli/src/repl/sidekick/requests.ts:147 — // when the read answers.
  • packages/core/src/computed-bindings.ts:129 — // whichever way the run ends.
  • packages/core/src/computed-bindings.ts:163 — // and no live environment left to read instead.
  • packages/core/src/computed-bindings.ts:216 — // engine.
  • packages/core/src/execute.ts:2442 — // is no description to read.
  • packages/core/src/execute.ts:3293 — // be read without being executed again.

Static Analysis

Oxlint: 60 diagnostics across 5 files (16 rules)
Density: 0.020 violations/added-line

no-shadow (14): packages/core/src/components/Fail.ts, packages/cli/src/repl/session.ts, packages/core/src/execute.ts
no-unused-vars (8): packages/cli/src/repl/session.ts, packages/core/src/execute.ts
unbound-method (7): packages/cli/src/repl/session.ts, packages/core/src/execute.ts
no-unnecessary-type-assertion (6): packages/core/src/execute.ts, packages/cli/src/repl/model.ts
no-floating-promises (5): packages/cli/src/repl/session.ts, packages/core/src/execute.ts
no-unsafe-type-assertion (5): packages/core/src/execute.ts
consistent-function-scoping (2): packages/cli/src/repl/session.ts, packages/core/src/execute.ts
no-array-sort (2): packages/core/src/execute.ts, packages/cli/src/repl/model.ts
no-unnecessary-type-arguments (2): packages/cli/src/repl/session.ts
consistent-return (2): packages/core/src/execute.ts
no-duplicate-type-constituents (2): packages/core/src/execute.ts
no-unused-private-class-members (1): packages/core/src/secrets/policy.ts
no-empty-function (1): packages/core/src/execute.ts
no-base-to-string (1): packages/core/src/components/Fail.ts
no-unnecessary-type-conversion (1): packages/cli/src/repl/model.ts
no-unnecessary-template-expression (1): packages/cli/src/repl/model.ts

Correctness

No extraneous code patterns detected.

@taras
taras marked this pull request as ready for review October 17, 2026 18:28
@taras taras changed the title ✨ Carry a REPL entry's root captures to the next entry (#939) ✨ Keep REPL captures across entries and cold reopen (#939) Oct 17, 2026
taras added 3 commits October 18, 2026 00:18
The per-binding publication protocol #939 shipped is removed whole: no
producer, mode, admission field, parser, counter, outcome marker or
expansion plumbing, and nothing renamed in its place. `expand.ts`,
`generated-xmd.ts`, `host.ts` and the CLI's `entries.ts` return to the
pre-#939 base byte for byte.

In its place, an execution computes the root data it hands back. A binding
is a byproduct of running the document, so one private owner per canonical
invocation is given the actual root environment by identity, and at the
result boundary it reads that root's current eligible data onto the
ordinary `DocumentResult` — on an authored failure as well as on success,
because a failure is an outcome. The journal gains no operation, and
`parseDocumentResult` stays the single interpretation point, so a cold
reader answers from the record it already parses.

Reading is owned the same way. `useSecretDetection` now returns the
disclosure policy beside the journal gate, so the owned read closes over
the exact scanner the gate closes over and a later same-name Context
cannot weaken it. `HostExecution.bindings()` exposes that read, and
`ReplSession.bindings()` layers it over the retained head, rechecking the
running entry's identity after the read suspends.

Ordinary authored failures now normalize inside the canonical result
boundary. Before this, a plain `<Fail>` left no `DocumentResult` at all —
the root Close held the durable protocol's serialized error — so its
rendered text was lost to every later reader. Durability and fatal Files
failures still escape ahead of it.
Repairs the five findings both exact-head reviews returned on 10f3cc8,
which stays as it was.

The owner is now an Effection resource, acquired in the canonical
invocation's own scope before the work it holds anything for, so its
finalizer is established before there is a live reference to release. It
releases the document's root environment and this execution's scanner on
its own teardown, whichever way the run ends, and a run halted or fatally
failed before it settled has nothing to read and no live environment to
read instead. The manually paired `release()` is gone.

Settling keeps the accepted data and lets go of the root and the scanner.
What arrives there came back through the root's own close, so the gate
that decides what may be written has already vetted it — which is what
lets the handle stay readable for its promised lifetime without holding a
live reference open to serve a read, and what keeps a replayed run from
scanning its own journal again.

Every successful read is copied rather than shared, live or settled. Two
reads of one settled execution are two graphs, so a reader cannot edit an
outcome the journal has already recorded.

A fragment expands against the containing document's environment, as it
always has, so a name it binds with `as` is written in that execution's
root and is eligible there. The earlier premise that it writes an
environment of its own was wrong; a generated root is the separate case.
Released fragment semantics are unchanged and nothing tracks provenance.

Completes two frozen observations that were claimed but not exercised: a
bound command's outcome crossing to a successor by its three channels,
and a transient JSON value overwritten by a function before anything
retained it, absent from the result, the next entry and a cold reading.

Cancellation carries no computed map of its own and does not unretain the
facts recorded before it. Its representative is now the real unfinished
question prefix with a cancellation recorded on a copy of it, and the
guide and spec say that distinction instead of "hands on nothing".
…own (#939)

Completes the two selected observations the Planner asked for twice, in the
core owned-handle controls. No production change: the resource and copy
fixes at babfb6f already behave this way, and these rows are what makes
that visible to a test rather than only to a trace.

A new C5 row captures safe nested data, holds the run at an explicit
barrier — a component that reports it was reached and then suspends, so the
invocation is genuinely unfinished rather than waiting on a timer — reads
the handle successfully there, then leaves the scope so the owner is halted
and joined. The same retained handle then refuses with no map. The
successful read before the halt is what makes that a refusal rather than an
owner that never had anything.

The C2 control now writes through the nested member of one returned settled
answer and reads again. The accepted value is unchanged, the retained bytes
are identical, and the separate cold execution over them still reads what
the run decided.

Both rows discriminate: reintroducing the settled-read alias fails C2, and a
finalizer that stops clearing its live references fails C5.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Found 11 redundant comments. Inline suggestions to remove them below.

terminal = settled;
// After the eval facts this segment already recorded, and through the
// same publishing path: the ordinary result is the last thing this entry
// said, so a name it carries wins over an earlier value for that name.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Redundant comment — restates what the code does.

Suggested change
// said, so a name it carries wins over an earlier value for that name.

}
// Read whole or not at all: a member this version cannot read refuses the
// outcome rather than being dropped, because dropping it would hand a later
// entry a smaller environment than the record describes.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Redundant comment — restates what the code does.

Suggested change
// entry a smaller environment than the record describes.

// Suspended, so this is a different moment. If the entry that owned the
// read is no longer the entry running, what it computed is either in the
// head now or was never acknowledged at all; either way the file is the
// only honest answer and the live half is dropped rather than carried.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Redundant comment — restates what the code does.

Suggested change
// only honest answer and the live half is dropped rather than carried.

return head;
}
// The live values win: they are this entry's current root, and the head
// holds what was true before this entry started.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Redundant comment — restates what the code does.

Suggested change
// holds what was true before this entry started.

// The session's own read, for the same reason `printing` is: the live
// half belongs to the entry running in this process, and only the
// session knows which entry that is and whether it is still that one
// when the read answers.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Redundant comment — restates what the code does.

Suggested change
// when the read answers.

// Whichever way this invocation ended. A run that settled keeps the
// answer it settled — that answer is data, and the handle was promised
// it — while a run halted or failed before settling has nothing to read
// and no live environment left to read instead.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Redundant comment — restates what the code does.

Suggested change
// and no live environment left to read instead.

// Defined rather than assigned, for the reason the root's own initial
// bindings are defined: `values["__proto__"] = …` reaches
// `Object.prototype`'s inherited setter, and what that does depends on the
// engine.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Redundant comment — restates what the code does.

Suggested change
// engine.

const wrapper = caught instanceof Error ? caught : new Error(String(caught));
// Without a printed description the failure speaks for itself: an authored
// `<Fail>` carries its own message and no separate segment account, so the
// record repeats that message rather than inventing a second one.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Redundant comment — restates what the code does.

Suggested change
// record repeats that message rather than inventing a second one.

}
liveEnvironment(rootEnv);
// The one place the owner learns which object this run's root is. Identity,
// not a lookup: what may be reported is this environment's own data.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Redundant comment — restates what the code does.

Suggested change
// not a lookup: what may be reported is this environment's own data.

const result = parseDocumentResult(returned);
// Accepted, live or restored: from here the owner answers from the result
// rather than from a root environment, which is what lets a completed run
// be read without being executed again.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Redundant comment — restates what the code does.

Suggested change
// be read without being executed again.

@taras taras changed the title ✨ Keep REPL captures across entries and cold reopen (#939) ✨ Reuse root JSON across REPL entries and cold reopen (#939) Oct 18, 2026
Repairs the three PR-caused CI failures at 1043460. The base and the
pre-correction PR head were both green, so all of them were this
correction's.

10f3cc8 made every undescribed error the document's own outcome, which
is the opposite of what the settling boundary has always decided:
`documentationFailure` reports a document's failure as its own outcome and
lets anything else escape as infrastructure. Git protocol refusals,
retained-history rejections, assertion aborts and a missing launcher were
being reported as document results instead of escaping.

The guard is restored with one narrow exception. A valid `<Fail>` marks the
Error it raises with a stable namespaced non-enumerable own property, and
the boundary reads that mark off the object it was handed. So the one
undescribed failure that is a decision the document made keeps its ordinary
result, its rendered text and its computed data, and every other undescribed
failure is rethrown unchanged. Nothing identifies it by class, name or
message: `<Fail>` still raises an ordinary Error carrying exactly the
author's sentence, through ordinary component reporting and recovery, and an
invocation `<Fail>` refuses is never marked. The mark is non-enumerable and
is never searched for underneath a wrapper, so a failure that merely carries
an authored stop as its cause is not adopted as one.

Separately, babfb6f pushed a binding checkpoint at the root Close's own
marker, and the REPL keys checkpoints by marker — so one marker had two
children with one key and the drawer refused to reconcile. The Close's
terminal checkpoint already owns that selectable position and the computed
data arrives with that outcome, so the second checkpoint is gone. The
binding transcript row, the terminal's bindings and the merged entry data
are unchanged.

And the new JSDoc line that failed the banned-words check is reworded.
@taras
taras added this pull request to stack #946 October 18, 2026 14:08

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Found 6 redundant comments. Inline suggestions to remove them below.

// The session's own read, for the same reason `printing` is: the live
// half belongs to the entry running in this process, and only the
// session knows which entry that is and whether it is still that one
// when the read answers.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Redundant comment — restates what the code does.

Suggested change
// when the read answers.

// The accepted data is kept, not the things that produced it. From
// here the root the document expanded against and the scanner that
// vetted it on its way into the journal are this owner's no longer,
// whichever way the run ends.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Redundant comment — restates what the code does.

Suggested change
// whichever way the run ends.

// Whichever way this invocation ended. A run that settled keeps the
// answer it settled — that answer is data, and the handle was promised
// it — while a run halted or failed before settling has nothing to read
// and no live environment left to read instead.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Redundant comment — restates what the code does.

Suggested change
// and no live environment left to read instead.

// Defined rather than assigned, for the reason the root's own initial
// bindings are defined: `values["__proto__"] = …` reaches
// `Object.prototype`'s inherited setter, and what that does depends on the
// engine.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Redundant comment — restates what the code does.

Suggested change
// engine.

// boundary was handed, never searched for underneath it, so a wrapper or a
// teardown failure that merely carries an authored stop is not adopted as
// one. `describeFailure` reads the wrapper for its own account when there
// is no description to read.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Redundant comment — restates what the code does.

Suggested change
// is no description to read.

const result = parseDocumentResult(returned);
// Accepted, live or restored: from here the owner answers from the result
// rather than from a root environment, which is what lets a completed run
// be read without being executed again.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Redundant comment — restates what the code does.

Suggested change
// be read without being executed again.

@taras
taras merged commit 0116500 into main Oct 18, 2026
44 checks passed
@taras
taras deleted the agent/repl-root-bindings-939-20261017 branch October 18, 2026 14:50
taras added a commit that referenced this pull request Oct 18, 2026
After #943 merged, GitHub rebased this branch onto the new main, so the remote
held 368aa6d while the signed integration held 3d10513. Both carried the same
tree. This merges the remote head into the signed branch, which keeps every
published object reachable, makes the remote an ancestor again, and leaves a
normal fast-forward as the way to publish.

The merge changes nothing: the tree is still 9fd3794,
the tree both sides already had and the one F1-F4 and the parent-boundary suites
passed on. Nothing was rebased, force pushed or reset, the deleted parent branch
stays deleted, and the pull request keeps main as its base.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.

Preserve root component and <Let> bindings across REPL entries

1 participant