Skip to content

feat(e2e): readable economy run + live consuming morphisms#191

Merged
scasplte2 merged 3 commits into
mainfrom
feat/riverdale-economy-observability
Jun 26, 2026
Merged

feat(e2e): readable economy run + live consuming morphisms#191
scasplte2 merged 3 commits into
mainfrom
feat/riverdale-economy-observability

Conversation

@ottobot-ai

Copy link
Copy Markdown
Collaborator

Follow-up to #190 (the now-merged riverdale-economy economy): make the e2e run readable and show the economy moving.

Why

A real run was unreadable — the background keepalive ([keepalive] N sent, every 3s) and per-send [dl1] update → 3/3 ✓ lines printed live (50+ lines over a 20-min run) while the flow output was buffered and dumped only at the end. You watched plumbing spam, then a wall of ✓ OK with no view of the economy actually moving.

Harness (shared by all lanes — back-compatible)

  • keepalive: first-accepted + per-10 heartbeat gated behind E2E_VERBOSE; stop() prints one line.
  • sendDataTransaction: fix describeUpdate (it read message.value on the unwrapped generator output → always "update"; now reads the envelope key + inner fiberId/assetId/name); the healthy 3/3 per-send line is gated behind E2E_VERBOSE. Divergence/failure lines always print.
  • FlowLogger: live (write-through) mode; flush() is a no-op when live.
  • Concurrency: an interactive single-example run (TTY) defaults to 1 so its flows stream live. The isTTY gate is load-bearing — it keeps CI identical (tictactoe is a single-example lane with 3 parallel flows that must not be serialized; CI has no TTY).

Visibility (riverdale-economy)

  • New poll-only step actions phase (section banner) and economy (reads the ML0 checkpoint once and prints a per-party table: state + a few stateData fields + held assets, with deltas vs the previous snapshot, e.g. inventory 1000→500, RVD-loan 10000→0).
  • assertState/assertAsset now summarize what they observed (retailer → received (seq 1), GOODS → Fiber(retailer) ×500) instead of a bare OK.
  • example.ts: 13 phase banners + 12 economy snapshots across P0..P12 — all functional/assert steps unchanged.

Sample

── P5  lending ─────────────────────────────────
 ✓ bank.underwrite → loan_servicing
 ✓ assertState consumer → debt_current (seq 1)
 ✓ assertAsset RVD-loan → Fiber(consumer) ×10000
    │ economy ──────────────────────
    │ consumer  debt_current  +RVD-loan×10000
    │ bank      loan_servicing  loanPortfolio 0→10000  RVD-loan 10000→0

tsc-clean. phase/economy are additive early-continue no-ops (other examples unaffected); verbose-gating defaults to quiet, so every lane gets a quieter, more readable run. Run npm test -- --only riverdale-economy (in a TTY) to watch it live.

🤖 Generated with Claude Code

ottobot-ai and others added 2 commits June 25, 2026 19:24
Follow-up to the green riverdale-economy economy (PR #190): the run was
unreadable — the background keepalive + per-send DL1 lines printed live
(50+ lines over 20 min) while the flow output was buffered and dumped only
at the end, and every step just said "OK" with no view of the economy
moving.

Harness (shared by all lanes, back-compatible):
- keepalive: gate the first-accepted + per-10 heartbeat behind E2E_VERBOSE;
  stop() prints one line ("[keepalive] silent · N sent, M failed").
- sendDataTransaction: fix describeUpdate (it read message.value on the
  UNWRAPPED generator output → always "update"; now reads the envelope key
  + inner fiberId/assetId/name); gate the healthy 3/3 per-send line behind
  E2E_VERBOSE. Divergence/failure lines always print.
- FlowLogger: live (write-through) mode; flush() is a no-op when live.
- Concurrency: an INTERACTIVE single-example run (TTY) defaults to 1 so its
  flows stream live. The isTTY gate keeps CI identical — tictactoe is a
  single-example lane with 3 parallel flows that must NOT be serialized.

Visibility (riverdale-economy):
- new poll-only step actions `phase` (section banner) and `economy` (reads
  the ML0 checkpoint once and prints a per-party table: state + a few
  stateData fields + held assets, with deltas vs the previous snapshot).
- assertState/assertAsset now summarize what they observed (state+seq /
  holder+amount) instead of a bare OK.
- example.ts: 13 phase banners + 12 economy snapshots across P0..P12 (all
  functional/assert steps unchanged); friendly assetAsset labels.

tsc-clean. phase/economy are additive early-continue no-ops; verbose-gating
defaults to quiet, so all lanes get a quieter, more readable run.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R5TUSJPD8FCtJagf7siXgt
Consuming-morphism confirmation in the runner's applyMorphism path (the two
modes a source-seq-advance confirm can't observe):
- FRACTIONALIZE removes the source + writes one shard per shardId → confirm
  via the FIRST output shard's existence (confirmPath points at it).
- BURN/DECOMPOSE remove the source record → confirm via the source's ABSENCE
  (it existed pre-send, so exists→404 means the morphism committed); a small
  resubmit-aware absence poll, never re-burning a gone asset.
Non-consuming morphisms (STAKE/Transfer/Wrap) keep the source-seq-advance
confirm.

example.ts P12: STAKE was already live; now FRACTIONALIZE (mint 900 RVD into
carol's wallet → 3×300 shards, asserted) and BURN (mint 200 into frank's
wallet → burn → the economy snapshot shows it disappear) run live too. All
three approved wallet morphisms are now exercised end-to-end.

Economy snapshots: color the deltas — yellow for a changed value / departed
instance (`taxesPaid 0→50`, `RVD-tax 50→0`), green for a newly-acquired
instance (`+RVD-loan×10000`) — so the eye lands on what moved. ANSI codes are
only in the value columns, so label alignment is unaffected.

tsc-clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R5TUSJPD8FCtJagf7siXgt
@ottobot-ai ottobot-ai changed the title feat(e2e): readable economy run - quiet logs + economy snapshots feat(e2e): readable economy run + live consuming morphisms Jun 26, 2026
Cut the riverdale-economy wall-clock by running the INDEPENDENT setup steps
concurrently. The causal economic chain (lend→buy→repay→tax) stays serial —
only steps with no inter-dependency are batched.

Runner: a `parallel: true` step flag. The per-step body is extracted into a
`processStep(step, i, sw, sl, slog)` closure; a maximal run of consecutive
`parallel` steps executes via Promise.allSettled, each writing to its OWN
buffered FlowLogger that flushes in step order (concurrent output never
interleaves). The SEQUENTIAL path is byte-for-byte unchanged — the else
branch calls processStep with the flow's live logger + the same
try/catch → {passed:false, failedStep:i+1} — so no other lane is affected
(no existing example sets `parallel`). 12 step-level `continue`s became
`return`s; tsc-clean guarantees none dangle.

example.ts FLOW 1 — 3 batches (12 steps):
- P0: the 2 createAssetPolicy + retailer.machine@1.0.0 (distinct registry
  names, no shared lineage). Same-package later versions (retailer@2.0.0,
  fed@1.0.0/2.0.0) stay SEQUENTIAL: a lineage is monotonic append-only
  (VersionLineage.publish → NonMonotonic), so racing 1.0.0/2.0.0 could land
  2.0.0 first and reject 1.0.0 (the N3 negative). Causal, not parallel.
- P1: all six fiber creates (each mints its own `as` alias — distinct
  session.fibers key, no shared-mutable race).
- P2: the three RVD-leg mints into the consumer fiber (distinct assetIds).
  GOODS + RVD_LOAN mints stay sequential (split off by their assertAsset).

Concurrency-safe: every batched step writes a distinct registry name / `as`
alias / assetId, so no shared key is touched by two concurrent steps.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R5TUSJPD8FCtJagf7siXgt
@scasplte2 scasplte2 self-requested a review June 26, 2026 02:00
@scasplte2 scasplte2 merged commit 96ac483 into main Jun 26, 2026
10 checks passed
@scasplte2 scasplte2 deleted the feat/riverdale-economy-observability branch June 26, 2026 02:00
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.

2 participants