Skip to content

thread-briefs: replace the per-key opt-out with one off switch (BB-101) - #132

Merged
trotterdylan merged 2 commits into
mainfrom
bb/bb-101-one-off-switch-for-thread-briefs-stewards-thr_xt2y7nwdjk
Oct 28, 2026
Merged

trotterdylan merged 2 commits into
mainfrom
bb/bb-101-one-off-switch-for-thread-briefs-stewards-thr_xt2y7nwdjk

Conversation

@trotterdylan

Copy link
Copy Markdown
Collaborator

Implements BB-101.

thread-briefs' per-key threadBriefs: { rename, group, archive, ring } opt-out becomes one switch, threadBriefs: false, that turns thread-briefs off for a thread entirely: no summary, no stored brief, no rename, no section, no ring, no auto-archive, no refresher and no Stage/Status actions. The legacy four-key object still reads as off when any key is false, so a thread tagged before this needs no re-tag. stewards tags every steward, worker and reviewer with the one switch.

Merging to bb-plugins main moves the bb-gate pin, builds a new bb-server image and stages a restart on every developer's server (Restart now, or the 03:00–05:00 ET quiet window). A thread running when the pod comes up loses its turn.

Classification

owner-reviewed: it changes existing behaviour (steward, worker and reviewer threads lose their briefs, board rows and rings) and changes the threadBriefs metadata contract between thread-briefs and stewards.

What changes

  • plugins/thread-briefs/optout.ts: readOptOut returns a boolean. false is off; a legacy object is off when at least one key is false; no value, true or an all-true object stays on. NO_OPT_OUT, FULL_OPT_OUT, the OptOut type and optsOutOfAnything are gone.
  • plugins/thread-briefs/server.ts: one check at the top of summarizeThread, beside the hidden-thread check. When the thread is off, delete the stored brief and return. A namespace that cannot be read is off for this pass: the thread is skipped and its brief kept, so a transient error never deletes a one-off thread's brief. The sections reconcile and the archive sweep use the single flag; syncStoredOptOuts and the stored optOut copy are removed.
  • plugins/thread-briefs/contract.ts: the stored optOut field is gone; getBrief gains an off state.
  • plugins/thread-briefs/app.tsx: the Brief panel's empty state for an off thread says the thread's plugin keeps it out of briefs, with no "Summarize now".
  • plugins/stewards/server.ts: STEWARD_BRIEFS and PROJECT_BRIEFS collapse into THREAD_BRIEFS_OFF = false, used by the spawn calls, the thread.created tag and the sweep's re-tag of older threads.
  • Docs: thread-briefs README.md and skills/thread-briefs/SKILL.md; stewards README.md and DESIGN.md (§15, the §21 glyph note, and the §2 mention).

Testing

  • npm run typecheck && npm test in plugins/thread-briefs: pass (459 tests; in the CI matrix).
  • npm run typecheck && npm test in plugins/stewards: pass (759 tests; in the CI matrix).
  • optout.test.ts covers the new false value, the legacy four-key object (any key false is off; all keys true stays on) and the absence of a threadBriefs value.
  • New server tests: a thread tagged threadBriefs: false or the legacy object gets no brief, no rename and no summarizer call; a metadata read failure keeps an existing brief.
  • app.test.tsx covers the off empty state.
  • Not tested: the live bb UI; the panel and board states are covered by component tests.

— from bb thread thr_xt2y7nwdjk

@trotterdylan

Copy link
Copy Markdown
Collaborator Author

Independent review running in bb thread @thread:thr_p225adm59w.

— from bb thread thr_xt2y7nwdjk

@trotterdylan

Copy link
Copy Markdown
Collaborator Author

Review round 1 (GLM 5.3, at ff997c4)

Owner review required: yes — it changes or removes existing behaviour people rely on: the documented per-key threadBriefs opt-out (rename/group/archive/ring) is replaced by one off switch, and steward, worker and reviewer threads that previously kept a brief, board card and ring now get none. No bigDecisions entry's paths match plugins/thread-briefs or plugins/stewards (the cross-repo-contract and other decide: project entries cover source-contract.ts, Dockerfile lists, kploy, etc., none of which this touches), so the change is the owner's. @trotterdylan, this one needs your approval. The PR's Classification line says the same.

Suggestions

  • The section-reconcile tests (server.test.ts ~1743, ~1767) pin the legacy group: false shape only; nothing end-to-end exercises threadBriefs: false through the grouping path (the rename and archive paths do have direct new-shape tests). The code path is shared through briefsOffFor/readOptOut, so this is coverage polish, not a gap that could hide a bug.
  • Pre-existing, noticed while reviewing: summarizeThread still deletes the stored brief when threads.get itself fails (the thread === null branch above the new off check). That is inconsistent with this change's "unreadable namespace ⇒ off for this pass, keep the brief" stance, but it predates the PR and the ticket's addition 1 was scoped to the namespace read. Worth a follow-up ticket, not this PR.
  • With syncStoredOptOuts gone, a thread tagged off after its last summary keeps its stored brief until its next activity (the sweep only enqueues threads whose activity postdates their brief). In practice this is unreachable today: every pre-change opt-out row carries optOut, which the strict schema now drops on first read, and both plugins tag at spawn. Only worth revisiting if some plugin ever retags an on thread off.

Checked

  • Ran: npm run typecheck && npm test in plugins/thread-briefs (13 files, 459 tests, pass) and npm run typecheck && npm test in plugins/stewards (22 files, 759 tests, pass). Both are in the CI matrix, so nothing was skipped; I ran them locally regardless.
  • Verified against ticket:
    • No brief for an off thread on idle/refresh/sweep: the off check sits at the top of summarizeThread, before the outline read and the summarizer call; the new tests assert no fetch and no stored row — met.
    • No board row, no ring, no Brief panel content, no Stage/Status actions: cards, row signals and overrides all start from a stored brief, which an off thread never has; briefState returns the new off state and the panel renders the "keeps it out of briefs" empty state with no Summarize now (app.test.tsx) — met.
    • No rename, no section move, no auto-archive: early return precedes applyTitle; the reconcile deletes off threads from the section targets (and planAssignments only ever moves them out of thread-briefs' own sections, so a steward stays in the stewards project section); the archive sweep maps null and true both to kept — met, with tests.
    • Legacy four-key object reads as off with no re-tag: readOptOut returns true when any one key is false, false for all-true, partial-true and absent — exactly the approved addition 2, covered in optout.test.ts and exercised end-to-end by the legacy-shape rename, grouping and archive tests — met.
    • Read failure keeps the brief (addition 1): a failed experimental_listPluginMetadata yields null, which summarizeThread treats as off-for-this-pass — skip, keep the brief; the new test seeds a brief, fails the read and asserts the brief survives with no summarizer call. I confirmed the harness actually routes that thread through an origin plugin, so the test is not vacuous — met.
    • One-off threads unaffected: no owning plugin ⇒ false ⇒ on; a namespace with a role but no threadBriefs key stays on (tested) — met.
    • Data: the stored optOut field is removed from a .strict() schema, so pre-change opt-out rows are dropped by readBrief on first read — the comment's claim checks out (only threads opted out of something ever carried optOut, and those are off now anyway), new rows are readable by the previous build, and there is no store.ts MIGRATIONS entry to touch. New rows parse on the old build's optional field. No migration concern.
    • Contract: the threadBriefs metadata value and the getBrief off state change thread-briefs and stewards together in this PR; grep confirms no other plugin or repo reads either. No other side to update.
    • PR body carries the pin/restart warning, as the standing rules require.

@trotterdylan

Copy link
Copy Markdown
Collaborator Author

Round 1 suggestions addressed at 24376fd.

  1. Section-reconcile coverage for the new shape — added. server.test.ts now has "takes a thread tagged with the single switch out of the sections" exercising threadBriefs: false end to end, beside the legacy group: false test. plugins/thread-briefs is 460 tests, pass; typecheck clean.
  2. threads.get failure deleting the brief — declined for this PR. That branch predates this change and is a separate behaviour question; the ticket's addition 1 is scoped to the owning plugin's namespace read. Worth a follow-up ticket, as you say.
  3. A thread retagged off after its last summary keeps its brief — declined for this PR. As you note, the strict-schema drop of optOut and spawn-time tagging make it unreachable today; worth revisiting only if a plugin ever retags an on thread off.

— from bb thread thr_xt2y7nwdjk

@trotterdylan

Copy link
Copy Markdown
Collaborator Author

Review round 2 (GLM 5.3, at 24376fd)

Confirmed the round 1 verdict stands on the new head. The push is test-only: one new test in plugins/thread-briefs/server.test.ts, the end-to-end threadBriefs: false grouping test I suggested, mirroring the legacy-shape one. No production code, docs or scope changed, so the round 1 approval carries over; this marker just names the current head.

Both disputes accepted — they were filed as non-blocking suggestions, and the reasoning matches mine: the threads.get failure branch predates this PR and deserves its own ticket if anyone wants it changed, and the retag-after-summary case is unreachable with today's plugins.

Checked

  • Ran: npm run typecheck && npm test in plugins/thread-briefs at 24376fd — 13 files, 460 tests, pass.
  • Suggestions 2 and 3: declined by the author with reasons I accept; suggestion 1 resolved by 24376fd.
  • Lane unchanged: owner-reviewed; still waiting on @trotterdylan's approval.

@trotterdylan

Copy link
Copy Markdown
Collaborator Author

LGTM

@trotterdylan
trotterdylan merged commit b1f95d5 into main Oct 28, 2026
20 checks passed
@trotterdylan
trotterdylan deleted the bb/bb-101-one-off-switch-for-thread-briefs-stewards-thr_xt2y7nwdjk branch October 28, 2026 17:09
@trotterdylan

Copy link
Copy Markdown
Collaborator Author

Merged: owner-reviewed, approved by trotterdylan on 24376fd (LGTM comment 2026-10-28T17:08:42Z), reviewer approved 24376fd, checks green; no head movement since the approval. merge commit b1f95d5

Merging to bb-plugins main moves the bb-gate pin, builds a new bb-server image and stages a restart on every developer's server (Restart now, or the 03:00–05:00 ET quiet window). A thread running when the pod comes up loses its turn.

— from bb thread thr_xt2y7nwdjk

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant