The session's first executor request pays for the prefix every later one
reuses, so the session-wide hit rate mixes "did the cache work once warm"
with "how much a cold start could reuse". usagereport already records the
cold start, but nothing a live session reads projected it.
The live figures come from the serve ledger, which restarts on /new,
/resume and /fork; usageTally does not, so its ColdStart can belong to an
earlier conversation in the same process. The broadcaster therefore takes
the cold start from the ledger's own population: the first request the
ledger files under the executor (pricing.LedgerSource, the rule Add
already used), split by the same CacheSplit the ledger applies, and reset
with it. SessionUsage carries it as coldStart.
- /status (TUI): "warm cache" row, ledger hit rate with the cold start
taken out of hit, miss and unknown; "out/in" row, output ÷ input.
- Desktop session overview behind the cache meter: the same two figures,
computed in state/overview beside cacheRate.
- wire-parity: ColdStartUsage mirrored in port/session.ts.
Planning ran on every keystroke and its write probe called MkdirAll on the target, leaving a folder per typed prefix. The probe now runs in the nearest existing ancestor, free space is read from it, and Move creates the target once the user starts the move.
The composer showed the connect strip, the trust question and the sandbox note
together, each with a paragraph, and a short stack clipped them over the input.
Now one strip is drawn, by priority (cannot send, trust, no sandbox): a single
line, the explanation in the hover text, calm grey for reminders and warm only
for "cannot send".
A terminal opened from a remote pane runs on that machine through the existing
forwarding, and its header carries the host. A test holds that the host's
requests are forwarded and a paired device's never reach the far kernel.
A fourth kind of tab opens a real shell (ConPTY on Windows, a pty elsewhere) in
the project folder, outside the model's permissions and sandbox and with the
host's provider keys left out of its environment. The kernel keeps each shell's
output, so a tab left or a window reloaded comes back as it was; a tab is named
for the command submitted while the shell is busy and carries a blue dot, and
closing a busy one asks first.
Also: the composer's note stack no longer clips to a few pixels when it holds
two notes, which left the second one overlapping the input.
The unused linter reports eight symbols in prune.go that the archive-to-file change left without a caller; the strategy type and its hint mapping, which are still used, stay.
The mark for a model came only from the preset a provider was installed from, so an entry pointing at api.deepseek.com by hand drew a letter tile. The address is now read through the curated preset serving it, as vision models already are. Setup service cards draw the mark their vendor declares.
Compaction moves the folded span into <session>.outputs/fold-<hash>.md and leaves a pointer the model reads back with read_file. The summarizer path, its retries, bounds and tests are removed.
Answering an ask with no selection ends the turn normally instead of reporting a failure.
Find bar, overview and context cards, compact dialog, image preview, root-missing banner, toasts, side panel and prompt refine are aligned to the Chat-Tools board; the agent preset picker follows the Agent-Picker board.
A fixed ten seconds reported a hang on a loaded Windows runner where the first-run test had already spent forty seconds. testenv.Budget exists for waits that only catch a hang.
A removal that lost a race with the walker was dropped, so the directory stayed behind and, because names are never reused, a later walk could not tell it from an unreadable one and failed after the five-second re-stat window. The churn now retries the removal until it succeeds, which is what the never-reused-name invariant assumes.
A background start carried its job's id only in the sentence the model reads,
so a window could not tie the call to the job without parsing it. The shell
execution now carries jobId on every layer to the wire. In the execution group
that call reads "放到后台运行", its row shows the job's live state from the
pane's job list — running and for how long, then how long it took and its exit
status — and while it runs a note says the turn goes on without it, with a way
to its output.
The run tabs hook no longer writes its list when a request adds nothing, which
re-rendered without end for a caller passing a fresh setter each time; the job
tab test that did so and hung its worker now keeps one. Execution's comment in
wire.ts states what the type is for rather than how it came to be.
The status surface carried running jobs only, so a job that ended left no
trace there: the rail could never read "failed", and a person had no way to
see how long a finished build took or how a test run exited. /status now also
carries endedJobs — this session's finished jobs, kept until the session is
purged — and every job view carries the last line it wrote; an ended one adds
when it ended and, for a command, its exit status. The last line is what the
command wrote itself, kept before the finished job's in-memory tail is
released, not the host's note of how it failed. jobs stays the running list,
since that is what its readers take it to be.
The rail's list follows the board: running jobs above ended ones, each with
how long it ran, what it runs and its last line; an ended one with its exit
status; stop asks again before it acts; ended jobs can be cleared from this
window. The reading is a blue pill while one runs, stays red for a failure
until the list has been opened on it, and is grey once all have ended.
Durations pad seconds as the board writes them (4 分 02 秒).
The plan card follows the Plan-Card and Chat-Plan boards. Proposed, running,
waiting on a person and finished are the same card changing in place: numbered
steps before it starts, then the kernel's live list with a done mark, a turning
mark on the step in hand, and a badge for where it stands. The work after a
started plan is filed under its card, and the plan's own todo_write rewrites
are left out of that work because the card already draws the list.
The strip above the composer is the card's stand-in: a tab inset 14px with the
step it is on and one segment per step, shown only while the card is off
screen and no decision is waiting. Opened, it is the same tab grown upward,
titled once, with a way back to the card through the transcript's own landing.
Cause: the pending card was one sentence and three buttons, because the plan
request carried no steps, and the live list lived only in the strip, so the
plan was shown twice once it ran. The kernel now sends the starter list the
approval seeds as the plan request's input, from the same parser, and the live
event names its kind as the replayed one already did.
Blast radius: plan approvals on every frontend (the TUI keys its plan answers
on kind, which only the replay carried), the wire form of a plan approval, the
transcript's work layout around a started plan, and the plan-progress
preference, now on unless a person turned it off.
Neighbouring behaviours tested: replayed plan prompt, seed equals the card's
list, unscoped calls still send no input, revise/exit cards, fold-work folding
a card's work, refused todo_write kept, strip collapse/escape/outside press,
goal-only strip, progress preference.
Why this layer: the controller is the one place that parses a plan into steps,
so the card shows what approving starts rather than a second parse.
Cause: ten fixtures in serve, ext/plugin and platform/repair built a symlink
with os.Symlink and failed the test on error. A non-elevated Windows run
without Developer Mode returns ERROR_PRIVILEGE_NOT_HELD there, so ten tests
failed and the whole serve suite went red, though CI's elevated runners never
saw it.
Fix: skip those fixtures with the underlying error as the reason, the pattern
the boot package already uses; the refusals they pin down still run wherever
symlinks can be built.
Blast radius: ten test sites in five files, no production code.
Neighbouring behaviours tested: the same tests run unchanged where symlinks
work (ext/plugin, platform/repair, serve), and the packages vet for windows.
Why this layer: the fixture owns whether it can build its own precondition.
Fixes#14969
Cause: Studio's inbox is schema 2 while 1.x writes schema 3, so a session
that had been used in 1.x opened as "written by a newer version" and its
queued messages could be neither sent nor deleted.
Fix: accept schema 3 and keep its fields (fingerprint, attachment identities,
image inputs and source refs) through every rewrite so nothing 1.x wrote is
dropped. This build cannot read 1.x image inputs, so an entry carrying them is
held with the foreign_images block code on both the run and steer paths
instead of being sent without the images.
Blast radius: state/sessioninbox (envelope, request hash, images flag), the
two dispatch paths in session/control, and the block-reason tables in the
desktop and terminal frontends.
Neighbouring behaviours tested: queue tests of the inbox, control, tui, serve
and i18n packages, plus the desktop queue and translation tests.
Why this layer: the envelope owns what is persisted and the shared
applyInboxReferences owns whether an entry may run.
CI's Windows full suite saw the index answer State=ready with Indexed=Total=1
while a rescan was still pending, so SearchIndexProgress honestly reported
building and the test, which had only waited for the hit to appear, failed.
The test now retries until the projection reports every source indexed and
nothing pending, fails at once on any unreadable-source signal, and only then
asserts that no incomplete-index signal is raised.
Not reproduced locally: the base passed 20x on macOS, 90x under six concurrent
processes on Windows, and a full package run on Windows.
The memory list now carries each fact's galaxy, importance, retention
state, use count, days left before it turns fuzzy, whether it decays,
and whether it is new (written in the last 14 days and not yet reviewed).
POST /memory/confirm reinforces a fact and marks it reviewed; a save from
the page also marks it reviewed and may move its galaxy, importance and
type. The review mark lives in the usage sidecar, so it never rewrites
the fact file.
Each fact has a retention of e^(-days since last use / strength). Reading a
fact multiplies its strength by 1.8 and an automatic recall by 1.2, capped at
365 days; constraints, pinned and evergreen facts never fade. Recall keeps a
clear fact's score, scales a fuzzy one down and holds a faded one at 0.35 so a
strong match still comes back. Facts recalled in the same turn build a link,
and a link of weight two brings its neighbour along. Usage lives in a
.usage.json beside the facts, so a recorded use never rewrites a fact file or
moves its revision. memory search and read report the state.
Automatic recall scores the name, title, description, galaxy and body as one
field and the synonyms as a second field at 0.6, then weights the result by
importance (0.85, 1.0, 1.15) and a 1.1 boost for facts used in the last 30
days. A constraint is brought whenever its galaxy is named in the turn or is
the galaxy of one of the three best hits, or when its own score reaches 8% of
the best, and it leads the block; at most three are held and an expired one is
never recalled.
Compacting by hand accepted any real saving only while the context was still
below the automatic trigger. Above it, the request had to land below the
trigger or was declined, so the moment compaction was most needed the user
was told there was nothing to compact. A manual request now accepts any fold
that is strictly smaller; an unchanged context and too little new history are
still declined as before.