Skip to content

Note-taker: honest chrome + walkable session-history drill-down (Closes #247) - #250

Merged
Ambisphaeric merged 1 commit into
mainfrom
feat/pad-history
Jul 18, 2026
Merged

Ambisphaeric merged 1 commit into
mainfrom
feat/pad-history

Conversation

@Ambisphaeric

Copy link
Copy Markdown
Owner

Closes #247.

What changed

Dead chrome removed. The left rail's disabled Notes / Summary / Search feature-nav tabs and the disabled Home button are gone — affordances with no live handler, per the standing interaction-honesty policy. The ◆ is now a non-interactive brand mark, not a button. The Search VIEW stays tracked by #230 (a disclosed follow-up, not silently dropped). The pad's navigation is now the real, walkable session-history list.

Machine header removed. The hard-coded "Enrichments" header on the right column is gone; its blocks self-label (Transcript / Actions / Fields), symmetric with the left column's Pinned + Sessions — never a bold machine word painted over possibly-empty content.

Session-history drill-down (headline). History rows are clickable nav controls (the wired session-open verb). Selecting a past session shows that session's read-only record in the CENTER column — its session-level summary and its moments — under a "Past session" header with an always-visible "Back to live" control. It is read-only navigation: it starts/stops no capture and never touches session lifecycle (consent boundary intact).

Mechanism

  • A generic Hud.mapQuery(block) seam remaps a block's query before hydration; the controller stays layout-agnostic.
  • NotetakerView (client-local, session-ephemeral) holds the selection and, via mapQuery, re-points the CENTER session-scoped blocks from session: 'current' to the selected past-session id, so a plain hud.refresh() re-hydrates the center against it. Row clicks route through the real mount-layer delegation to open/backToLive.
  • The engine already honors an explicit sessionId over current (query.ts) — locked by a new unit test. The seeded surface document is unchanged (the binding is applied at query time), so no migration is needed.
  • Honest states: a past session with no summary/moments renders "Nothing was captured in this session.", never a blank. New nav/decoration classes are non-selectable in the stylesheet (selection-hygiene stays stylesheet-derived; values stay selectable).

Proof

  • notetaker-history.test.ts (in-gate, driven): synthesizes a real click on the rendered session-open button → the real delegated listener → the real NotetakerView → a real mapQuery re-query → a real re-render; asserts the center shows THAT session's summary + moments (not the live one's), clicks back-to-live, asserts the live view returns, and covers the empty-detail honest state.
  • scripts/notetaker-history-e2e.mjs (served-DOM, Electron, GUI-only like the other e2e scripts): mirrors the flow against real hud.html + preload + a fake engine, driving DOM clicks and asserting the served center.
  • Updated notetaker-layout.test.ts and sessions.test.ts to pin the new chrome/behavior.

Gate

pnpm -r build green. Full pnpm -r test green except one pre-existing timing flake in summaries-surface-e2e (the #241 chronic-flake pair) — confirmed 3/3 green isolated and unrelated to this change (engine query logic is unchanged; only a comment + a test were added there). Schema regen: zero drift.

Remove the dead Notes/Summary/Search nav tabs and the dead Home button
(affordances with no live handler); the session-history list is the pad's
real navigation now. The Search view stays tracked by #230.

Remove the hard-coded machine "Enrichments" header from the right column;
its blocks self-label, symmetric with the left column — never a bold header
over possibly-empty content.

Make session-history rows clickable: selecting a past session shows that
session's read-only record in the center (its session-level summary + its
moments) under a "Past session" header with an always-visible Back-to-live
control. It is read-only navigation — no capture start/stop, the consent
boundary is untouched.

Mechanism: a generic Hud.mapQuery seam remaps a block's query before it is
hydrated; the note-taker's NotetakerView re-points the center session-scoped
blocks from session:'current' to the selected past-session id, so a plain
hud.refresh() re-hydrates the center against it. The engine already honors
an explicit sessionId over 'current' (query.ts) — locked by a new test.
The seeded surface document is unchanged (the binding is applied at query
time), so no migration is needed.

Honest states: a past session with no summary/moments says "Nothing was
captured in this session.", never a blank center. New nav/decoration classes
are non-selectable in the stylesheet (selection-hygiene stays derived from it).

Driven proof: notetaker-history.test.ts drives the real Hud + mapQuery +
mount-layer click delegation + renderNotetaker — a synthesized click on the
rendered session-open button flows through to a real re-query + re-render,
asserts the center shows that session (not the live one), clicks back-to-live,
asserts the live view returns, and covers the empty-detail honest state. A
served-DOM Electron harness (scripts/notetaker-history-e2e.mjs) mirrors it.

Closes #247
@Ambisphaeric
Ambisphaeric merged commit 3ac9258 into main Jul 18, 2026
2 checks passed
Ambisphaeric added a commit that referenced this pull request Jul 18, 2026
Fresh-eyes repairs on the correction slice:

- Focus/caret theft (the #225 pattern): SummaryEditSession now snapshots the
  editor focus + caret before a destructive live re-render and restores them
  after (rerenderInto), scoped to .sum-edit-text, with IME-safe wipe deferral.
  dev-entry nests it around the input block rerenderInto so both fields survive
  one wipe. Driven test asserts draft + focus + caret survive a background
  re-render (the probe that returned focused=false is now green).

- NUL bytes: the summaryCorrectionKey and correctSummary id-hash separators
  used raw 0x00 bytes; replaced with the backslash-u-0000 escape (byte-identical
  runtime, matching resolveClaimHeads). Zero raw NULs remain in the diff.

- Pad correction (unblocked by #250): renderNotetaker threads the summaryEdit
  context through renderZonePanel, so the pad center summary gets the pencil.
  A correction targets a summary identity (not session current), so the write
  path works on any session, live and past-session views alike; a read-only
  past view still forbids capture but allows correcting derived prose. Driven
  pad e2e covers the live-view open/type/save/persist flow.
Ambisphaeric added a commit that referenced this pull request Jul 18, 2026
)

* feat(summaries): make summary prose correctable in place (sovereign user revisions)

Closes #246

The summaries why-line promised "a draft you can correct" but no edit
affordance existed. This makes summary prose correctable in place, stored as
a sovereign, append-only user revision that outranks any machine revision on
read and survives re-derivation.

Contract (shared/contracts):
- Summary gains source ('model'|'user', optional — absent ⇒ model for pre-#246
  rows), a correction stamp, and a corrects link; proposal relaxed to boolean
  (a user correction is proposal:false). New SummaryCorrection shape and
  CorrectSummaryRequest payload; POST /summaries/correct route. Schemas regen'd.

Engine:
- store.correctSummary mints a source:'user' revision carrying the target's
  identity (level/window/session/children/bound), confidence 1, a correction
  stamp, and only STRUCTURAL provenance (no model-invoke fields — human prose
  is never attributed to a model). resolveSummaryHeads resolves supersession +
  sovereignty in one pass, keyed by a stable window/level identity so a later
  re-derivation cannot defeat the correction. The producer excludes user rows
  from the machine chain. A degraded target is refused. Purely local write.

Client:
- A pencil affordance on live rows (opt-in via a threaded correction context;
  degraded/empty rows get none) swaps the row to an inline editor; save posts
  the correction, the row re-renders with the corrected prose and an honest
  "edited by you" marker (user-select:none). SummaryEditSession controller
  dispatches the verbs (unioned into the interaction lint); a refused save
  surfaces a calm visible line with the raw reason on hover.

Tests: engine sovereignty proof (correct → re-run producer → user text wins,
incl. a new machine revision), served route e2e, egress seam unchanged; client
driven served e2e (click/type/save renders + persists; refused save shows
error), block + selection-hygiene + interaction-lint coverage.

* fix(summaries): keep resolveSummaryHeads in window read-order

A collected user correction was appended at the tail of the resolved list;
sort the result by (windowStart, createdAt, id) so a correction reads in its
window's place, matching the append-only order the SQL query establishes.

* fix(summaries): focus/caret survival, NUL escapes, and pad correction

Fresh-eyes repairs on the correction slice:

- Focus/caret theft (the #225 pattern): SummaryEditSession now snapshots the
  editor focus + caret before a destructive live re-render and restores them
  after (rerenderInto), scoped to .sum-edit-text, with IME-safe wipe deferral.
  dev-entry nests it around the input block rerenderInto so both fields survive
  one wipe. Driven test asserts draft + focus + caret survive a background
  re-render (the probe that returned focused=false is now green).

- NUL bytes: the summaryCorrectionKey and correctSummary id-hash separators
  used raw 0x00 bytes; replaced with the backslash-u-0000 escape (byte-identical
  runtime, matching resolveClaimHeads). Zero raw NULs remain in the diff.

- Pad correction (unblocked by #250): renderNotetaker threads the summaryEdit
  context through renderZonePanel, so the pad center summary gets the pencil.
  A correction targets a summary identity (not session current), so the write
  path works on any session, live and past-session views alike; a read-only
  past view still forbids capture but allows correcting derived prose. Driven
  pad e2e covers the live-view open/type/save/persist flow.
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.

Note-taker pad: honest chrome + walkable session history (center drill-down)

1 participant