Workspace IndexDev Notes › A boolean hides a state machine

#60PoC

A boolean hides a state machine

Five cards in this catalogue — rpc-view-not-consensus, receipt-is-not-settlement, bundler-paymaster-dependencies, private-rpc-visibility, walletconnect-session-authority — are one law seen five times. A single UI status ("connected", "sent", "success", a green dot) collapses a multi-owner state machine in which different parties observe and different parties decide. The bug is always the collapse; the fix is always to model the explicit states and never conflate the layers.

Not a build — a design audit you run on your own UI. List every status your app renders as a boolean (isConnected, pending, confirmed, sent, paid) and force each one into an explicit state machine: which distinct states does the boolean collapse, who is the authoritative witness of each, and what event moves between them. For each transition, assert the right invariant for its family — a lifecycle status may only advance toward final with evidence (a canonical receipt, then finality), and an authority status may only shrink or be re-granted, never silently widen. Then find the false positives (a green dot over an expired session, a receipt read as final, an accepted op read as settled) and the false negatives (an invisible private tx read as failed). The output is a table: status -> states it hides -> owner of each -> event that changes it. Anything that cannot fill all four columns is a boolean lying about a state machine.

Why

The shared shape is a lossy projection: one bit standing in for several states with different owners. Read it card by card and the same collapse appears each time. rpc-view-not-consensus: a value is one node's view, not the chain's consensus. receipt-is-not-settlement: an included receipt is not a final one. bundler-paymaster-dependencies: accepted by a service is not settled on-chain. private-rpc-visibility: invisible is not failed. walletconnect-session-authority: connected is not authorized-for-this-and-current. Every one of them is a UI that rendered two or more distinct states — with different authoritative sources — as a single word.

The collapse is dangerous in both directions, and that is why it earns a card of its own. A false positive is a green dot that survives stale state: the app acts confidently on an expired session, an unincluded transaction, or a receipt that later reorgs — the worst kind of bug, because the UI is most certain exactly when it is wrong. A false negative is the mirror: a private transaction with no public heartbeat, read as failure because the signal the app quietly relied on went missing. In every case the damage is a confident wrong action, not a visible error, which is precisely the failure mode monitoring is supposed to prevent.

The fix splits into two families, and naming them is the point of this card. Lifecycle honesty covers anything moving toward done — reads, sends, payments, inclusions: the state may only advance with evidence, each step names its witness (a receipt, then finality — never the submitting party's own word), and 'done' is reserved for final. Authority honesty covers anything granting power — sessions, sponsorships, capabilities: the grant may only shrink or be re-requested, every mutation event narrows or invalidates, and it must never silently widen. Both reduce to one instruction: name the owner of each state, make every transition an observable event, and never let one status stand in for several. The green dot is not the enemy; the green dot over an unmodeled state machine is.

How it works

The one law, five times

Card The boolean States it hides Authoritative owner
rpc-view-not-consensus "the chain says X" one node's view vs consensus independent nodes
receipt-is-not-settlement "confirmed" included vs final chain finality
bundler-paymaster-dependencies "sent" accepted-by-service vs settled bundler / paymaster, then EntryPoint
private-rpc-visibility "pending" invisible vs failed vs included an unrelated public node
walletconnect-session-authority "connected" relay-up vs authorized vs current the wallet's session events

Read the third column top to bottom: every row is two or more states wearing one word.

Two families, two invariants

Family Covers Invariant 'Done' means
Lifecycle honesty reads, sends, payments, inclusions advance only with evidence; each step names its witness final, not the submitter's word
Authority honesty sessions, sponsorships, capabilities may only shrink or be re-granted; never silently widen explicitly re-authorized

How to spot the collapse

  1. Point at a status your UI shows as one word (connected, sent, confirmed).
  2. Ask: how many distinct states does it stand for? If more than one, it is a projection.
  3. For each state, name its authoritative witness — and reject the submitting party's own word as the witness.
  4. Name the event that moves between states, and assert it only narrows/invalidates (authority) or advances-with-evidence (lifecycle).
  5. If you cannot fill all four — states, owners, events, invariant — the boolean is lying.

Why this is a card and not a footnote

Each of the five cards fixes its own instance; this one is the pattern, so the sixth instance is recognisable before it ships a bug. The next time a design reduces a multi-owner reality to a green dot — a cross-chain 'delivered', an oracle 'resolved', an agent 'authorized' — the question is already written: what states did that dot just collapse, and who owns each one?

← All Dev Notes · Workspace Index · Top ↑

불리언 하나가 상태 기계를 숨긴다

이 목록의 다섯 카드 — rpc-view-not-consensus, receipt-is-not-settlement, bundler-paymaster-dependencies, private-rpc-visibility, walletconnect-session-authority — 는 한 법칙을 다섯 번 본 것입니다. 하나의 UI 상태("연결됨", "전송됨", "성공", 초록 점)가 서로 다른 당사자가 관찰하고 서로 다른 당사자가 결정하는 다중 소유자 상태 기계를 뭉갭니다. 버그는 언제나 그 뭉갬이고, 해법은 언제나 명시적 상태를 모델링하고 계층을 절대 섞지 않는 것입니다.

만드는 일이 아니라 자기 UI 에 돌리는 설계 감사입니다. 앱이 불리언으로 그리는 모든 상태(isConnected, pending, confirmed, sent, paid)를 나열하고 각각을 명시적 상태 기계로 밀어 넣습니다 — 그 불리언이 어떤 구별된 상태들을 뭉개는지, 각각의 권위 있는 증인이 누구인지, 무슨 이벤트가 그 사이를 옮기는지. 각 전이에 대해 그 계열에 맞는 불변식을 단언합니다 — 생애주기 상태는 오직 증거와 함께(정규 receipt, 그다음 파이널리티) 파이널로 전진할 수 있고, 권한 상태는 오직 줄어들거나 다시 부여될 뿐 조용히 넓어지면 안 됩니다. 그다음 거짓 양성(만료된 세션 위 초록 점, 파이널로 읽힌 receipt, 정산으로 읽힌 accepted op)과 거짓 음성(실패로 읽힌 보이지 않는 프라이빗 tx)을 찾습니다. 산출물은 표 하나입니다 — 상태 -> 숨긴 상태들 -> 각각의 소유자 -> 그것을 바꾸는 이벤트. 네 열을 못 채우는 것은 상태 기계를 두고 거짓말하는 불리언입니다.

공통 모양은 손실 있는 투영입니다 — 서로 다른 소유자를 가진 여러 상태를 비트 하나가 대신합니다. 카드별로 읽으면 같은 뭉갬이 매번 나타납니다. rpc-view-not-consensus: 값은 노드 하나의 관점이지 체인의 합의가 아니다. receipt-is-not-settlement: 포함된 receipt 는 파이널이 아니다. bundler-paymaster-dependencies: 서비스가 접수함온체인 정산이 아니다. private-rpc-visibility: 보이지 않음실패가 아니다. walletconnect-session-authority: 연결됨이것에 대해 인가됨·최신임이 아니다. 하나같이 서로 다른 권위 소스를 가진 둘 이상의 구별된 상태를 단어 하나로 그린 UI 입니다.

그 뭉갬은 양방향으로 위험하고, 그래서 자기 카드값을 합니다. 거짓 양성은 스테일 상태를 살아남는 초록 점입니다 — 앱이 만료된 세션, 미포함 트랜잭션, 나중에 리오그되는 receipt 위에서 확신을 갖고 행동합니다. UI 가 틀린 바로 그 순간 가장 확신하기 때문에 최악의 버그입니다. 거짓 음성은 거울상입니다 — 퍼블릭 심장박동이 없는 프라이빗 트랜잭션이, 앱이 조용히 기대던 신호가 사라졌다는 이유로 실패로 읽힙니다. 어느 경우든 피해는 눈에 보이는 에러가 아니라 확신에 찬 틀린 행동이고, 이는 모니터링이 막아야 할 바로 그 실패 유형입니다.

해법은 두 계열로 갈리고, 그 둘에 이름을 붙이는 것이 이 카드의 목적입니다. 생애주기 정직성은 완료로 향하는 모든 것 — 읽기, 전송, 결제, 포함 — 을 덮습니다: 상태는 오직 증거와 함께 전진하고, 각 단계가 자기 증인을 지명하며(receipt, 그다음 파이널리티 — 제출 당사자 자신의 말이 아니라), '완료'는 파이널에만 씁니다. 권한 정직성은 권력을 부여하는 모든 것 — 세션, 후원, 권한 — 을 덮습니다: 부여는 오직 줄어들거나 다시 요청될 뿐이고, 모든 변경 이벤트가 좁히거나 무효화하며, 조용히 넓어지면 안 됩니다. 둘 다 한 지시로 수렴합니다 — 각 상태의 소유자를 지명하고, 모든 전이를 관찰 가능한 이벤트로 만들고, 하나의 상태가 여럿을 대신하게 두지 마라. 적은 초록 점이 아니라, 모델링되지 않은 상태 기계 위의 초록 점입니다.

동작 방식

한 법칙, 다섯 번

카드 그 불리언 숨긴 상태들 권위 있는 소유자
rpc-view-not-consensus "체인이 X 라고 함" 노드 하나의 관점 대 합의 독립 노드들
receipt-is-not-settlement "확정됨" 포함 대 파이널 체인 파이널리티
bundler-paymaster-dependencies "전송됨" 서비스 접수 대 정산 번들러 / 페이마스터, 그다음 EntryPoint
private-rpc-visibility "대기 중" 보이지 않음 대 실패 대 포함 무관한 퍼블릭 노드
walletconnect-session-authority "연결됨" 릴레이-켜짐 대 인가됨 대 최신 지갑의 세션 이벤트

세 번째 열을 위에서 아래로 읽으세요 — 모든 줄이 단어 하나를 입은 둘 이상의 상태입니다.

두 계열, 두 불변식

계열 덮는 것 불변식 '완료'의 뜻
생애주기 정직성 읽기, 전송, 결제, 포함 오직 증거와 함께 전진; 각 단계가 증인을 지명 제출자의 말이 아니라 파이널
권한 정직성 세션, 후원, 권한 오직 줄어들거나 재부여; 조용히 넓어지지 않음 명시적으로 재인가됨

뭉갬을 찾아내는 법

  1. UI 가 단어 하나로 보여주는 상태를 가리킨다(연결됨, 전송됨, 확정됨).
  2. 묻는다 — 그것이 몇 개의 구별된 상태를 대신하나? 하나보다 많으면 투영이다.
  3. 각 상태에 대해 권위 있는 증인을 지명하고 — 제출 당사자 자신의 말은 증인으로 기각한다.
  4. 상태 사이를 옮기는 이벤트를 지명하고, 그것이 오직 좁히거나 무효화(권한)하거나 증거와 함께 전진(생애주기)하는지 단언한다.
  5. 상태·소유자·이벤트·불변식 네 가지를 못 채우면, 그 불리언은 거짓말을 하고 있다.

왜 각주가 아니라 카드인가

다섯 카드는 각자 자기 사례를 고칩니다. 이 카드는 패턴이라, 여섯 번째 사례를 버그를 배포하기 전에 알아볼 수 있게 합니다. 다음번에 어떤 설계가 다중 소유자 현실을 초록 점 하나로 줄일 때 — 크로스체인 '전달됨', 오라클 '해결됨', 에이전트 '인가됨' — 질문은 이미 적혀 있습니다: 그 점이 방금 어떤 상태들을 뭉갰고, 각각을 누가 소유하는가?

← 전체 개발 노트 · 워크스페이스 인덱스 · 맨 위 ↑