Repository navigation
Make summary prose correctable in place (sovereign user revisions) - #251
Merged
Merged
Conversation
…ser 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.
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.
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
force-pushed
the
feat/summary-correct
branch
from
July 18, 2026 00:52
710d37e to
c84bbc7
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #246
What
The summaries block why-line promised "a draft you can correct", but no edit affordance existed and the "user corrections sovereign" invariant was unreachable for summary prose. This makes summary prose correctable in place, stored as a sovereign, append-only user revision.
Sovereignty (the acceptance bar)
A user-corrected summary OUTRANKS any machine revision on read AND survives re-derivation: correct → re-run the producer (even one that appends a NEW machine revision for the same window) → the read still returns the user text. Resolution mirrors the
resolveClaimHeadspair-key precedent — a stable window/level identity keyed so a freshly re-derived revision cannot defeat the correction. The machine chain is never mutated or deleted (retrievable withincludeSuperseded).Contract
Summarygainssource: 'model' | 'user'(optional — absent ⇒ model, back-compat), acorrectionstamp, and acorrectslink;proposalrelaxed to boolean (a user correction isproposal:false).SummaryCorrectionshape +CorrectSummaryRequestpayload;POST /summaries/correctroute. Schemas regenerated and committed (zero-drift).Engine
store.correctSummarymints asource:'user'revision carrying the target's identity,confidence:1, a correction stamp, and only STRUCTURAL provenance — no model-invoke fields, so human prose is never attributed to a model.resolveSummaryHeadsresolves supersession + sovereignty in one pass. The producer excludes user rows from the machine chain. A degraded target is refused. Purely local write — no new egress path.Client
user-select:none). TheSummaryEditSessioncontroller dispatches the verbs (unioned into the interaction-honesty lint); a refused save surfaces a calm visible line with the raw reason on hover. Copy stays value-only (carries the corrected bare text).Privacy
A correction is a local store write only. The summaries egress-seam tests are unchanged and still pass.
Tests
.corrmarker), and interaction-lint coverage.Full gate green: contracts 114, engine 1108, client 627; schema zero-drift.