diff --git a/plan/14-phase-story-tree.md b/plan/14-phase-story-tree.md index 8e873ce..2e42d49 100644 --- a/plan/14-phase-story-tree.md +++ b/plan/14-phase-story-tree.md @@ -312,10 +312,12 @@ was the pass condition. Six things worth not rediscovering: transaction, three statements, once per adventure ever. - **The identity map holds weak references, and it cost 25 % of the suite.** Resolving the head branch per node re-read the `branches` row for every node in the flush, because - nothing held a strong reference between two calls: 201 SELECTs to write 200 actions, - and 36 s → 45 s on the same 297 tests. The head is now resolved once per adventure per - flush (2 SELECTs), which put the suite back at 38.8 s *with* 20 more tests. Pinned by a - test, because the symptom is only ever a stopwatch. + nothing held a strong reference between two calls: **201 SELECTs to write 200 actions**, + and 36 s → 45 s on the same 297 tests measured back to back. The head is now resolved + once per adventure per flush — **2 SELECTs**, and the same 297 tests then time within + noise of SP1 (44.2 s each; this machine's load drifts by ~20 % between runs, so trust + the statement count, not the stopwatch). Pinned by a test that counts reads of + `branches`, because the stopwatch is all the symptom there ever was. - **The index screen is the one read scoped by head branch rather than by lineage.** `_latest_narration` picks one row per adventure for a hundred adventures at once, and a lineage clause each would put hundreds of OR-terms on that query. The two answers differ diff --git a/plan/STATUS.md b/plan/STATUS.md index e366a3e..ee9984c 100644 --- a/plan/STATUS.md +++ b/plan/STATUS.md @@ -130,9 +130,11 @@ Three things to carry forward: better invariant than the one SP1 shipped, and it was the contract that forced it. - **The SQLAlchemy identity map is weak, and that is a performance cliff.** Resolving the head branch once per node re-read the row from the database for every node in a flush — - 201 SELECTs to write 200 actions, and a 25 % slower suite (36 s → 45 s). Nothing about - the results changed; only a stopwatch could see it. Hoist the lookup out of the loop and - hold the reference for the length of the call. Now pinned by a test. + 201 SELECTs to write 200 actions, and a 25 % slower suite (36 s → 45 s, back to back). + Nothing about the results changed; only a stopwatch could see it. Hoist the lookup out + of the loop and hold the reference for the length of the call: 2 SELECTs, and the suite + back within noise of SP1. Pinned by a test that counts the reads rather than the + seconds — this machine's timings drift ~20 % between runs. - **Clause count is bounded by the window, and it is now measured.** A story forked 20 times reads its newest 32 actions naming *one* branch, for 1.07× what an unforked story of the same length costs. Reading the tail widens the lineage only when a deleted action