← 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 Private/Blind Roll · 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 · Seven axes

Three are shipped(T8's presence properties). Three were 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. A seventh arrived later(v630, ruling ⑮) and is a different animal from the other six: readout governs what a card says, not who may see it or when.

axisvalues(default first)status
visibility(while collecting)all · contributors-only · own · noneshipped(A/v620 · C/v622 · D/v625) — a prop on every kind; the per-kind defaults ARE the old hard-coding written down(roll=all, poll=contributors-only, deposit=own). B/v621 shipped the bottom rungnone)and C/v622 the missing middleown), so the ladder is whole: sealed→暗 · blind→盲 on the tag, three stacked rows in the dialog, and _shows_content() is the one place the axis is enforced — per row, on the wire
close triggerall-in · creator · any player · timershipped(A/v620)— close_trigger + close_at on every kind. ⚠ the clock is LAYERED on the trigger, not a substitute: all-in still closes first if the room gets there
reveal triggeron close · creator · player(own row)· timershipped(A/v620)— promoted off seal to every kind; T11's four words survive as the wire alias
blockingnone · panel · allshipped(T8/v578)
placeinline · pinnedshipped(T8/v578)
uniqueno · yesshipped(T8)
readout(dice only)sum · facesshipped(v630) — the first presentational axis, and the only one with no combo coercion: it changes what a card says, never who may see it. sum is today's card verbatim([4 + 1 + 4 + 2 + 1 = 12]); faces drops the total and sorts([1, 1, 2, 4, 4])for the games that bid on the dice rather than add them. A bare faces on the tag, a two-button row in the dice pane(2+ dice only). ⚠ it does not gate what the panel knows — see ruling ⑮

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: the modifier is the ladder, the verb names the tool. 明掷 · 暗掷 · 盲掷(dice)and 明转 · 暗转 · 盲转(slots)— perfectly regular, learned once and applied twice. English: Open / Private / Blind Roll · Spin. 盲 replaced 密(the v621 word)deliberately: 密封 · 保密 · 机密 all imply a keeper — someone holds the secret — which is the semantics of 暗, not of the rung where nobody has looked. 盲 states the actual property, and modern Chinese has already done the work(盲盒 · 盲测 · 盲选 · 盲投: determined, and unseen by everyone including the holder). 明→暗→盲 reads as a ladder because all three sit on the same axis; 明→暗→密 did not. In prose「盲模式」or 盲摇 still serves as a generic noun across both tools.
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」.
ruling ⑬Visibility is a four-rung ladder, and the parity law applies WITHIN each rung. An earlier draft of this ruling said「your own contribution is always yours」— that over-reached, and collapsed two genuinely different products into one. The owner's correction: there are three dice scenarios, and they form a ladder.
rungwho sees whatthe presets that live there
alleverything, as it lands明掷 · 明转 · 明发牌
contributors-onlyeverything, once I have contributed(pay-to-see)the poll's reveal gate
ownmine only, until the reveal暗掷 · 暗转 · 暗发牌 · the deposit
nonenothing, not even mine盲掷 · 盲转 · a blind deal
Why the bottom two rungs are different products, not shades of one: own gives you information to play with — 吹牛, a secret stealth check, damage you may bluff about; none gives the room a value nobody could react to, committed early and provably unchanged — the dice equivalent of a sealed note.(「the server could just roll at reveal time」is wrong: it could, and the commitment would evaporate.) 暗 is the default non-open mode, because the failure costs are asymmetric: wanting 盲 and getting 暗 leaks only to yourself; wanting 暗 and getting 盲 leaves you blind in a game that needed your own information. The SP exemplar must lead with 暗 — in-context shape decides what a persona reaches for(v553). Person-authored tools cannot reach none: you cannot hide from someone what they just typed, so a deposit is inherently own. Do not try to build it. What survives of the first draft — and it is the important half: the parity law(ruling ⑫)applies within each rung. In 暗 both a human and a persona see their own face; in 盲 neither does. And because a persona has no wire payload, each rung needs its riding note to say exactly what that seat knows — that is the general implementation shape of parity.
ruling ⑭A pill is a reminder, not an info widget — the tray-icon rule.(Owner, after task C: at 375px only ~2 pills fit.)The strip's job is「there is something to attend to, over there」— the CARD carries the information. So when space is tight a pill shows the minimum critical thing and nothing else, exactly as a Windows tray icon does. Two consequences the owner drew, both now shipped(v624): ① Order by obligation, not by urgency. Actionable-by-me first, then clocks soonest-first. A countdown is information and resolves itself; an act is an obligation and does not — so a clock that fires without me must never hold the visible space while a thing only I can do sits off the right edge. ② Different jobs, different shapes. An ACT pill keeps ICON · TITLE · verb(the title is the only thing that tells two waiting reveals apart); a CLOCK pill shrinks to ICON · digits — no title, no「to close」/「to open」— because a pill I cannot act on only has to say HOW LONG. 85px instead of ~200px, which is what lets an act and the room's clocks share one strip. The trade is accepted, not hidden: a bare「2:28」does not say whether that clock closes or opens the card. The accessible name says it, the card says it, the pill does not — and that is the correct place for it to be said, because the pill's whole job is to get you to the card.
ruling ⑮A presentation axis never gates what the panel knows.(Owner, 2026-07-26, from a 吹牛 table — shipped v630.)The report was a feature request:「the persona can't see it as 5 independent dice — add a sum/faces toggle」. It came with a screenshot of a 盲掷 card that plainly showed [4 + 1 + 4 + 2 + 1 = 12]. The card was never the problem. The panel does not read cards — it reads the transcript — and every panel-facing roll surface was built from result alone, so the host read「你 12 · Dan 20」and could not count a single six. 阿测's「系统给的就是加总,没有独立面」was an accurate bug report from inside the room. The general shape, and why the requested toggle would not have fixed it: a toggle whose default is「sum」leaves the default path blind, and the one game that needs faces is normally GM-hosted — the persona opens the dice, so a human dialog's toggle is never passed. So the fix splits in two, and only the second half is the feature: ① The faces reach the panel in BOTH readouts, unconditionally. The sum is derivable from the faces; the faces are not derivable from the sum. There is no readout, and no game, in which withholding them from the host helps. _panel_roll_face() is the one formatter behind the settle line, the settle cue and the open-roll riding note. On a sealed roll the settle line is the ONLY path a number has(the per-throw line is suppressed by ruling ①'s read-path law)— so this was not「the faces arrived late」, it was「they never arrived」. ② The readout moves the TOTAL, on every surface at once. Card row, settled record and the panel's line share one spelling — a host that says「你那手 4+1+4+2+1」about a card reading [1, 1, 2, 4, 4] has re-introduced in prose exactly the mismatch this removed(v628's one-head law). And the faces sort under faces: counting「几个6」off a sorted row is the entire job, and throw order carries no information for dice. The reusable test: when a request asks for a control so the panel can see something, check first whether the panel was ever told it. A control that gates a fact the host already lacks ships a preference and leaves the bug.

4 · The six presets — the owner's matrix

D/v625 corrected one cell: the ordinary face-down deal is own, not none — ruling ⑥'s「always flipped on receipt」is exactly what puts it there, and 盲发牌none)became its own preset beside it.

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
Private Roll(暗掷)ownall-in · creator · any · timercreator · player · timer · on closen/a
Open Spin(转盘)allall-in · creator · any · timeron close(coerced)n/a
Private Spin(暗转)ownall-in · creator · any · timercreator · player · timer · on closen/a
Poll(投票)contributors-onlyall-in · creator · any · timeron closeyes
Deposit(密封收集)ownall-in · creator · any · timeron close · creator · writer · timeryes
Deal · face down(暗发牌)ownno close stagecreator · player · timer · on dealn/a
Deal · blind(盲发牌)noneno close stagecreator · timer · on dealn/a
Deal · face up(明发牌)allno close stageon deal(coerced)n/a

5 · The card's three states

1 · COLLECTING OPEN Dan 发起暗掷 · 2d6 Dan(你) [3 + 4 = 7] CW 🔒 已摇 🎲 ROLL waiting for: Bobby visibility = own(暗掷)· your own face is yours, others are sealed 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 · SHIPPED v620 B · Private/Blind Roll SHIPPED v621 C · the pending pill SHIPPED v622 D · the deal SHIPPED v625 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 · SHIPPED v620

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. ⚠ If you touch the riding-note builders, _deal_note() has TWO branches and both are load-bearing(added mid-task 2026-07-25): the GM-knows-the-map branch(bound:「he may reason from it and must never say it」)and the blind branch(「YOU DO NOT KNOW who holds what … never guess at, hint at or reason from anyone's card」). The blind wording is what stops a dealer-less GM improvising a role assignment — the Cameron-class failure. Generalizing the binding is welcome; flattening the two branches into one is not. See task D's D2.
  6. Client: the third band state + a masked-row variant per kind(ruling ④); one revealBubble(); the countdown renderer(ruling ⑨)with the「next deadline only」rule.
  7. 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 · SHIPPED v621

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

amended after shippingThis card's text is the contract B was given(shipped v621)and is kept as history. Two things changed after it landed, both in task C's item 0: the sealed subtype B built is the none rung and is now called 盲掷/盲转(ruling ⑩ — 密 wrongly implies a keeper), and the 暗 rung(own)that sits above it did not exist and must be added(ruling ⑬). B's implementation was correct for the rung it built.
  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.

What task A left you(read its findings entry in the tracker first):

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. All met v621 — including live: the panel, released by the close, said「两个密封骰子,我看不到里面」and named no face, and Tess armed her own 密摇 from a plain ask and opened it with <reveal/>. Three things the build settled that this card did not say: a sealed roll masks the THROWER's own row too(§5's mock is literal — nobody has looked, which is what makes「谁先看?」a question), its close trigger is all-in by ARGUMENT(the deposit's「deferred ⟹ never all-in」is a per-kind default, not a law), and reveal-by-player degrades to creator(ruling ③'s「show your hand」needs a dice row-reveal record — deliberately not built; see the findings).

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

Goal: §6 — the chip strip gains automatic chips for instruments that owe someone an action. Plus item 0 below, the ladder correction that B could not have known about.

⚠ ITEM 0 — do this FIRST, before the pill(rulings ⑩ + ⑬, decided after B shipped):

  1. Add the own rung to the visibility axis. _shows_content() gains a fourth value between contributors-only and none: own = my row's content rides the wire, everyone else's is withheld until the reveal. B's none(nothing, not even mine)is correct and stays.
  2. The riding note per rung(the parity law's implementation shape). A persona has no wire payload, so _one_gate_note()'s sealed branch must split: under own it tells the persona its own face and only its own; under none B's existing「NOBODY has seen a result, you included」is right as written and must not be softened.
  3. Rename 密 → 盲, and add 暗. The ladder is 明掷 · 暗掷 · 盲掷(dice)and 明转 · 暗转 · 盲转(slots)— the modifier is the ladder, the verb names the tool. English: Open / Private / Blind. i18n keys, the dialog, the band, the capsules, the SP.
  4. The dialog shows all three(owner ruling)as stacked rows, each with its own plain line — B's two-row pattern extended to three(it measured 55px and 71px at 375px; verify the third fits). 暗 is the DEFAULT non-open mode and the SP exemplar must lead with 暗 — in-context shape decides what a persona reaches for(v553), and the failure cost is asymmetric: a persona that produces 盲 when 暗 was wanted leaves the roller blind in a game that needed their own number.

Then the pill itself:

  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. All met v622 — item 0 first(the own rung is a fourth value in _shows_content, sealed→暗 and blind→盲 on the tag, the riding note split per rung, three stacked dialog rows at a uniform 53.2px English / 55.2px Chinese), then the pill(37px at 375px in both themes, four pending cards ordered clock-first with a +1, the pinned+pending card carrying ONE chip, every card's own scrollTop still 0 after a jump). Three things the build settled that this card did not say: a persona's own face survives the CLOSE(the closed note keeps it, or the panel reads「nothing has been shown to you」about a number it was given last turn), the reveal cue's past tense is rung-shaped too(「hidden from everyone」is false about a 暗掷), and the deposit's honest rung is own, which is what ruling ⑬ says and what the code always did.

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

Goal: migrate self.deal onto the instance store and the lifecycle — the same move T8/T9/T10 made for the poll, roll and deposit — and add the dealer's-eyes toggle(the owner's design, 2026-07-25, below).

  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. The deal rides the SAME ladder(ruling ⑬, written after this card): 明发牌 = all(every hand visible)· 暗发牌 = own(your card face up, everyone else's 🂠 — this is the default face-down deal, and ruling ⑥「always flipped on receipt」is exactly what puts it on the own rung rather than below it)· 盲发牌 = none(nobody has looked, holder included — a fate envelope; legitimate and expressible, distinct from ⑥'s abolished pickup ceremony because nobody is waiting to look). 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).

D2 · The dealer's-eyes toggle — how a GM learns who the wolves are

The problem it solves(owner, 2026-07-25): werewolf's GM opens a private den for the wolves through the generic invite(the outcome bridge, T7)— so the GM must know who holds 狼人. But a face-down deal shows a card only to its holder, and v565 deliberately made a guest-dealt deal blind to everyone including the dealer(「hand that map to a player who dealt and they are the wolf-knower」). That ruling was right about a player who deals and over-broad about a dealer who doesn't play.

Rejected — seat="card:狼人"(a door that seats by predicate): it would make the door know about cards, coupling two mechanisms, and would put a rule of werewolf(「wolves share a room」)inside the server. The boundary law forbids both: the mechanism states facts, the contract owns meaning. The GM invites people, generically, by knowing who they are.

the settingthe design
defaultsee-none, for humans and personas alike — v565's normal case preserved, and symmetric by ruling ⑫(a GM is a role, not a species). It also makes the public line below mean something: a warning that is always on is one nobody reads.
the toggleworded as a role, not a permission:「我是主持人(看得见全部)」/「I'm running this, not playing it」— it says why you would want it, and makes the coercion self-evident.
the coercionsees-all ⟹ the dealer holds no card(and dealing yourself in locks the toggle off)— a player who deals, plays AND sees every hand is simply cheating, so make the cell unexpressible(locked button + live hint, the v578 pattern). Expressible today: _tool_who() already takes any subset.
the public linethe card states which way it is on its face, before anyone accepts a card:「发牌人看得见全部」/「发牌人也不知道」. Conceal must be visible — a dealer who could secretly see every hand would make the whole deal untrustworthy. ⚠ REVISED v628(owner): the line is OFF the card. The default's removal follows this table's own reasoning(a warning that is always on is one nobody reads); the sighted case went with it. The fact survives on the deal_settle record and in the panel's riding note — put the line back on the OPENER line, not as a row, if a game ever contests the dealer's sight.
when blind_deal_note()'s existing language stays verbatim:「YOU DO NOT KNOW who holds what … never guess at, hint at or reason from anyone's card」. That is what makes the safe default safe — a blind GM knows it is blind and says so, instead of improvising(the Cameron-class failure).
who sets itthe card, once cards exist(T5 — a scenario states what it needs, so the model needs no memory); until then the SP's dealing exemplar shows it set(in-context shape moves compliance — v553). Per ruling ⑫ this is a harnessing problem and must NOT be solved by giving the persona a privileged default.

⚠ Do not lose the GM's copy in the migration. The shipped _deal_note() hands the panel the map every turn while a deal is live, bound like a sealed note(「he may reason from it and must never say it」). This contract's earlier draft said only「per-viewer render」and never mentioned it — a faithful migration could silently drop it and reintroduce exactly the bug this section exists to fix. When task A generalizes the binding, the deal's note should fold into that one mechanism(both branches — knows-the-map and blind)rather than surviving beside it as a special case.

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. Plus the toggle: default-blind for a human AND a persona dealer(the panel's note says it does not know); toggled on, the dealer sees every hand and the card says so publicly; the coercion locks(dealt-in ⟹ toggle off, and vice versa); a blind GM asked who the wolves are says it cannot know rather than guessing; a sighted GM opens a den by the generic invite without naming anyone in visible speech. All met v625 — the wire check from three seats(exactly one row carries content on each and it is that seat's own, the viewer-less broadcast none at all, 盲发牌 none even for its holder, and the paired「present after the reveal」that stops the absence test proving itself); the sighted dealer's own payload carrying every hand while the players' still carry one; the coercion refusing a dealt-in dealer's eyes on the server AND locking the switch in the dialog; and live on DeepSeek — Tess emitted <roll deck="狼人×2, 平民×1" for="u7,u8,u13" into="safe" dealer="sees" label="身份牌"/> from a plain ask, refused「谁是狼」without leaking a face, opened one hand with <reveal who="u8"/>, and — dealt a deal it had NOT made — answered「牌是你们自己发的,我没经手——谁拿了什么,我不知道」and then refused to guess. Two things the build settled that this card did not say: the toggle is the DEALER's, and the panel is only sometimes the dealer(a human who runs the game sees every hand on their own wire while the panel stays a blind player — v565 was right about a player who deals and over-broad only about a dealer who does not play), and a deal's player reveal is REAL — it is the one kind that has had a per-row record since T3, which is what ruling ③'s「own row only」needs and what task B's sealed roll still lacks.

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. L shipped v616(owner passes v617–619)· A shipped v620 · B shipped v621 · C shipped v622(item 0's ladder + the pill)· D shipped v625(the deal on the store + the dealer's-eyes toggle) — the arc is complete: every instrument in the room now rides one lifecycle, one visibility ladder and one timer. Post-arc: v630 added the readout axis and, behind it, fixed the panel-blindness of ruling ⑮ — a reminder that a shared lifecycle does not by itself make a tool legible to the seat that has no wire payload.