Review follow-up. provenLocalCallee inferred file-local calls from module
scoping but borrowed non-exportedness from its one caller and never checked
module-ness: a helper in a global script file (no import/export) is
program-visible and callable cross-file with no same-file reference, so the
proof passed and those call sites were dropped as silently missing matrix
cells. Guard both premises at the proof entry, failing toward the global
fallback.
- State the EVENT_API_METHODS obligation: a visitSource branch for an
unlisted method name is dead because the prefilter drops the call first.
- Add gen-doc-graphs.spec.ts pinning fast path vs global fallback equivalence
on fixture programs: a proven-local helper, an alias-escaping helper, and a
global-script helper (negative control that keeps the fallback exercised).
- Record the demand-driven indexing decision in the Program-backed semantic
gates Agent Note (both languages, pairing re-recorded).
Generated docs stay byte-identical (verify-doc-graphs green).
The event-relation collector resolved every CallExpression in all package
sources up front (getResolvedSignature is the most expensive checker query)
and type-classified every property-access receiver before looking at the
method name. Both costs served a tiny fraction of call sites.
- Filter by event API method name first; receiver classification now runs
on those calls only.
- Replace the eager global call-site index with demand-driven indexing:
when a non-exported local helper's same-file references are all provably
direct callees, only that file is indexed; any other reference shape
(alias escape) falls back to the original full package-source index.
Generated docs are byte-identical; verify-doc-graphs stays green. Halves
the script's CPU time (23.4s -> ~13s user on a warm run).
fix(web): keep one composer bar DOM across the no-workspace transition
The composer.bar slot moves from session to session-maybe scope: with no
current session the entry still mounts, the machine faces (keyboard, stop,
command) arrive undefined, and the bar renders its normal DOM inert via the
disabled owner prop. DisabledInputBar and its parallel tree are gone, so the
textarea node survives the cold-start workspace pick instead of flashing
through a remount. A blank session whose workspace was deleted takes the
same inert path through owner props.
test(web): add the composer DOM-continuity acceptance probe
Drives a real dsh web server with headless chromium through the cold-start
-> pick-workspace -> type flow and asserts the composer textarea is the
same DOM node throughout (a marker property must survive). Rerun
prerequisites are in the header comment.
docs(web): session-maybe identity is adoption, not hold-forever
fix(web): session-maybe entries adopt the first session, then remount like strict entries
A session-maybe entry used to keep one React instance across every
transition, so component-local state leaked between sessions once the
composer bar moved to that scope (PermissionSelect's optimistic pick, the
IME composition guard). Identity is now adoption: an incarnation born
session-less holds through the arrival of the first session (the blank
shell's DOM survives the workspace pick), and afterwards behaves exactly
like a strict session entry — a switch or a drop to no-session remounts,
clearing local state by construction. The child key is an incarnation
counter kept in the stable outlet wrapper via render-phase setState.
chore: knip knows the root acceptance probe's playwright dependency
scripts/hero-composer-dom-continuity.mjs resolves playwright through
apps/web's devDependency tree (createRequire), which knip cannot follow;
ignore it at the root workspace.
Master independently refreshed the same stale web aria goldens this branch had
absorbed in 08aa0ca54, so every conflict was golden-vs-golden with no source
overlap. Goldens are recorded rather than merged: master's recordings win here,
and the following commit re-records to reapply this branch's one added
occupancy segment on top of them.
The chat stats line took its token totals from the loaded conversation nodes,
so paging changed them and compaction erased the billing behind replaced
content. It also had no way to show context occupancy: the numerator and
capacity never reached the browser.
Both now come from token-meter session projections read through the standard
useProjection seat. Window nodes keep supplying turn and step counts plus LLM
and tool wall times, which are correctly window-scoped facts about what is on
screen; accounting no longer comes from there.
`tokenUsage` supplies billing and cache hit. `contextPressure` supplies
occupancy, pairing the newest provider-reported prompt size with the newest
capacity recorded by `request/context`. Deployments without token-meter drop
the token groups; a route whose adapter advertises no capacity drops the
occupancy group rather than rendering a placeholder.
Occupancy is deliberately approximate: the numerator and capacity are
independent last-wins fields, not one atomic request observation, so switching
models pairs a fresh capacity with the prior route's pressure until the next
request reports usage. It is a user-facing reference figure that nothing in the
harness makes decisions from, and it matches how the TUI status line has always
computed occupancy. The Agent Note and token-meter README state this as a
decision, including why the atomic alternative was implemented and rejected, so
it is not re-litigated as a defect.
Snapshot delta is one added `Context N% of 128K` segment across eight web
goldens; the preceding commit absorbed master's pre-existing golden drift.
Conflict resolution notes:
- StatsLine: master redesigned the row into pipe-separated groups with LLM and
tool wall times. Kept that design and swapped only the token accounting
source, so counts and durations stay window-scoped while billing and context
occupancy read the durable projections.
- Generated artifacts (cordis catalog, module graph, event producer/consumer,
i18n pairing hashes) and web snapshots took master's side; they are
regenerated and re-recorded after this merge.
- Web e2e goldens and details-panel/timeline assertions took master's side:
that evolution is unrelated to this branch.
- ui-conversation package.json: kept master's devDependency ordering, re-adding
only the token-meter entry this branch needs.
Both files fit their ceilings on each parent; the merge union of this
branch's settings rows with master's typert row and source-launch rewrite
overflows by 6 and 2 words. Every added row is a fixed-format layout or
package-table entry with nothing to relocate, so the ceilings move to the
union size.