# Contract v3.6: changes from v3.5

*W-build6-entered-not-counted, 2026-09-28 evening Beirut. Brief: `briefs/W-build6-entered-not-counted.md` (Sprint V19 of `SPRINT-CHAIN-2026-09-27.md`). Trigger: build-4 CHECKS §4 finding 2, still open after build-5: on both real rows the cumulative is null with a reason, and Now printed `0 entered`. One item, a reader rule. No field changes, no schema changes, no vector changes, no fixture migration. 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: 153 passed, 0 failed (v3.5: 152; now-v36 added)
python3 contract/validate.py --v34-compat                 # exit 1 by design, as under v3.5 (and --v33, --v32, --v31, --v3)
python3 contract/validate.py --doc build-6/data/real/bsc-now.json      # exit 0, document: OK
python3 contract/validate.py --doc build-6/data/real/solana-now.json   # exit 0, document: OK
```

The full run over the fixtures, the staged documents and both real documents is `build-6/scripts/validate-v36-output.txt`. `VALIDATE.out` is left as the v3.5 record.

## Item 1. A null cumulative stays null at read (§7.4, the never-zero rule applied)

| | File (v3.6) | Before (v3.5) | After (v3.6) |
|---|---|---|---|
| **The rule** | Contract §7.4, the **v3.6** paragraph | §7.4 said partial coverage stays partial, never zero, but `wallets_at` did not read `cumulativeDistinctEntrants` at all | `wallets_at(row, t)` returns `cumulative: null` and `reason`: the document's reason, at every `t`, whenever `wallets.cumulativeDistinctEntrants.value` is null, whatever the admitted intervals sum to. The intervals are still returned and still drawn |
| **The code** | `nowat.py` `wallets_at` | `{intervals, cumulative: sum of admitted intervals or null}` | `{intervals, cumulative, reason}`; on a number the cumulative is the admitted sum as before and `reason` is null |
| **The readout** | `nowat.py` `readout_text` | `N entered`, or `no money seen` before any interval is admitted | `entered not counted` where `wallets_at` returns a reason; otherwise unchanged |
| **The check** | `validate.py` `now-v36`; `flow-rule-outputs-unchanged` | 152 checks | 153: `now-v36` reads every fixture row at asOf and 12, 30, 45 min before (the admitted sum, reason null), and SPRING with its cumulative nulled (null with the reason at every clock, the intervals kept, readout `entered not counted`). The v3.4 comparison takes out the new `wallets.reason` after checking it is null on every row |
| **Version strings** | CONTRACT title line, `validate.py` docstring and its before/after label, `README.md` | v3.5 | v3.6. The document stamp stays `companion-v3.5`: the schemas do not change, so every v3.5 document is a v3.6 document (v3.4 kept v3.3's stamp the same way) |

**Why.** A tape that attributes every buy to its transaction signer has no attributable first buy, so each wallets interval carries `distinctFirstBuys: 0`. The writer says so: the cumulative is null with the reason. v3.5's reader summed the intervals anyway and Now printed `0 entered`, a count nobody made. Situation already printed `not counted` for the same fact (build-5 `situation.html` line 529).

**The case.** Both real documents (build-5 `data/real/`), one row each:

| Document | Row | asOf | Intervals | Their sum | `cumulativeDistinctEntrants` | Now, v3.5 | Now, v3.6 |
|---|---|---|---|---|---|---|---|
| `real/bsc-now.json` | 螃蟹, BSC | 2026-09-28T13:27:28Z | 1,673 | 0 | null | `0 entered` | `entered not counted` |
| `real/solana-now.json` | STONK, Solana | 2026-09-28T13:27:42Z | 3,374 | 0 | null | `0 entered` | `entered not counted` |

The reason on both: `no attributable first buy on this tape; every buy is attributed to its transaction signer, not a transfer-correlated recipient`. Now prints it as the title of the entered slot.

**The fixtures, unchanged.** Every row of `fixtures/now.json`, `now-supply.json` and `now-marlin.json` carries a number, so `wallets_at` returns the same cumulative as v3.5 and `reason` null. OBOL and KESTREL have no intervals, and their slot still prints `no money seen`. The staged SPRING and Solana documents carry a null cumulative too, but `now_at` refuses their rows at every moment, so Now renders nothing different there. No fixture file changed.
