# Contract v3.7: changes from v3.6

*W-contract-v37, 2026-09-28 19:10 Beirut onward. Brief: `briefs/W-contract-v37.md` (Sprint V20 of `SPRINT-CHAIN-2026-09-27.md`, chained after V19, build-6). Trigger: `build-4-doc/SOURCES.md` §5 item 3 and the 13:18 ruling that market cap leads on every card. `Supply.amount` was a u64 decimal string (max 18446744073709551615), which is about 18.4 whole tokens at 18 decimals. The BSC token 螃蟹 (`0x7bc023e0693589817ed258cd1507b66b1e207777`) has 1,000,000,000 tokens at 18 decimals, raw `1000000000000000000000000000` (1e27), so the build-4-doc assembler refused the read with its u64 refusal line and the BSC row carries no supply. Every 18-decimal EVM token on BSC, Base and Robinhood Chain hits the same wall. v3.7 widens the one field, keeps the readers exact at that width, and moves the stamp. No key is renamed or added; the v3.6 vocabulary stands. This is not a release.*

## How to check this

```
cd /home/botbox/.openclaw/workspace/projects/caverio/companion-2026-09-26
python3 contract/validate.py                     # exit 0: 166 passed, 0 failed (contract/VALIDATE.out; v3.6: 153)
python3 contract/validate.py --v36-compat        # exit 1 by design: 9 of 9 v3.7 vectors fail on v3.6; the pins V82 and V90 pass on both
python3 contract/validate.py --v34-compat        # exit 1 by design, line-identical to v3.6 (and --v33, --v32, --v31, --v3)
python3 contract/migrate_v36_to_v37.py --check   # exit 0: the one-time migration over legacy-v36/now-v36.json and build-6's two real documents
python3 contract/validate.py --doc /tmp/bsc-now-migrated-v37.json      # exit 0, document: OK
python3 contract/validate.py --doc /tmp/solana-now-migrated-v37.json   # exit 0, document: OK
node contract/js/parity-v37.mjs                  # exit 0: the JS reader against nowat.py; writes contract/PARITY-v37.out
python3 contract/migrate_v34_to_v35.py --check   # exit 0 (re-pointed at legacy-v36's v3.5 schemas, then one step into v3.7)
python3 contract/migrate_v32_to_v33.py --check   # exit 0 (the same, one step further)
grep -rn 'exceeds the contract [u]64' contract/    # no output
```

"Before" means v3.6 exactly as it stood at 19:10, before the first edit. `legacy-v36/` holds `nowat_v36.py`, `clocks_v36.py`, `adapter_v36.py`, `schemas_v36.py`, `projection_v36.py`, `coverage_v36.py`, `board_v36.py`, `validate_v36.py`, `vectors_v36.py`, `companion-v36.schema.json`, `now-v36.schema.json`, `COMPANION-CONTRACT-v36.md`, `state-vectors-v36.json`, `now-v36.json` (the v3.6 `fixtures/now.json`) and `VALIDATE-v36.out`, with `legacy-v36/SHA256` (`sha256sum -c` passes, 15 files). Key hashes: nowat `9268e5b1…`, clocks `d56ef6b8…` (unchanged since v3.4), companion schema `91ea623c…`, now schema `f07e8205…`, contract `7ebc5e0b…`, vectors `aa398ab5…`, now fixture `b16a9a47…`, VALIDATE `dd5ba400…`. Before the first edit, `make.py` and `vectors.py` reproduced v3.6 byte for byte (`git status` clean after the rerun). A v3.7 vector counts only if it passes on v3.7 **and** fails on v3.6, except the two pins, which restate kept rules and must pass on both.

**Vector ids.** V80 to V90, 90 in total. Each carries `briefId` and `since: v3.7`; the pins also carry `pin: true`. V01 to V79 are byte-equal to v3.6 (`v36-vectors-unchanged`).

## Item 1. `Supply.amount` width (schema, `schemas.py`, §7.2)

| | File and line (v3.7) | Before (v3.6) | After (v3.7) |
|---|---|---|---|
| **The pattern** | `schemas.py:31` `SUPPLY_AMOUNT`, used at `schemas.py:428` (`Supply.amount`) | `U64`, 0 to 18446744073709551615 | `^(0\|[1-9][0-9]{0,77})$`: 1 to 78 digits, no sign, no leading zero, no exponent, no fraction, no separators. 78 digits covers u256 (max about 1.16e77), the widest `totalSupply()` an EVM chain returns |
| **Beside it** | `schemas.py:429` `Supply.decimals` | integer 0 to 36, required | unchanged (V90 restates it) |
| **Not touched** | `schemas.py` `$defs.RawU64` | u64 | u64. It describes on-chain u64 fields (the pump.fun reserves), which really are u64 |
| **The §7.2 sentence** | Contract §7.2, `market.supplyReads[]` row, **v3.7** | none | `amount` is the raw base-unit integer as read, exact, never rounded, never a float. The token count is `amount / 10^decimals` and is derived at read, never stored. `RawU64` stays u64 |
| **The schema text** | `Supply.amount` description | "canonical u64 decimal string" | the same rule in the schema's own words, emitted into all six `*.schema.json` |

## Item 2. Exact arithmetic in both readers

| | File and line (v3.7) | Before (v3.6) | After (v3.7) |
|---|---|---|---|
| **Python count** | `nowat.py:509` `supply_tokens` | none; `market_cap_at` computed `float(p * Decimal(amount) / 10**decimals)` under the default 28-digit context | `Decimal(int(amount)).scaleb(-decimals)` under `_EXACT` (`nowat.py:133`, precision 200), exact for any 78-digit amount |
| **Python cap** | `nowat.py:538` `market_cap_at` | the product rounded at 28 significant digits, then `float` | `float(_EXACT.multiply(supply_tokens(s), p))`: the count exact, the price multiplied last, one `float` at the end. No `amount` ever passes through a float |
| **JS mirror** | new `contract/js/nowat.js` (`supplyTokensString` `:322`, `marketCapAt` `:341`, `capDisplayAt` `:530`); `contract/js/README.md` | build-6 `lib/nowat.js` (not edited) | build-6's file plus the v3.7 reader, staged for build-7 to copy in. `BigInt(amount)`, split at `decimals` into an exact integer and fraction string, then `dec()` of that string times the price and `Number` once, of the exact product (Choice 1) |
| **Parity** | `node contract/js/parity-v37.mjs` (with `contract/js/parity-v37.py`) | | writes `contract/PARITY-v37.out`, both outputs line by line. V80, V81, V82, V89 and the fixture's KESTREL row at three clocks: **9 of 9 byte-equal** (same cap to the cent, same basis, same text and title). `now_at` as build-6 `verify.cjs` section 2 compares it (build-3's nine documents, the v3.7 fixture, both real documents): **12 of 12 byte-equal**. The BSC real row with its provenance read put in: equal |

**What the width changes in numbers.** v3.6's reader already took `Decimal(amount)` exactly, so on every document on disk the v3.7 figures equal v3.6's (`supply-v37`: 1,107 row-moments over the fixtures, build-3's supply fixture and both real documents; build-3's parity files reproduce). The 28-digit context could round only when amount times price has more than 28 significant digits, which a wide amount makes likely. The u64 limit was the schema's alone.

## Item 3. The refusal reason is retired, and one new one

| | File and line (v3.7) | Before (v3.6) | After (v3.7) |
|---|---|---|---|
| **The retired line** | `build-4-doc/assemble.py:42` (`R_SUPPLY_U64`), build-7's to change | the assembler's u64 refusal, not in §10 | no reader under `contract/` refuses a canonical amount of 78 digits or fewer; `grep -rn 'exceeds the contract [u]64' contract/` returns nothing. The assembler line is listed under Still open |
| **The new reason** | Contract §10, **Supply reads (v3.7, §7.2)**; `nowat.py:132` `R_SUPPLY_AMOUNT`; `nowat.py:500` `admit_supply` | none | `supply read is not a canonical integer; not admitted`, returned as `("amount", reason)`, naming the key. It covers a sign, a fraction, an exponent, a leading zero, separators, more than 78 digits, empty and a non-string. `supply_valid_at` (`nowat.py:514`) skips a refused read, so it never reaches the cap (the row stays on basis `estimate`); the schema refuses the same shapes. `validate.py --doc` runs `admit_supply` on every `supplyReads[]` entry and on `marketCap.supply.value` |
| **The price title** | Contract §7.6a, **v3.7**; `nowat.py:753` `cap_display_at` | `cap not read` always titled `supply not read at <moment>` | the same text and basis, but when a supply read is valid at `t` and the price is what is missing, the title is `market_cap_at`'s price reason (`no USD price at this moment`, or `not on our tape yet`). Never a figure, never a tilde (V89). No reason is added for USD availability |

**The BSC real document, read with the supply admitted.** Build-7 will admit the read and still print `cap not read`, because the pool is quoted in oANTHROPIC and the tape's `priceUsd` is null throughout, so nobody should read build-7's BSC cap slot as a failure. `PARITY-v37.out`, last section: the provenance read (log id 75, amount 1e27, decimals 18, observed 13:27:21.596Z, closing read id 83 at 13:27:36.123Z) put into the row in memory gives `admit_supply` None, tokens `1000000000`, valid at asOf 13:27:28Z, `market_cap_at` `{value: null, reason: "no USD price at this moment", basis: "estimate"}`, and `cap_display_at` `cap not read` titled `no USD price at this moment`, in Python and in JS. The same title now shows on Solana's STONK at its asOf (supply valid, no USD), which is `build-4-doc/SOURCES.md` §5 item 2's wording finding, closed.

## Item 4. Vectors: see the table below (V80 to V90)

`vectors.py` `neg37` (`:946` to `:1010`), `state-vectors.json` (90 vectors, `contract: companion-v3.7`), `validate.py` ops `admit_supply` (`:774`), `supply_schema` (`:780`, the Supply schema of the version under test: v3.7's, or legacy-v36's for `--v36-compat`) and `cap_at` (`:784`, `market_cap_at` plus `cap_display_at` on one row, with `cents`).

## Item 5. Schemas, version, and the migration

| | File and line (v3.7) | Before (v3.6) | After (v3.7) |
|---|---|---|---|
| **Schemas** | `schemas.py`, emitted by `make.py` into the six `*.schema.json` | `$id .../contract/v3.5/...`, titles v3.5 | `$id .../contract/v3.7/...`, titles v3.7. Hashes: `companion.schema.json` `aeefae9c4f40e9f63503aba13cf545bfa2a5ad0e5ae1656342ee1b92e9bcc44d`, `now.schema.json` **`7ebe24dd61d25f848831cba74877fb30ec0de32608863d9e802ba64033941868`** |
| **Version** | `schemas.py:710` `Meta.contractVersion`; `make.py:258`; contract §11 | `companion-v3.5` (v3.6 kept it) | `companion-v3.7`. The pattern change is not additive in the direction that matters (a v3.7 document with a wide amount is invalid under v3.6), so the stamp moves |
| **A v3.6 document is refused** | `validate.py` `check_v37` (`:1362`) | valid | `legacy-v36/now-v36.json`'s meta under v3.7: `contractVersion: 'companion-v3.7' was expected` |
| **Migration** | `contract/migrate_v36_to_v37.py` (`migrate`, `check`) | | deterministic; moves `companion-v3.5` to `companion-v3.7` and nothing else. No field is added or renamed, no value derived, `meta.etag` left as written, no supply read invented. A bare Now has no stamp and passes unchanged. Exit 2 and nothing written on anything half-shaped: a stamp that is neither v3.5 nor v3.7, a row without `flow` (a v3.4 document), a supply amount that is not a canonical integer, an amount wider than u64 under the v3.5 stamp (no v3.6 writer wrote it), or neither a payload nor a bare Now. Idempotent |
| **Its check** (`--check`) | | | `legacy-v36/now-v36.json`: stamp moved; v3.7 Now schema 0 errors, Companion 0; the input had 1 error under v3.7 (the stamp); stamp put back gives the input exactly; `now_at` equal to v3.6's at asOf and `history.since`. Output **`/tmp/now-v36-migrated-v37.json` sha256 `bab7002650e1fe6652c8c178bc82e85eb9008815f3da1c6dcd6a1af8a1aac97e`**. `build-6/data/real/bsc-now.json` (sha256 checked `466224bc…`, read only): a bare Now, no stamp to move; v3.7 Now schema 0 errors; `now_at` unchanged. Output **`/tmp/bsc-now-migrated-v37.json` sha256 `c978f8f19520aae24b2014bd2dbc61ae83e2f09de3a88dfb42ab0d36190e0ab6`**. `build-6/data/real/solana-now.json` (sha256 checked `6e9cd3e1…`, read only): the same. Output **`/tmp/solana-now-migrated-v37.json` sha256 `4d5dbfed6b901d44eb175dc72d33077ce151ea434156cb221b2f6fb82b15a3e9`**. `validate.py --doc` on all three: exit 0, `document: OK` |
| **BSC after migration** | | | `marketCap.supply` is still null (with the assembler's reason) and `supplyReads` still empty. That is right: the assembler refused the read at write time and a migration never makes a read. Build-7 re-assembles the document from the pinned provenance bytes |
| **The older migration checks** | `migrate_v34_to_v35.py` `check`; `migrate_v32_to_v33.py` `check` | validated against the current schemas (v3.5's) | validate against `legacy-v36/`'s schemas, the v3.5 ones they were written for, then take one more step through `migrate_v36_to_v37` into v3.7 with 0 errors. Every line they printed under v3.6 is unchanged, hashes included; each adds one line for the v3.7 step |

## Item 6. Fixtures

| Fixture | v3.7 |
|---|---|
| `fixtures/now.json` KESTREL (BSC, grade C, illustrative), **extended** | `market.supplyReads` gets one 18-decimal read: amount `1000000000000000000000000000`, decimals 18, block 61234567, observed 17:14:20Z, available and valid from 17:14:25Z to 18:00:00Z, `rpc:bsc` (`make.py:1290` `KESTREL_SUPPLY`; block and clocks made up, like the row). `marketCap.basis` becomes `rpc_supply` and `marketCap.supply` holds the read. The stored cap value is unchanged (61,800 = 0.0000618 x 1e9 either way). The cap prints `$61.2K` at 17:14:25Z, `$61.8K` at asOf, and `cap not read` before 17:14:25Z (the row's first read is at 17:14:00Z). No new row |
| every other row | unchanged in value (checked: every row but KESTREL equal to `legacy-v36/now-v36.json`, and the document apart from the rows equal apart from the stamp and the etag) |
| `fixtures/agrippa.json`, `mossy.json`, `spring.json`, `board.json` | the stamp (`companion-v3.7`) and the etag over it, nothing else |
| `staging/board.json` | **not touched** (still v3.4's file byte for byte, stamp `companion-v3.3`, checked against legacy-v34's schema as before) |
| Bolo's staged documents | not touched |

`flow-rule-outputs-unchanged` now records KESTREL's basis: at the check's seven clocks, `rpc_supply` with value 61,800 at the two from 17:14:25Z on, `estimate` before, everything else equal to v3.4's outputs.

**build-0 and build-1 innerText.** `scripts/build0-fixtures.py` was run as v3.5 ran it, over http with v3.5's harness (full text kept, `/tmp/v37/it/`). build-1 and every design pass page 7 to 10: identical before and after (15 of 15); build-1 reads its own `data/`. build-0 (4 pages) differs in exactly these lines and nothing about supply: `Contract companion-v3.3` becomes `Contract companion-v3.7` on `now`, `board` and `situation?f=spring`, and on `index` `406 fields` becomes `428` and `276 illustrative fields` becomes `298`. Neither difference is v3.7's content: build-0's committed fixtures are still v3.4's, so a re-sync carries v3.5's stamp move and v3.5's 22 flow intervals too; KESTREL's supply read adds no illustrative field and no page reads it. build-0 was then restored (`git checkout -- build-0/index.html build-0/fixtures`), and all 19 pages equal the before run (Choice 4).

## Vectors (V80 to V90)

| Id | briefId | What it pins | v3.7 | v3.6 (legacy-v36/) |
|---|---|---|---|---|
| V80 | I4-wide-admitted | amount `1000000000000000000000000000`, decimals 18: `admit_supply` admits it, token count `1000000000` exactly; the v3.7 Supply schema accepts it | pass | `AttributeError: no admit_supply`; its schema refuses the read |
| V81 | I4-wide-cap | the V80 read and a tape_usd price 0.0000123 at `t` 13:27:28Z: cap 12,300.00 usd (`cents` `12300.00`), basis `rpc_supply`; `cap_display_at` prints `$12.3K`, no title; at 13:27:21Z, before both reads are available, `cap not read` titled `supply not read at 13:27:21Z` | pass | its reader gives the same figure; its schema refuses the read |
| V82 | I4-u64-unchanged (pin) | the STONK read, `814418335339229805`, decimals 9, priced 0.0000123: 10,017.35 usd (`10017.345524672526`), `rpc_supply`, `$10.0K`; both schemas accept it | pass | pass, the same output (a pin) |
| V83 | I4-refuse-sign | `-1`: refused, `amount`, `supply read is not a canonical integer; not admitted`; on a row the cap stays `estimate`, `cap not read`; the schema refuses it | pass | no callable; its reader prints a figure from it (`rpc_supply`) |
| V84 | I4-refuse-fraction | `1.5`: the same | pass | the same |
| V85 | I4-refuse-exponent | `1e27`: the same | pass | the same |
| V86 | I4-refuse-leading-zero | `0100`: the same | pass | the same |
| V87 | I4-refuse-79-digits | `1` followed by 78 zeros (79 digits): the same | pass | no callable; its reader admits it (the u64 pattern was the schema's alone) |
| V88 | I4-refuse-empty | the empty string: the same | pass | no callable; its reader raises `InvalidOperation` |
| V89 | I3-no-usd | the V80 read admitted and valid at 13:27:28Z; the one tape read quotes oANTHROPIC with `usd.value` null: `market_cap_at` null with `no USD price at this moment`, basis `estimate`; `cap_display_at` `cap not read` titled `no USD price at this moment`, never a figure, never a tilde | pass | title `supply not read at 13:27Z`; no `admit_supply` |
| V90 | I4-decimals-37 (pin) | decimals 37 refused by the Supply schema; 36 and 0 accepted | pass | pass (a pin) |

`--v36-compat`: exit 1, `9 of 9 negative vectors fail on v3.6; 2 pins pass on both, as they must`. For a pin, `validate.py` requires a pass on v3.6 as well, and a pin passing does not count toward the compat exit.

## For Bolo (B8)

1. **The field is unchanged in shape.** `market.supplyReads[]` entries are `{amount, decimals, block, observedAt, availableAt, validFrom, validTo, basis: "rpc", source: "rpc:<chain>..."}`, and `marketCap.supply` holds the read valid at asOf. No key is added, removed or renamed.
2. **`amount` is the raw integer string, up to 78 digits,** exactly as `totalSupply()` (EVM) or `getTokenSupply` `amount` (Solana) returned it, in base units: no sign, no leading zero, no exponent, no fraction, no separators. **`decimals` beside it** (0 to 36, required), read from the token contract or mint. Do not scale it, do not round it, and do not write the token count; the reader derives `amount / 10^decimals` exactly.
3. **Stamp:** `meta.contractVersion: companion-v3.7` on a payload; a bare Now carries none. Pin `now.schema.json` sha256 `7ebe24dd61d25f848831cba74877fb30ec0de32608863d9e802ba64033941868` (`$id .../contract/v3.7/now.schema.json`). The v3.5 pin `f07e8205…` refuses any 18-decimal EVM read.
4. **The validator command for a staging document**, from `companion-2026-09-26/`:
   ```
   python3 contract/validate.py --doc <path to the staging document>
   ```
   It takes a payload with `now.value` or a bare Now, checks the v3.7 schemas, runs `admit_flow` and `admit_supply` on every row, prints each row's admitted supply amounts and its cap at asOf, and runs `now_at` at asOf. Exit 0 and `document: OK` means admitted; a refused amount prints `<symbol>: market.supplyReads[i].amount: supply read is not a canonical integer; not admitted`.
5. **Nothing in your B8 plan changes.** The 16:10 note (`inbox/bolo/2026-09-28-1610-vesper-execution-scoped-continuation-b9-boot-parse-first-then-b8-supply-then-b10-flow-forward-to-the-direct-session.md`, the 16:38 append, item 1) already asked you to file the supply as the raw integer string plus decimals; v3.7 is the contract side of that request.

## Choices you may want to overrule

1. **The JS reader multiplies exactly, then takes `Number` once.** The brief's wording is `Number` of the scaled string times the price. I kept build-6's exact decimal product (`dec()` of the BigInt-split string, `decMul` by the price, `Number` of the product), because `Number(tokens) * price` is two roundings and can differ from Python in the last bit, which would break build-6's byte parity on `now_at` (verify section 2). The count still never passes through a float, and the figures agree to the cent either way.
2. **`cap_display_at`'s title changes when the price is what is missing.** The brief's V89 asks for `cap not read` and the price reason. I put the reason in the existing `title` slot, only when a supply read is valid at `t`, rather than adding a key to the return value, so every other outcome (and V78, and build-6's `{text, title, basis}` consumers) is unchanged. On disk this changes one row-moment: STONK at its asOf.
3. **A refused amount drops the read, not the row.** `now_at` does not list the row under `refusals`; the read never reaches `supply_valid_at`, the cap stays on `estimate` and prints `cap not read`. The schema refuses the document anyway, and `--doc` reports the path and reason.
4. **build-0 was restored, not re-synced** (as v3.5 did). The rerun rewrites `build-0/index.html` and the page prints the stamp, so byte-equal build-0 innerText and a re-synced build-0 cannot both hold. The rendered difference is recorded under Item 6.
5. **KESTREL was extended rather than a row added,** so the row count, order, flow checks and every page's row set stay as they were. It is BSC and illustrative already. Its supply read has no `illustrative` key because `Supply` has no such key (`additionalProperties: false`); the row is `grade C, illustrative: true`.
6. **Two pins (V82, V90) pass on v3.6 by design.** A v3.7 vector is otherwise required to fail on v3.6. The brief asks for both (u64 byte-identical, decimals 37 restated), and neither can fail on v3.6 because neither rule changed.
7. **V79 runs against the v3.5 schemas it was written for** (`legacy-v36/`), and `validate.py` also requires the v3.7 schema to refuse the same instance. V79's mention text is the `companion-v3.5` stamp, which the v3.7 schema no longer names.
8. **The migration refuses a wide amount under the v3.5 stamp** (exit 2) instead of moving the stamp over it: such a document was written against a contract that forbade it, which is half-shaped by definition.
9. **`--doc` also reads `marketCap.supply.value`,** not only `supplyReads[]`, because the BSC case put the refusal on that field.

## Verification

- `python3 contract/validate.py`: exit 0, **166 passed, 0 failed** (v3.6: 153). New: `negative:V80` to `V90`, `v36-vectors-unchanged`, `supply-v37` (the stamp refusal, no retired line in any `.py` under `contract/`, KESTREL's read, and 1,107 row-moments equal to v3.6 plus 1 with the new title). The page-string check `now-v33` (SPRING against pass 7 at 17:27, 16:57, 16:42, 16:32Z) is line-identical to v3.6's `VALIDATE.out` line and passes. `contract/VALIDATE.out` is this run.
- `--v34-compat`, `--v33-compat`, `--v32-compat`, `--v31-compat`, `--v3-compat`: exit 1 each, and each output is byte-identical to v3.6's (run from a `git archive HEAD` copy and compared with `cmp`). `--v36-compat`: exit 1, 9 of 9, 2 pins.
- `migrate_v36_to_v37.py --check`: exit 0, three outputs, hashes above. `validate.py --doc` on each: exit 0. `migrate_v34_to_v35.py --check` and `migrate_v32_to_v33.py --check`: exit 0; `diff` against v3.6's output shows only the added v3.7 lines.
- `grep -rn 'exceeds the contract [u]64' contract/`: nothing.
- **Parity (Python and JS):** `contract/PARITY-v37.out`, 9 of 9 cases (V80, V81 twice, V82, V89 twice, KESTREL three times), 12 of 12 `now_at` runs, the BSC row with its read: equal.
- **build-3 parity guard:** `build-3/scripts/dump-nowat.py`'s canonical output from the v3.7 `nowat.py`, at each `build-3/scripts/parity-*.py.json` file's own clocks and document (`/tmp/v37/parity-guard.py`): **9 of 9 byte-equal to v3.6's `nowat.py`**, and 9 of 9 byte-equal to build-3's files once `wallets.reason` (null on every row) is taken out. Without that step, 5 of 9 are byte-equal: `now`, `now-since`, `now-extra` and `now-supply` carry the `wallets.reason: null` key v3.6 added to `now_at`, which build-3's v3.5 files predate. That was already so under v3.6 and is what build-6 `verify.cjs` strips; v3.7 changes no byte of it.
- **Generators:** `make.py` and `vectors.py` rerun give byte-identical fixtures, schemas and vectors (`sha256sum -c`). Hashes: `fixtures/now.json` `7610134b…`, `state-vectors.json` `64918f1d…`, `nowat.py` `e5b793dc…`, `js/nowat.js` `f37578a0…`, `migrate_v36_to_v37.py` `3f871f74…`.
- `legacy-v36/SHA256`: `sha256sum -c` passes.
- No file under any `design-pass*` or `build-*` directory was changed: `build-0/` was restored after the rerun, the rest were only read, and `git status` shows none of them modified by this worker. No deploy. Nothing sent. No em dashes in any file written here (`grep -rn $'\xe2\x80\x94'` over them: nothing).

## Still open (for build-7, not in this brief)

- **The assembler reason line.** `build-4-doc/assemble.py:42` `R_SUPPLY_U64` and its use. Replace it with `nowat.admit_supply` (or the §10 reason `supply read is not a canonical integer; not admitted`) and admit any canonical amount of 78 digits or fewer.
- **BSC re-assembly from provenance.** Re-assemble `real/bsc-now.json` from the pinned provenance bytes (`bsc-now.provenance.json` `supply.read`, log id 75, and the closing read, id 83), stamped `companion-v3.7`. Expect the read admitted, valid 13:27:21.596Z to 13:27:36.123Z, and the cap still `cap not read`, titled `no USD price at this moment` (Item 3).
- **Pages on v3.7.** Copy `contract/js/nowat.js` into build-7's `lib/`, route the cap slot through `capDisplayAt` (so the price-reason title shows), re-pin `now.schema.json` to `7ebe24dd…`, and re-sync build-0 if wanted (Choice 4).
- **B8** files the supply as raw integer plus decimals (For Bolo) and re-pins to the v3.7 schema.
- Everything in CHANGES-v3.5 and v3.6 "Still open" stands.

Status: DONE
