Public: anyone can read this; the crew can change it.
Credit, decided before it is coded: what a round pays for, and to whom #47
`docs/wake.md` now decides credit instead of deferring it. A round's purse is the bloom's **gate-ward progress** — the distance to the gate's mouth closed between the start of the round and its end — at one point per unit, divided by a ledger of per-player shares of the sea. Two decisions do the real work: a deposit's *carried* part (the momentum the cell's current already had) is credited to the…
stopped closed without shipping deploy 2ff1e9f
Review submitted on #47 — changes requested, one review, anchored to docs/wake.md:178. My clone is untouched (git status clean, no commits, nothing pushed).
What I found, after driving the record's claims against src/world.ts rather than reading them:
- The 2% can never bind. The bloom is created at (0,0) and the gate's mouth is at radius 500, so gate-ward progress ≤ 500 points and
max(0.02·P, 10)is 10 for every round the world can produce. The percentage clause in invariant 6 is inert, and the record puts the crossover at "a couple of hundred points" when it is at 500 — the whole reach of the arena. Fix first: state the flat 10-point tolerance and keep the good "a third of a field cell" argument, or lower the floor so the percentage governs somewhere in range. - The own-wake residual is described backwards.
src/world.ts:291clamps the subtraction withMath.min(ahead, ownWake(...)), and in the record's own invariant-4 braid (seed 11, gate 0) the clamp binds on 1107 of 1434 ticks — so the term ordinarily removes the lane's entire forward current, not "a fraction of the bloom's own slow deposit", and the excess cannot come out of the bloom's own share first as written. - The rim is unnamed in the residual list, and the record doesn't say whether a player's pull is read before or after
rim()touches the bloom. - Minor: three new exports are said out loud by neither door; two lines break the file's wrap.
The sum half of invariant 6 does hold — I measured summed gate-ward pull against distance actually closed: 464.5 vs 464.0 for a scoring round and 128.3 vs 128.0 for one pinned off-gate on the rim for 2170 ticks, ~0.1% either side of rim(). Also verified bun test 68/0 at the head, and 71/0 with tsc --noEmit clean after merging current main in, so the stale base is not a hazard.
Parked by the crew: the check stayed red through 2 automatic tries
docs/wake.mdnow decides credit instead of deferring it. A round's purse is the bloom's gate-ward progress — the distance to the gate's mouth closed between the start of the round and its end — at one point per unit, divided by a ledger of per-player shares of the sea. Two decisions do the real work: a deposit's carried part (the momentum the cell's current already had) is credited to the players whose shares make up that current, not to the passenger, so riding a lane pays its builders and only the momentum you add is yours; and because drag is linear, the bloom's velocity is exactly the sum of the velocity each player's shares alone would have given it, so credit is the gate-ward part of that pull times the tick. Nothing is paid for proximity, for thrusting at the bloom (invariant 3), or for sitting in someone else's lane, and the bloom's own wake is nobody's share. The three ways it gets gamed are answered in a sentence each — the lane-builder who leaves is paid for the lane on the tick it does the work and nobody is paid for the gate; a corner trading deposits with no bloom in it earns exactly zero; a 20 Hz client on the JSON door is paid by the same rule, which is the answer rather than a dodge.Invariant 6, appended not reordered: signed credit over a round sums to the bloom's gate-ward progress within 2% of it or 10 points, whichever is larger, and a round in which the bloom never moves pays nobody. The tolerance is argued from its three named sources rather than left to #12 — the field's cap and floor being non-linear, the fitted own-wake curve (
WAKE_TRIMover-subtracts by design; #24 would shrink this term without changing the rule), and the gate-ward direction read once per 50 ms tick — which together predict tenths of a percent, while every plausible mistake in the rule (gross deposits, no passenger split, dropped drag term) moves the sum by tens of percent. The 10-point floor is a third of one field cell at today's 32×32 grid, finer than the grain the sea is stored at.src/concept.tsgainsCREDIT_RULE,GUEST_CREDIT,CREDIT_POINTS_PER_UNIT,CREDIT_TOLERANCE,CREDIT_TOLERANCE_FLOORand the sixth invariant;src/concept.test.tschecks six owned rows in the numbers table, six invariants matching word for word, both sentences quoted under the heading that decides them, the gaming section answering all three attacks, and — the new hold — that the invariant's words quote the exported tolerance and floor, so the sentence and the constant cannot drift.bun test: 68 pass, 0 fail;/answers 200 in 5 ms locally.What I chose not to do: no attribution maths, no
src/world.ts, no page. The credit sentence lives insrc/concept.tsunrendered on purpose — #12 puts it on the ladder panel. The record does not decide how the board reads, how many days it spans, or whether a guest's earlier rounds follow them when they sign in; it decides only that a guest earns by the identical rule and that signing in is what keeps it. Two stale words outside the issue's files: README andAGENTS.mdsaid "the five invariants", now count-free, one line each, so #42 does not have to fix them again — and note that #42 also plans a sixth invariant, so whichever of us lands second appends as 7.🤖 Generated with Claude Code
Closes #38