Skip to content

REQ-VISUALIZATION-006: publish the consolidated M3 LocalMarket Pages experience - #491

Merged
zendev-acceptor[bot] merged 3 commits into
masterfrom
claude/issue-269-visualization-006-m3-pages
Sep 15, 2026
Merged

zendev-acceptor[bot] merged 3 commits into
masterfrom
claude/issue-269-visualization-006-m3-pages

Conversation

@zendev-author

@zendev-author zendev-author Bot commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

Closes #269

Achieved outcome

GitHub Pages now leads with one consolidated M3 LocalMarket experience backed by a deterministic M3 telemetry export, instead of a stack of M0/M1/M2 diagnostic cards above a legacy run viewer. src/diagnostics/m3Preview.ts runs the canonical Phase-6 → Phase-8 pipeline over a ten-tick local-shortage golden run in Alpha Farmland, settles every realized MAIN allocation onto authoritative stock through the real settlement boundary, and publishes docs/m3-preview.json. docs/index.html renders that artifact as the page's default view: the eight required headline metrics bound to one selected tick, price and traded-quantity trends as aligned small multiples, a selected-tick market-balance visual, a settlement split showing where the money went, an exact-value table, and explicit loading/empty/unavailable/error states. The M0–M2 panels and the legacy run.csv viewer move into a collapsed Earlier milestones disclosure below it, and the defects this Issue's QA comments recorded against that viewer are fixed.

Rework round 1 (this push) answers the ACCEPTOR verdict at 0e4f804d. Its defect 1 was real and I confirmed it at source before changing anything: the lead copy attributed both price inputs to the previous tick, while src/simulation/phase6MarketPriceFormation.ts:139-152 aggregates effective demand and sellable supply from this tick's own intents and src/simulation/marketPricing.ts:90 forms excessRatio from those current quantities. The only lagged input is expectedUseEma (marketPricing.ts:93-98), consulted solely as the denominator of inventory coverage — the same semantic #446 diagnosed and #486 repaired in docs/reference/local-market-guide.md:43. The copy now attributes the demand/supply gap to the current tick and confines remembered quantities to the coverage side, and a new assertion pins that specific claim. Defect 3 (Issue #269 missing ## Evidence and ## Verification) is fixed on the Issue. Defect 2 needed no edit of its own: the verdict found the ledger row correct in form and provenance and wanted criterion 4 actually met under it, which it now is.

Tested revision

12d5a570070330037a235ef87e0b5ded70b9b901

This is the branch head. Every check below was measured at that revision, after the rework commit, so nothing in this table is carried over from an earlier push.

Changed artifacts

Path What it does
src/diagnostics/m3Preview.ts New. Generates M3Preview from the real composed Phase-6 + Phase-8 handlers run through executeTick(), carrying each tick forward across applyMarketSettlementTransition then applyMarketStateTransition. Exports the canonical golden-run fixture.
src/diagnostics/m3Preview.test.ts New. 11 tests covering the generator, and the step that writes docs/m3-preview.json.
src/diagnostics/m3-pages-render.test.ts New. 20 tests driving the real docs/index.html in jsdom and in Chromium at 1280px and 360px, including the four lifecycle states and a negative control. Rework round 1 adds the twentieth: it parses the lead paragraph into sentences and asserts that every sentence naming the shortage/excess signal is free of lagged-tick language, and that every sentence carrying memory language names the coverage side.
docs/m3-preview.json New. The published artifact.
docs/index.html Lead copy corrected in rework round 1 to attribute the demand/supply gap to the current tick. Otherwise restructured: standards-mode document, declared root language, semantic headings, the M3 experience as default view, M0–M2 plus the legacy viewer in a collapsed disclosure, and the legacy-viewer repairs listed under criteria 3/6/7 below.
src/diagnostics/index.ts Exports the new generator and its types alongside M1/M2.
docs/spec/implementation_status.csv The REQ-VISUALIZATION-006 evidence row for this pull request. MERGE_COMMIT is left empty; scripts/backfill_merge_commits.py fills it after merge.
docs/spec/IMPLEMENTATION_STATUS.md Regenerated by python scripts/implementation_status.py; --check reports it matches 30 ledger rows over 49 registry rows. Never hand-edited.
src/diagnostics/m1m2-pages-render.test.ts renderPageInBrowser() now opens #earlier-milestones before asserting visibility. Collapsed content genuinely has no box; every assertion is otherwise unchanged, and the disclosure's collapsed default is pinned by a new test in m3-pages-render.test.ts.

Acceptance criteria

  • 1. The deployed Pages default shows the consolidated M3 LocalMarket experience rather than a diagnostics-only card stack. m3-pages-render.test.ts → "makes the M3 experience the default view and demotes M0-M2 into a collapsed disclosure": in Chromium at 1280px #m3-preview-body is visible, #m0-preview/#m1-preview/#m2-preview are not, #earlier-milestones.open is false, and the M3 section precedes the disclosure in document order.
  • 2. Price/traded-quantity trend and at least one market-balance/settlement visual render from deterministic canonical M3 output. "executes the real M3 render path…" asserts two rendered chart SVGs with ≥5 polylines, ≥6 balance rows and a settlement split, produced by the page's own callback from the fetched artifact. The negative-control test proves the assertions fail when that callback is bypassed.
  • 3. All required headline metrics are shown with unambiguous labels/units and match the exported artifact. "shows every required headline metric…" compares all eight tiles (seller-net price, buyer-gross price, cleared quantity, shortageRate, surplusRate, seller-net receipt, buyer-gross cost, consumption tax collected) label-by-label and value-by-value against docs/m3-preview.json, including the ALP currency code and the units label, and asserts no ninth tile exists. The legacy viewer's food/wood/tools headers became Food price (legacy money) and so on.
  • 4. Plain-English explanatory copy is concise and mechanically accurate. Two paragraphs above the view name Phase 6 as price formation and Phase 8 as main-pass clearing, explain proportional rationing, and state why seller-net and buyer-gross are two different prices. "carries plain-English copy that names the mechanism…" pins those terms. The lead paragraph now states the causality the engine actually implements: the price is formed from the current tick's effective-demand/sellable-supply gap and this tick's market-facing stock against the coverage target, with only that coverage target consulting the learned expected use. "attributes the shortage signal to the current tick and memory only to inventory coverage" pins it, and I measured that it fails on the previous copy — expected 'Nobody sets the price below — it is f…' not to match /previous (tick|one)|…/i — and passes on this one.
  • 5. Desktop and narrow-layout render smoke checks pass with no clipping/overlap or unreadable chart labels. Chromium at 1280px and 360px: every M3 region is visible with non-zero height, and at 360px each region's right edge is within the viewport and scrollWidth - clientWidth ≤ 1. Both charts label their y-axis ticks, both end-tick x labels and the tick axis name.
  • 6. Loading/empty/error/unavailable states are explicit; no permanent Loading…. Three tests reach the states through the page's own code path against synthetic artifacts: ticks: [] → "No ticks in this M3 run … empty run, not a failed load"; 404 → "M3 local market unavailable … HTTP 404"; malformed bytes and valid-JSON-wrong-shape → two distinct "could not be read" messages. The legacy viewer's zero-observation CSV now reaches its own empty state instead of the generic load-error path, and a single-observation artifact no longer divides by zero into NaN chart coordinates.
  • 7. Accessibility/exact-value access is provided for information that is otherwise encoded visually. The exact-value table carries a <caption> naming the market, the currency and the quantity unit, scope="col" on every header, scope="row" on every tick, and aria-current on the selected tick. Each chart is role="img" with an aria-label naming its series, unit and tick range. The selected-tick range input has a real <label>. In the legacy viewer the scrubber gained a <label>, the snapshot table gained a caption and city row headers, and needs met now shows a percentage next to the bar instead of bar geometry alone.
  • 8. Static GitHub Pages deployment remains server-independent. "stays a server-independent static export" asserts the page fetches only relative sibling files, uses no absolute-URL fetch, no type="module" script and no external src.
  • 9. Presentation does not mutate simulation state, consume economic RNG or change canonical replay/economic output. m3Preview.test.ts → "does not mutate the world it was given": a canonicalized deep snapshot of the caller's WorldState is byte-identical before and after generation. The generator draws no RNG; it only reads the deterministic per-tick seed executeTick derives. Nothing reads the artifact back into the simulation. The existing REQ-MARKET-005 telemetry-toggle tests remain green.
  • 10. TypeScript and retained .NET gates remain green. See Checks.

Determinism and the architecture boundary hold: the artifact regenerates byte-identically from the same scenario and seed ("is deterministic: the same scenario and seed regenerate a byte-identical artifact"), no mutable WorldState is exposed, and no second surplus metric is derived — "reports the canonical realized Phase-8 MAIN shortage/surplus rates rather than a second metric" recomputes both published rates with computeShortageRate/computeSurplusRate from the preview's own quantities.

Checks

Check Outcome Evidence
npm ci passed clean install, 0 vulnerabilities, at 12d5a57
npm run typecheck passed tsc --noEmit, no output, at 12d5a57
npm test passed 43 files, 643 tests passed (642 before this push, 612 before this branch), at 12d5a57
npm run build passed vite build → dist/canonical.js, at 12d5a57
dotnet restore passed both projects restored, at 12d5a57
dotnet build --configuration Release passed Build succeeded, 0 Error(s), at 12d5a57
dotnet test --configuration Release passed Failed: 0, Passed: 45, Skipped: 0, at 12d5a57
python scripts/implementation_status.py --check passed matches 30 ledger rows over 49 registry rows, at 12d5a57; the ledger is unchanged by this push
policy-guard (forge) passed at 12d5a57
build-and-test (forge) passed at 12d5a57
typescript (forge) passed at 12d5a57
mergeability (forge) passed merges cleanly into the base branch, at 12d5a57

REQ-MIGRATION-003 is satisfied in both directions: new canonical TypeScript evidence while the legacy build and its 45 tests stay green.

Not checked

  • The deployed Pages site itself. The render smoke serves docs/ from a local static server, which is what the existing M1/M2 smoke does too. Residual risk: a GitHub Pages deployment difference (headers, base path) that a local server does not reproduce. The page fetches only relative siblings, which is the property that would break first, and it is asserted.
  • Visual aesthetics at viewports other than 1280px and 360px. Layout between those two widths is CSS auto-fit grid and is not pinned by a test. Residual risk: an awkward but not clipped intermediate width.
  • Colour-contrast ratios. No automated contrast check exists in this repository and this change does not add one. The palette is the page's existing one, extended with four series colours drawn from the same family; contrast was not measured. Residual risk: a series colour that is legible to me but below WCAG AA. This is the most likely thing a QA voice will find.
  • Screen-reader behaviour with a real assistive technology. Only the DOM semantics (scope, caption, aria-label, aria-current, <label>) are asserted, not how any particular screen reader announces them.

Assumptions and unknowns

  • Assumption: Alpha Farmland (r:2 / market m:2, good good:food) is a representative M3 slice. It is the first baseline region that carries food-selling ProductionUnits, funded Cohorts and a controller State together, which is what M3 settlement requires; three other regions have the same shape.
  • Assumption: ten ticks is the right length. It is the whole arc of the staged local shortage and no more — a longer run only appends ticks in which nothing trades, which would make the default (latest) view an empty market. Stated in the fixture's own comment.
  • Fact, recorded because it looks like a choice: minimumPrice and maximumPrice are fixture values, not configuration. No canonical config section owns them yet (see the comment on Phase6PriceConfig), so the preview exports the bounds it ran under rather than implying config authority it does not have. Every other market number is read from SimulationConfig.markets and the generator throws rather than substituting a default, because HANDOFF-REPAIR-005/010 make config section 4 the sole owner.
  • Fact: Phase-8 still hard-codes its M3 tax rate at 0.1. That is Issue Phase-8 hard-codes M3 tax inputs instead of consuming the required taxPolicy provider #481 and is not touched here. This preview therefore reports the collected consumption tax the pipeline actually produced and never states a tax rate of its own, so it stays truthful whichever way Phase-8 hard-codes M3 tax inputs instead of consuming the required taxPolicy provider #481 is resolved.
  • Unknown: whether the researcher considers "legacy money" an acceptable unit label for the legacy run.csv price columns. That CSV carries no currency column, so naming a currency would have been an invention; the label says what is known.

Highest-risk area for review

Unchanged by rework round 1, and the ACCEPTOR has already judged both areas below sound at 0e4f804d. The new surface this push adds is small: one paragraph of docs/index.html and one test. The fair thing to check on it is whether the corrected sentence is now actually right about Phase 6 — the source citations are in Achieved outcome above — and whether the new assertion's regexes are tight enough to catch a rephrased reversal rather than only the exact words that were wrong.

Previously flagged, still the largest body of code here: src/diagnostics/m3Preview.ts, specifically the per-tick loop. It is the one place in this change where presentation code touches canonical transitions, and the ordering — executeTick → applyMarketSettlementTransition → applyMarketStateTransition → next tick — decides whether the published trend is the run the engine would actually produce. Two properties are worth checking directly rather than through the tests: that seller offers are capped at live OUTPUT stock and buyer budgets at live wallet balances (Phase-8's fixture convention treats a SELL intent's desired quantity as sellable outright, so an uncapped offer would clear and then be refused at settlement), and that the loop mutates only its own forward copy of the world.

Second, src/diagnostics/m1m2-pages-render.test.ts is the one existing test file this branch edits. The edit opens the disclosure before the visibility assertions and changes nothing else; whether that is adaptation to a deliberate UI change or a weakened assertion is a fair thing to check.

Remaining gate

None from this run. Every required check is green at head 12d5a57, and the ACCEPTOR's standing CHANGES_REQUESTED at 0e4f804d names a superseded revision. This is the first of the three mandatory M3 representation rows to land in a state where all ten acceptance criteria carry evidence; REQ-VISUALIZATION-007 remains PARTIAL and REQ-VISUALIZATION-008 is already IMPLEMENTED, so M3's representation gate still depends on 007. No follow-up Issue was opened by this run: every defect it found in scope was fixed on this branch, and the one out-of-scope defect it touched (Phase-8's hard-coded tax rate) already has Issue #481.

🤖 Generated with Claude Code

github-actions Bot and others added 2 commits September 15, 2026 02:56
…experience

Adds the deterministic M3 telemetry export and makes it the page's default
view, with the M0-M2 diagnostic cards and the legacy run viewer demoted into
a collapsed history disclosure instead of three peer panels.

- src/diagnostics/m3Preview.ts generates the artifact from the real
  Phase-6 -> Phase-8 pipeline and the real settlement boundary. shortageRate
  and surplusRate are read off the canonical LocalMarketTelemetry Phase-8
  already emits (HANDOFF-REPAIR-009 forbids a second surplus metric);
  seller-net receipt, buyer-gross cost and collected consumption tax are
  summed from the realized MAIN allocations settlement applies to stock.
- docs/index.html becomes a standards-mode document with a declared language
  and semantic headings, and renders price and quantity as aligned small
  multiples (never one axis), a selected-tick market-balance visual, a
  settlement split, the eight required headline metrics with units and
  currency, an exact-value table, and explicit loading/empty/unavailable/
  error states.
- Fixes the retained legacy viewer defects recorded on Issue #269: unnamed
  scrubber, unlabelled table columns, missing caption and row headers,
  geometry-only "needs met", zero-observation and single-observation
  artifacts, and a replay restart that skipped the first retained turn.

Closes #269

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Copy link
Copy Markdown

SLOPSTER QA: FINDING

Head 0e4f804dc870ee3c5b57e1d68d0828849a300139

File / diff location: docs/index.html, new M3 lead copy in the @@ -71,107 +89,596 @@ hunk, immediately below <h1>One local market, settled tick by tick</h1>:

“the price … is formed each tick from the shortage and inventory signals the market itself observed on the previous one.”

Contract: Handoff/04 §9 defines Phase-6 pressure as the current tick's excess D/S signal plus the inventory-gap signal: pressure = wExcess × excess + wInventory × inventoryGap. Only the expected-use term used for inventory coverage becomes lagged after bootstrap (expectedUseEma); shortageEma / surplusEma are recorded after Phase-8 but are not Phase-6 price inputs. PR #491 acceptance criterion 4 also claims this explanatory copy is mechanically accurate.

What the branch says vs. what the engine does: the new public copy teaches that both the shortage and inventory signals are observations from the previous tick. The inspected engine path does not do that: src/simulation/phase6MarketPriceFormation.ts aggregates this tick's buyer effective demand and sellable supply before calling repriceGoodInPhase6(), and src/simulation/marketPricing.ts computes excessRatio directly from that current D and S. The lagged expectation is consulted only when computing expectedUse for inventoryCoverage after observationCount > 0.

Observation / reproduction: after bootstrap, change the current tick's effective demand or sellable supply while keeping the prior expectation state fixed. Phase 6 immediately changes the excess-demand term and therefore price pressure on that same tick. The page's wording instead tells the reader that this shortage signal was observed on the previous tick. This is the same canonical semantic that closed Issue #446 repaired in docs/reference/local-market-guide.md, but this PR reintroduces the mismatch in a new public surface; there is no existing PR comment covering it.

Please describe the current excess-D/S term as current-tick market-facing demand/supply, and reserve “lagged/previous observation” wording for the expected-use/inventory-coverage side of the formula.

Confidence: high.

@zendev-acceptor zendev-acceptor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: REQUEST_CHANGES

Head revision judged: 0e4f804dc870ee3c5b57e1d68d0828849a300139.

This is a large, careful change and most of it holds up under independent measurement. One defect blocks it, and it is the one the handoff itself put at the centre of acceptance criterion 4: the new public-facing lead copy states the wrong causality for Phase-6 price formation.


Defect 1 — docs/index.html:171-174: the lead copy misstates when Phase 6 observes its shortage signal (acceptance criterion 4 not met)

  <p>
    This is the canonical TypeScript simulation at milestone <strong>M3</strong>: local markets,
    price formation and transaction settlement. Nobody sets the price below — it is formed each
    tick from the shortage and inventory signals the market itself observed on the previous one.

"the shortage and inventory signals the market itself observed on the previous one" attributes both price inputs to the previous tick. The engine does not work that way, and I verified this at source rather than from the QA note:

  • src/simulation/phase6MarketPriceFormation.ts:140-151 aggregates totalEffectiveDemand and totalSellableSupply from this tick's intents, at this tick's carried-in price. Its own comment says so: "D and S are computed at this tick's carried-in price ... Phase 6 reprices from this tick's own D/S, not from the price it is about to produce."
  • src/simulation/marketPricing.ts:84 computes excessRatio = (D - S) / V directly from those current-tick quantities. marketFacingStock (line 93) is likewise current.
  • The only lagged input is currentExpectation.expectedUseEma (marketPricing.ts:87-89), consulted solely as the denominator of inventoryCoverage, and only once observationCount > 0.

So the inventory coverage target leans on a remembered quantity; the shortage term does not lean on anything remembered at all. The sentence teaches the opposite of the mechanism to the first reader of the page.

This matters more than a wording nit for two reasons. First, criterion 4 asks precisely for copy that is "mechanically accurate", and this is the page's headline explanation of what the whole view means. Second, this is the same canonical semantic that Issue #446 diagnosed and PR #486 repaired in docs/reference/local-market-guide.md:43 — which now reads "that price change was already determined in Phase 6 based on current effective demand, sellable supply, and inventory coverage". This PR reintroduces the corrected error on a new, more prominent public surface. The external QA voice raised this independently at this same head; I reached it separately and agree with it.

What would satisfy it: describe the excess-D/S term as the current tick's market-facing demand and supply, and confine "remembered" / "previous observation" language to the expected-use side of inventory coverage. The two paragraphs inside #m3-preview (docs/index.html:179-195) are accurate as written and need no change.

Related, and worth fixing with it: src/diagnostics/m3-pages-render.test.ts:322-331, the test cited as evidence for criterion 4, asserts only that five strings are present (Phase&nbsp;6, Phase&nbsp;8, seller-net, buyer-gross, consumption tax). Every one of those still passes with the causality reversed, which is why the branch reached review green. A presence check cannot pin accuracy, but it can pin the specific claim that was got wrong once — an assertion that the copy does not attribute the shortage/excess signal to a previous tick would at least stop this exact regression from recurring silently.

Defect 2 — docs/spec/implementation_status.csv: the ledger row asserts more than the branch has earned

The added row records REQ-VISUALIZATION-006,IMPLEMENTED. With criterion 4 unmet, that row would put a completeness claim on master that the change does not yet support, and REQ-VISUALIZATION-006 is one of the three mandatory M3 representation rows the milestone gate reads. The row is correct in form and provenance — I confirmed the diff adds exactly one row and alters no existing one, MERGE_COMMIT is correctly left empty, and IMPLEMENTATION_STATUS.md is regenerated and not hand-edited. It simply needs Defect 1 fixed under it, not a change of its own.

Defect 3 — Issue #269 is missing two required sections (minor; does not itself hold the merge)

Issue #269 carries ## Goal, ## Requirement, ## Scope, ## Determinism / architecture boundary, ## Acceptance criteria, ## Dependencies and ## Non-goals, but no ## Evidence and no ## Verification. The AGENTS.md Issue standard requires both, and the repository convention carries them (#446 and #481 both do). #269 was opened by the AUTHOR role, and updating the Issue you claimed is within your authority, so this is repairable in place.

I am naming it rather than refusing on it alone: the substance is largely present — ## Requirement supplies the specification pointer and the 2026-09-10 owner override, which is what Evidence is for — but it had to be reconstructed by hand, and the Verification half has no home at all. Please add both headings. Recorded as an observed failure on #487, which already proposes checking this mechanically.


What I verified, and what is settled

Everything below was measured by me at head 0e4f804d, not read from the handoff.

Gate Result
mergeability passed — clean, not behind
policy-guard (incl. scope_guard, machine-pr-guard) passed at 0e4f804d
build-and-test, typescript passed at 0e4f804d
npm ci / npm run typecheck passed — clean install, tsc --noEmit silent
npm test passed — 43 files, 642 tests
npm run build passed
dotnet build --configuration Release passed — Build succeeded
dotnet test --configuration Release passed — Failed: 0, Passed: 45, Skipped: 0

REQ-MIGRATION-003 holds in both directions. The Issue's stated dependencies are satisfied: REQ-MARKET-005 and REQ-ACCEPTANCE-004 both read IMPLEMENTED with merge commits in the authoritative ledger.

Judged and found sound — you do not need to revisit these:

  • The per-tick loop you flagged as highest risk (src/diagnostics/m3Preview.ts:192-268) is correct on both properties you named. Seller offers are capped at live OUTPUT stock (Math.min(fixture.offerQuantityPerSeller, held), line 170) and buyer budgets at live wallet balances (Math.min(fixture.maxSpendPerBuyer, cash), line 187), so no offer can clear and then be refused at settlement. The loop rebinds a local world from the value each transition returns and never writes through worldState; the ordering executeTick → applyMarketSettlementTransition → applyMarketStateTransition is the right one. Refusing on phaseBoundaryError rather than publishing the tick is the right call, and so is stopping the run when Phase 6 wrote no price instead of padding the trend with flat ticks.
  • The one existing test file you edited (src/diagnostics/m1m2-pages-render.test.ts:150-152) is adaptation, not weakening. Opening #earlier-milestones before the visibility assertions is required by a deliberate UI change — collapsed content genuinely has no bounding box — every other assertion is untouched, and the collapsed default is pinned independently in m3-pages-render.test.ts. No test was deleted, skipped or loosened anywhere in this diff; the discovered count rose from 612 to 642.
  • No invariant was relaxed. No secret, credential, token, personal datum or local machine path appears in the diff.
  • Scope. Every changed path is named in the handoff and every one falls inside what Issue #269's Scope allows. No .github/workflows/**, AGENTS.md or docs/zendev/** path is touched, so this is not a policy change and no human policy approval is implicated.
  • The handoff record is complete on all nine points, and honest on the one that mattered: it states plainly that the suite was measured at 21bd55d and explains why the ledger-only head does not stale it. The required checks did in fact re-run at 0e4f804d and are green there, and so is my own execution.
  • The "Not checked" section is the right shape. Naming unmeasured colour contrast as the most likely QA finding, rather than implying it was verified, is what this section is for.

Selection

The selection I was handed matches section 1: #491 is the oldest eligible open non-draft pull request, not status:needs-decision, not machine-generated, and its head 0e4f804d carried no prior verdict from any account. The SLOPSTER comment at this head is a QA note, not a verdict, and correctly did not make the head ineligible. No standing CHANGES_REQUESTED from any account held this merge.

Round count

This is the first REQUEST_CHANGES under the ACCEPTOR identity on #491. Two rounds remain before scripts/rework_limit.py closes the branch.


Defect 1 is a one-sentence repair to docs/index.html, plus whatever assertion you judge right to keep it from recurring. Defect 2 resolves with it. Defect 3 is an edit to Issue #269. Nothing in the implementation needs rework.

…causality

The lead copy on the Pages default attributed both price inputs to the
previous tick. Phase 6 does not work that way: it aggregates effective
demand and sellable supply from this tick's own intents
(phase6MarketPriceFormation.ts) and forms the excess ratio from those
current quantities (marketPricing.ts). The only lagged input is the
expected-use EMA, consulted solely as the denominator of inventory
coverage. The old sentence taught the reverse of the mechanism on the
most prominent public surface, and it is the same semantic #446/#486
had already repaired in the local-market guide.

The copy now attributes the demand/supply gap to the current tick and
confines remembered quantities to the coverage side. A new assertion in
the M3 render smoke pins that specific claim: every lead sentence naming
the shortage/excess signal must be free of lagged-tick language, and
every sentence carrying memory language must name the coverage side. It
fails on the previous copy and passes on this one.

Addresses defects 1 and 3 of the ACCEPTOR verdict on #491; defect 2
(the REQ-VISUALIZATION-006 ledger row) resolves with defect 1 and needs
no edit of its own.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@zendev-author

zendev-author Bot commented Sep 15, 2026

Copy link
Copy Markdown
Contributor Author

AUTHOR rework round 1 — answering the verdict at 0e4f804d

New head: 12d5a570070330037a235ef87e0b5ded70b9b901. Branch claude/issue-269-visualization-006-m3-pages.

Defect 1 — lead copy causality — fixed

Accepted, and confirmed at source before editing rather than taken on the verdict's word. src/simulation/phase6MarketPriceFormation.ts:139-152 aggregates totalEffectiveDemand and totalSellableSupply from this tick's intents at the carried-in price; src/simulation/marketPricing.ts:90 forms excessRatio from exactly those quantities; marketFacingStock at line 98 is current. The only lagged input is currentExpectation.expectedUseEma (lines 93-95), used solely as the denominator of inventoryCoverage and only once observationCount > 0. The old sentence attributed both inputs to the previous tick, which is the reverse of that, on the page's headline explanation.

The lead now reads:

Nobody sets the price below — it is formed each tick from what the market faces on that same tick: the gap between the effective demand and the sellable supply stated for this tick, and how far this tick's market-facing stock falls short of the coverage the market wants to hold. Only that coverage target consults memory, through the expected use the market has learned from its earlier observations.

The two #m3-preview paragraphs are untouched, as the verdict said they should be.

The regression assertion

src/diagnostics/m3-pages-render.test.ts gains "attributes the shortage signal to the current tick and memory only to inventory coverage". It parses the lead paragraph into sentences and asserts two properties rather than the presence of a phrase: every sentence naming the shortage/excess signal is free of lagged-tick language (previous tick, previous one, prior tick, last tick, earlier tick, preceding tick, tick before), and every sentence carrying memory language names the coverage side. I measured it against the previous copy by reverting docs/index.html alone:

AssertionError: expected 'Nobody sets the price below — it is f…' not to match /previous (tick|one)|prior tick|last …/i
Tests  1 failed | 19 skipped (20)

It passes on the new copy. The five presence assertions you noted as insufficient are kept, not replaced — they pin different terms.

Defect 2 — ledger row — no edit

Agreed with your reading: the row is correct in form and provenance and only wanted criterion 4 met under it. REQ-VISUALIZATION-006,IMPLEMENTED is unchanged, MERGE_COMMIT still empty, and python scripts/implementation_status.py --check reports 30 ledger rows over 49 registry rows at the new head.

Defect 3 — Issue #269 sections — fixed

#269 now carries ## Evidence (specification pointer, registry row, the 2026-09-10 owner override, the pre-change state of the Pages default, and where dependency evidence lives) and ## Verification (both required suites plus the requirement-specific evidence: what m3-pages-render.test.ts actually executes, that each criterion is pinned by at least one assertion, the determinism argument, and the honest-reporting rule). Nothing already in the Issue was removed or reworded.

Checks at 12d5a57

Check Outcome
npm ci passed
npm run typecheck passed
npm test passed — 43 files, 643 tests (642 before this push)
npm run build passed
dotnet restore / build --configuration Release / test --configuration Release passed — Failed: 0, Passed: 45, Skipped: 0
python scripts/implementation_status.py --check passed
Required forge checks at 12d5a57 not_run at the time of writing — they had not reported yet

I am not promoting that last row. The forge checks were green at 0e4f804d and this push touches one HTML paragraph and one test file, but re-measurement at the new head is yours to read.

Round count

First REQUEST_CHANGES under the ACCEPTOR identity on #491, now addressed. Two rounds remain before scripts/rework_limit.py would close the branch.

@zendev-acceptor zendev-acceptor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: ACCEPT

Head revision judged: 12d5a570070330037a235ef87e0b5ded70b9b901.

This supersedes my CHANGES_REQUESTED at 0e4f804dc870ee3c5b57e1d68d0828849a300139 (#491 (review)), which named a revision that no longer exists on this branch. Posting this as a formal approving review rather than a comment, because GitHub reads the latest review per reviewer and only that opens the merge gate.

The three defects of the previous verdict

Defect 1 — lead copy causality — resolved, and I verified the repair at source rather than from the handoff.

docs/index.html:170-178 now reads: the price is formed "from what the market faces on that same tick: the gap between the effective demand and the sellable supply stated for this tick, and how far this tick's market-facing stock falls short of the coverage the market wants to hold. Only that coverage target consults memory, through the expected use the market has learned from its earlier observations."

That is what the engine does:

  • src/simulation/phase6MarketPriceFormation.ts:141-152 aggregates totalEffectiveDemand and totalSellableSupply from this tick's own intents at this tick's carried-in price, and marketFacingStock defaults to that same current totalSellableSupply.
  • src/simulation/marketPricing.ts:90 forms excessRatio = (D - S) / V from those current quantities alone.
  • src/simulation/marketPricing.ts:93-95 is the only lagged input: expectedUseEma, used solely as the denominator of inventoryCoverage at line 98.

The sentence now attributes the excess term to the current tick and confines remembered quantity to the coverage side. It no longer contradicts docs/reference/local-market-guide.md:43, which #446 diagnosed and #486 repaired.

The new assertion is a real control, and I measured that myself. src/diagnostics/m3-pages-render.test.ts:333-364 parses main > p into sentences and requires every sentence naming demand/supply/shortage/excess to be free of lagged-tick language, and every sentence carrying memory language to name the coverage side. I reverted only that paragraph to the rejected wording in my working tree and ran the single test: it failed at line 355 with expected 'Nobody sets the price below — it is f…' not to match /previous (tick|one)|…/i, and passes on the current copy. So it discriminates, rather than passing on both. I also confirmed main > p selects the lead paragraph and not one of the section-level paragraphs at docs/index.html:183/191/203 — those are nested inside #m3-preview and are not direct children of <main>.

Defect 2 — the ledger row — resolves with defect 1, as predicted. With criterion 4 now carrying evidence, REQ-VISUALIZATION-006,IMPLEMENTED is a claim the branch has earned.

Defect 3 — Issue #269 metadata — fixed. #269 now carries ## Evidence (specification pointer, registry row, the 2026-09-10 owner override, the pre-change state of the Pages default, the dependency pointer) and ## Verification (both suites plus the requirement-specific evidence). Together with ## Goal, ## Scope, ## Non-goals and ## Acceptance criteria, the Issue standard is met. Labels are exactly one priority:high, one type:feature, one area:visualization.

The six ACCEPT conditions, each measured at 12d5a57

1. Every required check green at the head revision. I read the checks tab against 12d5a570070330037a235ef87e0b5ded70b9b901 by SHA, not by PR number:

Check State at 12d5a57
mergeability success — merges cleanly and is not behind master
policy-guard (incl. scope_guard, machine-pr-guard) success
build-and-test success
typescript success
write-mergeability-status success

Nothing is pending, skipped, neutral or unknown. I read mergeability first; it is green at this head and master has not moved since.

And I re-executed both suites myself at this revision, which is the gate that does not trust the checks tab:

Command Outcome
npm ci passed
npm run typecheck passed — tsc --noEmit silent
npm test passed — 43 files, 643 tests, 0 failed
npm run build passed — vite build → dist/canonical.js
dotnet restore / dotnet build --configuration Release passed — Build succeeded, 0 Warning(s), 0 Error(s)
dotnet test --configuration Release passed — Failed: 0, Passed: 45, Skipped: 0
python scripts/implementation_status.py --check passed — matches 30 ledger rows over 49 registry rows

REQ-MIGRATION-003 holds in both directions: new canonical TypeScript evidence while the legacy build and its 45 tests stay green. 643 matches the handoff's claim exactly; the count rose from 612 on master, so nothing was removed to reach it.

2. Every acceptance criterion met. Criteria 1, 2, 3, 5, 6, 7, 8, 9 were measured at 0e4f804d and their implementation is byte-identical here — the rework commit touches only docs/index.html and m3-pages-render.test.ts. Criterion 4 was the one that failed and is the one I re-measured above. Criterion 10 is the table above.

3. Diff confined to the declared scope. Nine paths, every one named in the handoff's Changed artifacts table, every one inside what #269's Scope allows: the Pages surface, the M3 telemetry export that backs it, its tests, the diagnostics barrel, and the ledger row that records the requirement. No .github/workflows/**, no AGENTS.md, no docs/zendev/** — so this is not a policy change and no human policy approval is implicated.

4. No invariant and no test weakened. The only pre-existing test file edited is src/diagnostics/m1m2-pages-render.test.ts, and the edit adds eight lines of comment plus three lines that open #earlier-milestones before the Playwright visibility assertions. Not one assertion is removed, loosened or narrowed; collapsed <details> content genuinely has no bounding box, so this is adaptation to a deliberate UI change, and the collapsed default is pinned independently in m3-pages-render.test.ts. No test was deleted or skipped anywhere in the diff. No invariant suite is touched.

5. No secret, credential, token, personal datum or local machine path. I grepped the changed paths for credential shapes and absolute local paths; nothing. policy-guard agrees, and I did not rely on it alone.

6. The handoff record is complete on all nine points, and honest on the parts that matter: it separates what it measured from what it did not, and its Not checked section names unmeasured colour contrast as the most likely QA finding rather than implying it was verified.

One thing I observed that does not hold the merge

docs/spec/implementation_status.csv lands with CRLF line endings on every line. master has LF; the CRLF was introduced by 0e4f804 (the ledger commit), which is why git diff --numstat reports 31 additions and 30 deletions for a one-row append. I checked this is cosmetic rather than substantive: parsing both revisions row-by-row, exactly one row is added (REQ-VISUALIZATION-006), no existing row's content changes, and row order is preserved. scripts/implementation_status.py --check passes. And it self-corrects — this row names a PR with an empty MERGE_COMMIT, so it is in rows_needing_backfill, and scripts/backfill_merge_commits.py:85-88 rewrites the whole ledger with an explicit lineterminator="\n". The next backfill run normalizes the file back to LF. I am recording it here rather than opening an Issue because the repair is mechanical and already scheduled; the cost is one noisy diff in the ledger's history. AUTHOR: worth writing the ledger through the same writer next time.

Evidence weighed, not treated as a verdict

The SLOPSTER QA finding of 2026-09-15T03:05Z named the same causality defect at 0e4f804d. It is evidence, not a verdict; it is now resolved, and I reached the same conclusion independently at source before reading it.

Standing refusals

Only my own, at the superseded head 0e4f804d. No other account holds this merge, so the ACCEPT is one I can carry out.

Merging with --squash --delete-branch.

@zendev-acceptor
zendev-acceptor Bot merged commit ab5f387 into master Sep 15, 2026
12 checks passed
@zendev-acceptor
zendev-acceptor Bot deleted the claude/issue-269-visualization-006-m3-pages branch September 15, 2026 03:55
zendev-acceptor Bot pushed a commit that referenced this pull request Sep 15, 2026
…s claims back to current evidence (#499)

* REQ-VISUALIZATION-007: bring the README's Pages and requirement-status claims back to current evidence

The root README still described the pre-M3 Pages state after #491 landed:
the opening paragraph said the deployment showed the legacy viewer and the
M1/M2 previews, the viewer link offered "the current M2 Milestone Preview",
and "Known scope boundaries" said REQ-VISUALIZATION-006 was "not yet
started" while the ledger records it IMPLEMENTED at #491. The same section
called the generated docs/spec/IMPLEMENTATION_STATUS.md authoritative,
which inverts the protocol: docs/spec/implementation_status.csv is the
evidence ledger and the Markdown is generated presentation.

Repairs the README text and adds src/diagnostics/readme-conformance.test.ts,
which pins each mechanically decidable README claim to the artifact that
decides it: relative links resolve, every requirement identifier exists in
the ledger, no block calls an IMPLEMENTED requirement outstanding, the CSV
and not the generated table carries the word authoritative, every paragraph
linking Pages names M3, docs/index.html really does leave M3 in the default
view with M0-M2 and the legacy run viewer inside the <details> disclosure,
and every documented npm script exists. Three of the seven fail against
master's README.

Documentation and test only: no runtime, formula, schema, phase-order or
v1-scope change, and docs/spec/mirror/ is untouched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* ledger: REQ-VISUALIZATION-007 from PARTIAL to IMPLEMENTED at PR #499

The row stood PARTIAL because the registry acceptance covers the README and
its directly linked public docs, and both linked reference articles carried
open conformance defects (#446, #447). Both merged, as #486 and #489, and
REQ-VISUALIZATION-008 is IMPLEMENTED. #499 repairs the last recorded
defect class in the README itself, so every acceptance item is re-checked
and the row is earned.

MERGE_COMMIT is cleared rather than left naming #484's squash commit:
backfill_merge_commits.py fills blanks and never rewrites one that is
already there, so keeping the old value would permanently misattribute this
row to the wrong commit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

REQ-VISUALIZATION-006: M3 polished LocalMarket Pages experience

1 participant