From aeab41555a4f94c15d79924dbcbb75fcebfdefcd Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Thu, 6 Aug 2026 18:00:39 +0200 Subject: [PATCH] =?UTF-8?q?docs(meta):=20D-258=20=E2=80=94=20the=20storage?= =?UTF-8?q?=20question=20was=20premature=20(T-1211=20re-scope)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 2026-07-27 amendment closed by naming the live question: does biome un-summarisation need a stored layer, or does it ride the existing sample-fresh-at-every-rung mechanism. A descent ladder answers a prior one: it is not happening in any form, stored or derived. One body, one land-anchored point, one capture per rung, no overlays, at the panel's native 3440x1440. Ferrath's heightmap is 1024x512 over a 38,089 km circumference -- 37.2 km per source pixel. Global draws at 35.267 km/gridunit, about 1:1 with the source, and reads as a world. Region draws at 0.379 -- 98x finer than anything stored -- and is a uniform colour field with dither. District, at 0.0038, is ~9,800x finer and identical in character. The Atlas is legible exactly where it samples the heightmap and flat everywhere it invents. So the D-227 carve-out cannot be argued yet on any basis, disproven or measured, because there is no artefact to store. Ruling: build the expansion as a pure function first, following the mechanism that already exists (D-255(f) mechanism B), measure that, and reopen storage only if the numbers force it. T-1211 re-scoped, T-1212 retired as a gate with its measurement moved downstream, T-1213 unblocked as the epic's first child. Recorded with the same process note the previous amendment earned: this was found by capturing the ladder and looking at it, after the goldens had been failing for 15 commits with two of them passing against blank screens. Co-Authored-By: Claude Opus 5 (1M context) --- .pql/changelog/ticket_history/2026-08.sql | 100 ++++++++++++++++++++++ .pql/changelog/tickets/2026-08.sql | 96 +++++++++++++++++++++ governance/decisions/architecture.md | 8 ++ 3 files changed, 204 insertions(+) create mode 100644 .pql/changelog/ticket_history/2026-08.sql diff --git a/.pql/changelog/ticket_history/2026-08.sql b/.pql/changelog/ticket_history/2026-08.sql new file mode 100644 index 000000000..77b0abe08 --- /dev/null +++ b/.pql/changelog/ticket_history/2026-08.sql @@ -0,0 +1,100 @@ +INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FT0TX2W0BA10PRR7NMJ2362M', 'description', 'D-258: the Atlas cascade gains a single expanded layer (''rung 0.5''), generated once per body from the rung-0 input pair (heightmap.png + reliefmap.png, never displayed), and every zoom tier below it (Region/District/Quarter/Block/Chunk) derives from that layer instead of independently re-deriving from the source files. Hydrology (drainage, course routing, lake fill) resolves ONCE on rung 0.5 and nowhere else -- it is a whole-body computation, not derivable per-window. Global displays rung 0.5 directly (biome-from-orbit, not a photograph). Same-session amendment: lake shorelines run the same shore-morphology code as ocean shorelines (coastline warp applied to both surfaces in the single rung-0.5 pass; shore-morphology gates key on proximity to water, not to ocean; sea-flavored types like TidalFlat/Estuarine-vs-Delta separated by tidal energy, a derived quantity, never by an is-it-the-ocean switch; salinity excluded from morphology entirely). This is a named, principled carve-out from D-227 derive-don''t-store: a whole-body flow solve is not locally computable, so it cannot be re-derived per window at any price -- storage here buys correctness, not convenience. Not yet ticketed prior to this epic (D-258''s own Implementation note). See governance/decisions/architecture.md#d-258. + +RE-SCOPE REQUIRED BEFORE ANY CHILD STARTS (2026-07-27, D-258 amendment). The structural rationale for this epic was disproven on evidence the day after it was written. D-258 claimed hydrology ''was not derivable at all'' per-window; in fact layer1.rs::run_layer1_with_moisture already solves drainage AND settled-equilibrium hydrology once per body, folds the filled surface into TerrainAnalysis, and every rung bilinearly samples it -- the code''s own comment calls it ''a coarse continuous primitive computed once, sampled fresh at every rung, never re-solved'' (mechanism B, D-255(f)). Compute-once-sample-everywhere already exists. What actually made Global look flat was serve_step_canvas_request zeroing Global''s wire extent (a pre-extent-inversion sentinel), producing a 2x1 canvas -- fixed 2026-07-27; once sized correctly Global reads as a world with no hydrology work at all. Rivers at Global were measured as negligible: 375 courses present, 458 of 518,400 pixels different vs courses-off, because at ~39.7 km/gridunit most courses are shorter than one gridunit. SURVIVES: biome un-summarisation (reliefmap as plurality), composition-on-descent, the conservation invariant, and the lake-shore amendment. WEAKENED: the stored expanded layer and its D-227 carve-out. The live question is no longer ''what does rung 0.5 cost'' but ''does biome un-summarisation need a stored layer at all, or does it ride the existing sample-fresh-at-every-rung mechanism''. Re-scope this epic and T-1212 against that question first.', 'D-258: the Atlas cascade gains a single expanded layer (''rung 0.5''), generated once per body from the rung-0 input pair (heightmap.png + reliefmap.png, never displayed), and every zoom tier below it (Region/District/Quarter/Block/Chunk) derives from that layer instead of independently re-deriving from the source files. Hydrology (drainage, course routing, lake fill) resolves ONCE on rung 0.5 and nowhere else -- it is a whole-body computation, not derivable per-window. Global displays rung 0.5 directly (biome-from-orbit, not a photograph). Same-session amendment: lake shorelines run the same shore-morphology code as ocean shorelines (coastline warp applied to both surfaces in the single rung-0.5 pass; shore-morphology gates key on proximity to water, not to ocean; sea-flavored types like TidalFlat/Estuarine-vs-Delta separated by tidal energy, a derived quantity, never by an is-it-the-ocean switch; salinity excluded from morphology entirely). This is a named, principled carve-out from D-227 derive-don''t-store: a whole-body flow solve is not locally computable, so it cannot be re-derived per window at any price -- storage here buys correctness, not convenience. Not yet ticketed prior to this epic (D-258''s own Implementation note). See governance/decisions/architecture.md#d-258. + +RE-SCOPE REQUIRED BEFORE ANY CHILD STARTS (2026-07-27, D-258 amendment). The structural rationale for this epic was disproven on evidence the day after it was written. D-258 claimed hydrology ''was not derivable at all'' per-window; in fact layer1.rs::run_layer1_with_moisture already solves drainage AND settled-equilibrium hydrology once per body, folds the filled surface into TerrainAnalysis, and every rung bilinearly samples it -- the code''s own comment calls it ''a coarse continuous primitive computed once, sampled fresh at every rung, never re-solved'' (mechanism B, D-255(f)). Compute-once-sample-everywhere already exists. What actually made Global look flat was serve_step_canvas_request zeroing Global''s wire extent (a pre-extent-inversion sentinel), producing a 2x1 canvas -- fixed 2026-07-27; once sized correctly Global reads as a world with no hydrology work at all. Rivers at Global were measured as negligible: 375 courses present, 458 of 518,400 pixels different vs courses-off, because at ~39.7 km/gridunit most courses are shorter than one gridunit. SURVIVES: biome un-summarisation (reliefmap as plurality), composition-on-descent, the conservation invariant, and the lake-shore amendment. WEAKENED: the stored expanded layer and its D-227 carve-out. The live question is no longer ''what does rung 0.5 cost'' but ''does biome un-summarisation need a stored layer at all, or does it ride the existing sample-fresh-at-every-rung mechanism''. Re-scope this epic and T-1212 against that question first. + +--- +RE-SCOPED 2026-08-06 (Jeroen''s call) — the epic is unblocked, and its question has changed again. + +EVIDENCE. A descent ladder was captured on Ferrath (GJ820Bc) at native 3440x1440, +anchored on land, one shot per rung, no overlays (scenarios atlas_GJ820Bc_land_* +in tests/visual.json). Ferrath''s heightmap is 1024x512 over a 38,089 km +circumference = 37.2 km per source pixel. Against that: + + Global 35.267 km/gridunit ~1:1 with the source pixel a real map + Region 0.379 km/gridunit 98x finer flat wash + District 0.0038 km/gridunit 9,800x finer flat wash + Quarter/Block/Chunk finer still flat + +The Atlas is legible exactly where it SAMPLES the heightmap and flat everywhere +it must INVENT. Every rung below Global is a single uniform colour field with +dither noise; the courses/settlements readout is 0 at all of them. + +WHAT THIS SETTLES. D-258''s amendment (5) framed the live question as "does biome +un-summarisation need a stored layer at all, or does it ride the existing +sample-fresh-at-every-rung mechanism". The ladder answers a PRIOR question: +un-summarisation is not happening in ANY form. There is no expansion to decide +the storage policy for. Storage is therefore a downstream optimisation, not the +decision this epic turns on. + +NEW SCOPE. Build the expansion first as a PURE FUNCTION, following the mechanism +that already exists rather than inventing a second one: layer1.rs''s +compute-once-sample-everywhere primitive (D-255(f) mechanism B) is the model, and +the amendment established hydrology already works that way. Measure it. Add a +stored layer ONLY if the measured cost forces it — and if it does, that is when +the D-227 carve-out argument gets made, on numbers rather than on the disproven +"not locally computable" claim. + +Order: T-1213 (the un-summarisation generator) is now the first child and is +UNBLOCKED. T-1214 (hydrology onto rung 0.5) stays parked — the amendment showed +that solve already runs once per body and does not need to move. T-1216 (Global +biome-from-orbit palette) and T-1217 (lake shores through the shared shore path) +survive unchanged; both were independent of the storage question. + +T-1212 does not gate this any more (see its own note).', NULL, '2026-08-06 15:59:03', '2026-08-06 15:59:03.757', '2026-08-06 15:59:03.757', NULL, 'eef80bb095e745421957ffdcf7ae7975', 2) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FT0TYBD74TQNVKTJMKA8D9KM', 'description', 'MUST run and be reviewed before any other T-1211 child starts -- this measurement could reshape the rung-0.5 design, per the pair session''s explicit sequencing note. Measure, at minimum: (1) per-body derive cost for the expanded layer at a resolution sized so a whole body draws at 2 screen px per gridunit on a large display (the D-258 sizing rule) -- both single-body cold-derive time and the full ~271-body population sum; (2) per-body and total disk footprint if the layer is cached/stored (rung 0.5 is a named D-227 carve-out -- storage is deliberate, but its size must be known, not assumed); (3) whole-body hydrology solve cost on this layer (drainage + course routing + lake fill) at the same resolution, since D-258 requires this to run exactly once per body and nowhere else. Reference point: D-255''s own rung-0 always-keep tier estimate went from ~8.85 MB (measured against a stale ~18K-cell/body figure) to an estimated 226 MB (1080p) / ~900 MB (4K) once the extent inversion made Global viewport-sized -- D-255 amendment item 6 explicitly says ''re-measure against rung 0.5, not against this record.'' This ticket is that re-measurement. Report back to the team before T-1211''s other children are started; if the numbers are structurally bad (e.g. rung 0.5 at the sizing D-258 specifies costs an order of magnitude more than the old rung-0 model), that is grounds to revisit the resolution target with Jeroen before writing generator code. See governance/decisions/architecture.md#d-258 (rationale + Implementation note). + +SCOPE INVALIDATED 2026-07-27 (see T-1211 and the D-258 amendment). This ticket was written to measure the cost of moving a whole-body hydrology solve onto rung 0.5. That solve does not need to move -- it already runs once per body in layer1.rs and is sampled fresh at every rung. Do NOT run this measurement as written; it would price work that is not required. If a measurement is still wanted after T-1211 is re-scoped, the question is narrower: what does BIOME un-summarisation cost, and does it need storing at all.', 'MUST run and be reviewed before any other T-1211 child starts -- this measurement could reshape the rung-0.5 design, per the pair session''s explicit sequencing note. Measure, at minimum: (1) per-body derive cost for the expanded layer at a resolution sized so a whole body draws at 2 screen px per gridunit on a large display (the D-258 sizing rule) -- both single-body cold-derive time and the full ~271-body population sum; (2) per-body and total disk footprint if the layer is cached/stored (rung 0.5 is a named D-227 carve-out -- storage is deliberate, but its size must be known, not assumed); (3) whole-body hydrology solve cost on this layer (drainage + course routing + lake fill) at the same resolution, since D-258 requires this to run exactly once per body and nowhere else. Reference point: D-255''s own rung-0 always-keep tier estimate went from ~8.85 MB (measured against a stale ~18K-cell/body figure) to an estimated 226 MB (1080p) / ~900 MB (4K) once the extent inversion made Global viewport-sized -- D-255 amendment item 6 explicitly says ''re-measure against rung 0.5, not against this record.'' This ticket is that re-measurement. Report back to the team before T-1211''s other children are started; if the numbers are structurally bad (e.g. rung 0.5 at the sizing D-258 specifies costs an order of magnitude more than the old rung-0 model), that is grounds to revisit the resolution target with Jeroen before writing generator code. See governance/decisions/architecture.md#d-258 (rationale + Implementation note). + +SCOPE INVALIDATED 2026-07-27 (see T-1211 and the D-258 amendment). This ticket was written to measure the cost of moving a whole-body hydrology solve onto rung 0.5. That solve does not need to move -- it already runs once per body in layer1.rs and is sampled fresh at every rung. Do NOT run this measurement as written; it would price work that is not required. If a measurement is still wanted after T-1211 is re-scoped, the question is narrower: what does BIOME un-summarisation cost, and does it need storing at all. + +--- +RETIRED AS A GATE 2026-08-06. This no longer blocks T-1213 or the T-1211 epic. + +It was already SCOPE INVALIDATED (2026-07-27) for pricing a hydrology move that +does not need to happen. The 2026-08-06 descent ladder (see T-1211) closes the +remaining reason to keep it as a gate: every rung below Global renders a flat +wash, so biome un-summarisation is not happening at all. There is no artefact +whose cost or disk footprint can be measured, because none is produced. + +The measurement question survives, but it is now DOWNSTREAM of T-1213 rather +than upstream of it: once the un-summarisation exists as a pure function, measure +THAT, and only then decide whether a stored layer is warranted. Re-scope this +ticket to that measurement when T-1213 lands, or close it and let T-1213 carry +its own measurement step.', NULL, '2026-08-06 15:59:12', '2026-08-06 15:59:12.825', '2026-08-06 15:59:12.825', NULL, '177c4abeb3d8bc4cb2260f81fe9f5d09', 2) ON CONFLICT(hash) DO NOTHING; +INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FT0TZC9MJV6KZTSRVRYQ327M', 'description', 'Build the deterministic expansion from rung 0 (heightmap.png 1024x512 16-bit elevation + reliefmap.png 1024x512 colour biome) to rung 0.5, sized per D-258''s 2-px-per-gridunit-at-large-display rule. Same body + same seed must produce the same layer every time (byte-identical, per D-227''s determinism discipline extended by this carve-out). The reliefmap is a PLURALITY, not ground truth: each reliefmap cell already voted-and-discarded the dominant biome across ~38 km of ground, so this generator un-summarises it -- it does not upscale/interpolate it. Three binding invariants from D-258: (1) biome edges are gradients, never lines -- transitions blend so no boundary falls on a rung-0 cell edge (the D-243 climate edge-fuzz rule applied to biome); (2) descending the ladder reveals COMPOSITION not sharpness -- a cell reading ''forest'' globally must be able to contain clearings/marsh/rock/scrub the vote suppressed, emerging deterministically as the ladder descends; (3) CONSERVATIVE invention is the binding acceptance gate -- downsampling rung 0.5 must reproduce the rung-0 summary it came from (a forest cell may gain marsh pockets but must still read as forest from orbit). Blocked on T-1212 (cost/size measurement) landing first. Depends on: nothing else in this epic to start scaffolding, but hydrology (sibling ticket) and this generator are tightly coupled -- coordinate sequencing with whoever picks up hydrology. See governance/decisions/architecture.md#d-258.', 'Build the deterministic expansion from rung 0 (heightmap.png 1024x512 16-bit elevation + reliefmap.png 1024x512 colour biome) to rung 0.5, sized per D-258''s 2-px-per-gridunit-at-large-display rule. Same body + same seed must produce the same layer every time (byte-identical, per D-227''s determinism discipline extended by this carve-out). The reliefmap is a PLURALITY, not ground truth: each reliefmap cell already voted-and-discarded the dominant biome across ~38 km of ground, so this generator un-summarises it -- it does not upscale/interpolate it. Three binding invariants from D-258: (1) biome edges are gradients, never lines -- transitions blend so no boundary falls on a rung-0 cell edge (the D-243 climate edge-fuzz rule applied to biome); (2) descending the ladder reveals COMPOSITION not sharpness -- a cell reading ''forest'' globally must be able to contain clearings/marsh/rock/scrub the vote suppressed, emerging deterministically as the ladder descends; (3) CONSERVATIVE invention is the binding acceptance gate -- downsampling rung 0.5 must reproduce the rung-0 summary it came from (a forest cell may gain marsh pockets but must still read as forest from orbit). Blocked on T-1212 (cost/size measurement) landing first. Depends on: nothing else in this epic to start scaffolding, but hydrology (sibling ticket) and this generator are tightly coupled -- coordinate sequencing with whoever picks up hydrology. See governance/decisions/architecture.md#d-258. + +--- +UNBLOCKED 2026-08-06 (T-1211 re-scope, Jeroen''s call). The T-1212 blocker edge is +removed: that measurement priced a hydrology move that is not happening, and the +descent ladder showed there is no expansion artefact to measure yet anyway. + +BUILD IT AS A PURE FUNCTION FIRST, not as a stored layer. The stored-layer half of +D-258 was materially weakened by its own 2026-07-27 amendment (the "not locally +computable" argument for the D-227 carve-out does not hold, because the whole-body +solve it cited already runs once per body in layer1.rs and is sampled at every +rung). So follow the mechanism that exists — D-255(f) mechanism B, +compute-once-sample-everywhere — measure it, and only argue for storage on those +numbers. Do NOT open with a cache. + +WHAT "FLAT" MEANS CONCRETELY, so the fix has a target. Ferrath''s heightmap is +1024x512 over a 38,089 km circumference: 37.2 km per source pixel. Global draws at +35.267 km/gridunit, roughly 1:1 with the source, and reads as a real map. Region +draws at 0.379 km/gridunit — 98x finer than any stored datum — and is a single +uniform colour with dither. District is 0.0038 km/gridunit, ~9,800x finer, also +uniform. So the acceptance bar is not subtle: at Region, ~98 gridunits across a +single source pixel must carry visible, deterministic, non-repeating composition +that still downsamples back to that pixel''s summary (D-258''s conservation +invariant, the binding gate). + +VERIFY BY CAPTURE, NOT BY REASONING. The scenarios exist: atlas_GJ820Bc_land_* +(Region/District/Quarter/Block/Chunk, one land-anchored world point, no overlays) +in tests/visual.json. Captures run offscreen under gamescope at native 3440x1440 +via tests/run-visual --screenshot — they do not steal the desktop. Re-shoot +the ladder and look at it; a green unit test proves nothing here. + +Note the ladder currently also reports courses=0 at every rung below Global — +rivers vanish on descent. That is tracked separately as T-1239 and is NOT this +ticket''s scope, but it will be visible in the same captures, so do not mistake it +for a failure of the un-summarisation work.', NULL, '2026-08-06 15:59:39', '2026-08-06 15:59:39.623', '2026-08-06 15:59:39.623', NULL, 'fff0549b0da56272e5c13e9de4374f76', 2) ON CONFLICT(hash) DO NOTHING; diff --git a/.pql/changelog/tickets/2026-08.sql b/.pql/changelog/tickets/2026-08.sql index 60d1f03df..3b6902c77 100644 --- a/.pql/changelog/tickets/2026-08.sql +++ b/.pql/changelog/tickets/2026-08.sql @@ -1 +1,97 @@ INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FXF1VDVQDQ8EFGTXX787M90R', 'bug', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Atlas rivers vanish at native resolution — 375 courses arrive, 0 drawn', 'Found 2026-08-06 when the visual capture resolution was raised from 960x540 to the native 3440x1440. On Ferrath (GJ820Bc) Global the wire delivers 375 river courses and the annotation layer draws NONE: ''courses=375 drawn=0'' in the view-transform readout. At 960x540 the SAME build drew them as visible strokes, so this is resolution-dependent, not a river-generation failure -- the courses are present and correct on the wire. Suspect the D-261 cull (drop a course below 15 px of on-screen length, 3x the 5 px stroke) or the water-truncation step: T-1237 computes the clipped/culled polylines ONCE on canvas adoption (set_frame) rather than per draw, so if adoption runs against a pre-layout or stale viewport the screen-length measurement is wrong for every course at once -- which matches an all-or-nothing drawn=0 rather than a partial cull. Note the scale moved the RIGHT way for visibility (46.792 km/gridunit at 960x540 vs 35.267 at 3440x1440 -- more gridunits across the body, so a river spans MORE of them), which makes a legitimate cull an unlikely explanation. Reproduce: tests/run-visual --screenshot atlas_GJ820Bc_Global and read the drawn= count.', 'backlog', 'high', NULL, 'client', 'D-261', '2026-08-06 14:43:24.765', '2026-08-06 14:43:24.765', NULL, '9597ed74aa67fb7ebeef78f60374d89c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); +INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FT0TX2W0BA10PRR7NMJ2362M', 'epic', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Rung-0.5 expanded layer — whole-body hydrology + biome-from-orbit base (D-258)', 'D-258: the Atlas cascade gains a single expanded layer (''rung 0.5''), generated once per body from the rung-0 input pair (heightmap.png + reliefmap.png, never displayed), and every zoom tier below it (Region/District/Quarter/Block/Chunk) derives from that layer instead of independently re-deriving from the source files. Hydrology (drainage, course routing, lake fill) resolves ONCE on rung 0.5 and nowhere else -- it is a whole-body computation, not derivable per-window. Global displays rung 0.5 directly (biome-from-orbit, not a photograph). Same-session amendment: lake shorelines run the same shore-morphology code as ocean shorelines (coastline warp applied to both surfaces in the single rung-0.5 pass; shore-morphology gates key on proximity to water, not to ocean; sea-flavored types like TidalFlat/Estuarine-vs-Delta separated by tidal energy, a derived quantity, never by an is-it-the-ocean switch; salinity excluded from morphology entirely). This is a named, principled carve-out from D-227 derive-don''t-store: a whole-body flow solve is not locally computable, so it cannot be re-derived per window at any price -- storage here buys correctness, not convenience. Not yet ticketed prior to this epic (D-258''s own Implementation note). See governance/decisions/architecture.md#d-258. + +RE-SCOPE REQUIRED BEFORE ANY CHILD STARTS (2026-07-27, D-258 amendment). The structural rationale for this epic was disproven on evidence the day after it was written. D-258 claimed hydrology ''was not derivable at all'' per-window; in fact layer1.rs::run_layer1_with_moisture already solves drainage AND settled-equilibrium hydrology once per body, folds the filled surface into TerrainAnalysis, and every rung bilinearly samples it -- the code''s own comment calls it ''a coarse continuous primitive computed once, sampled fresh at every rung, never re-solved'' (mechanism B, D-255(f)). Compute-once-sample-everywhere already exists. What actually made Global look flat was serve_step_canvas_request zeroing Global''s wire extent (a pre-extent-inversion sentinel), producing a 2x1 canvas -- fixed 2026-07-27; once sized correctly Global reads as a world with no hydrology work at all. Rivers at Global were measured as negligible: 375 courses present, 458 of 518,400 pixels different vs courses-off, because at ~39.7 km/gridunit most courses are shorter than one gridunit. SURVIVES: biome un-summarisation (reliefmap as plurality), composition-on-descent, the conservation invariant, and the lake-shore amendment. WEAKENED: the stored expanded layer and its D-227 carve-out. The live question is no longer ''what does rung 0.5 cost'' but ''does biome un-summarisation need a stored layer at all, or does it ride the existing sample-fresh-at-every-rung mechanism''. Re-scope this epic and T-1212 against that question first. + +--- +RE-SCOPED 2026-08-06 (Jeroen''s call) — the epic is unblocked, and its question has changed again. + +EVIDENCE. A descent ladder was captured on Ferrath (GJ820Bc) at native 3440x1440, +anchored on land, one shot per rung, no overlays (scenarios atlas_GJ820Bc_land_* +in tests/visual.json). Ferrath''s heightmap is 1024x512 over a 38,089 km +circumference = 37.2 km per source pixel. Against that: + + Global 35.267 km/gridunit ~1:1 with the source pixel a real map + Region 0.379 km/gridunit 98x finer flat wash + District 0.0038 km/gridunit 9,800x finer flat wash + Quarter/Block/Chunk finer still flat + +The Atlas is legible exactly where it SAMPLES the heightmap and flat everywhere +it must INVENT. Every rung below Global is a single uniform colour field with +dither noise; the courses/settlements readout is 0 at all of them. + +WHAT THIS SETTLES. D-258''s amendment (5) framed the live question as "does biome +un-summarisation need a stored layer at all, or does it ride the existing +sample-fresh-at-every-rung mechanism". The ladder answers a PRIOR question: +un-summarisation is not happening in ANY form. There is no expansion to decide +the storage policy for. Storage is therefore a downstream optimisation, not the +decision this epic turns on. + +NEW SCOPE. Build the expansion first as a PURE FUNCTION, following the mechanism +that already exists rather than inventing a second one: layer1.rs''s +compute-once-sample-everywhere primitive (D-255(f) mechanism B) is the model, and +the amendment established hydrology already works that way. Measure it. Add a +stored layer ONLY if the measured cost forces it — and if it does, that is when +the D-227 carve-out argument gets made, on numbers rather than on the disproven +"not locally computable" claim. + +Order: T-1213 (the un-summarisation generator) is now the first child and is +UNBLOCKED. T-1214 (hydrology onto rung 0.5) stays parked — the amendment showed +that solve already runs once per body and does not need to move. T-1216 (Global +biome-from-orbit palette) and T-1217 (lake shores through the shared shore path) +survive unchanged; both were independent of the storage question. + +T-1212 does not gate this any more (see its own note).', 'backlog', 'high', NULL, NULL, 'D-258', '2026-07-26 21:53:56.448', '2026-08-06 15:59:03.757', NULL, '923892406469abdd3fb6ee9041ae1cbf', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); +INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FT0TYBD74TQNVKTJMKA8D9KM', 'task', '06FT0TX2W0BA10PRR7NMJ2362M', 'Measure rung-0.5 cost/size BEFORE implementing (compute + disk, whole-body)', 'MUST run and be reviewed before any other T-1211 child starts -- this measurement could reshape the rung-0.5 design, per the pair session''s explicit sequencing note. Measure, at minimum: (1) per-body derive cost for the expanded layer at a resolution sized so a whole body draws at 2 screen px per gridunit on a large display (the D-258 sizing rule) -- both single-body cold-derive time and the full ~271-body population sum; (2) per-body and total disk footprint if the layer is cached/stored (rung 0.5 is a named D-227 carve-out -- storage is deliberate, but its size must be known, not assumed); (3) whole-body hydrology solve cost on this layer (drainage + course routing + lake fill) at the same resolution, since D-258 requires this to run exactly once per body and nowhere else. Reference point: D-255''s own rung-0 always-keep tier estimate went from ~8.85 MB (measured against a stale ~18K-cell/body figure) to an estimated 226 MB (1080p) / ~900 MB (4K) once the extent inversion made Global viewport-sized -- D-255 amendment item 6 explicitly says ''re-measure against rung 0.5, not against this record.'' This ticket is that re-measurement. Report back to the team before T-1211''s other children are started; if the numbers are structurally bad (e.g. rung 0.5 at the sizing D-258 specifies costs an order of magnitude more than the old rung-0 model), that is grounds to revisit the resolution target with Jeroen before writing generator code. See governance/decisions/architecture.md#d-258 (rationale + Implementation note). + +SCOPE INVALIDATED 2026-07-27 (see T-1211 and the D-258 amendment). This ticket was written to measure the cost of moving a whole-body hydrology solve onto rung 0.5. That solve does not need to move -- it already runs once per body in layer1.rs and is sampled fresh at every rung. Do NOT run this measurement as written; it would price work that is not required. If a measurement is still wanted after T-1211 is re-scoped, the question is narrower: what does BIOME un-summarisation cost, and does it need storing at all. + +--- +RETIRED AS A GATE 2026-08-06. This no longer blocks T-1213 or the T-1211 epic. + +It was already SCOPE INVALIDATED (2026-07-27) for pricing a hydrology move that +does not need to happen. The 2026-08-06 descent ladder (see T-1211) closes the +remaining reason to keep it as a gate: every rung below Global renders a flat +wash, so biome un-summarisation is not happening at all. There is no artefact +whose cost or disk footprint can be measured, because none is produced. + +The measurement question survives, but it is now DOWNSTREAM of T-1213 rather +than upstream of it: once the un-summarisation exists as a pure function, measure +THAT, and only then decide whether a stored layer is warranted. Re-scope this +ticket to that measurement when T-1213 lands, or close it and let T-1213 carry +its own measurement step.', 'backlog', 'high', NULL, NULL, 'D-258', '2026-07-26 21:54:06.825', '2026-08-06 15:59:12.825', NULL, 'e0d88ae134ccd57737d8eab2627e2b88', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); +INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FT0TZC9MJV6KZTSRVRYQ327M', 'story', '06FT0TX2W0BA10PRR7NMJ2362M', 'Rung-0.5 expanded-layer generator (deterministic un-summarisation of rung 0)', 'Build the deterministic expansion from rung 0 (heightmap.png 1024x512 16-bit elevation + reliefmap.png 1024x512 colour biome) to rung 0.5, sized per D-258''s 2-px-per-gridunit-at-large-display rule. Same body + same seed must produce the same layer every time (byte-identical, per D-227''s determinism discipline extended by this carve-out). The reliefmap is a PLURALITY, not ground truth: each reliefmap cell already voted-and-discarded the dominant biome across ~38 km of ground, so this generator un-summarises it -- it does not upscale/interpolate it. Three binding invariants from D-258: (1) biome edges are gradients, never lines -- transitions blend so no boundary falls on a rung-0 cell edge (the D-243 climate edge-fuzz rule applied to biome); (2) descending the ladder reveals COMPOSITION not sharpness -- a cell reading ''forest'' globally must be able to contain clearings/marsh/rock/scrub the vote suppressed, emerging deterministically as the ladder descends; (3) CONSERVATIVE invention is the binding acceptance gate -- downsampling rung 0.5 must reproduce the rung-0 summary it came from (a forest cell may gain marsh pockets but must still read as forest from orbit). Blocked on T-1212 (cost/size measurement) landing first. Depends on: nothing else in this epic to start scaffolding, but hydrology (sibling ticket) and this generator are tightly coupled -- coordinate sequencing with whoever picks up hydrology. See governance/decisions/architecture.md#d-258. + +--- +UNBLOCKED 2026-08-06 (T-1211 re-scope, Jeroen''s call). The T-1212 blocker edge is +removed: that measurement priced a hydrology move that is not happening, and the +descent ladder showed there is no expansion artefact to measure yet anyway. + +BUILD IT AS A PURE FUNCTION FIRST, not as a stored layer. The stored-layer half of +D-258 was materially weakened by its own 2026-07-27 amendment (the "not locally +computable" argument for the D-227 carve-out does not hold, because the whole-body +solve it cited already runs once per body in layer1.rs and is sampled at every +rung). So follow the mechanism that exists — D-255(f) mechanism B, +compute-once-sample-everywhere — measure it, and only argue for storage on those +numbers. Do NOT open with a cache. + +WHAT "FLAT" MEANS CONCRETELY, so the fix has a target. Ferrath''s heightmap is +1024x512 over a 38,089 km circumference: 37.2 km per source pixel. Global draws at +35.267 km/gridunit, roughly 1:1 with the source, and reads as a real map. Region +draws at 0.379 km/gridunit — 98x finer than any stored datum — and is a single +uniform colour with dither. District is 0.0038 km/gridunit, ~9,800x finer, also +uniform. So the acceptance bar is not subtle: at Region, ~98 gridunits across a +single source pixel must carry visible, deterministic, non-repeating composition +that still downsamples back to that pixel''s summary (D-258''s conservation +invariant, the binding gate). + +VERIFY BY CAPTURE, NOT BY REASONING. The scenarios exist: atlas_GJ820Bc_land_* +(Region/District/Quarter/Block/Chunk, one land-anchored world point, no overlays) +in tests/visual.json. Captures run offscreen under gamescope at native 3440x1440 +via tests/run-visual --screenshot — they do not steal the desktop. Re-shoot +the ladder and look at it; a green unit test proves nothing here. + +Note the ladder currently also reports courses=0 at every rung below Global — +rivers vanish on descent. That is tracked separately as T-1239 and is NOT this +ticket''s scope, but it will be visible in the same captures, so do not mistake it +for a failure of the un-summarisation work.', 'backlog', 'high', NULL, NULL, 'D-258', '2026-07-26 21:54:15.245', '2026-08-06 15:59:39.623', NULL, 'd9bfabaf6b4f1751a9261995f84c0b7b', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); diff --git a/governance/decisions/architecture.md b/governance/decisions/architecture.md index 66a16725d..448bc54e9 100644 --- a/governance/decisions/architecture.md +++ b/governance/decisions/architecture.md @@ -2393,6 +2393,14 @@ Technical foundation decisions that constrain implementation: engine, client-ser **Process note, recorded because it is the reusable lesson:** the false claim survived review because the regression tests for the sizing fix called `resolve_canvas_extent` directly instead of exercising the serve path — the function that was changed, not the path the data takes. The Atlas capture goldens could not have caught it either: the scenarios never supplied `body_radius_km`, Global's only spacing input, so every Global golden had been a degenerate block since creation. Two verification layers, both green, neither looking at the thing. +- **Amendment (2026-08-06 — the storage question is premature; the expansion does not exist):** the previous amendment closed by naming the live question as *"does biome un-summarisation need a stored layer at all, or does it ride the existing sample-fresh-at-every-rung mechanism."* A descent ladder captured on Ferrath (GJ820Bc) answers a **prior** question instead: un-summarisation is not happening in any form, stored or derived. + + **The measurement.** One body, one land-anchored world point, one capture per rung, no overlays, at the panel's native 3440×1440 (scenarios `atlas_GJ820Bc_land_*`). Ferrath's heightmap is 1024×512 over a 38,089 km circumference — **37.2 km per source pixel**. Against that datum: **Global** draws at 35.267 km/gridunit, roughly 1:1 with the source, and reads as a world; **Region** at 0.379 km/gridunit is **98× finer** than anything stored and renders a single uniform colour field with dither; **District** at 0.0038 km/gridunit is ~**9,800× finer** and renders the same. Quarter, Block and Chunk likewise. The pattern is exact: **the Atlas is legible precisely where it samples the heightmap, and flat everywhere it must invent.** + + **Consequence.** There is no expansion artefact whose storage policy can be decided, so the D-227 carve-out argument cannot be made yet on any basis — neither the disproven "not locally computable" claim nor a measured one. The ruling is therefore to build the un-summarisation **as a pure function first**, following the mechanism that already exists ([D-255](#d-255)(f) mechanism B, compute-once-sample-everywhere — the pattern the previous amendment established hydrology already uses), measure *that*, and open the storage question only if those numbers force it. [T-1211](../../.pql) re-scoped accordingly; [T-1212](../../.pql) retired as a gate and its measurement moved downstream of [T-1213](../../.pql), which is now the epic's first child and unblocked. + + **Process note:** this was found by capturing the ladder and looking at it, after the goldens had been failing for 15 commits and two of them had been *passing* against blank screens. Consistent with the previous amendment's lesson — the verification that finally saw the problem was an eyeball on a real render at a real resolution, not a green assertion. + --- ### D-259: Enclosed settlements — open-air requires a breathable atmosphere