# Design pass 13: the Money in/out track under Wallets in on Situation

Built on the pass 12 files (`design-pass12-2026-09-28/d2-tracks/`). One new track on Situation, `Money in/out`, directly under `Wallets in`. It comes with its compare row, its what-changed item and its Evidence block, and nothing else changes. `now.html`, `board.html` and `market.html` are byte-equal to pass 12 (cmp). The Mini Clock strip is untouched.

The edit is scripted and replayable. `scripts/patch13.py` rebuilds `situation.html` from the pass 12 file and fails unless every anchor matches exactly once.

## (a) Changes, with file and line (pass 13 `situation.html`)

The diff against pass 12 has six hunks (`diff` headers `406a407`, `462a464,474`, `547a560,581`, `747c781`, `749a784,785`, `783a820,831`):

1. `situation.html:407`: Evidence. A new `<details open>` block, `Money in/out`, with `#sumFl` and `#bFl`, directly after the `Wallets in` block.
2. `situation.html:464-474`: data and the reader:
   - The `FLOW` fixture, one entry per `IV` interval `{buyUsd, sellUsd, availableAt}`. The source comment marks it as a FIXTURE.
   - `FLOW_UNREAD` (the fixture-only `?flow=unread` switch) and `FLOW_WHY`.
   - `flowAt(m)`: the only place the page reads flow.
   - `flowLast(m)`, plus the formatters `fu()` (USD) and `fnet()` (the net phrase).
3. `situation.html:560-581`: the track, `{id:'flow', t:'Money in/out', h:84}`, inserted in `TR` right after `in`. It uses the same row markup and focus button as the other tracks: they come from the shared `TR.forEach` builder, which is unchanged.
4. `situation.html:781`: compare table. A `Money in/out` row after `Wallets entered`.
5. `situation.html:784-785`: compare what-changed. The Money in/out observation is added to `c.obs` inside `renderCompare` only.
6. `situation.html:820-831`: `renderEvidence`. The Money in/out summary and body, right after `bMo`.

**CSS: none.** The new row reuses `.tr`, `.tl`, `.ro`, `.cap`, `.t-v`, `.t-l`, `.tiles`, `.tile`, `.reads` and the `hatch()` pattern. The new SVG colours are attributes on the new elements: buy `#72C3E6`, sell `rgba(230,234,237,.45)`, net `#E6EAED` over a `#161C22` halo.

`changes()` is not touched. The header chips, the moment panel's Since you looked list and the For you counts therefore stay byte-equal. See (e) 3.

## (b) The track as built

**Place.** The row order is `Price > Wallets in > Money in/out > Participants > Holders > Attention > Safety > You`. The track shares the Wallets in column and width, 8 px below it. At 1280 its chart is 84 px tall, the same as Wallets in; the row measures 87 px.

**Draw** (`after()`, rebuilt at every moment):
- A zero line at mid-height (`h/2`), drawn full width like the other tracks' base lines. The future cover (`.fut`) sits over it, as on every track.
- Per completed interval (`end <= t`), a group `g.fb[data-i]` containing:
  - buy USD as a bar up from the zero line, `#72C3E6`;
  - sell USD as a bar down from it, `rgba(230,234,237,.45)`;
  - a 14 px horizontal net tick at `zero - net/max*H`, in `#E6EAED` on a dark halo. It sits above the line when net is positive and below when negative.
- Bar x and width are the Wallets in bar's `X(start)+1` and `X(end)-X(start)-2`. The verify reads the `rect` attributes and they match to 0.01 px.
- One scale for every interval: the largest buy or sell in `FLOW` sets the half-height `H = h/2 - 14`. The scale does not move while dragging, as with Wallets in's fixed `mx`.
- An interval with a zero buy or sell draws nothing on that side, so clean ground means read and zero. A nonzero value is at least 1.5 px.
- The current interval and every interval after the moment are not in the DOM at all.
- Opacity is the Wallets in formula applied to each group: `1` on the interval holding the moment (only `[16:57Z, 17:27Z)` at 17:27Z qualifies among completed ones), `.8` for earlier ones. The verify checks this equals the Wallets in bar's opacity at every minute.

**Value labels.**
- Labels go on the first and last drawn interval only, tabular:
  - first: above the bars, at `y=11`;
  - last: below the bars, at `h-3`.
- Long form: `$38.5K in · $4.1K out`. Phone form (width under 500 px): `+$38.5K · -$4.1K`.
- If either label would cross the moment line, both switch to the phone form. If one still crosses, that label is left out; the readout carries the figure. So nothing, text included, is drawn right of the moment. At 1280 the labels drop only for 16:32Z to 16:40Z (one narrow interval). At 390 and 360 no label shows from 16:32Z to about 16:55Z, and just after a new interval completes only the first label may show. The minute sweep is in (c).

**Readout** (the `ro` cell):

| Moment | Line 1 | Line 2 (caption) |
|---|---|---|
| A completed interval exists | `net +$14.5K in` / `net -$4.7K out` / `net $0` | `buy $26.4K · sell $11.9K · tape · 17:27Z` |
| Before the first completed interval | `not read yet` (muted) | `first read 16:32Z` |
| Tape not read (`?flow=unread`) | `not read` (muted) | `tape not read on this chain` |

- Line 1 gets its sign and word from the net of the last completed interval.
- The caption time is that interval's `availableAt`.
- The muted states return the third element `1`, like the other tracks.

**Missing data.**
- An unread interval (a `null` entry in `FLOW`) prints a hatch rect over its own extents, never a zero.
- With the tape not read, the whole track is one hatch rect from `PAD` to `w-PAD`, with the `t-l` label `money not read`. That is the Safety pattern and the pass 4 grammar.
- The default fixture has every interval read.

**Compare.**
- Table row `Money in/out` after `Wallets entered`. Each cell holds the net on line 1 and `buy $X · sell $Y` in `.cap` on line 2. With no completed interval at that side the cell is `not known at HH:MMZ`; with the tape not read it is `not read`.
- What changed: one observation, only when A and B sit in different completed intervals with different nets. Its shape is `Money in/out net -$4.7K out to net +$14.5K in`, or `Money in/out first read, net -$4.7K out` when A has none. It is timed at B's interval `availableAt` and sorted in with the other observations.
- It is never material. There is no money line in `RULE`, and adding one would be a new rule.

**Evidence** (`Money in/out`, open by default, same body pattern as `bMo`):
- Summary: `net +$14.5K in from 16:57Z to 17:27Z · 4 intervals read`, or `not known at HH:MMZ` before the first interval, or `not read · tape not read on this chain`.
- Two tiles:
  - the last interval's net, with `buy · sell`;
  - the net over completed intervals since 16:27Z, with `tape · HH:MMZ`.
- A `reads` table, one row per completed interval: `16:27Z to 16:32Z / available 16:32Z | buy $38.5K · sell $4.1K / net +$34.3K in`.
- The caption `completed intervals at or before HH:MMZ · USD at each swap's price · tape`.
- With the tape not read, one hatched tile, `not read`, `tape not read on this chain`.

**Fixture** (`FLOW`, USD):

| Interval | Wallets | Buy | Sell | Net |
|---|---|---|---|---|
| 16:27Z to 16:32Z | 638 | 38,450 | 4,120 | +34.3K |
| 16:32Z to 16:42Z | 121 | 9,580 | 14,260 | -4.7K |
| 16:42Z to 16:57Z | 102 | 18,740 | 7,210 | +11.5K |
| 16:57Z to 17:27Z | 78 | 26,380 | 11,890 | +14.5K |

- The 16:32Z to 16:42Z interval has more wallets and less money than the one beside it (121 wallets, $9.6K in, against 102 and $18.7K).
- The last interval goes the other way (78 wallets, $26.4K in, against 102 and $18.7K).
- The net-out interval is the one where the price fell (0.00142 to 0.00106).
- The page draws the pair and names nothing.

## (c) Verify output

`NODE_PATH=/home/botbox/node_modules node scripts/verify.cjs > scripts/verify-output.txt 2>&1`, foreground, 119 s, exit 0. The full output is 171 lines, in `scripts/verify-output.txt`. Pass 12 is opened in the same run.

The diff method runs at 1280, 390 and 360, with and without the entry fixture. The moments are 16:30Z (before the first interval), 16:57Z (mid-window), 17:11Z (the entry moment) and live, plus four compare pairs. On each run:
- collect every rendered string from pass 12 and pass 13: body `innerText` with all details open, plus titles, aria labels and SVG titles;
- in pass 13, first remove the new track row, the Evidence block, the compare row and the Money in/out what-changed item. When that item was the only observation, the list is put back to pass 12's `None.`;
- compare the two strings exactly.

```
== Byte-equal pages (cmp against pass 12)
PASS now.html byte-equal to pass 12 (61053 bytes, sha256 cfe6d9541bad)
PASS board.html byte-equal to pass 12 (72416 bytes, sha256 1dba6add61f2)
PASS market.html byte-equal to pass 12 (23968 bytes, sha256 906a21d5aeea)
== situation.html against pass 12: innerText outside the new track, its compare row, its what-changed item and its evidence block
PASS 1280 no entry before: 5521 chars byte-equal after removing the new elements; new-element lines +17
PASS 1280 no entry live: 6389 chars byte-equal after removing the new elements; new-element lines +31
PASS 1280 no entry cmp 16:42Z vs live: 6303 chars byte-equal after removing the new elements; new-element lines +37
PASS 390 +entry entry: 6141 chars byte-equal after removing the new elements; new-element lines +28
PASS 360 +entry cmp 17:11Z vs 17:20Z: 6096 chars byte-equal after removing the new elements; new-element lines +31
... (48 runs: 3 widths x 2 entry states x 8 moments, all PASS)
== Place: directly under Wallets in, same column, bars on the Wallets in x extents
PASS 1280 DOM order: price > in > flow > part > hold > att > safe > you
PASS 1280 rendered column: same left and width as Wallets in, 8px below it, chart height 87
PASS 1280 x extents equal the Wallets in bar of the same interval: #0 x 11.0 w 50.2 (fin+fout), #1 x 63.2 w 102.3 (fin+fout), #2 x 167.5 w 154.5 (fin+fout), #3 x 324.0 w 311.0 (fin+fout)
PASS 360 x extents equal the Wallets in bar of the same interval: #0 x 11.0 w 22.2 (fin+fout), #1 x 35.2 w 46.3 (fin+fout), #2 x 83.5 w 70.5 (fin+fout), #3 x 156.0 w 143.0 (fin+fout)
PASS 1280 lane label "Money in/out"   (and 390, 360)
== Nothing right of the moment; only completed intervals; opacity as Wallets in
PASS 1280 every minute 0 to 60: drawn intervals are those with end <= t, nothing past the moment line, opacity equals Wallets in   (and 390, 360)
     m0: 0 drawn, right edge none <= 10.0, labels []
     m5: 1 drawn, right edge 61.2 <= 62.2, labels []
     m15: 2 drawn, right edge 165.5 <= 166.5, labels [+$38.5K · -$4.1K | +$9.6K · -$14.3K]
     m30: 3 drawn, right edge 322.0 <= 323.0, labels [$38.5K in · $4.1K out | $18.7K in · $7.2K out]
     m60: 4 drawn, right edge 635.0 <= 636.0, labels [$38.5K in · $4.1K out | $26.4K in · $11.9K out]
== Readout strings
PASS 1280 live readout "net +$14.5K in" / "buy $26.4K · sell $11.9K · tape · 17:27Z"
PASS 1280 ?t=16:42Z readout "net -$4.7K out" / "buy $9.6K · sell $14.3K · tape · 16:42Z"
PASS 1280 ?t=16:30Z readout "not read yet" / "first read 16:32Z" (muted)
... (5 moments x 3 widths, all PASS)
== Value labels, first and last drawn interval only
PASS 1280 live labels: $38.5K in · $4.1K out | $26.4K in · $11.9K out
PASS 390 live labels: +$38.5K · -$4.1K | +$26.4K · -$11.9K
== Not-read form (?flow=unread)
PASS 1280 ?flow=unread: hatch x 10 to 626 of 636, text "money not read", readout "not read" / "tape not read on this chain", evidence "not read · tape not read on this chain"
... (3 moments x 3 widths, all PASS)
PASS 1280 ?flow=unread compare row: "Money in/out not read not read"
== Compare row and what changed
PASS 1280 compare 16:42Z vs live: row after Wallets entered: "Money in/out | net -$4.7K out buy $9.6K · sell $14.3K | net +$14.5K in buy $26.4K · sell $11.9K"; what changed: 17:27 ● Money in/out net -$4.7K out to net +$14.5K in
PASS 1280 compare 16:30Z vs 16:45Z: row after Wallets entered: "Money in/out | not known at 16:30Z | net -$4.7K out buy $9.6K · sell $14.3K"; what changed: 16:42 ● Money in/out first read, net -$4.7K out
PASS 1280 compare 17:11Z vs 17:20Z: ... what changed: no Money in/out item (same interval)
== Evidence block
PASS Evidence order: Wallets in > Money in/out > Participants > Holders > Attention > Safety > Market > About this data
PASS Evidence rows at live, summary "net +$14.5K in from 16:57Z to 17:27Z · 4 intervals read":
     16:27Z to 16:32Z available 16:32Z buy $38.5K · sell $4.1K net +$34.3K in
     16:32Z to 16:42Z available 16:42Z buy $9.6K · sell $14.3K net -$4.7K out
     16:42Z to 16:57Z available 16:57Z buy $18.7K · sell $7.2K net +$11.5K in
     16:57Z to 17:27Z available 17:27Z buy $26.4K · sell $11.9K net +$14.5K in
PASS Evidence at 16:47Z lists the 2 completed intervals only
== Fixture: at least one interval each way (wallets vs money in)
PASS FLOW has one entry per IV interval, no stored net; more wallets with less money: #1 (121 wallets, $9.6K in) beside #2 (102, $18.7K), ...; fewer wallets with more money: #3 (78 wallets, $26.4K in) beside #2 (102, $18.7K), ...
PASS source marks FLOW a fixture and the ?flow= switch as fixture-only
== AA contrast on the new strings (row ground, compare, evidence)
PASS 1280 AA 4.5:1 on 33 new strings, min 5.61
PASS 390 AA 4.5:1 on 33 new strings, min 5.61
== Phone: readout in two lines, no truncation; the You track
PASS 390 live readout two lines (label and "net +$14.5K in" on one, "buy $26.4K · sell $11.9K · tape · 17:27Z" on 1), no overflow
PASS 360 live readout two lines (label and "net +$14.5K in" on one, "buy $26.4K · sell $11.9K · tape · 17:27Z" on 1), no overflow
... (4 states x 2 widths, all PASS)
PASS 1280 You track top 1040 to 1135 (+95 px; Wallets in row 87 px, Money in/out row 87 px; fold 900, You bottom 211 to 306 px below it)
PASS 390 You track top 1459 to 1599 (+140 px; Wallets in row 149 px, Money in/out row 132 px; fold 844, You bottom 711 to 852 px below it)
PASS 360 You track top 1481 to 1621 (+140 px; Wallets in row 149 px, Money in/out row 132 px; fold 844, You bottom 733 to 873 px below it)
== Words
PASS "Money in/out" present byte for byte (150 renders)
PASS no lane or evidence heading named "Money" alone: Price, Wallets in, Money in/out, Participants, Holders, Attention, Safety, You, ...
PASS volume, capital flow, inflow, outflow: absent in rendered text and source
PASS pages: banned words and internal names in rendered text zero, em dashes 0 rendered, 0 in sources
PASS NOTES.md: banned words zero, em dashes 0
PASS page errors: none
ALL PASS (121 passed, 0 failed) in 119 s
```

**You track delta.** The You track moves down by the new row plus its gap: +95 px at 1280 and +140 px at 390 and 360. That is less than the Wallets in row (87 px + 8 gap at 1280; 149 px at the phone widths). You was already below the fold at every width in pass 12: its bottom edge was 211 px below it at 1280 and 711 px at 390.

**Shots** (`scripts/shots.cjs`, JPEG, all under 500 KB, largest 254 KB):
- `shots/situation-1280-live.jpg`: 1280, live, full page.
- `shots/situation-390-live.jpg`: 390, live, full page.
- `shots/situation-1280-compare-a1657.jpg`: 1280, compare with Pin A at 16:57Z against live. It shows the compare row and the aligned A line through both tracks.
- `shots/situation-1280-flow-unread.jpg`: 1280, `?flow=unread`, the not-read form.

Hashes:
```
cfe6d9541bad5ecab014b5a2d16e11bcbdca4d51114494debaac0e7a93881886  now.html (byte-equal to pass 12)
1dba6add61f231fb74870cacb7a24dad0f751d94bab9ff598e395e12c7a05989  board.html (byte-equal to pass 12)
906a21d5aeeac8fea6a73d2a371472a4985b199c2836423937e3eaff19f4d2ac  market.html (byte-equal to pass 12)
4d7ce26a1026203371b18ea0bee47908965b1d74776fd12fc42766c1ed5ee38d  situation.html
```

## (d) What pass 12 printed that no longer prints

Nothing. With the new elements removed, the rendered text matches pass 12 exactly in all 48 runs (widths, entry states, moments and compare pairs).

The one case that looks like a change is in compare mode. When pass 12's Observations list was empty (`None.`) and A and B fall in different completed intervals, the list now shows the Money in/out item instead of `None.`. That is the what-changed list gaining its new item, as the brief asks.

## (e) Open questions and the proposed contract field

1. **Totals against rates.** Wallets in draws a rate (`N a min`) because the intervals are unequal (5, 10, 15, 30 min). Money in/out draws the interval total, as the brief's labels ask (`$12.4K in`). So on the 30 min interval, the money bar is a total next to a wallet rate. The columns line up, but the heights are not the same kind of number. Should money also be drawn per minute (`$880 a min in`)? That would make the two tracks the same kind of number. It is a one-line change in `after()`.
2. **Scale.** The one shared scale is set by the launch interval ($38.5K in). The later intervals read small beside it at 390. A per-track scale is honest but flattens everything after launch. Worth a look on the phone shot.
3. **What changed and the chips.** The Money in/out item lives only in the compare list. It is not in `changes()`, because that function also feeds:
   - the header chip counts (`3 material changes · 1 observation`);
   - the moment panel's Since you looked list;
   - the entry chip.

   All three had to stay byte-equal. If Money in/out should count as an observation since your look, that is a separate change to the chip counts.
4. **Labels at narrow moments.** At 390 and 360 the value labels are left out until the drawn intervals are wide enough to hold them left of the moment, about 16:55Z. The readout carries the figure meanwhile. The alternative is anchoring the label at the moment line, flowing left, over the earlier columns.
5. **About this data.** It does not yet mention Money in/out: no source line, and no USD pricing rule. About was not a listed element. It needs a line when the field is real, `Money in and out per interval: tape swaps, USD at each swap's price`.
6. **The fixture switch.** `?flow=unread` is fixture-only. A document build removes `FLOW`, `FLOW_UNREAD` and the switch. `flowAt()` is fed by the document field below, and the not-read form is driven by the field being `null` with a reason. No `?flow=` value is read from a document.
7. **Swaps count.** The fixture does not carry a swap count, which the contract field below has. The Evidence table could show `N swaps` per interval once the field lands.

**Proposed contract field (v3.5, proposed only; `contract/` is not edited).** It mirrors §7.4 wallets:

```
flow: {
  intervals: [ { start, end, availableAt, buyUsd, sellUsd, swaps } ],   // completed intervals only (end <= asOf), same grid as wallets.intervals
  source: "tape",                                                       // USD at each swap's priceUsd
  reason: null
}
// flow = null with reason "Tape: not read on this chain." where capabilities.tape is not true
// an interval the tape did not read is present with buyUsd = sellUsd = null (hatch), never 0
// netUsd is derived by the reader (buyUsd - sellUsd), never stored
// the volume1h and netFlow1h scalars stay as they are
```

Build-4 wires it by replacing `flowAt(m)`'s body with an adapter over `flow.intervals`. The draw, readout, compare and Evidence read only `flowAt()` and `flowLast()`, so they do not change.

## (f) Freeze statement

- **Mini Clock strip:** untouched. It lives on `now.html` and `board.html`, which are byte-equal to pass 12. "No more lanes on the strip" holds.
- **Board:** frozen at pass 12 (`board.html` sha256 `1dba6add...`, byte-equal).
- **Now and Market:** byte-equal to pass 12 (`cfe6d954...`, `906a21d5...`).
- **Situation:** changes only by the new track, its compare row and what-changed item, and its Evidence block. There is no CSS change. There is no trade language, and nothing names the pair of tracks or draws a verdict from them. Nothing is deployed and nothing is sent.

Status: DONE
