agentgui 1.0.959 → 1.0.960

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,88 @@
1
+ export const meta = {
2
+ name: 'gui-logic-predictability',
3
+ description: 'Drive a maximum-effort LOGIC + PREDICTABILITY sweep of the agentgui GUI: per-lens agents audit whether every element is presented and operates in the most logical, predictable way (interaction state machines, cross-surface consistency, information architecture, realtime truth, input ergonomics, scale robustness), an adversarial verifier confirms each finding against the live source (kept-typography guard), a synthesizer orders them into a kit-vs-app-vs-server build plan',
4
+ whenToUse: 'Run after the completion sweep (8th run) has landed. Distinct from all five prior workflows: gui-audit hunts JANK, gui-overhaul DESIGNS surfaces, gui-predictability-polish polishes primitives, gui-cohesion hunts one-product feel, gui-completion hunts scoped-out coverage. This one audits OPERATING LOGIC - whether each control behaves the way a user would predict (full lifecycle states, race/double-fire safety), whether the same fact reads the same on every surface, whether things live where a user would look, whether realtime counters agree across tabs, whether input ergonomics match a desktop-class chat agent, and whether the UI survives scale (huge transcripts, 1000-entry dirs, dozens of live sessions). Reference bars: claude.ai/code, cowork, Claude Desktop, fsbrowse. All visual/component work lands in c:\\dev\\anentrypoint-design; the app keeps wiring; server changes must be confineToRoots-confined.',
5
+ phases: [
6
+ { title: 'Hunt', detail: 'one agent per logic/predictability lens audits the shipped source against the reference bar' },
7
+ { title: 'Verify', detail: 'adversarially confirm each finding is real and soundly fixable (kept-typography guard)' },
8
+ { title: 'Plan', detail: 'synthesize confirmed findings into a dependency-ordered kit-vs-app-vs-server build plan' },
9
+ ],
10
+ };
11
+
12
+ // Shared grounding. Eight sweeps have shipped; this one audits whether what shipped OPERATES logically and predictably.
13
+ const GROUND =
14
+ ' GROUND IN REAL SOURCE (read, do not guess - eight sweeps HAVE shipped: jank audit, redesign, polish, cohesion, completion; the Files manager has full CRUD, hash routing carries tab/sid/dir/file/q/project/section, conversation has edit/retry/export/followups, resilience has ws-grace/health-reprobe/install-hints): agentgui front-end c:\\dev\\agentgui\\site\\app\\js\\app.js + backend.js + index.html; kit c:\\dev\\anentrypoint-design\\src\\components\\{shell.js,sessions.js,agent-chat.js,chat.js,files.js,files-modals.js,context-pane.js,content.js,forms.js} + {app-shell.css,chat.css}; server c:\\dev\\agentgui\\lib\\http-handler.js + lib\\ws-handlers-util.js + server.js. PUNCHLIST-COMPLETION.md + PUNCHLIST-COHESION.md + AGENTS.md record what already landed - do NOT re-report it; hunt what still operates illogically or unpredictably.' +
15
+ ' POLICY: fully-destructive run - reshape anything; ALL visual/component work lands in the KIT as defaults/props; app keeps state+callback wiring; NEVER new index.html !important overrides; kit tokens not hex; NO decorative glyphs (ASCII words + CSS .status-dot-disc) but KEEP middot/ellipsis/em-en-dash; any server mutation stays confineToRoots realpath-confined; every change needs a11y (roles/aria/focus/44x44/keyboard), responsive (420px), explicit empty/loading/error states, plain-language copy.';
16
+
17
+ const LENSES = [
18
+ { key: 'interaction-lifecycle', prompt: 'LOGIC LENS - INTERACTION STATE MACHINES. For EVERY actionable control in the GUI (send, stop, retry, edit-resend, followup chips, file rename/delete/mkdir/upload, download, stop-all/stop-selected, clear-data, export, copy buttons, theme toggle, drawer toggles, load-older), audit its FULL lifecycle: idle -> hover/focus -> pressed -> in-flight (busy/disabled? spinner? label change?) -> success feedback -> error recovery -> re-enabled. Hunt: double-click/double-submit races (can send fire twice? can delete fire while a delete is in flight? does retry during streaming corrupt state?), controls that stay enabled during an operation they invalidate, missing in-flight indication, success with no feedback, operations with no way to cancel, confirm steps that auto-reset at the wrong time, focus lost after an action completes (where does focus land after a dialog closes, a row deletes, a message sends?). Name every control whose lifecycle is incomplete or racy, with the concrete kit-vs-app fix.' + GROUND },
19
+ { key: 'cross-surface-consistency', prompt: 'PREDICTABILITY LENS - CROSS-SURFACE CONSISTENCY. The same fact must read the same everywhere. Audit: session identity (does the same session show the same title/label in chat rail, history rail, live dashboard, running panel?), timestamps (relative vs absolute, same format across chat/history/live/files?), cost/token figures (composer context line vs ContextPane vs history - same units, same rounding?), status vocabulary (connected/connecting/offline vs running/idle/stale vs healthy - one vocabulary per concept?), agent naming (id vs display name), cwd/project rendering (full path vs slug - consistent?), selection semantics (does clicking a session row do the same thing on chat tab vs history tab - and is that predictable?), icon/action placement (is copy always in the same corner? is destructive always rightmost?), empty-state copy tone, capitalization (sentence-case everywhere?). Name every divergence with which surface is canonical and the concrete fix.' + GROUND },
20
+ { key: 'information-architecture', prompt: 'LOGIC LENS - INFORMATION ARCHITECTURE + DISCOVERABILITY. Is everything where a user would look first? Audit: rail order (chat/history/files/live/settings - logical?), whether live-session management is discoverable from chat (a running chat is on the live tab - does chat say so?), whether settings panels are grouped logically (connection vs agents vs data vs keyboard vs server), whether the ?-overlay is discoverable without knowing ?, whether file actions are discoverable (hover-revealed actions on touch devices?), whether followup chips read as suggestions vs buttons, whether the composer context line communicates what will HAPPEN on send (which agent, which model, which cwd, resume vs fresh - is resume-vs-fresh visible ANYWHERE before sending?), whether history search scope is communicated (titles? bodies? all sessions?), whether export options are findable, whether the crumb communicates location. Hunt hidden functionality, mislabeled groups, and anything requiring tribal knowledge. Name every misplacement with the logical home and concrete fix.' + GROUND },
21
+ { key: 'realtime-truth', prompt: 'PREDICTABILITY LENS - REALTIME TRUTH + STATE SYNC. Counters and statuses must agree with reality and each other. Audit: the live dashboard tally vs history event counts vs chat turn count (can they disagree? when?), staleness derivation (45s idle -> stale: does it flap? does a slow tool wrongly read stale?), what happens when the SAME session is open on chat tab while events stream on live tab (do both update?), multi-browser-tab behavior (two GUI tabs open: do they fight over localStorage drafts/resumeSid? does one tab\'s stop kill the other\'s view?), ws reconnect vs SSE reconnect divergence (one recovers, one does not?), the 3s chat.active poll vs SSE push skew (running panel shows a session the dashboard does not?), cost accumulation across resume (does cumulative cost survive reload? double-count on retry?), event dedup on reconnect replay, clock skew in relative timestamps, and whether ANY surface can show stale data with no indication it is stale. Name every truth divergence with the concrete fix.' + GROUND },
22
+ { key: 'input-ergonomics', prompt: 'LOGIC LENS - INPUT ERGONOMICS + COMPOSER DEPTH. Benchmark the claude.ai/code / Claude Desktop composer. Audit: multiline behavior (Enter vs Shift+Enter - communicated?), composer autosize (grows with content? max height? scroll?), paste behavior (pasting a large block? pasting an image - handled or silently dropped?), drag-drop onto the composer (file path insertion? or lost?), IME composition safety (Enter during CJK composition must not send), undo history survival across draft restore, keyboard shortcut completeness (is there a shortcut to stop generation? to focus composer from anywhere? are they in the ? overlay?), Escape semantics (consistent close/cancel everywhere: dialogs, drawers, edit-mode, confirm-states?), Tab order across the shell (rail -> sessions -> main -> pane logical?), text selection inside streaming messages (does a render wipe selection?), form validation timing (cwd validation on blur vs save?), and search input ergonomics (clear button? Esc clears? result count announced?). Name every ergonomic gap with the concrete kit-vs-app fix.' + GROUND },
23
+ { key: 'scale-robustness', prompt: 'PREDICTABILITY LENS - SCALE + DEGENERATE STATES. The UI must stay logical at the extremes. Audit with the REAL rendering paths: a 500-message transcript (does the chat virtualize or render all? does jump-to-latest survive? does per-block code-copy injection rescan everything per token?), a 1000-entry directory (FILE_GRID_CAP=200 show-more: does sort/filter apply before or after the cap - is that predictable?), 20 simultaneous live sessions (dashboard sort stability while cards re-sort under the cursor mid-click?), a 100k-character single message (markdown render time? copy button on a giant block?), zero-state every tab (fresh install: chat/history/files/live/settings all have designed empty states - and do they explain the NEXT action?), an enormous event list in history (300-limit + load-older: predictable?), localStorage full/corrupt (restore path throws -> blank app or graceful?), offline boot (server up, network down for jsdelivr markdown stack - does chat degrade gracefully?), and extremely long session titles/cwd paths/agent names (truncation with title= everywhere?). Name every scale failure with the concrete fix.' + GROUND },
24
+ ];
25
+
26
+ const GAP_SCHEMA = {
27
+ type: 'object',
28
+ required: ['lens', 'gaps'],
29
+ properties: {
30
+ lens: { type: 'string' },
31
+ gaps: {
32
+ type: 'array',
33
+ items: {
34
+ type: 'object',
35
+ required: ['title', 'where', 'fixLocation', 'fix', 'severity'],
36
+ properties: {
37
+ title: { type: 'string', description: 'the illogical/unpredictable behavior' },
38
+ where: { type: 'string', description: 'file:line or component (or "absent")' },
39
+ fixLocation: { type: 'string', enum: ['kit', 'app', 'server', 'kit+app', 'app+server', 'kit+app+server'], description: 'where the fix lands' },
40
+ fix: { type: 'string', description: 'the concrete change: component/prop/css/wiring/endpoint' },
41
+ benchmark: { type: 'string', description: 'which reference product sets the bar' },
42
+ severity: { type: 'string', enum: ['high', 'medium', 'low'] },
43
+ keptTypography: { type: 'boolean', description: 'true if this touches the middot/ellipsis/dash set - which must NOT be flagged as a glyph violation' },
44
+ },
45
+ },
46
+ },
47
+ },
48
+ };
49
+
50
+ const VERDICT_SCHEMA = {
51
+ type: 'object',
52
+ required: ['title', 'real', 'reason'],
53
+ properties: {
54
+ title: { type: 'string' },
55
+ real: { type: 'boolean', description: 'true if the behavior is genuinely illogical/unpredictable in the shipped source and the fix is sound' },
56
+ reason: { type: 'string', description: 'why - cite the source you read' },
57
+ },
58
+ };
59
+
60
+ phase('Hunt');
61
+ const verified = await pipeline(
62
+ LENSES,
63
+ (l) => agent(l.prompt, { label: 'hunt:' + l.key, phase: 'Hunt', schema: GAP_SCHEMA }),
64
+ (report, l) => parallel((report?.gaps || []).map((g) => () =>
65
+ agent(
66
+ 'Adversarially verify this GUI logic/predictability finding against the REAL source (read the cited files - do not trust the claim). '
67
+ + 'KEPT-TYPOGRAPHY GUARD: middot, ellipsis, em/en-dash are intentional product typography - flagging one of those as a decorative glyph is NOT a real finding (real=false). '
68
+ + 'A finding is real only if the behavior genuinely exists in the shipped source AND was not already fixed by a prior sweep (check PUNCHLIST-COMPLETION.md / PUNCHLIST-COHESION.md / AGENTS.md) AND the proposed fix is sound, lands in the right place (kit vs app vs server), and any server mutation stays confinement-safe. '
69
+ + 'Reject vague findings with no concrete source-grounded fix. '
70
+ + 'Finding: ' + JSON.stringify(g),
71
+ { label: 'verify:' + (g.title || '').slice(0, 32), phase: 'Verify', schema: VERDICT_SCHEMA }
72
+ ).then((v) => ({ ...g, lens: report.lens, verdict: v }))
73
+ ))
74
+ );
75
+
76
+ const confirmed = verified.flat().filter(Boolean).filter((g) => g.verdict && g.verdict.real);
77
+ log('confirmed ' + confirmed.length + ' real logic/predictability findings across ' + LENSES.length + ' lenses');
78
+
79
+ phase('Plan');
80
+ const plan = await agent(
81
+ 'Synthesize these adversarially-confirmed GUI logic/predictability findings into a dependency-ordered build plan for agentgui + the anentrypoint-design kit + the server. '
82
+ + 'Order: server changes first, then kit components (each edited ONCE with all changes batched), then app wiring, then the single build->vendor->witness step. '
83
+ + 'Call out which findings share a component (batch), which are independent (parallelizable), which conflict, and the highest-leverage few. '
84
+ + 'Confirmed findings: ' + JSON.stringify(confirmed),
85
+ { label: 'synthesize-plan', phase: 'Plan' }
86
+ );
87
+
88
+ return { confirmed, plan, lensCount: LENSES.length, confirmedCount: confirmed.length };
package/AGENTS.md CHANGED
@@ -1,22 +1,24 @@
1
1
  # AgentGUI — Agent Notes
2
2
 
3
- ## GUI completion sweep (2026-06-10) — eighth maximum-effort run
3
+ ## GUI logic+predictability sweep (2026-06-10) — ninth maximum-effort run
4
+
5
+ Audits whether everything OPERATES logically and predictably (not coverage, not cohesion). New workflow `.claude/workflows/gui-logic-predictability.js` (6 lenses: interaction-lifecycle, cross-surface-consistency, information-architecture, realtime-truth, input-ergonomics, scale-robustness; hunt -> adversarial verify (kept-typography guard) -> plan). 78 agents -> 67 confirmed findings (`PUNCHLIST-LOGIC.md`). ALL implemented across kit/app/server.
4
6
 
5
- Coverage run: hunts what the seven prior sweeps scoped out or never examined. New workflow `.claude/workflows/gui-completion.js` (6 coverage lenses: file-management-crud, routing-deeplinks, conversation-control, history-settings-depth, onboarding-recovery, crosscut-new-surface; hunt -> adversarial verify (kept-typography guard) -> plan). Ran 75 agents -> 46 confirmed gaps (`PUNCHLIST-COMPLETION.md`). ALL implemented.
7
+ **Interaction lifecycles.** Kit `ConfirmDialog`/`PromptDialog` gain `error` (inside `.ds-modal-body`, role=alert) + `busy`/`busyLabel` (disables actions AND Escape/backdrop close via `data-busy`); Backdrop's Escape listener is **document-level** (focus can sit outside the dialog) and focus-restore fires only on genuine close (queueMicrotask remount guard) - the app's global Escape ladder ALSO closes `state.files.dialog` as belt-and-braces (a witness caught Escape dead with focus on H1). Per-session stop: `state.live.stopping` Set + kit `session.stopping` ('stopping...', disabled); bulk stops await `Promise.allSettled`, announce 'stopped N of M', partial failures keep their selection. Upload: one drain loop, concurrent drops append, 409 rows get `replace` (overwrite=1) + dismiss (kit `UploadProgress {actions,onDismiss}`). new-chat/backend-change/stop confirms are arm-only with bound values + 4s reset; chips never clobber a typed draft.
6
8
 
7
- **Files is a full manager now (the read-only scope cut is REVERSED).** Server `lib/http-handler.js`: shared `fsAllowRoots()` (one allowlist construction for list/file/download/mutations), `sanitizeEntryName()` (single path component; rejects separators, traversal, ADS colon, reserved Windows device names, trailing dot/space), `readBody()` (hard cap, 413), `isAllowRoot()` (roots are never mutation targets). New confined routes: `POST /api/rename` `{path,newName}`, `POST /api/delete` `{path,recursive}` (non-empty dir without recursive -> 409), `POST /api/mkdir` `{dir,name}`, `PUT /api/upload-file?dir&name[&overwrite=1]` (raw bytes, 50MB, no multipart dep), `GET /api/stat/<path>` (confined cwd validation). **CSRF guard on every POST/PUT/DELETE**: reject when Sec-Fetch-Site is cross-site AND body is a simple-form content type AND no Authorization header. `/health` gains `projectsDir` + `allowRoots`. All validated live by `scripts/validate-mutations.mjs` (17 checks: traversal/out-of-roots/root-refusal/reserved-names/ADS/CSRF/409 conflicts/round-trip) run it after touching the mutation surface. App `filesMain`: rename/delete row actions -> kit `PromptDialog`/`ConfirmDialog` (destructive copy states recursion), `new folder` + `upload` toolbar buttons, `DropZone` wraps the grid (keyboard path = the upload button), `UploadProgress` per-file rows, one `loadDir` refresh per mutation, status->plain-copy map (403/404/409/413).
9
+ **Realtime truth.** Dashboard joins on `realSid = claudeSessionId || sessionId` - server `chat.active` rows now carry `claudeSessionId`; `streaming_cancelled` is broadcast (an aborted turn never also completes; backend maps it to `{type:'cancelled'}`, app marks the turn 'stopped'); a 60s per-session terminal-frame buffer replays on re-subscribe (`replayedTerminal`) so a turn finishing during a ws drop cannot hang busy; `chat_active_changed` hints (started/ended/cancelled) trigger immediate refreshActive. Error status derives from recency (not cumulative count - a session is not 'error' forever); stale derivation honors any session's running tool (per-sid `toolRunning` off SSE); SSE counter increments dedup by `ev.i` maxI; counters take max(index,tally) and never move backwards; clock-skew clamps to 'just now'; external (non-owned) sessions render as read-only dashboard cards; sorts compare real timestamps with sid tiebreaker; tally pruned 24h/200-LRU. persistChat: 500ms debounce, 100-msg cap, >4KB tool payloads trimmed (`truncatedForStorage`), quota failure banners once, cross-tab `storage` listener with ts guard ('updated in another tab' banner instead of clobber).
8
10
 
9
- **Full hash routing (`HASH_KEYS = tab,sid,dir,file,q,project,section`).** `buildHash` reads all view state; `writeHash({push})`; user nav pushes, passive sync replaces; popstate diffs the full set (no more navTo side-effect clobber - `navTo(tab,{writeHash:false})` from popstate); chat+sid deep-links name `tab=chat` explicitly (bare sid historically meant history); Files dir/file round-trip (reload restores the dir + open preview, Back walks the tree - witnessed live); history q/project restore + re-search; settings `section=` scroll+focus.
11
+ **Input ergonomics.** IME guards (composer, PromptDialog, SearchInput - `isComposing || keyCode===229` never sends). Escape ladder: shortcuts overlay > file dialog > confirmingEdit > new-chat arm > stop-arms > stop generation (and Esc in composer cancels while busy). Window-level dragover/drop preventDefault outside `.ds-dropzone` (a dropped file never navigates the page). Composer: `onPasteFiles`/`onDropFiles` kit props (image paste with no handler -> polite transient note), `.chat-composer-hint` 'Enter to send · Shift+Enter for a new line', context `bits` may carry per-bit `onClick` (cwd is its own target; agent/model inert). `Mod+Shift+L` focuses composer from anywhere (the one chord BEFORE the modifier early-return). cwd validates on blur (debounced `/api/stat` -> kit `cwdError`/`cwdChecking`). Streaming re-render pauses while a selection is held inside the thread (kit `hasSelectionInside` + autoscroll pause).
10
12
 
11
- **Conversation control.** `editAndResend` is two-step (`state.chat.confirmingEdit` banner) and **clears `resumeSid`** on truncation - never `--resume` a session whose tail diverged (retry of the last turn keeps it). Draft persists. Followups derive from the settled turn (tool error -> fix, code fence -> explain, file path -> open). `exportActions` (copy all / export md / export json) when messages exist; `transcriptToMarkdown`. Composer context appends `N turns`; cumulative cost feeds `ContextPane session:{turns,cost}`.
13
+ **Scale.** `AgentChat {shownMessages,onShowEarlier}` windowed thread (`MESSAGE_CAP=100`, keyed 'show N earlier turns' row); >20k streaming part renders a 4k tail window ('streaming · N KB so far'); history events sliced to last 5000 in-app (server adds a `?limit=N[&before=]` slicing shim in server.js - ccsniff itself has no limit support, do NOT edit node_modules); markdown loader failure no longer latches degraded (30s retry, cache never stores escaped fallback).
12
14
 
13
- **Resilience.** `backend.js streamChat` holds a 12s grace timer on ws closed (reconnect re-subscribes and the turn continues); stream-error banner gains `retry`; `/health` re-probe on ws drop + 10s poll while not-ok + `reconnected` announce + agents refetch; `loadAgents()` with boot backoff + error banner; `errText` plain-language map (raw kept in title); cwd validated via `/api/stat` before save; ccsniff warmup copy escalates after 5s (`loadingText`); `installHint` (npx commands + recheck) when zero agents are available.
15
+ **Consistency/IA.** ONE `fmtDuration` (kit sessions.js) + ONE `fmtBytes` (= fmtFileSize, `0 B` not em-dash) kit-wide with app fallbacks; SessionCard `title` shares the rails' title expression; `session.external` + `session.elapsedMs`; STREAM_WORD `offline`; coarse-pointer always-visible file row actions; idle status never reads 'resuming...' (plain 'continues session <sid8>' in composer context); `/` focuses the files/live filter; running panel links 'open in live'; settings reordered backend -> server -> agents -> appearance -> keyboard -> data; crumb says 'settings' and Files crumb carries the parent trail.
14
16
 
15
- **History/settings depth.** Event rail finally honors tool_use=purple; `FilterPills` event-type filter (filtered BEFORE the eventsLimit slice); jump-to-first-error; copy-event-payload on expanded rows (kit `Row actions` slot, stopPropagation); per-session JSON export; `SessionMeta` header (cwd/duration/sid/events); search-hit `highlight` mark + title windowed around the first match + relative timestamps. Settings: `server` panel (version/uptime/ws/roots+copy/projectsDir), `keyboard` panel + ?-overlay fed by ONE `SHORTCUTS` array, export-chat + local-data size line; live sort/errorsOnly + files sort persist to localStorage (live selection Set deliberately NOT persisted - stale sids would arm stop-selected wrongly); two-step stop-all/stop-selected (`confirmingStop*` + 4s auto-reset).
17
+ **Witness.** localhost:3000/gm/ 0 console/page errors across chat/files/live/history/settings; composer hint renders; rename dialog opens + Escape closes + focus restores; 64-row files grid + crumb trail; 420px chat+live no h-scroll; decorative-glyph count 0 (kept middot/ellipsis/dash). Joint risk to re-check after parallel agent runs: prop-name contracts (this run caught app `onPasteImage` vs kit `onPasteFiles`, and backend missing the new `streaming_cancelled` type).
16
18
 
17
- **Kit additions** (`anentrypoint-design`): files.js `FileRow {actions,busy}` + permission-disabled rename/delete + no download on dirs; content.js `Row {highlight,actions}` + `Panel/PageHeader {id}` + `FilterPills`; sessions.js `SessionMeta` + dashboard `confirmingStopAll/Selected + onArmStop*` + `ConversationList {loadingText}`; agent-chat.js `installHint/exportActions/confirmEdit+onArmEdit`; context-pane.js `session {turns,cost}`. NOTE: `.ds-session-meta` was already taken (ConversationList row meta) - the strip is `.ds-session-meta-strip`.
19
+ ## GUI completion sweep (2026-06-10) eighth maximum-effort run
18
20
 
19
- **Witness.** localhost:3000/gm/ 0 console/page errors on chat/files/history/settings/live; files deep-link in+out+Back witnessed; FilterPills/SessionMeta/export/purple-rails(45) live; server+keyboard panels render; 420px live tab no h-scroll; decorative-glyph count 0. The stale scope-cut lines from the 7th run (read-only browser / upload not reusable / retry last-turn-only) are superseded by this section.
21
+ Coverage run reversing the prior scope cuts. Workflow `.claude/workflows/gui-completion.js` (6 lenses) -> 46 gaps (`PUNCHLIST-COMPLETION.md`), ALL implemented. Load-bearing remnants: Files is a FULL manager (confined `POST /api/rename,/api/delete,/api/mkdir`, `PUT /api/upload-file`, `GET /api/stat` via `fsAllowRoots()`/`sanitizeEntryName()`; CSRF guard on POST/PUT/DELETE; **run `scripts/validate-mutations.mjs` (17 checks) after touching the mutation surface**). Full hash routing `HASH_KEYS=[tab,sid,dir,file,q,project,section]` (popstate diffs the full set; `navTo(tab,{writeHash:false})`). `editAndResend` clears `resumeSid` on truncation (never --resume a diverged tail). `.ds-session-meta` was taken - the strip is `.ds-session-meta-strip`. One `SHORTCUTS` array feeds the ?-overlay + settings. Live selection Set deliberately NOT persisted (stale sids would arm stop-selected wrongly). Full detail in rs-learn (recall "agentgui GUI completion sweep").
20
22
 
21
23
  ## GUI cohesion sweep (2026-06-10) — seventh maximum-effort run
22
24