Dialogue · The toolbox · The lifecycle
← The orthogonal toolbox — the architecture

The tool lifecycle — open · close · reveal

The owner's state × trigger × setting matrix(2026-07-25)and the design session it produced. Every instrument turns out to have up to three phases, not two — and the axis that was missing is when the contents become visible, which is separate from when the collecting stops. This page is the design record and the work breakdown; toolbox.html keeps the architecture, toolbox-build.html tracks execution.

The discovery, in one line: v613 shipped「Close now stops the collection — it does not reveal」for the deposit. That was not a deposit quirk. Close and reveal are different events for every tool, and the settings that drive them are the toolbox's fourth, fifth and sixth axes.

1 · Three phases

THE STATE MACHINE — EVERY INSTRUMENT COLLECTING input accepted · visibility dial rules who sees close trigger CLOSED · SEALED input shut · contents still hidden reveal trigger REVEALED contents public · enter the transcript THREE SHAPES — WHICH PHASES A TOOL ACTUALLY USES FUSED · close = reveal poll · open roll · deposit(on close) SPLIT · sealed after close Sealed Roll · Sealed Spin · the note NO CLOSE · nothing to collect card dealing — dealt, then revealed THE TWO SPEAKING MOMENTS(both legitimate, each keeps its existing rule): · CLOSE releases a blocked panel — it speaks having seen WHO acted, not WHAT(the symmetry ruling ①) · REVEAL delivers content — it enters history and the transcript HERE, never before(the read-path law, along time) When the two are the same moment you get one beat, as today. When they are split you get two — which is the sealed-roll drama:「都摇完了」…(tension)…「开!Dan 6, CW 3」.
Close is about input; reveal is about output. Conflating them is what made「Close now」ambiguous before v613.

2 · Six axes

Three are shipped(T8's presence properties). Three are new — and the first of them, visibility, is the one that was hiding inside the「Open」column of the matrix: it isn't a trigger at all, it is who sees others' contributions while collecting.

axisvalues(default first)status
visibility(while collecting)all · contributors-only · noneNEW — today it is hard-coded per kind: roll=all, poll=contributors-only, deposit=none
close triggerall-in · creator · any player · timerpartly — all-in/creator/any exist; close_at(timer)is unbuilt
reveal triggeron close · creator · player(own row)· timerbuilt for seal only(T11)— reveal_at exists
blockingnone · panel · allshipped(T8/v578)
placeinline · pinnedshipped(T8/v578)
uniqueno · yesshipped(T8)

Why naming visibility matters: that single rung unifies three behaviours we built separately — the poll's reveal gate(contributors-only), the roll's public rows(all), the deposit's sealed rows(none). The middle rung is a general pay-to-see device — commit before you may look — that today only the poll enjoys and any tool could use. Your own contribution is always visible to you; that is a constant, not a setting.

3 · The rulings

ruling ①Blocking releases at CLOSE, not reveal — the panel sees what the humans see. Symmetry: the panel is a participant with the same sight-lines. A closed-but-sealed roll releases it to speak blind(「五个人都摇了,谁先看?」)— which is the best beat in the mechanic, not a bug. The implementation this demands: sealed content must not enter the panel's history or the transcript until the reveal fires — the read-path law extended along time.
ruling ②Coercion: visibility=all ⟹ reveal=on close. If everything is public as it lands there is nothing left to reveal; a reveal control on an open roll is meaningless(the v585 lesson formalized — the roll dropped its 🔒 precisely because it was public the whole way).
ruling ③Reveal-by-player means own row only, always. On a deposit that is the writer trigger; on a Sealed Roll it becomes「show your hand」. It must never mean「any player reveals everyone」— that would break the answer-key case, where only the creator may open. Close-by-any-player is the stall valve and stays.
ruling ④The card has three visual states, not two. The middle one — collected but still sealed — needs its own band, badge and watermark(「已封存 · 5/5 · 未开封」), masked rows instead of contents, and the reveal control for whoever holds the right. The deposit has had this since v613; every tool inheriting the split inherits it.
ruling ⑤Anonymous × self-reveal: revealing your own row identifies you. That is the person's choice, but the promise must read「hidden unless you reveal it yourself」.
ruling ⑥Card dealing: always flipped on receipt. A dealt card is visible to its owner the instant it lands — no pickup ceremony. This removes a state and an excuse(「我还没看牌」is no longer available in werewolf). So dealing is genuinely two-state: dealt → revealed; there is no close.
ruling ⑦The poll needs no deferred reveal.「Vote now, results at 8pm」is a choice deposit with a timer reveal. Don't grow a dial on the simple tool — point the person at the right object(preset thinking).
ruling ⑧A sealed roll stays DICE — but extract the lifecycle, don't copy it. Mechanically a sealed roll is a deposit whose payload the server draws; experientially people reach for 骰子, never for「deposit」, so the kind stays roll and the face stays dice(keep the kind aligned with the mental model, or every future dice feature gets special-cased inside a kind called deposit). But do not mimic the deposit's state machine — promote it. Copying is how v586 happened(textGate() matched「any gate that is not a vote」, true until a third kind existed); two copies agree today and diverge at the first fix.
ruling ⑨Timers stay flat — per-instrument deadlines, never bound to the wall clock. The requirement that makes flat safe: a deadline must be visible where the instrument is(a live countdown on the card, client-side from the timestamp — the T1 chip's pattern, CLOCK_SKEW already solved). Then the card is its own clock and binding buys nothing. The wall clock keeps its job(ruling ④ of toolbox §9): timing phases that aren't instruments, its ring a cue to the host. Display rule: show only the next deadline, labelled with what it does —「⏱ 4:32 后截止」then「⏱ 12:04 开封」. Deadlines are opt-in. 「The clock rings and everything open resolves」is a session concern(T5's orchestration), not a per-instrument dial.
ruling ⑩Naming: Sealed Roll · Sealed Spin ·「密摇」for both. A sealed roll means reveal later(its default reveal trigger is creator, not on-close). The word sealed now marks the three-state lifecycle across the whole toolbox — 密封收集 · 密摇 — so the vocabulary teaches the mechanic.
ruling ⑪Icons: tools wear the new SVG set, states wear the house emoji. TOOL_ICONS/toolIcon()(7 keys, per-tool accents)everywhere a tool is named; tEmo() house glyphs(never OS emoji — the v556 rule)for states: 🔒 sealed · 🔓 revealed · 🔑. Both are house-owned, so a die and a lock are the same picture on every device.
ruling ⑫Dice and Slots get separate doors; the subtype lives inside. The drawer button already answered「which tool」— re-asking it at the top of the dialog spends the best real estate on a settled question. The segment becomes open / sealed, which is the consequential choice(it picks the whole lifecycle). Two doors, one dialog engine — they share everything but the payload editor(NdM steppers vs option rows), and the T9 findings already recorded what copies do:「the narrow-mode commit line still sits in the roll and sealed-collect dialogs」.

4 · The six presets — the owner's matrix

The matrix's「use case」column is the preset list — these six are what a person sees and picks; the axes are how they are configured underneath. That is ruling ⑩ of toolbox §9(three tiers)doing its job: adding axes must not add UI.

presetvisibilitycloserevealanon
Open Roll(掷骰)allall-in · creator · any · timeron close(coerced)n/a
Sealed Roll(密摇)noneall-in · creator · any · timercreator · player · timer · on closen/a
Open Spin(转盘)allall-in · creator · any · timeron close(coerced)n/a
Sealed Spin(密摇)noneall-in · creator · any · timercreator · player · timer · on closen/a
Poll(投票)contributors-onlyall-in · creator · any · timeron closeyes
Deposit(密封收集)noneall-in · creator · any · timeron close · creator · writer · timeryes
Deal · face down(暗发牌)none(owner sees own)no close stagecreator · player · timern/a
Deal · face up(明发牌)allno close stageon dealn/a

5 · The card's three states

1 · COLLECTING OPEN Dan 发起密摇 · 2d6 Dan 🔒 已摇 CW 🔒 已摇 🎲 ROLL waiting for: Bobby visibility = none · nobody sees a face 2 · CLOSED · SEALED 已封存 Dan 发起密摇 · 2d6 Dan 🔒 CW 🔒 Bobby 🔒 🔓 开封 3/3 已摇 · 等发起人开封 3 · REVEALED 已开封 Dan 发起密摇 · 2d6 Dan [3 + 4 = 7] CW [5 + 5 = 10] Bobby [1 + 2 = 3] 封存于 14:02 · 开封于 14:09 contents enter the transcript HERE
The middle state is the new one(ruling ④). Note what does not change: the opener head, the band's position, the row grammar — the poll specimen holds throughout.

6 · The pending-action pill

Once reveal and close come apart, the card scrolls away while still owing someone an action. The reveal bubble(T11)tells the room after; nothing tells you before. That surface is the chip strip we already built(T-UI v569, ~35px under the topbar)— it just gains a second reason for a chip to exist: today a chip means you chose place=pinned(placement, by config); now it also means this instrument is waiting on something(state, automatic). If a card is both, they merge into ONE chip.

topbar · 房间名 🎲 谁先手 · 1:35 开封 ✉ 晚饭 · 开封 +1 …the chat… A pill is a LOCATOR, never a button — tap jumps to the card. Clocks: everyone. Creator-reveal: the creator. Own row: you.
Tap → jump to the card and flash it(the quote-jump idiom). The reveal action stays on the card, where it has context and its two-tap confirm — a one-tap pill that opens a sealed answer key is a footgun with no undo.
pillshown tolabel
close / reveal countdowneveryone — a shared upcoming event「🎲 TITLE · 1:35 截止」/「· 1:35 开封」
creator revealthe creator only「🎲 TITLE · 开封」
writer reveal(own row)each person holding a sealed row「✉ TITLE · 开封」

Ordering: soonest clock first, then actionable-by-me. Cap the visible count with a +N overflow rather than wrapping — the 35px budget is what made the strip work. Ageing: clocks always earn a pill; a manual reveal earns one for a bounded window(the session, or a day), after which the card stays findable in the tools drawer as「my sealed cards」— otherwise a prediction sealed for a week is six days of permanent chrome. In the bubble: the countdown takes the place「Close now」occupies, but the early-close stays for whoever holds the valve — a timer must not remove agency the valve table grants.

7 · Where the code actually stands

Verified 2026-07-25 — the starting point for every task below.

8 · The work — five tasks

L · icon sweep independent · S A · the lifecycle the foundation · L B · Sealed Roll / Spin C · the pending pill D · the deal the new faces the strip surface the last tool Recommended order: L → A → B → C → D
L is a low-risk warm-up that also cleans the surfaces C will build on. A is the only step everything else waits for.
LThe icon sweepS · independent · do it first — every later card, pill and dialog is written against the result · SHIPPED v616 · owner pass v617

Goal: ruling ⑪ made real — one picture per tool, one per state, everywhere.

  1. Audit all ~50 tEmo() sites and split them: tool references(die · wheel · card · vote · board · clock · seal)→ toolIcon(key); state references(lock · unlock · key)→ stay tEmo() house glyphs.
  2. The chip strip and the stream capsules are the biggest cluster — they still draw tools with emoji.
  3. Size/alignment: the strip's chips and the bubble band already agree at 24px(v607/3e2fb46); match it.
  4. Retire any TOOL_EMO key that no longer has a caller; keep the state keys.

Accept: no tool is drawn with an emoji anywhere(grep-provable); no state glyph is drawn with an OS character(the v556 rule holds); light/dark/e-ink all read; zero layout shift in the strip at 375px.

AThe shared lifecycleL · the foundation — everything else waits for it

Goal: promote the three-phase machine out of seal and into every instrument, per ruling ⑧(extract, never copy). Ships one visible feature so it is testable: close-by-timer on the tools that exist today.

  1. Shared fields: visibility(props)· close_trigger + close_at(NEW)· reveal_trigger + reveal_at + revealed{} — all promoted from seal-only to every kind. _seal_trigger() becomes the shared reader.
  2. One evaluator: _maybe_close() / _maybe_reveal() called uniformly; one reveal route carrying the valve table(ruling ③); one timer arm/re-arm with the T1 traps verbatim(non-daemon guard · evict_guard membership · re-arm on load ≥1s fuse · a missed deadline fires once).
  3. Coercions: ruling ②(visibility=all ⟹ reveal=on close)beside the v578 pair.
  4. Ruling ① wiring: blocking releases at CLOSE; the close cue carries WHO, not WHAT; content enters history + transcript at REVEAL only(write the test that greps the built turn content mid-seal).
  5. Client: the third band state + a masked-row variant per kind(ruling ④); one revealBubble(); the countdown renderer(ruling ⑨)with the「next deadline only」rule.
  6. Defaults preserve today's behaviour exactly: roll=all/on-close, vote=contributors-only/on-close, seal=none/its T11 triggers.

Accept: every existing poll/roll/deposit behaves bit-identically(re-run the T8/T9/T10 matrices); a poll and a roll each accept a close-timer and fire it, surviving a restart and a missed deadline; the mid-seal transcript proof; smoketest green.

BSealed Roll · Sealed Spin(密摇)+ the dialog splitM–L · needs A · the new faces

Goal: rulings ⑩ and ⑫ — the sealed subtype, and dice/slots as separate doors.

  1. Two doors, one engine: the 🎲 button opens a dialog whose top segment is 明掷 / 密摇; the slots button opens the same engine with 明转 / 密摇. Shared: who participates · title · Advanced dials · the lifecycle settings. Different: the payload editor only.
  2. One plain line under each option(the three-tier principle):「明掷 · 结果落下即可见」/「密摇 · 全部摇完后封存,稍后开封」.
  3. Sealed defaults: visibility=none, close=all-in, reveal=creator(reveal later is the point — ruling ⑩). Reveal-on-close is available in Advanced for the simultaneity case.
  4. Masked dice rows for the collecting and sealed states; the revealed row keeps T9's [3 + 4 = 7] format.
  5. i18n:「密摇」for both dice and slots; English Sealed Roll / Sealed Spin. Face wording vs the internal wheel key — pick one word for the face(Slots or Wheel)and keep wheel internal.

Accept: a sealed roll hides every face while collecting(wire-checked, not CSS-hidden); closes at all-in with the panel released to speak blind(ruling ①); the creator's reveal opens all rows + the reveal bubble + the cue; a sealed spin does the same for options; the open variants are unchanged; the two dialogs share one code path.

CThe pending-action pillM · needs A(B makes it worth having)· benefits from L

Goal: §6 — the chip strip gains automatic chips for instruments that owe someone an action.

  1. A chip appears when an instrument has a pending action for me or a running clock for anyone(the audience table in §6); merges with the place=pinned chip when both apply.
  2. Locator, not button: tap jumps to the card and flashes it. Never performs the reveal.
  3. Live countdown from the deadline timestamp(CLOCK_SKEW); the「next deadline only」label rule.
  4. Ordering(soonest clock → actionable-by-me), a +N overflow rather than wrapping, and the ageing rule for manual reveals.
  5. In-bubble: the countdown takes「Close now」's place, with the early-close preserved for whoever holds the valve.

Accept: a deferred-reveal card scrolled far out of view is findable in one tap; a creator-reveal pill is invisible to non-creators; two pending instruments order correctly and a third overflows; the strip still measures ~35px at 375px; no double chip for a pinned+pending card.

DThe deal joins the storeL · needs A · the last tool off the old model

Goal: migrate self.deal onto the instance store and the lifecycle — the same move T8/T9/T10 made for the poll, roll and deposit.

  1. kind="deal" on self.gates; the legacy self.deal + roll_offer path retires(legacy replay stays — old rooms must still render).
  2. Two-state by ruling ⑥: dealt → revealed; no close stage, and no pickup — a card is flipped for its owner the instant it lands.
  3. Per-viewer render: face-down deals show your card face up and everyone else's as 🂠; face-up deals show every hand. The wire discipline is the acceptance: others' cards must be absent from your payload, never merely hidden in the render — replay included.
  4. Reveal triggers: creator · player(own)· timer, per §4; the deck composition editor keeps ruling ⑦'s without-replacement guarantee(shuffle at arm — the whole fairness claim).

Accept: a 6-card werewolf deal gives exactly the declared multiset; a devtools/wire read of another player's payload contains no card of mine; a face-up deal shows all hands at once; the creator's reveal opens everything with the reveal bubble; an old room's legacy deal capsules still replay.

out of scope, on purposeBinding an instrument's deadline to the wall clock(ruling ⑨ — session orchestration, T5)· the poll's deferred reveal(ruling ⑦ — use a choice deposit)· folding a sealed roll into the deposit kind(ruling ⑧ — the face and the kind stay aligned)· anonymous bubbles(rows without names already suffice).
The tool lifecycle · owner's matrix 2026-07-25, designed + documented same day · the discovery was v613(「Close now stops the collection — it does not reveal」)· architecture: toolbox.html(rulings ①–⑪ + §9 presence properties)· execution: toolbox-build.html(T1–T11 shipped)· the specimen: poll.html. Five tasks — L · A · B · C · D — one CC session each, owner-triggered.