Skip to content

Commit c2613b0

Browse files
authored
Give the REPL a responsive workspace and independent Stops (#1004)
1 parent 70e3315 commit c2613b0

42 files changed

Lines changed: 18724 additions & 1051 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎architecture.md‎

Lines changed: 103 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6686,6 +6686,19 @@ pending one from starting rather than appending on its behalf. Settled segments
66866686
are projected and never replayed; only an unfinished final segment is given back
66876687
to Core to continue.
66886688

6689+
Entry Stop is the one way a running entry ends as interrupted. It cancels that
6690+
entry's task, retains a final interrupted outcome in the entry's own segment and
6691+
joins the task's cleanup, and only then do both facts above hold for a
6692+
successor. The outcome is an interruption, never a success inferred from
6693+
cancellation: effects the entry completed stand, output it produced stays
6694+
partial, and the segment is settled — projected like any other and never handed
6695+
back to Core, so the stopped entry cannot resume as that same entry. Exit is
6696+
different and keeps its recovery. It appends no outcome, so an entry it leaves
6697+
running is still the unfinished final segment, and reopening the history
6698+
continues it. Entry Stop belongs to the session that owns the entry; the
6699+
Sidekick's own Stop and its Follow setting are the response owner's, described
6700+
under [Follow and the two Stops](#follow-and-the-two-stops).
6701+
66896702
A location is resolved against the retained history before a session opens.
66906703
Opening one starts or resumes the execution, and replay past the retained prefix
66916704
appends — so a route naming a scope or drawer the file never held is answered
@@ -7030,18 +7043,39 @@ one resolved reading → candidate rows + a layout manifest
70307043
```
70317044

70327045
**The engine places; this boundary only states constraints.** Profiles, column
7033-
widths, the drawer's integer rectangle and the footer's seven rows are product
7034-
facts declared once; where a row lands and how many rows a region holds are
7046+
widths, the drawer's integer rectangle and the fixed rows a composition keeps
7047+
above and below its body are product facts declared once; where a row lands and how many rows a region holds are
70357048
answers the engine gives. Nothing computes a cell coordinate or a capacity
70367049
twice, because a question asked in two places is a question answered two ways.
70377050

70387051
**A column's width can be a legibility requirement rather than a share.** The
7039-
sidebar is a fixed thirty-six columns at both shared profiles, because the rows
7040-
in it are text whose meaning is lost when it is cut: the fitter keeps a turn's
7041-
state whole and degrades to a hard cut only when even that does not fit, so the
7042-
column has to be wide enough that it never does. The Transcript and the right
7043-
pane divide what is left. A geometry change that narrows this column is a change
7044-
to what the product can say.
7052+
left column is a fixed thirty-six columns at both shared profiles, because the
7053+
rows in it are text whose meaning is lost when it is cut: the fitter keeps a
7054+
turn's state whole and degrades to a hard cut only when even that does not fit,
7055+
so the column has to be wide enough that it never does. The centre and right
7056+
columns divide what is left — halved in the ordinary composition, and 66 and 58
7057+
of 160 in the staged one below. A geometry change that narrows the left column
7058+
is a change to what the product can say.
7059+
7060+
**One staged composition is under image review.** The screen the root draws is
7061+
the v2 composition, which is the wide screen #971 accepted: a Transcript of agent
7062+
work on the left, the selected work with its breadcrumbs, exact source, state,
7063+
results and its own multi-row Draft in the centre, and Bindings/Sidekick on the
7064+
right with the trays this build offers above the composer and the Sidekick's
7065+
Send/Stop beside them, under one identity row and above one compact History row
7066+
and one guidance row. It is selected by a view carrying the inert workspace
7067+
presentation, and the root supplies that presentation from what this execution
7068+
actually holds: the selected tray, no queued rows because this build has no
7069+
shared queue, and the entries its Sidekick's acknowledged Submits admitted. A
7070+
build without the continuation Follow governs offers neither Follow nor a QUEUE
7071+
tab, so neither is drawn and nothing dispatches them. It is not a second
7072+
pipeline: it is the same reading, prepared, measured, admitted, reconciled into
7073+
the one mounted tree and drawn by the same renderer pair, and every rule in this
7074+
section holds for it unchanged. Its first geometry at 160x36 — columns of 36, 66
7075+
and 58 cells with their dividers, 33 body rows, a four-row Draft — and its cell
7076+
adaptations of the reference await the Product Owner's image acceptance; no
7077+
capture of it is a regression target until then, and the 120x30 and 72x20
7078+
compositions follow that review.
70457079

70467080
**A row's surface comes from its semantic role, never from its key or its
70477081
label.** `surfaceOf()` maps roles to backgrounds, and a window's two navigation
@@ -7803,8 +7837,8 @@ accepted separation rules out. A pane's title sits in a band with a surface of
78037837
its own, and that band's bottom border is the header's accepted edge: the engine
78047838
takes that row out of the band, so the rows below are built to what it leaves and
78057839
the two passes account for the same decoration. A titled column therefore holds
7806-
one row fewer of its reading than an untitled one, and the footer keeps its seven
7807-
rows — the edge belongs to the header, not to the footer. A pane's own edges are not part of the room inside it: a bordered
7840+
one row fewer of its reading than an untitled one, and the rows below the body keep
7841+
their count — the edge belongs to the header, not to the footer. A pane's own edges are not part of the room inside it: a bordered
78087842
pane carries a border-free content box, and rows are built to the width the engine
78097843
reports for that box rather than to the pane's outer bound. A drawer's own
78107844
decoration is held to the same rule: the rule along the top of its rectangle and
@@ -7887,12 +7921,15 @@ The renderer stays
78877921
model-blind — it receives ops and geometry, classifies no row text, and no
78887922
production string carries an escape sequence.
78897923

7890-
The layout owns where things are, and the footer's seven rows are fixed in one
7891-
order: the contextual status and action row, the five History rows, and the draft.
7892-
Each is stated as geometry rather than inferred from a list's length, because the
7893-
one thing on that screen that is not a mounted cell is the History band — its
7894-
labels come from the model, so nothing else can say where it goes, and a renderer
7895-
left to place it on its own put it at the terminal's origin over the sidebar. A
7924+
The layout owns where things are. The ordinary composition fixes its footer's
7925+
seven rows in one order: the contextual status and action row, the five History
7926+
rows, and the draft. The staged composition fixes one identity row above the body
7927+
and two rows below it — compact History, with the contextual action controls
7928+
right-aligned on it, then the guidance — and draws the draft as a field of the
7929+
selected-work column. Each is stated as geometry rather than inferred from a
7930+
list's length, because History is not a mounted reading — its labels come from
7931+
the model, so nothing else can say where it goes, and a renderer left to place it
7932+
on its own put it at the terminal's origin over the left column. A
78967933
control the row cannot hold whole is left out of the frame entirely, so what a
78977934
pointer can reach and what a person can see are the same set.
78987935

@@ -8588,7 +8625,7 @@ travels with the results, which is how a correction becomes possible at all,
85888625
together with the statement that what already happened stands — so the reply
85898626
continues rather than repeating effects, and earlier successes are not replayed.
85908627

8591-
**Stop ends the asking and nothing else.** The cycle runs in a task of its own
8628+
**Sidekick Stop ends the asking and nothing else.** The cycle runs in a task of its own
85928629
precisely so Stop has something to halt: it suspends in three places a person
85938630
may want out of — provider generation, a response's controls, and a Submit
85948631
waiting for its entry — and none of them can be interrupted by a flag read
@@ -8607,6 +8644,50 @@ only the waiting, and the submission's intent stays retained with no outcome —
86078644
an operation that began and whose result nobody knows, which is exactly the
86088645
state Stop leaves.
86098646

8647+
#### Follow and the two Stops
8648+
8649+
**Follow is not in the shipped build.** The layout and the two Stops ship
8650+
first; the continuation Follow governs ships with the shared queue, so no screen
8651+
offers the choice today and nothing watches an entry to start a turn after it.
8652+
What this section states about Follow is the contract that delivery is held to
8653+
rather than behaviour a reader can exercise now. **The two Stops below are
8654+
implemented**: an entry's and the Sidekick's, each owning exactly what it says.
8655+
8656+
Follow continues a Sidekick Send through the evaluation that Send invokes. It is
8657+
a setting of the running REPL: on when the REPL starts, kept across rounds and
8658+
navigation, and saved nowhere, so no preference, history or configuration record
8659+
carries it between sessions. A round is one admitted entry the Sidekick
8660+
submitted during Send, never a provider turn, and only such an entry takes part
8661+
— an entry sent from the Draft has no continuation. The continuation is created
8662+
and owned by that evaluation, so no observer, orchestration loop or scheduler
8663+
watches entry outcomes and starts turns on its own.
8664+
8665+
When the exact submitted entry settles, and the current exchange and its cleanup
8666+
have joined, the continuation supplies two separate facts: the entry's actual
8667+
outcome — completed, failed or interrupted, each distinct — and its actual
8668+
output. The Submit answer itself stays the receipt above, the outcome and the
8669+
read instruction, so output never reaches the reply through status prose. With
8670+
Follow on, the next eligible queued message is served before another autonomous
8671+
round, under the queue's own ordering, holds and refusals (#964); nothing here
8672+
grants one origin priority over another or restarts a held queue. Turning Follow
8673+
off ends automatic continuation after the current round and does not interrupt
8674+
it. The authority of the surrounding contract is unchanged: fatal storage,
8675+
disclosure and cleanup failures keep their outcome, feedback whose acceptance is
8676+
unknown is never resent, and only explicit evaluated Output becomes the
8677+
assistant's chat — the facts of associated work are shown beside the
8678+
conversation as work, not as something the Sidekick said.
8679+
8680+
There are two Stops, with two owners. Sidekick Stop is the response owner's: it
8681+
ends the current Send and its continuation, joins both, and leaves Follow on for
8682+
the next explicit Send. It is available while the reply is generating and while
8683+
the Sidekick's question is waiting, with or without an entry. An admitted entry
8684+
keeps running on its own terms, and its later settlement cannot restart the
8685+
continuation that was stopped. Entry Stop is the session's: it finishes the
8686+
running entry as interrupted, as [sequential entries](#sequential-entries-over-one-physical-journal)
8687+
states, and that interrupted outcome reaches the Sidekick as the round's result
8688+
while Follow stays on. Shared TODO context is not part of either: it belongs to
8689+
the shared TODO work (#901).
8690+
86108691
**The boundary is the exact entry's acknowledged admission, and an allocated
86118692
task is not it.** A submission's task is started *before* the record that gives
86128693
its entry a position, and that interval is real: the execution installs its
@@ -8622,9 +8703,11 @@ does nothing at all, which is what keeps an admitted entry independent.
86228703

86238704
Two consequences follow. A cancelled startup frees the slot it held, because it
86248705
admitted nothing and there is no entry for anything to follow — whereas an
8625-
*entry* that was interrupted still occupies it, since nothing may follow an
8626-
entry without an outcome; the two are told apart by that same acknowledgement
8627-
and by nothing else. And the reservation withdraws itself as its submission
8706+
admitted *entry* holds it until it has an outcome and its cleanup has joined,
8707+
since nothing may follow an entry without one. An entry left unfinished by Exit
8708+
or by a lost process keeps holding it; one finished by Entry Stop releases it
8709+
once its interrupted outcome is retained and its cleanup has joined. The startup
8710+
and the entry are told apart by that same acknowledgement and by nothing else. And the reservation withdraws itself as its submission
86288711
unwinds: `live` means the asker still wants this, and a cancelled submission is
86298712
the asker not wanting it, so the reservation answers for itself instead of being
86308713
revoked by a separate call that would have to be sequenced correctly.

0 commit comments

Comments
 (0)