Compare commits
4 commits
6e34c72906
...
4293200615
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4293200615 | ||
|
|
e966a72fd9 | ||
|
|
4e76ec24bb | ||
|
|
198695c4cc |
2 changed files with 66 additions and 22 deletions
File diff suppressed because one or more lines are too long
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
- **Type:** subsystem (live measurement + static classification)
|
||||
- **Status:** **verified — the answer is NO**, at every scope the question can be asked at
|
||||
- **Confidence:** high on the negative (measured on two boards, four AI clients, five fresh
|
||||
- **Confidence:** high on the negative (measured on two boards, three AI clients, six runs in six fresh
|
||||
processes, with the instrument's autosaves byte-identical to the published oracle);
|
||||
medium on the completeness of the site inventory (§6 says what is not covered)
|
||||
- **Owner / date:** lane PAR · 2026-09-08 · VM140 (reference) + VM145
|
||||
|
|
@ -16,11 +16,11 @@
|
|||
|
||||
---
|
||||
|
||||
## 0. The verdict, at four scopes
|
||||
## 0. The verdict, at five scopes
|
||||
|
||||
**The hypothesis is false, and it is false in the strongest available way: it fails at the
|
||||
primitive, at the site, at the client and at the turn.** There is no scope at which an AI client's
|
||||
word count is fixed.
|
||||
primitive, at the site, at the client, at the turn, and even at the point where the turn begins.**
|
||||
There is no scope at which an AI client's word count is fixed.
|
||||
|
||||
| scope | claim | measured |
|
||||
|---|---|---|
|
||||
|
|
@ -28,6 +28,7 @@ word count is fixed.
|
|||
| **per client, across turns** | one client costs the same each turn | client 32: **3** on turn 2, **7** on turn 1 |
|
||||
| **per client, across processes (path fixed)** | one client's count is a property of the board | client 512, turn 1, **one and the same `cl_RandRange` call** (the research tie-break, `0x006a8495`): **1 word** in one process, **3 words** in another |
|
||||
| **per site** | a site that is reached always costs the same | `RNG_Chance` costs **0 words** at `p ≤ 0` and `p ≥ 1`; `RNG_NextInt` is an **unbounded rejection loop** |
|
||||
| **at the start of the turn** | a client's stream position is a function of the save | client 32 began its turn at block index **9** in one process and **11** in another, from the same file |
|
||||
|
||||
The two shadow empires (496, 512) own nothing at all — no colonies, no fleets, no systems — and
|
||||
they still do not agree with each other: on turn 1, 496 spends **0** and 512 spends **1 call
|
||||
|
|
@ -230,19 +231,30 @@ It is also the sharpest available warning against the wrong conclusion: **"the c
|
|||
when the seed changed" is not evidence for roll parity.** The count is stable here because the
|
||||
*path* was stable. §3.2 holds the path fixed and moves the seed, and the count moves.
|
||||
|
||||
### 3.5 An observation this lane could not resolve
|
||||
### 3.5 The `turn1-state` outcome set is not being sampled the way the campaign assumes
|
||||
|
||||
All three `turn1-state` runs produced the same post-turn autosave, `d59bb9f2fd0eb535`, even though
|
||||
client 512's stream demonstrably differed between them (1 word, 3 words, 1 word). Lane L5 reports
|
||||
**three different files** from three runs of this pair on VM146, and `campaign/board.md` records
|
||||
`turn1-state → turn2` as non-deterministic on that basis.
|
||||
All three `turn1-state` runs produced the same post-turn autosave, `d59bb9f2fd0eb535` — **and they
|
||||
were unpinned**, each process drawing its own AI seeds, with client 512's stream demonstrably
|
||||
different between them (1 word, 3 words, 1 word: the same single `cl_RandRange` call resolving with
|
||||
different numbers of rejections, so different generator values reached the decision).
|
||||
|
||||
Both cannot be a complete description. Three identical outcomes from a k = 6 tie set (lane L4) is a
|
||||
1-in-36 coincidence, so "it is deterministic after all" is not supported either. The honest
|
||||
statement is that **the draw differs and the outcome did not**, on this guest, three times — and
|
||||
that whatever maps the drawn word onto the chosen tech is not a plain uniform index into the
|
||||
shortlist. Flagged, not resolved; it wants the tech id logged next to the draw, which is one line in
|
||||
a probe on `0x006a8390`.
|
||||
Lane CB, concurrently and on a different guest, reports the same file from **three pinned** runs,
|
||||
and notes that lane L5's own `hooks=off` run produced it too. So the tally on that workload now
|
||||
stands at roughly **seven observations of `d59bb9f2` against lane L5's report of three different
|
||||
files**, and `campaign/board.md`'s "`turn1-state → turn2` is non-deterministic" is true but much
|
||||
narrower than it reads.
|
||||
|
||||
The new thing this lane can add is that **the draw differed and the outcome did not**. Lane CB
|
||||
pinned the seed and removed the variation; this lane left the seed free, watched the variation
|
||||
happen *inside* the generator, and still got one file. Those are different experiments and they
|
||||
agree in a way that constrains the mechanism: whatever maps client 512's drawn word onto a research
|
||||
target is **not a uniform index into a six-member shortlist**. If it were, three unpinned runs
|
||||
agreeing would be a 1-in-36 coincidence on top of lane CB's 1-in-36.
|
||||
|
||||
Not resolved, and it is one line to resolve: log the chosen tech id beside the draw in a probe on
|
||||
`0x006a8390`, whose `cl_RandRange(0, n-1)` bound `n` is the shortlist size the whole `k` question is
|
||||
about. Lane CB's own honest note — that player 512's target `282` is outside the named set and
|
||||
"k = 6, all six nameable" is not closed — is the same open item seen from the outcome side.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -365,11 +377,20 @@ Listed so a later lane does not double-count them:
|
|||
as a 0/1/2 selector, while the four real `AIObject` sinks read `[pkt+0]` as the code — and none of
|
||||
those four draws anything.)*
|
||||
|
||||
The load-time cost is large and asymmetric. Measured with the lifetime census on the canonical pair:
|
||||
the three AI clients arrive at their first turn already **17, 424 and 427** words into their
|
||||
streams, and the human client's generator is at 0. `g_GlobalRNG 0x00af6e58` shows **3 words drawn,
|
||||
one per AI client construction** — a second, independent falsification of
|
||||
`ai-turn-logic.md` §5.1's "every draw from it returns 0", after lane L1's.
|
||||
**The load-time cost is large, asymmetric, and itself not fixed.** With the lifetime census on the
|
||||
canonical pair, the three AI clients arrive at their first turn already **9, 411 and 421** words
|
||||
into their streams (build `par4`, in which the nested double count is corrected), while the human
|
||||
client's generator is at word 0. And the figure moves between processes: client 32 began its turn at
|
||||
block index **9** in one run and **11** in another, because the rejection loops it runs during
|
||||
Prepare Turn resolve differently under different seeds.
|
||||
|
||||
So the AI's generator position at the start of a turn is **not** a function of the save. Two loads of
|
||||
the same file put the same client at two different stream offsets. That is a second, independent
|
||||
reason a reimplementation cannot reach a byte match on an AI empire by counting draws.
|
||||
|
||||
`g_GlobalRNG 0x00af6e58` shows **3 words drawn, one per AI client construction** — a second,
|
||||
independent falsification of `ai-turn-logic.md` §5.1's "every draw from it returns 0", after lane
|
||||
L1's, and from a different instrument.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -481,4 +502,21 @@ extend it.
|
|||
`par-{br-p1,br-p2}` (canonical pair, unpinned, two fresh processes),
|
||||
`par-pin-a1` (canonical pair, pinned), `par-{t1-br-p1,t1-br-p2,t1-br-p3}` (`turn1-state`, three
|
||||
fresh processes, the third with façade attribution), plus `parse_airng.py`, the reader
|
||||
- Addresses: `ghidra/addresses.d/lane-par.json`
|
||||
- Addresses: `ghidra/addresses.d/lane-par.json` (2 entries; validated to a scratch path,
|
||||
1,219 → 1,221, no duplicate names and no same-address-different-name)
|
||||
|
||||
### Gates, run as separate commands on a fresh build directory (rules 13, 24)
|
||||
|
||||
* `tools/clean_room_check.sh` — **OK**
|
||||
* host `ctest` — **55/55**
|
||||
* CT111 shim cross-build — **OK**, `build-shim` removed first, `par-gate-20260908T2330Z`
|
||||
|
||||
The build **deployed to the guests** was `par4-6ba2c79-20260908T2322Z`, which differs from the
|
||||
committed source only in that the two façade hook targets were written as RVA literals rather than
|
||||
`sots::addr::cl_Chance` / `cl_RandRange`. Those constants resolve to the same two RVAs
|
||||
(`0x00178cf0`, `0x001798e0`), so the gate build and the measured build are the same instrument;
|
||||
the rename is recorded here rather than left for a reader to notice.
|
||||
|
||||
`sots-engine` `main` moved to lane CB's merge while this lane ran, so the generated header on
|
||||
`wip/par` was regenerated against the pre-merge base. It must be **regenerated, never
|
||||
hand-resolved**, at merge time (rule 14).
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue