Repository navigation
Conversation
Contributor
CoverageThreshold: |
Adds compass_runtime/session_summary.py, a producer with no store, thread or subprocess. It turns the bounded in-order source into the closed shape DEC-28 rules on: a lede and phases of titled, cited bullets, written in 16 KiB windows through the existing guarded model seam. - The menu labels the person's words, relayed text (other agents, resumed-conversation summaries), the agent's words, checks with the tool-reported result, and file writes. Every line is redacted before clipping and before it enters a prompt. - Windows are cut before the last person message in the back half. At most 32 are kept, newest first, and the earlier part becomes a gap that points to the outline. - Parsing follows reading.parse_reply: a fenced reply parses, and a cut reply keeps only complete phases. A window with nothing valid becomes a stated gap while the others survive. - The code sets each bullet's kind from its citations (failed > did > asked > said). A bullet citing only person and agent words is asked. - The completion backstop covers the summary's own voice only, and attributed speech and the tool's own report are admitted. Failing strings are withheld in place with a reason. - Ceilings, output bounds and the summary rolling cap are RuntimeConfig fields taken from the measurement. The plan refuses before the first call, and an empty reply is retried once. - update() summarizes only the appended spans. A changed, truncated or replaced source is reported to the caller without a model call. The design record gains a Producer contract section and an amendment, by name, narrowing the DEC-28 question 1 backstop to the summary's own voice. Implements DRC-4904 Signed-off-by: Jared Scott <jared.scott@variable.team> Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A reader whose session drifted now sees each departure as its own card in the Drift card: which constraint it departs from, that constraint's own saved words as the headline, What as the cited entries by number with what each entry is in Compass's words, and "Why Compass reads this as drift" as the reading's stored detail. Nothing about the reading changes: the producer, what it stores and the evidence rules are as before. - The card header names the model and "Analysis last run HH:MM"; the level line says "Analysis last run" too. The drift__level comparison projects that prefix back to the recorded words; the recording is untouched and the departure is recorded under Held to recorded answers. - Every other line follows a divider as one quiet row, in the words resultStatus and claimStatus already use. "Model assessment" and "Show cited entries" are gone; each cited number opens Full activity at that entry, and "Load the cited entries" keeps the older-page read where no cited entry is held yet. - Steer back follows the rows with its primary rule unchanged. Mark as inaccurate and What the analysis read share one footer row. - The sample's Back to the finding is no longer held as an edit, and the tour's marks follow the new order. - One story per result state, with assertions on citations and attribution beside neverDone; the shared checks move to stories/drift.checks.tsx. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
…otice
The first press of Analyze drift now runs the reading. The consent card
("Send this session to ... for analysis?", Allow and analyze, Not now) is
gone. When the server records a notice for a press (first time, a changed
destination, a wider content tier or a new tool-output destination), a
non-blocking notice names what is sent in the server's own words, the
provider, where the words go and where tool output goes, with Turn off
readings beside it. The running job carries the notice, so a reload
mid-run still shows it; a press whose reply carries none shows none.
A stored off now reads as off: Analyze is not offered, the card says
readings are off, and the one control is Turn on readings and analyze,
which sends the turn-on fields and runs the reading in the same press.
Turn off readings shows whenever readings are on, no longer from the
legacy per-provider Allow map. Keep runs its analysis directly.
Goal summaries in the Console lose their browser Allow card: Summarize
this session is offered when the run allows it, a goal notice shows with
Turn off readings beside it, and a readings-off status reads as off.
The recorded admission answers in route.differential.test.ts and the
consent case in ReadingCapBanner.test.tsx are withdrawn narrowly, with
the departure recorded under Held to recorded answers. Reader-state rows,
the migration inventory, the sample session's reading permission and its
README follow. Stories with play functions cover the first press and its
notice, a second press with none, a changed destination, readings off,
and tool output named in the notice.
Implements DRC-4915 (frontend half)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: Jared Scott <jared.scott@variable.team>
…he latest chip press - Own the outline chip reader-state row in the migration inventory, so the inventory check and its dashboard test pass again. - The card reads the focused context itself once per board revision, so the outline loads under --no-annotations. - Only the latest chip press moves focus or leaves the missing-entry note. - A failed refresh no longer stamps the kept outline as updated. - Say the outline starts partway only when start_offset is above zero or a region is before_window, not for a time or byte stop from offset 0. - Count dropped groups as earlier parts of this session, not messages of yours. - Drop the parsed fields the card never draws. - Stories use outline check ids that differ from the record's, as measured, and cover a cold prompt chip, the latest-press race, the missing-entry note, annotations off and a failed refresh; the matched-id story is labelled as the future case. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
…oal came from The Intent card now follows the designer's mockup: - A lede saying what the goal is for and that Compass never writes into the session. - A header status derived in one place (intentStatus) from the held edit, the pending save request and the confirmed receipt: Saving..., Not confirmed, Not saved, Unsaved changes or Saved. A pending save outranks every receipt, so "Saved" never sits beside "Saving...", and an edit held over a newer board revision stays "Unsaved changes". - One goal source line (goalSourceLine) from the annotation's provenance and the held state: Typed / From your prompt, saved or not saved, and "From your prompt, edited" for a prompt that was adopted and then typed over. The not-saved prompt line names Analyze's 1,000-character read (reading.LEDGER_WORDS_CAP_CHARS). - "Use your prompt" lists "Your prompts in this session", each with its label and time on its own line above the prompt text. The option label the recorded answers compare is unchanged; the menu takes the longer text from the choice it names. - "Expected outcome · up to 6 lines", numbered lines, and the mockup's placeholders. - Save intent before Undo changes, and the controls moved from the retired More in one quiet wrapping row beneath them. The keep-or-clear outcome lines question, the pending later-direction line and the ended-session caveat keep their behaviour. Stories with play functions cover typed, from-prompt, adopted-then-edited, saving, saved, not confirmed, refused, concurrent revision, prompt menu pick, the moved controls and the ended-session caveat. Implements DRC-4906. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
The review found the own-voice relaxation implemented as ruled when the
owner has accepted only the shape and the ceilings. The backstop now
withholds every completion word, quoted, attributed or named, except a
check's own report ("<check> reported <result>, as the tool reported").
It folds NFKC, withholds mixed-script words and covers finish, solve,
repair, implement, deliver, deploy and accomplish. A passed check no
longer licenses pass or green. The own-voice rule stays a proposal in
the design record.
Updates:
- Prior blocks must tile the source; an entry between two spans is
late_evidence and makes no call.
- A pending check resolved inside the newest block re-summarizes that
block with the appended entries instead of returning source_changed.
- An update with no room left under the output bound refuses before
any call (output_bound_full), and a failed new lede keeps the prior.
Producer:
- A complete reply followed by prose is unreadable, not salvaged.
- The lede reports cites_cut; malformed bullet rows are shape_fault
markers in place; a refused retry is not counted; any seam exception
stops the job and keeps finished blocks; a bytes drop reports bytes.
Docs: the producer contract names a summary-specific guard rather than
the reading GuardedModel, and SECURITY.md lists the carriers and clips.
Implements DRC-4904
Signed-off-by: Jared Scott <jared.scott@variable.team>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ined claim Review fixes for the departure cards. - A contradicted claim with an empty or blank stored detail again says no explanation was retained and lists each cited entry's record under Evidence, as the account did before the cards. - A cited number shows only the kind of entry Compass names, never the entry's own summary, so an agent's "Done" or check mark cannot be drawn inside the result. A story cites such a message so neverDone and noCheckMark test the invariant. - The reason for Can't tell stays inside Evidence, as the 2026-10-14 ruling keeps it; the amendment now says it does not supersede that. - Remove the unreachable "departure with no held entry" branch: the shape demotes a departure with no resolved citation. The record says so. - A repeated cite draws one number. - The header stamp hides while an analysis runs, as the body does. - DriftStamp joins the Tailwind source list. - Reader-state rows, comments and the on-demand parity proof use the number and "Load the cited entries" wording. - A story asserts the single-outcome label "Departure · Expected outcome". The tracked built page is stale on this branch by design; the integrator rebuilds once after the lanes merge. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
Review fixes for the notice change. - Console goal summaries: the notice the last Summarize reply carried is held in the board store per context key, so the passive read at the next revision no longer removes it. It stays until the next Summarize reply or a turn-off. Turn off readings is drawn whenever readings are on, inside the notice or beside Summarize. The readings-off sentence says where readings are turned back on. - A goal-summary decline this browser stored before the upgrade is kept. Summarize is withheld behind Turn on summaries, and the loader refuses the request. - The reading notice names the provider it was recorded for. It draws the route's disclosure parts only while the route still uses that provider, and otherwise a neutral line based on the content tier. - Notices are announced once through the polite region, and the notice card is a named region. - With readings off, a running job and an open direction question, the page draws one job box and the off sentence. No second box, Cancel or run control is drawn. Turn off readings is not drawn twice beside a notice. - policyReason follows the server's ranking: run-disabled, then store-unavailable, then the cap, then off. The refusal line puts the reason that stops turning readings on first. - A current result no longer draws Turn on readings and analyze. - The migration inventory drops drift-parity.mjs from the Analyze notice row, and UNCONSENTED is renamed FIRST_PRESS. The sample fixture build now writes the readings-on policy, and its README says so plainly. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
… adoptions and edits Review fixes for the Intent card: - A landed prompt adoption clears an earlier "changed" or "refused" request note, and an untouched draft's adoption marks the save, so the header no longer stays on "Not saved" or "Not confirmed" after a retry lands. - "Unsaved changes" now means only what Save intent would write. Typing the stored goal back over a chosen prompt drops the choice. - The drafted-prompt line uses the ruled cap sentence, "Analyze reads at most the first 1,000 characters of any prompt.", from one constant in sentences.ts. test_reader_words pins it to reading.LEDGER_WORDS_CAP_CHARS. - An adopted goal's source line carries no time, so a lines-only revision cannot restamp it. The saved excerpt note now follows a full stop. - "From your prompt, edited" is decided by word overlap with the adopted prompt, so words typed over a selected-all prompt read "Typed". - A prompt menu item's title shows the whole prompt. Every character count reads "n / cap". - Removed the dead draft-marks CSS and the draft-source badge variant and its story. Updated the on-demand e2e selectors and the editor deviations projection, recorded the departure under Held to recorded answers, documented the held `cleared` set in the reader-state record and restored the 25px rationale beside the source line. - The moved-controls story now opens the Saved stamp and arms and cancels Discard everything from the quiet row. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
Conflicts: frontend/css-budget.json (both lanes shrank independent CSS files; budget set to the combined total, re-checked by test:styles) and frontend/e2e/support/intent-worlds.mjs (kept the notice state from lane/notice and the draft-marks selector from lane/intent). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
Conflicts: docs/design-frontend-migration.md (kept both the Intent card and the analysis level departure paragraphs), frontend/css-budget.json (combined total of independent reductions, re-checked by test:styles) and frontend/src/sample/ViewOnly.tsx (comment names both the new cited entry controls and the readings on/off hold). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
Conflict: frontend/src/sessions/SessionDetail.tsx (kept the outline's running and harness props on WhatItDid and the drift lane's DriftStamp). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
…are off The outline card reads the focused context once per board revision whatever annotations say, so the Intent request test now holds that the Intent card adds no read of its own: no project-scope read and one focused read. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
… when it is out of date Implements DRC-4907, without the job: no model call, timer or start route. - summary_store.py: compass-summaries.json under the Compass home, keyed by harness and session, independent of saved intent and of Discard everything. Closed versioned schema; every string redacted on the way in and again on the way out; 64 MiB aggregate bound with eviction by last read or write, which cannot reach the annotation store; written under a process lock and the file lock through an owner-only temp file and rename; torn, oversized or unknown files refuse whole. - Out of date from the stored spans and fingerprints against a fresh source read: unchanged, appended (Update summary), changed_earlier with the affected block, truncated, replaced. session_summary gains a model-free change_report that update() now shares. - Publishing: a small `summary` row field declared in base_session, DECLARED_SESSION_FIELDS and the store's published(); blocks travel only on the focused /api/project-context answer as sources.summary. The parsed store is reused while the file is unchanged, an access touch is written at most hourly, and the focused freshness report is cached by transcript stamps, so polls pay a stat. - POST /api/summary/delete, refused for navigation and non-loopback peers before the body or store is read. --forget deletes the store. - SECURITY.md invariant 2, MANUAL.md, the store contract and the module map name the store; route counts and the import allowlist updated; client fixtures regenerated. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
…ng the summary store - Do not cache a freshness report whose read stopped on the time allowance, as the outline already does; byte-limited reads still cache. - --forget deletes the store when the filesystem lock is unsupported, denied or uncreatable; only a busy lock refuses it. - forget and delete answer absent before locking a missing store, so no state home or lock file is made. - Refuse a record whose identifiers (harness, sid, cites, block ids, fingerprints, source metadata) redaction would change, instead of storing it under a key no lookup can find. - Bound model_stamp with summary_store_model_stamp_cap_chars (256). - Recheck the touch interval after the locked reload, so concurrent focused reads rewrite the store once. - Board rows carry the last cached focused report's kind and reason for the same record, still with no transcript read per row. - SECURITY.md names the access-time write on GET /api/project-context; the architecture map lists both focused-session caches. - The HTTP serving test no longer claims the generate-on-first-open criterion, which belongs to the job lane. Signed-off-by: Jared Scott <jared.scott@variable.team> Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…cord capture Commit the anonymized record of a ninety-minute stretch of a real milestone burndown, the session the next sample will be made from, as the owner's recorded exception of 2026-10-19. The page still draws the first sample; sample-session/README.md says why this session and this cut, the checks it passed, and the step that switches the page to it. - scripts/cut_sample_session.py keeps one stretch of a session and only the record kinds the page reads, re-parenting across dropped records. - The sanitizer replaces screenshots nested in tool results, the short form of a session id, and times written as text (local times turned into UTC), maps listed numbers held as JSON integers, and sweeps for tracker references, encoded home directories, machine temp paths and remote-session links. - build_sample_fixture.py captures every record page back to the start under older-<n> cursors, and refuses a record longer than the page can resolve; the sample's server answers each older page and treats an unknown cursor as stale instead of claiming the record's start. - Stories show citations on the newest, a middle and the oldest page opening in Full activity. - frontend/build/page-size.test.mjs bounds react.html at 2,294,347 bytes (the page as built on 2026-10-19 plus 400 KiB) and the fixture at 250,000 compact bytes, in pnpm test. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
…istory A review against the repository found what the file-only reviews could not: eight quoted short commit hashes, branch names, pull-request titles and commit subjects that resolve in public history, tracker slugs that spell issue titles, and a project key hashed from the real path. - The sanitizer takes an optional commit_repo and regenerates every 7 to 40 character hex token that names a commit there (from the full hash, so a short form stays the prefix of its full form's replacement); --verify fails on any surviving or newly resolving one. - --verify now reads JSON integers too: a listed number under any key but a count (tokens, durations, positions) is a leak. - milestone-session.jsonl is regenerated: branches read work/branch-<x>, slugs are dropped, quoted titles and subjects (whole or cut short) reworded, quoted pull-request description lines replaced by a placeholder, and the project key is the hash of the replaced path. Both leak reviews ran again; their findings, checked against the repository, name the replacements or what is kept on purpose. - File tests: no hex token resolves as a commit, no gitBranch is a known ref, and the project key is the hash of the sample's own path. A test holds the capture's page constants to record.ts. - The README says what is and is not replaced; the size bounds live only in the design record. The built page under compass_runtime/web/ is not rebuilt here: the integration merge must run pnpm build and pnpm build:check and commit the regenerated artifacts, and page-size.test.mjs bounds that page. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
…utes The store lane added POST /api/summary/delete, which deletes a stored summary and launches or sends nothing. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
The owner narrowed DEC-28 question 1 on 2026-10-19: a summary string is withheld when the summary itself states work is fixed, done, working or verified, not when it reports what a named speaker said, quotes a tool's own output, names a branch or file, or names a tracker state. completion_claim now checks structure rather than the bare word list: clauses split at sentence ends, commas, semicolons and so/which/and/but/ then/because/while; a completion word is admitted only under a speaker followed directly by its speech verb in the same clause, a quote with a trailing attribution, an implicit-subject opening on a code-set said or asked bullet, a tracker state, a name, or the tool-report form. The refusals stay: unattributed quotations, a second clause after a speech verb, result verbs and named states in the summary's voice, unreported check results, NFKC folding, mixed-script words, and the whole-string check before any cap. "read" and "wrote" are not speech for a person or the agent, and a later speaker without a verb ends the licence. The design record's proposal becomes the ruled amendment, and the producer contract and both prompts follow it. Implements DRC-4904 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
… and ledger Implements DRC-4913 and the session-summary half of DRC-4915 (DEC-28). - A summary grant of its own, on by default, with a first-summary notice (kind "summary") and an independent stored off. Turn off summaries and Turn summaries on never touch the Analyze or goal-summary answers; --no-observer-model refuses every summary call. - summary_jobs.py: one server-owned job per session, an identifier-only marker in state_dir/summary-jobs/ before the first charge, recovery that reports an interrupted job with its finished parts and never resumes, Cancel, published progress, and a guard that rechecks grant, generation and destination before every part and charges each attempt once against a new summary_spends ledger (200 calls per 24 hours), separate from Analyze's spends. - Finished parts are saved incrementally; the windows not yet answered are a named "stopped" gap, so a cancelled summary never compares as unchanged while lacking its newest entries. No late reply publishes after Delete summary, Turn off summaries or Cancel. Discard everything leaves summaries alone, as the ruling requires. - POST /api/summary (start, update, rerun; origin open only for a finished session with no stored summary) and POST /api/summary/cancel, refused before reading the body for non-loopback peers and document navigation. The plan refuses oversized jobs before any charge and names the largest read allowed. - Board-level `summaries` block and per-row `summary.job`; client fixtures regenerated. SECURITY.md invariant 2 and Session summary calls updated; the Job and grant contract is documented in docs/design-session-summary.md. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
… needs recovery Serving ran summary_jobs.recover under the summary publication lock on every start, which created summary-jobs.lock in a fresh compass home even with no markers to recover. The installed-copy characterization test requires a launch and stop to leave that home empty. Recovery now returns early when no marker exists, as reading_jobs.recover already does. Also records the new summary_jobs module and its importers in the reviewed runtime import graph allowlist, including http_api's session_source read for the summary start route. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
Review found the own-voice completion check admitting claims it should withhold, and withholding attributed speech the owner's 2026-10-19 ruling admits. Withheld now: - The clause splitter fails closed. It also breaks at dashes, colons (except one directly after a speech verb), brackets, line ends (checked before display whitespace is collapsed), a sentence mark before a letter or a closing single quote, and Unicode terminators. The joiners gain after, although, though, yet, until, since, as, once, when, or, however, thus and therefore. A closed quote followed by unquoted words ends its clause. Cf format characters are removed after NFKC. - Only an error speaks for a tool (read/reads/said/says). A paraphrased check result is withheld. - The tool report needs its comma, and the whole match, "reported" included, becomes a clause break. The postfix "<check> passed, as the tool reported" form is dropped. - A name needs a name's shape: a dotted token needs an extension, underscore or digit, filler words make a compound a phrase, and backticks alone no longer make one. A backticked tracker state is one to three words without filler. Bare "work" joins the word list. Kept now: - A speaker opening the reported words, objects included - then/also/later/again/first as adverbs - from-states, issue keys and multi-word states that end the clause - result verbs inside names Both prompts teach the error-output form. The design record lists the new structures and the over-withholding that failing closed still costs. Implements DRC-4904 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
…honest - Turn off summaries stops every running job: reason and marker are set and a spawned call is cancelled. A charged part rechecks the grant after its board publish and before the model seam, so an off landing there sends nothing. - A stored Turn off readings also refuses summary admission and each later part (reason readings-off), and the reading off route stops running jobs. SECURITY.md no longer claims the two switches are independent. - An update's intermediate parts carry the saved lede, so a stopped update keeps it. - Producer stops (daily-cap, model-unavailable, stopping) still save the final result; only publication bars refuse it. - An update re-reads the stored summary under the publication lock and refuses when Delete summary removed or another job replaced it. - A job's marker is removed without the lock when the lock fails at its end; a torn marker no longer blocks Delete summary or leaves the session in flight, and recovery removes it. - Under --no-observer-model the summaries block reports a stored off. - SECURITY.md lists the summary disk writers in ordinal order. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
…ewed import graph The outline title cut (e7744ad) made session_source call transcripts.clip to cut a bounded prompt title back to a whole word. transcripts depends only on config, io, records, sessions and state, so the edge adds no cycle. The reviewed allowlist now lists it. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
…ist of prompts The reader-state design record renamed its row to "An open Select popup, or the open list of prompts" when Use your prompt became a button opening a popover. The migration inventory row takes the same name, keeps owner DRC-4823, and adds PromptSelect.test.tsx as an oracle. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
…ind prefix A model-written bullet that already opened with "The agent" or "The person" was drawn as "The agent said: The agent read ..." and "You said: The person chose ...", because the page prefixed every bullet by kind unless the text opened with a speech verb. A line whose subject is the agent now keeps its words as written, and one whose subject is the person reads "You ..." with the verb agreed, at the start of the line only. The summary prompts also ask the model not to write entry numbers in text: the citation chips carry them. Implements DRC-4931 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
…review notes Outline: a failure is counted fixed or listed once, in the first part it failed in; a failure the highlight cap dropped is listed by the next part; a complete title of exactly the bound is kept whole; the server-cut title story draws a fixture the server test holds equal to its own output. Departure cards: the title carries the entry's time and the constraint, a long written path keeps its file name, a long URL is cut at a separator, and the correction dates the same entry the card titles. The correction label drops a closing ? or ! and keeps an ASCII ellipsis. Summary wording: withheld lines, titles and runs use plain words, an opening summary is not called a line, the failure badge knows more runners and refusals, the opening paragraph says "You", and the written-again note ends with the rerun. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
… the entry counts A session whose Claude Code worktree was removed now files under its repository and names the worktree; the git checkout is read once per session. Sessions rows label the worktree as "worktree <name>". The summary size, the header and the since-intent count read one count, which says it is a floor while older record pages remain unread. The tab title and breadcrumb take the heading's goal or first-prompt stand-in for an identifier-only title, and the identifier pattern no longer matches real titles such as gpt-4 or utf-8. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
The header and summary size dropped their "at least" wording once the loaded record reached back past the intent window, though older pages stayed unread. The floor now follows the record alone. The design record names the tab title and breadcrumb as heading substitutions and records the floor wording. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
… and counts Signed-off-by: Jared Scott <jared.scott@variable.team>
…ole, anchor refusal phrases Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
… draws it Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
…nces, answers and pastes
Drift: a result word shares a clause only with its own kind of check, so a
rule or an action ("must never fail", "are removed") no longer cites a pass,
and "Tests: all passing" and "don't fail" now count as claims. A claim that
names no kind says how many checks the record held. The unreachable failed
check trigger of Steer back is gone, and a departure replaced by a different
one is named on the next reading even with no correction between.
Discard: a refused or unknown summary answer no longer reads as "its summary is
gone"; a stopped job with nothing stored says so; a failed departure store now
also says what became of the summary. The racing-save tests interleave a real
concurrent save.
Answers and pastes: an answer opening its own outline phase is held by a
test, the vacuous capture assertion is dropped, and a direction on the Course
tab and the timeline draws without the harness's paste tags.
The design records, the skill body and the stale delegated-work comments and
browser proofs follow.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: Jared Scott <jared.scott@variable.team>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
…mmary wording Signed-off-by: Jared Scott <jared.scott@variable.team> # Conflicts: # compass/skills/compass/compass_runtime/web/react.html # compass/skills/compass/compass_runtime/web/react.integrity.json
Signed-off-by: Jared Scott <jared.scott@variable.team>
…equirement "The tests should pass", "Tests must pass" and "Make sure the tests pass" state the result the reader expects, so a recorded passing run of that kind covers them. The modal branch of the not-a-result guard is removed; the passive "what was done to something" branch stays. Signed-off-by: Jared Scott <jared.scott@variable.team>
…es, answers and Signed-off-by: Jared Scott <jared.scott@variable.team> # Conflicts: # compass/skills/compass/compass_runtime/web/react.html # compass/skills/compass/compass_runtime/web/react.integrity.json
Signed-off-by: Jared Scott <jared.scott@variable.team>
…rd sentences The discard route now publishes one sentence per summary outcome, so the live-server client fixtures moved. Generated with scripts/regen_client_fixtures.py; frontend/test/golden is untouched. Signed-off-by: Jared Scott <jared.scott@variable.team> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gcko
added a commit
that referenced
this pull request
Oct 22, 2026
…edock tap (#635) * feat(release): render and publish the Homebrew formula for a release Add scripts/update_homebrew.py, which renders Formula/compass.rb for a release tag from the checksums.txt that scripts/publish-cli.sh attaches, and scripts/publish-homebrew.sh, which fetches that file over public HTTPS, clones spacedock-dev/homebrew-tap with a deploy key, commits "compass <version>" and pushes to main, retrying from a fresh clone when another product's release lands first. The renderer refuses a checksums file that is not exactly the four archives of the version, and never moves the tap's formula backwards, so a resumed older release or a re-run is a no-op. The formula installs the whole archive folder into libexec and links it as compass and spacedock-compass, the name Spacedock looks for on PATH. Tests cover the rendered v1.3.0 formula against its real checksums and the publisher against a local bare repository standing in for the tap. The release workflow job that runs the publisher follows separately. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Kent <iamcxa@gmail.com> * ci(release): write the Homebrew formula into the tap after each release Add a homebrew job to the release workflow, after attach-cli because the formula names the archives and their published checksums. It copies the marketplace job's shape: a checkout of exactly the target without credentials, a read-only repository token, and one script. The tap deploy key, HOMEBREW_TAP_DEPLOY_KEY, is bound at that one step and reaches only spacedock-dev/homebrew-tap. The release workflow tests pin the boundary on purpose and are updated for it: the job set and its needs, one key per job, three secrets each named once, and a checkout without persisted credentials. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Kent <iamcxa@gmail.com> * docs(release): describe the homebrew job in the release workflow Say in AGENTS.md that the release workflow is eight jobs and what the homebrew job holds, writes and refuses, and mention it in the contributor release walkthrough. README and COMPATIBILITY.md are left alone until a formula has been published to the tap, since there is nothing to install before that. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Kent <iamcxa@gmail.com> * ci: read the current Antigravity validator summary line Cherry-picked from a399b4a (feature/session-redesign, #631) so this PR's latest-client-smoke check reads the current Antigravity summary line. Only the workflow hunk is taken: the test_unasked.py hunk needs an `import shutil` that lives elsewhere in #631, and main's test_unasked.py passes without it. Signed-off-by: Jared Scott <jared.scott@variable.team> (cherry picked from commit a399b4a) Signed-off-by: Kent <iamcxa@gmail.com> * feat(cli): add --version, stamped from the release in the standalone binary `compass --version` prints the bare version on one line and exits 0. The standalone binary is built before the release job bumps the plugin manifests, so the manifest still names the previous release when the archive is made. package-cli.sh therefore stamps the version it is given (the same one that names the archive) into the bundle, and the binary prints that. Run from source or an installed plugin, `server.py --version` reads the manifest instead. When neither records a version it says so on stderr and exits 1. smoke-cli.sh now fails an archive whose --version differs from the version in its file name. MANUAL.md gets the option row and exit-status wording, and COMPATIBILITY.md and AGENTS.md describe the stamp. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Kent <iamcxa@gmail.com> * feat(release): state the version in the Homebrew formula and test it with --version The rendered formula carries an explicit `version` line, and its test asserts that `compass --version` prints it. The `--help` check is dropped: `--version` already needs the same interpreter, imports and bundled files. The never-backwards check reads the explicit field first and falls back to the version in the download URLs, so a tap formula written before the field existed is still compared correctly. brew audit reports the explicit line as redundant with the version scanned from the URL, in strict and in default mode alike. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Kent <iamcxa@gmail.com> * test(release): prove the Homebrew publisher keeps a concurrent tap commit A second product's commit landing between the clone and the push must survive. Changing the push to a force push, or to a +HEAD:main refspec, left the suite green; now it fails. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Kent <iamcxa@gmail.com> * docs(release): check the tap after a tag, and say what a failed homebrew job needs The compass-release skill checks the marketplace after a tag and has a recovery entry for it, but had neither for the Homebrew formula. It now names the formula in what pushing the tag will do, checks the tap's version, and explains a failed homebrew job, including that Re-run all jobs rebuilds the archives and breaks brew install until it succeeds again. MANUAL.md says --version is checked before the operation flags. The AGENTS.md homebrew bullet lists jq among the tools the job runs. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Kent <iamcxa@gmail.com> --------- Signed-off-by: Kent <iamcxa@gmail.com> Signed-off-by: Jared Scott <jared.scott@variable.team> Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com> Co-authored-by: Jared Scott <jared.scott@variable.team>
Conflicts resolved: - MANUAL.md: the exit-status row keeps this branch's forget wording and adds main's --version. - http_api.py and test_http_api.py: this branch removed --allow-tool-output, so main's clearing of tool_output_pre_grant on "readings off" (#634) has no flag to clear here. Both the code and its two tests are dropped; pause keeps this branch's behaviour. - sentences.ts, ReadingResult.tsx: both helpers kept. The idle line wins, then main's own-property scope lookup (#632) replaces the bare READ_SCOPE index. - legacy_goldens.ts: LATER_FIELDS keeps checkId and adds resultReason (#636). - vocabulary.test.ts, Activity.stories.tsx: both sides' imports and stories kept. - drift-parity.mjs: main's beforeDepartures helper kept without the delegated-work loop this branch removed; the Allow-owed step keeps FIRST_PRESS with main's skip list. - react.html, react.integrity.json: rebuilt from the merged sources (pnpm build). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
…or coverage main's coverage gate (#638) now certifies a selector list only when every selector is covered. The desktop rule .next-crumb:hover, .next-breadcrumb [aria-current=page] was certified by its :hover half alone, and the record holds no used entry for the other half until coverage is collected again, so it is held to a named exception. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team>
…'s goal verdicts as claims (#642) * chore: open the intent-from-the-session branch An empty commit so the draft pull request can open before the first change. The plan lives in docs/plans/intent-from-the-session.md, which is gitignored. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * docs(captures): record how Claude Code writes a /goal into its transcript Shapes only, measured on Claude Code 2.1.308 (macOS): the set and verdict goal_status attachments, the command's user and local_command records, and the hook payloads, which carry no goal field. The README row names the shapes not captured: replacing an active goal, Goal cleared: for an active goal, the not-met and impossible verdicts, a very long condition, resume and interactive sessions. Implements [DRC-4945](https://linear.app/recce/issue/DRC-4945/record-how-claude-code-writes-a-goal-into-its-transcript) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * feat(sessions): read a Claude Code /goal as a goal source A Claude Code session that states its goal with /goal now publishes it as session_goal ({text, at}), read forward and incrementally from the goal_status and local_command records. The latest set wins, a cleared goal publishes none, a met goal keeps its condition and its set time, and a condition that cannot be held whole publishes nothing. session-goal joins the closed goal sources (spelt once in records, re-exported by reading, mirrored by the page and pinned by the vocabulary fixture), and the server resolves it from its own row for adoption. The published mapping leaves room for the harness verdict without a rename. Docs record the read and its privacy limits. Implements [DRC-4946](https://linear.app/recce/issue/DRC-4946/read-a-claude-code-goal-as-a-goal-source) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(frontend): rebuild the page for the session-goal source Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(drift): read session-goal as a prompt source in the work list anchor workList.ts kept its own three-token goal-source list, so an adopted /goal was treated as typed words when deciding whether the window anchor sentence applies. Use PROMPT_SOURCES like every other site. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(web): rebuild the page for the work list goal-source fix Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(intent): name a session's /goal where the log and goal box say none exists The Intent log listed three sources and closed with "No goal available from these sources" over a session that publishes a /goal, and the goal box said only that there was no first prompt to draft from. Both read as a session with no goal. The log now lists the /goal as a source and counts it, and the box says which /goal the session holds. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(web): rebuild the page for the /goal source in the Intent log Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * feat(sessions): publish an excerpt of a /goal longer than the Goal field A /goal condition over the Goal field's 240 characters now carries offered (the bounded excerpt an adoption stores) and cut: true on session_goal. The server resolves offered for adoption and counts the session's /goal as the draft time ahead of the prompts, so the page, the adoption and the store agree on one string and nothing clips on its own. Implements [DRC-4947](https://linear.app/recce/issue/DRC-4947/use-a-detected-goal-until-the-reader-edits-it-and-offer-a-later-one-as) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * feat(intent): use a detected goal until edited and offer a later one as an update A /goal the session set fills the Goal field, marked "Goal detected" with a "From /goal" line, ahead of the prompts and over a session that opened with a command, and Analyze drift adopts it by name. Typing or choosing a prompt replaces it and the line says so. After the reader saves a goal, a newer /goal is offered beside the field with Use this goal and Keep my goal, and never replaces the saved words. A goal over the limit is offered as its excerpt with a note that it was cut. The how-to says where a detected goal comes from. Implements [DRC-4947](https://linear.app/recce/issue/DRC-4947/use-a-detected-goal-until-the-reader-edits-it-and-offer-a-later-one-as) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * docs(intent): record how a detected goal is used and offered Records the owner rulings on using a /goal until edited and offering a later one, the excerpt fields on session_goal, and the reader state the update offer holds. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * docs(intent): inventory the declined /goal update as reader state Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(web): rebuild the page for the detected goal Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(intent): call an untouched detected goal a draft and keep the cut note once it is saved Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * docs(intent): record that a detected goal also reads as a draft Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(web): rebuild the page for the detected goal status and cut note Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * feat(intent): fold Expected outcome into an optional accordion Expected outcome sits under the Goal in an accordion labelled optional, closed until a saved or drafted line, a pending later direction or a departure citing an outcome line is held. It opens on each rise of that condition, so a reader's close holds. Add a line moves inside it. Disclosure gains an openWhen prop for the rise rule. Stories, the first view tests and the how-to are updated. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * docs(intent): record the optional Expected outcome accordion Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(web): rebuild the page for the Expected outcome accordion Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(intent): drop dead CSS rule for the removed lines heading OutcomeLines no longer renders the held-heading wrapper, so the rule never matches. GoalField still uses the other held-heading rules. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(frontend): rebuild the page after dropping the dead lines-heading rule Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(intent): say in the how-to that a level needs an expected outcome Step 1 called the expected outcome optional while the paragraph below said no level without one. Step 1 now states the cost, and the paragraph is shortened to stay within the popover word budget. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(frontend): rebuild the page for the how-to wording Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(intent): keep the how-to inside its word budget Keep the no-outcome-line sentence the docs test pins and trim two words elsewhere in the popover. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(frontend): rebuild the page for the how-to wording Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * feat(reading): give a goal alone a level, and refuse a goal too vague to read An analysis no longer needs an outcome line. With none, the producer prompt reads the goal's own stated end state as the outcome, the level rules treat the Goal row as the one line, and the reading's cutoff says it read against the goal. Rule L7 and its reason stay as a known token for older payloads. The model may instead answer the goal "goal_unclear" before it reads the session. That is a new closed result on the Goal row alone: it takes no citation, publishes every other row as not asked, leaves the analysis with no level (reason goal-unclear), is stored like any reading and still counts against the daily cap. The intent's prompt share rises from 9,216 to 9,728 bytes for the two added instructions. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * feat(intent): warn under the Goal field when the goal is too vague to analyze Draw the refusal where the reader can act on it: the agreed sentence under the Goal field, cleared when the goal is edited or saved again. The Drift card answers a refused goal in one line with no level, quiet rows or Steer back, and a goal alone is answered from its own row. The how-to drops the claim that a level needs an outcome line. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * docs: say a goal alone is read for its own end state, or refused Record the 2026-10-22 amendment under the four-levels ruling and the frontend departure, and restate the promise in the README, promise map and skill. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(frontend): rebuild the page for the goal-alone reading and refusal Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(drift): match goal-only wording, hide the mark on a refusal, name /goal A reading of the goal alone says the goal is the line no check shows, not "a line of your intent". A refusal for a goal too vague to analyze no longer offers Mark as inaccurate, since it sets no level and offers no Steer back. A goal from /goal reads "from /goal" under What the analysis read, and the reading's cutoff no longer says the prompt it came from was not found. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(frontend): rebuild the page for the goal-only wording and refusal fixes Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * feat(goal): find a session's goal in its prompts on a press Add POST /api/goal/find and the goal_find producer behind it. The route is guarded as Analyze is: press, observer_model, navigation and origin checks, the stored pause and the rolling cap all refuse before the prompts are read, and the charge is taken at the model seam. Only the reader's own prompts are sent. A goal is returned only when the model quotes the words it comes from, each quote is verbatim in the prompt it names as Compass sent it, and the model calls the goal clear. Nothing is stored. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * feat(intent): add Find goal beside the prompt list Find goal shows while no goal is saved and no /goal was detected. A press sends one request, shows a busy state, and puts the found goal in the box marked Goal detected, with "Detected from your prompts" and a citation to each prompt it quotes that opens that entry in Full activity. Nothing found, a pause and a spent day are said beside the button and leave the box alone. A saved goal and a /goal outrank a found goal, and an edit replaces it. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * docs: record Find goal Add the decision record, the route and its limits in SECURITY.md and the skill's route table, the module map row, the reader-state row and the how-to paragraph. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(frontend): rebuild the page for Find goal Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * docs(goal-find): say the prompt matches the reading rule instead of applying it Goal finding builds its own end-state wording; it does not import reading.GOAL_UNCLEAR_RULE. Reword the docstring, design record and SECURITY.md to say the wording matches and a test holds it. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(intent): show the quoted words under each cited prompt of a found goal The popover shows a cited entry as the activity list abbreviates it, so a reader could not tell which words of the prompt the goal came from. List the server-verified quotes under the citations, led by the entry number. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(frontend): rebuild the page with the quoted words of a found goal Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * feat(goal): publish the harness's met verdict and test it against the record The latest met verdict joins the session's goal as session_goal.verdict (met, time, masked and bounded reason). A reading tests it with code over the recorded writes and checks and stores the answer as goal_verdict beside the criteria: agrees, disputed or unconfirmed, with closed reason tokens. The verdict never changes a criterion and is not a check the record holds. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * feat(drift): note the harness's goal-met verdict on the Drift card The card says Claude Code's verdict as the harness's claim, with its time and reason, and Compass's check beside it where a reading made one. With no analysis yet it is the claim alone and implies no level. Stories assert the claim only, agreeing, disputed, unconfirmed, newer-than-reading and absent states. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * docs(goal): record that a goal-met verdict is a claim Compass tests Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * test(drift): wait for the record before asserting the level beside a goal verdict Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(frontend): rebuild the page with the harness goal-verdict note Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * docs(goal): place the goal verdict in its own paragraph and give a product reason for met-only Move the harness goal-met sentences out of the Find goal paragraph. State that a not-met verdict is not published because the evaluator repeats it every iteration while the goal is open, replacing the stale not-captured reason. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(drift): match an elided verdict path by its tail and align the verdict note The evaluator writes long paths as ".../tail", which the file matcher rejected, so a reason that named a file read as naming none. Strip the elided head and match the tail. The note now uses the card's own inset class so it lines up with the level and the criteria rows. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(frontend): rebuild the page for the verdict note fix Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(intent): analyze drift reads a found goal as the working goal A goal found from the prompts is the working goal until edited, as a /goal is. It no longer counts as an unsaved edit, so Analyze drift is not refused and Undo changes has nothing to undo. The press stores the found words as typed words, then reads against the revision that minted, adopting nothing. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(frontend): rebuild the page for the found-goal analyze fix Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(drift): read a quoted verdict path that ends a sentence A goal-met reason that quoted a path followed by a closing quote and a period (docs/plans/x.md".) was read as naming no file, so the Drift card said its reason names no file or check. The word trim ran one strip then rstrip("."), so the closing quote shielded the period. Trim in a loop until stable and add curly quotes. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(intent): add a line goes to the empty box already drawn An empty outcome list is drawn as one empty row, and "+ Add a line" then added a second, so typed text sat under a blank row. Adding now focuses a trailing blank row instead of stacking another. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(frontend): rebuild the page for the add-a-line fix Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(drift): dispute a goal verdict the record contradicts, and name why A file the harness's reason or the goal names that a later rm, unlink, rmdir or mv took away now disputes the verdict, with the file and the moment on the card. The removal is read at the press and never sent or published as a fact. Also: a /goal is named "/goal" wherever its source is shown, the "could not be read whole" notice no longer appears for a /goal that was not cut, a found goal groups its quotes under one entry number, and a goal-only reading that finds nothing says what check would let a level be drawn (owner decision, evidence floor kept). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(frontend): rebuild the page for the verdict, provenance and citation fixes Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(drift): name the file, not its folder, when both are removed at once A verdict whose file was removed by `rm file && rmdir folder` records both removals at one time, and the dispute named whichever came first. On a tie it now names the file the verdict relied on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(goal-find): clear the in-flight mark before the reply is written The mark was cleared in a finally after the answer went out, so a press sent the moment the previous answer arrived could be refused as in-flight (409). Measured in CI on 2026-10-23, where the spent-day test sends presses back to back. Both reply paths now clear the mark first, and a test checks the mark is gone when each reply is sent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(goal): read a clear by its sentinel and accept the documented 4000-character limit Measured on Claude Code 2.1.309: clearing an active goal writes the set sentinel with met true. It was read as the evaluator's verdict, so an interactive clear, which writes no other record, showed the cleared goal as marked met. A condition between 2000 and 4000 characters, accepted by the harness, published nothing because the cap borrowed the record reader's message cap. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * docs(captures): record /goal clear, replace, not-met, impossible, resume and interactive shapes Eight throwaway 2.1.309 runs, field names and closed vocabulary only. The README row says what each shows and what was not captured; the security and design records state the 4000 limit, the clear marker and what a reader sees for a goal set before the 8 MiB cold read. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(goal): read only the two measured met values on a goal_status sentinel A sentinel whose met was absent, null or not a bool was read as a clear and wiped a live goal. Only met false (set) and met true (clear) were measured; any other value is now ignored, as before the clear fix. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(session): name a Claude session by the goal it holds, not the /goal it opened with The session name came from the first prompt, so a replaced or cleared /goal opener named the session by a condition it no longer held. A held goal now names it; with none held, a /goal opener is skipped and the next real prompt names it. A generated ai-title still wins, and sessions without /goal are named as before. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * test(session): prove every surface names a replaced-goal session by its held goal Stories cover the Sessions row, the tab, the crumb and the heading for a session that replaced its /goal, and a session without /goal keeping its name. SKILL.md and the runtime map state the naming order. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(session): keep the /goal opener as a name when no held goal is authoritative session_goal reads at most turn_scan_max_bytes from the end, so a goal set before that window is not seen and its absence proves nothing. The first-prompt fallback now skips a /goal opener only when the file fits the window. Also corrects the session_title docstring to the ai-title, held goal, first prompt order. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(session): say a command-opened session was not named, not that no title was published A session whose only prompt was a /goal that has since ended published that prompt; Compass declines to name a session by a command. The session heading, tab title and breadcrumb now say "No name: the session opened with a command" instead of "Title not published". Sessions rows keep the published-title wording. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(frontend): rebuild the page Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(session): keep a cleared /goal from naming the session when the transcript outruns the read window The goal read records whether it saw the whole file or any goal event, and the opener is skipped only then; a mid-file read that saw nothing keeps it as the last resort. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(session): word a command-opened session the same on every surface that names it The Sessions row said Title not published where the heading, tab and breadcrumb said the session opened with a command. Differential tests restate the recorded phrase for those rows only. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(frontend): rebuild the page Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * docs(captures): record that a goal ends when Claude Code gives up on it A real Claude Code 2.1.309 run showed the goal is ended after the failed record: a later bare /goal and /goal clear both print the fixed "No goal set" words and write no goal record, and a goal set afterwards carries no link to the earlier one. Shapes and fixed words only. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * feat(session): publish when a /goal was given up, cleared or replaced Claude Code ends a goal after it gives up on it (measured), so a give-up now ends the held goal and is published beside it as session_goal_gave_up with its time and masked reason, never under verdict. A clear is published as session_goal_cleared, and a goal that followed another carries earlier {how, at} (replaced, met or gave-up) without the earlier words. Absent means unknown: a cold read that starts mid-file publishes none of it. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * feat(frontend): say when a /goal was given up, cleared or replaced The Drift card shows a give-up as the harness's claim, never met and never a level or a check. The Intent card says under the Goal field what became of an earlier /goal, and that a clear left no goal; where the session opened with /goal the existing sentence carries the clear, so it is said once. None of it shows while the update offer is on screen. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * docs(session): record that a given-up, cleared or replaced /goal is said to have ended A dated amendment in the reading design record, the security note under the session history store, the how-to paragraph and one sentence in the skill body. The earlier lines that called a failed verdict neither a verdict nor an end now point at the measured result. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * test(frontend): share the saved-goal setup between the goal stories Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(frontend): rebuild the page Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(frontend): keep the cleared /goal note when a chosen prompt hides the opened-with sentence The note deferred to the opened-with-/goal sentence whenever that sentence had text, but the sentence is not drawn over a drafted box, so a chosen prompt left the clear said nowhere. Also move the noDraftWhy comment back above it. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(frontend): rebuild the page Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(frontend): date the earlier-goal notes and name Claude Code in the give-up claim The earlier-goal and cleared notes on the Intent card now use the dated clock, as the Drift notes do, so an event on a previous day no longer reads as today. The Drift give-up claim names Claude Code rather than the payload harness label, matching the Intent card. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(frontend): rebuild the page Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(frontend): name Claude Code in both Drift harness claims and story the cleared /goal note The goal-met claim used the payload harness label ("Claude") while the give-up claim said "Claude Code". Both now name the product. Add a story proving the cleared note shows after a prompt is chosen over a session that opened with /goal. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(frontend): rebuild the page Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(frontend): name the prompt draft under a cleared /goal note The cleared note sat directly above a Goal field pre-filled from a prompt, so it could read as describing the draft. Over an untouched prompt draft it now ends "; the draft below is your first prompt" (or your latest prompt, a prompt you chose, a goal found in your prompts). Typed words and an empty box keep the plain sentence, and the update offer still suppresses it. Implements [DRC-4957](https://linear.app/recce/issue/DRC-4957) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(frontend): rebuild the page Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * test(frontend): prove the cleared note yields to the update offer and names a found goal The offer test now uses a saved goal older than a newer /goal, so goalUpdate is non-null and the replaced note would otherwise show; it fails without the suppression. The found-goal clause gets a unit test and a story, including that editing the box drops it. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * feat(frontend): move the goal hint under the box and the source line above it The Intent lede becomes a hint under the Goal textarea, beside the count, and reads "Write what should be true when this session is done. Compass checks the session's work against it and never writes into the session." The goal source line moves from beside the count to directly above the box, under any ended note, and says what the words are: "Drafted from your first prompt", "Your edit of your first prompt", "From your /goal at 11:53", "Found in your prompts at 23:11", "You typed this". The cut suffixes name the real goal limit. The cleared note no longer names the draft, since the source line directly under it does. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(frontend): rebuild the page Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(frontend): keep the Goal label whole at phone width and align the proofs with the new source line The Goal label no longer breaks mid-word when Find goal and Use your prompt squeeze the heading row: the label does not shrink or wrap, and the row wraps at 760px and below so the buttons drop beneath it. A story at 400px proves the label sits on one line. The reader-state record and the on-demand editor proof now use the source line's new wording. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(frontend): rebuild the page Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * feat(frontend): show the summary's phases collapsed by default Every phase of What the session has done now starts closed, including one that holds a departure. The opening paragraph stays open, and the departure pills and failed-run count stay on the phase heading. A phase the reader opens stays open through later boards. The departure card's line that names the phase holding its evidence now opens that phase before focusing its heading, so the jump lands on visible lines. Records the reversal of "Phases arrive open" as a 2026-10-23 owner amendment and updates the reader-state row. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(frontend): rebuild the page Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * docs(readme): say the summary phases start closed The README still said a phase opens with its lines and cites, which you can fold. Phases start closed since the last change, and a reader opens the ones they want. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * feat(sample): save the sample session a goal alone and read it again The sample saved a goal and an expected outcome that said the same thing, so its Drift card showed two departures on the same evidence. It now saves one goal written as an end state, with a new reading made against it. The stored summary is the earlier one, kept. The capture drops the cutoff sentence about unsaved outcome lines, and a test holds the intent to a goal alone. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * feat(frontend): say how to reach the sample's page with your own session The sample banner now lists the steps in order: open a session, set its goal, press Analyze drift, read the departures and use Steer back. The tour drops every expected-outcome reference and matches the new fixture and the closed summary phases. The ended-session notice says what saving now does and what Analyze still uses. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(frontend): rebuild the page Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(reading): drop the unsaved-outcome clause from a goal-only reading A goal-only reading said "Read against your goal; no expected outcome lines were saved." Noting the absence of an optional field tells a reader nothing, so it now says "Read against your goal." A reading stored before keeps its stored sentence. The ended-session journey proof asserts the new notice. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * feat(sample): make the summary and the reading in one run The kept summary read as made from a replaced record, so the sample told a reader to summarize again. The summary and the reading are now made together from the same transcript, the sample-only cutoff rewrite is gone, and the tour and the sample records match the new capture. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(frontend): rebuild the page Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * feat(frontend): show each cited entry in its own words on the Drift card A departure card and the claims row draw every cited entry as one line in its own words with its number, and drop the Evidence and Source folds that repeated the same entries. The stored why and the harness limit move inline. Implements [DRC-4960](https://linear.app/recce/issue/DRC-4960) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * docs(drift): record that the citations are the source on the Drift card Adds the 2026-10-23 owner amendment, and brings the sample tour and the skill body in line with a card whose cited entries speak for themselves. Implements [DRC-4960](https://linear.app/recce/issue/DRC-4960) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(frontend): rebuild the page Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(frontend): draw every cited entry in its own words and drop the last Evidence fold Quiet goal and outcome rows and a departure's titled entry now use the same cited line as the claims row. The Evidence fold on quiet rows is gone; its status qualifier, why, detail and limit draw in view. Stories assert no Evidence or Source button on any row. The amendment no longer claims that HOW_TO_USE.md was updated. Implements [DRC-4960](https://linear.app/recce/issue/DRC-4960) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * build(frontend): rebuild the page Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> --------- Signed-off-by: Jared Scott <jared.scott@variable.team> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…ated pull requests count as evidence (#643) * chore(drift): open the Haiku live monitor branch Signed-off-by: Jared Scott <jared.scott@infuseai.io> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(reading): amend DEC-15, DEC-26 and DEC-27 so the Live monitor may call Haiku Record the owner's 2026-10-23 ruling as dated amendments: cadence evaluation for the Live monitor only, while the session is viewed; the four follow-up rulings; the lane, caps, TTL, stops and reload decisions; Analyze cancels a tick without refunding its spend (decided). DEC-16 and DEC-26 item 5's "raises nothing" stand. The live monitor row's prose in the reader-state inventory now says the switch drives a server lease. No existing heading is renamed. Implements [DRC-4961](https://linear.app/recce/issue/DRC-4961) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * feat(monitor): check a monitored Claude Code session with Haiku about once a minute Add the server-callable check behind the Live monitor and its policy, with no route that starts it yet: - a monitor model setting (--claude-monitor-model) and validator that admit only an explicit Haiku id, defaulting to claude-haiku-5-5; the reading validator and its Sonnet floor are unchanged - live_monitor: a window per monitored session, spacing of at least 60 s, the shared reading slot, a skip that costs nothing for an unchanged transcript, a closed reply shape held to the model-free level's floor, provenance on every tick, and cancel by Pause and by an Analyze press - the monitor's own ledger and caps in reading_policy (30 ticks per session per window, a rolling 24 h cap across the board), apart from Analyze's - a monitor notice kind with its "What is sent" copy - a compass-release pre-flight item for bumping the Haiku default Implements [DRC-4962](https://linear.app/recce/issue/DRC-4962) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * feat(checks): count pnpm shorthand for a closed runner as a check `pnpm vitest run X` now reads as the same check `pnpm exec vitest run X` does, including a lone call piped to an output filter. A pnpm word that is not a closed runner stays unread. Recorded as a dated DEC-23 amendment. Implements [DRC-4970](https://linear.app/recce/issue/DRC-4970) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * feat(drift): read a created pull request and a used skill as evidence A Claude Code session that created a pull request now publishes a pull request fact read from the structured `gitOperation.pr` on the shell result (repository, number, URL, time), and one that launched a skill publishes the skill's name. Neither reads command text, output or arguments. A reading is sent both under the tool-output grant and may cite them as consistent, the goal-met verdict check agrees on a reason that names a created pull request, and the Drift card's note names the pull request it confirmed. Recorded as dated amendments to the closed lists and the verdict amendment, with a shape-only capture taken against a stub `gh`. Implements [DRC-4969](https://linear.app/recce/issue/DRC-4969) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(drift): disclose pull request and skill evidence and keep it out of cap artifacts The consent sentence now names the repository and number of a created pull request and the names of skills used, so a changed sentence asks again. Skill and URL shapes are matched whole, dot-only repository segments are refused, a created pull request is listed beside the entry cap and reserved like a pass, skills rank after every counted entry so they cannot evict a written path, the check scan sentence counts both, and the verdict check reads "PR 7", "PR (#7)" and lists of pull requests. Contract fixtures are regenerated from the server. Implements [DRC-4969](https://linear.app/recce/issue/DRC-4969) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * chore(build): rebuild the page bundle for the evidence fixes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * docs(reading): rule the Haiku level's own None or low floor and correct the monitor amendment Add the owner's 2026-10-23 floor ruling as its own amendment under DEC-26: a model None or low stands when Haiku cites a turn it was sent and the estimate shows no failed check and no unsettled later direction; no passing check does not block it; the live-only shell blocker is not included. Correct the amendment bullet that said every remaining decision was as recommended, say that consent under the widening means "not paused", and mark the reader-state row's server-lease sentence as applying once the switch is rebuilt. Implements [DRC-4961](https://linear.app/recce/issue/DRC-4961) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(monitor): hold the Haiku level to its own floor and give the lease a clock - the floor works both ways: a raised estimate is published over a lower model level, and a model None or low stands only with a cite and no failed check or unsettled later direction - a success word in the reason is a verdict, however qualified - each check re-sends the recent window beside its new turns, so a quiet turn cannot flip the level - the notice and the disclosure name the commands of checks and the paths of files written, those rows are dropped where the destination cannot be named, and only this session's facts are sent - the lease gets begin_window holders and renewal, a window accessor with the banner and deadline, an ended input, and an end that cannot be followed by a launch; a window that runs out drops its level - an Analyze press waits long enough for a cancelled tick, turns new ticks away while it takes the slot, and retries once - the in-flight limit counts one board, the prompt cap is 6,000 characters, and a ledger of its own cannot be combined with a job marker Implements [DRC-4962](https://linear.app/recce/issue/DRC-4962) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Jared Scott <jared.scott@variable.team> * feat(monitor): hold a Live monitor lease on the server and tick it while the session is viewed Add POST /api/live-monitor with start, beat, confirm and stop, and a lease table with a ticker that calls the Haiku check for a lease that is due: - one lease per Claude Code session, held by any number of tabs, in memory only, so a restart starts with no lease - a visible tab that stops beating is gone after 50 s with no stop post and no beacon; a hidden tab keeps the lease and pauses the checks - the TTL clock is the server's: the question stands from 20 to 30 minutes, Yes resets it, No or no answer ends the lease - the lease ends for ended, left, paused, unanswered, declined, stopped or cap, and the session's end is read from the row after the overlay pass - start is refused for an ended session, another harness, the sample, paused model calls and --no-observer-model - Pause ends every lease and kills a check in flight; closing the server stops the ticker - the state is published on the focused context's sources.work and on no row - SECURITY.md names what the monitor sends and the CLI-cache exposure at cadence Implements [DRC-4963](https://linear.app/recce/issue/DRC-4963) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019324xLBLyAdr2QHFngRAro Signed-off-by: Jared Scott <jared.scott@variable.team> * feat(drift): drive the Live monitor switch from the session view and disable it once the session ends The switch now drives the server's lease instead of a key in the browser: - turning it on posts start, a visible tab beats about every 20 seconds, a hidden tab says so once and stops, and turning it off, leaving the route or moving to another session posts stop, with a beacon as the page goes away - a reload shows it off until it is pressed, and the live-estimate storage key is retired - the pill and the card show the Haiku level labelled Live monitor · Haiku, an Analyze reading outranks it, and the estimate shows whenever the monitor has no level - it is aria-disabled with its reason once the session has ended or while model calls are paused or off, and flips to off with a note if the session ends while it is viewed - each end the server reports leaves a note in the Drift card, the monitor's own limit worded apart from Analyze's - the hint names the model call, the cadence and the provider - the sample session shows it on and never takes a lease The two recorded answers it departs from are named in the design record and neither golden is re-recorded. Implements [DRC-4964](https://linear.app/recce/issue/DRC-4964) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019324xLBLyAdr2QHFngRAro Signed-off-by: Jared Scott <jared.scott@variable.team> * feat(drift): ask "Do you still want to monitor this session?" after 20 minutes and turn the monitor off if nobody answers The server publishes the question from 20 minutes after the monitor started, or after the last Yes, until 10 minutes later; the page counts down to that time on the clock it holds: - Yes posts confirm yes, which resets the server's clock, and the next question comes 20 minutes on; No posts confirm no and turns the monitor off - with no answer by the deadline the monitor turns off with a note saying why, and beats no more - a lease that ends another way while the question is up clears it and shows that reason's note instead - an answer from any tab clears the question in every tab, because the next state the server publishes carries no deadline - the question is announced through the live region when it opens and is reached by keyboard - the timings are the server's config; the shipped defaults are 20 and 10 Implements [DRC-4965](https://linear.app/recce/issue/DRC-4965) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019324xLBLyAdr2QHFngRAro Signed-off-by: Jared Scott <jared.scott@variable.team> * chore(build): rebuild the page bundle for the Live monitor lease, switch and question Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019324xLBLyAdr2QHFngRAro Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(monitor): never tick a hidden tab, keep one holder set, and answer a start without telling which sessions exist - a start can say the tab is hidden, and a hidden holder is never ticked - a beat or an answer from a tab that did not start cannot join the lease, so the holders here and in the check stay one set - a check that cannot run is found before its inputs are built - an ended session, one not on the board and one the board lists twice are refused in the same words, and a twice-listed session keeps its lease - the ticker exits when no lease remains and returns with the next start, and a table made after the server closed starts none - the route-count pin counts hyphenated routes, and SECURITY.md counts twenty ungated routes Implements [DRC-4963](https://linear.app/recce/issue/DRC-4963) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019324xLBLyAdr2QHFngRAro Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(drift): never tick a hidden tab from the page, keep the estimate after a pause or cap, and settle the question on the server's word - the page asks whether the tab is hidden: a start from a hidden tab says so, each beat says what is so now, and a tab hidden by the time the start answers beats once as hidden and holds the lease without a visible cadence - a start the reader left before it answered is not aborted, and its lease is stopped when it does answer - a pause or the monitor's own limit leaves the model-free estimate as the level until the reader leaves or turns it on again; every other end shows nothing live - leaving a session and turning the switch on forget the old lease, so its question and level cannot reach the new monitor - at the question's deadline the page beats once and acts on the server's answer, so another tab's Yes is not undone - the question is a labelled region and focus returns to the switch, or to the control that opens it, after an answer; the pill names the monitor - copy: the hint and the monitor's line say what is asked and of whom, and the left, declined and cap notes and the unreachable refusal read as the owner worded them Implements [DRC-4964](https://linear.app/recce/issue/DRC-4964) Implements [DRC-4965](https://linear.app/recce/issue/DRC-4965) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019324xLBLyAdr2QHFngRAro Signed-off-by: Jared Scott <jared.scott@variable.team> * chore(build): rebuild the page bundle for the Live monitor fixes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019324xLBLyAdr2QHFngRAro Signed-off-by: Jared Scott <jared.scott@variable.team> * docs(monitor): say the Live monitor calls Haiku, what it sends and costs, and every way it stops Reconcile the docs with the model-backed Live monitor, the lease, the switch and the question, and with the pull request and skill evidence: - README, the promise map, HOW_TO_USE, the skill and SECURITY.md say it asks Haiku about once a minute while a session is viewed, name what is sent and to whom, its own caps and each stop, and say its accuracy check has not been run yet - Pause model calls lists the monitor, in the promise paragraph and its duplicate in the 2x2 items, and in a new dated amendment under the Pause amendment, whose heading is unchanged - SECURITY.md names the monitor's model setting and that the estimate stays as its fallback; the skill documents the model flag and the lease route - the reading's evidence lists name a created pull request and a used skill - the estimate's docstrings say they are the monitor's model-free fallback - a documentation test holds that no page or docstring says the monitor calls no model Implements [DRC-4966](https://linear.app/recce/issue/DRC-4966) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019324xLBLyAdr2QHFngRAro Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(drift): let a pull request or skill line say it was successfully done, and keep numbers stable A consistent line resting only on a created pull request or a used skill no longer has "successfully" or "confirmed" read as a stated verdict, which had withdrawn the goal line on a live session. The words stay a verdict beside any check, and every other success word still withdraws it. Pull requests and skills take their places in a message's group from 1,000, so no check, file or launch already numbered shifts when either joins the group. Implements [DRC-4969](https://linear.app/recce/issue/DRC-4969) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019324xLBLyAdr2QHFngRAro Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(drift): number a pull request or skill in time order like any other entry Reverts the 1,000 place offset: a citation reading 4.1001 is worse for a reader than the shift it avoided, and summaries and readings never read ordinals. Implements [DRC-4969](https://linear.app/recce/issue/DRC-4969) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019324xLBLyAdr2QHFngRAro Signed-off-by: Jared Scott <jared.scott@variable.team> * feat(drift): let an analysis level rest on a created pull request or a used skill An Analyze reading may draw None or low with no passing check when every Consistent outcome line cites a recorded harness fact, a created pull request or a used skill, beside the floor's unchanged blockers. The agent's words alone still never lift the level. Recorded as a dated DEC-26 amendment extending the monitor's floor, taken under the owner's standing instruction to act on recommendations. Implements [DRC-4969](https://linear.app/recce/issue/DRC-4969) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019324xLBLyAdr2QHFngRAro Signed-off-by: Jared Scott <jared.scott@variable.team> * chore(build): rebuild the page bundle for the analysis floor change Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019324xLBLyAdr2QHFngRAro Signed-off-by: Jared Scott <jared.scott@variable.team> * fix(drift): drop the no-model-assessment line under a Live monitor level A Haiku level is a model assessment, so the card no longer says there is none. The line stays under the estimate. Also pins that a tab shown again beats visible at once. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019324xLBLyAdr2QHFngRAro Signed-off-by: Jared Scott <jared.scott@variable.team> * chore(build): rebuild the page bundle for the monitor card line Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019324xLBLyAdr2QHFngRAro Signed-off-by: Jared Scott <jared.scott@variable.team> --------- Signed-off-by: Jared Scott <jared.scott@infuseai.io> Signed-off-by: Jared Scott <jared.scott@variable.team> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.
Summary
DRAFT. Do not merge to main until the owner signs off.
Redesigns the session page into one column: Intent, What the session has done, Drift, then a collapsed Full activity. The new card shows a deterministic outline of the session on Claude Code and Codex with no model call, and a cited, stored model summary on Claude Code. Each departure is a card saying what happened and why it is drift.
Model calls a reader starts (Analyze drift, goal summaries, session summaries) now run without a consent step. The first call of each kind shows a one-time notice naming what is sent and to whom. Pause model calls stops all of them; Turn off summaries stops summaries only and is disabled while paused. Unasked drift checks stay off by default. The owner's rulings are recorded in
docs/design-session-summary.md(DEC-28) andSECURITY.md.The sample session is replaced by a milestone-length run with its own stored summary and reading, and the tour is rewritten.
What is new
session_source,session_outline: an ordered, paged, bounded read of a session with stable fact ids and fingerprints, and the outline built from it.session_summary: the producer (16 KiB windows, immutable blocks, code-assigned bullet kinds, the completion check on the summary's own voice).summary_store: a store of its own that survives Discard everything, with redaction in and out and an aggregate bound.summary_jobs: the multi-part job with its own grant, ledger, per-part receipts, ceilings (37 calls, 768 KiB, 600 s) and rolling cap (200 per 24 hours).How it was checked
Test plan
AGENTS.md, serially: ruff, ruff format, mypy,validate_plugins.py, version-guard diff, biome, typecheck,test:styles,pnpm test, Storybook build and 312 stories,test:dev,build:check, client fixtures check, dashboard suite (5295), scripts suite (1614)claude plugin validate ./compass --strictandagy plugin validate ./compasspass (agy warns thatSKILL.mdis 112,841 bytes and only the first 24,000 are loaded)Decisions the owner made on 2026-10-20
Decisions the owner made on 2026-10-21
Known limits
test_lifecyclehangup, times out under heavy load and passes alone. A second test,test_default_on_reader_permission_never_authorizes_an_unasked_call, failed once in a three-worker run and did not reproduce in three reruns; the owner had it removed instead of chasing it.compass-summaries.jsonfrom a developer build reads as unavailable until it is deleted.Implements DRC-4902
Implements DRC-4903
Implements DRC-4904
Implements DRC-4905
Implements DRC-4906
Implements DRC-4907
Implements DRC-4908
Implements DRC-4909
Implements DRC-4910
Implements DRC-4911
Implements DRC-4912
Implements DRC-4913
Implements DRC-4914
Implements DRC-4915
Every path, not only the finished analysis
Nine walks of the built page on real sessions, one per path a reader takes (a finished session, a running one, updating the intent, a later direction, Steer back, Mark as inaccurate, Discard everything, and creating and deleting a summary), are recorded in
docs/redesign/.docs/redesign/recommended-changes.mdmerges them. They are grouped into the milestone Session page: every path a reader takes, not only the finished analysis, and that work lands on this pull request:Implements DRC-4919
Implements DRC-4920
Implements DRC-4921
Implements DRC-4922
Implements DRC-4923
Implements DRC-4924
Implements DRC-4925
Implements DRC-4926
Implements DRC-4927
Implements DRC-4928
Implements DRC-4929
Implements DRC-4930
Implements DRC-4931
Implements DRC-4932
Implements DRC-4933
Implements DRC-4934
Implements DRC-4935
Implements DRC-4936
Implements DRC-4937
Implements DRC-4938
Implements DRC-4939
Implements DRC-4941
🤖 Generated with Claude Code