Context
There are two version matrices in this repo and only one of them is real.
scripts/testbed/matrix.json (B1, ADR-0003) holds the eight pinned Grafana tags with churn_role notes, Docker Hub URLs, GitHub release URLs, and access_date values.
experiments/gate-v1/versions.json (B4) holds exactly one entry:
{ "id": "pending-b1@placeholder", "site_key": "local-demo", "status": "placeholder",
"notes": "Awaiting B1 test-bed pin. Do not invent a console version here." }
experiments/gate-v1/run-matrix.ts iterates versionsDoc.versions, so npm run gate:matrix currently walks a one-element placeholder list. Any report generated from it is a report about nothing. experiments/gate-v1/README.md lists "Wire versions.json to ADR-0003 / scripts/testbed/matrix.json pins" as an open question.
Two sources of truth for the same list will drift. Collapse them.
What to build
- Make
scripts/testbed/matrix.json the single source of truth for the version list. experiments/gate-v1/run-matrix.ts reads it directly (via the existing src/testbed/matrix.ts loader rather than a second ad-hoc JSON import).
- Keep
experiments/gate-v1/versions.json only if it carries information matrix.json genuinely should not — per-run gate settings such as site_key / task_key defaults or a version subset filter. If it holds nothing but a duplicated list, delete it and say so in the PR.
- Add a
--versions <a,b,c> flag to npm run gate:matrix to run a subset, and --versions all (the default) for the full matrix. Reject any id not present in matrix.json with an error naming the valid ids — never fall through to a placeholder.
- Skip versions marked
"status": "unavailable" in matrix.json (see the tag-verification issue), log that they were skipped, and record the skip in the run output so a later report cannot silently under-count denominators.
- Per-version and aggregate outputs land under
experiments/gate-v1/out/ — already gitignored.
Constraints
- Do not invent a version pin. If
matrix.json lacks something the harness wants, that is a matrix change with an ADR-0003 amendment, not an inline default.
- Do not change the
--dry-run gating in this PR. Live execution is a separate issue; this one is about the harness walking the right list.
- The existing dry-run behaviour (
PASS outcomes, zero tokens, "not a gate measurement" note) must survive unchanged — just over the real eight versions instead of one placeholder.
How to test
npm run gate:matrix -- --dry-run # walks every available matrix version
npm run gate:matrix -- --dry-run --versions 11.0.0,12.0.0
npm run gate:matrix -- --dry-run --versions 99.0.0 # must error, listing valid ids
npm run gate:report
npm run ci
Confirm experiments/gate-v1/out/metrics.ndjson contains one run row per version walked, each with the correct testbed_version, and that npm run gate:report renders them without inventing rates. Every token count stays 0 — this is still a dry run and must be labelled as such.
Before you open the PR
Context
There are two version matrices in this repo and only one of them is real.
scripts/testbed/matrix.json(B1, ADR-0003) holds the eight pinned Grafana tags withchurn_rolenotes, Docker Hub URLs, GitHub release URLs, andaccess_datevalues.experiments/gate-v1/versions.json(B4) holds exactly one entry:{ "id": "pending-b1@placeholder", "site_key": "local-demo", "status": "placeholder", "notes": "Awaiting B1 test-bed pin. Do not invent a console version here." }experiments/gate-v1/run-matrix.tsiteratesversionsDoc.versions, sonpm run gate:matrixcurrently walks a one-element placeholder list. Any report generated from it is a report about nothing.experiments/gate-v1/README.mdlists "Wireversions.jsonto ADR-0003 /scripts/testbed/matrix.jsonpins" as an open question.Two sources of truth for the same list will drift. Collapse them.
What to build
scripts/testbed/matrix.jsonthe single source of truth for the version list.experiments/gate-v1/run-matrix.tsreads it directly (via the existingsrc/testbed/matrix.tsloader rather than a second ad-hoc JSON import).experiments/gate-v1/versions.jsononly if it carries informationmatrix.jsongenuinely should not — per-run gate settings such assite_key/task_keydefaults or a version subset filter. If it holds nothing but a duplicated list, delete it and say so in the PR.--versions <a,b,c>flag tonpm run gate:matrixto run a subset, and--versions all(the default) for the full matrix. Reject any id not present inmatrix.jsonwith an error naming the valid ids — never fall through to a placeholder."status": "unavailable"inmatrix.json(see the tag-verification issue), log that they were skipped, and record the skip in the run output so a later report cannot silently under-count denominators.experiments/gate-v1/out/— already gitignored.Constraints
matrix.jsonlacks something the harness wants, that is a matrix change with an ADR-0003 amendment, not an inline default.--dry-rungating in this PR. Live execution is a separate issue; this one is about the harness walking the right list.PASSoutcomes, zero tokens, "not a gate measurement" note) must survive unchanged — just over the real eight versions instead of one placeholder.How to test
Confirm
experiments/gate-v1/out/metrics.ndjsoncontains one run row per version walked, each with the correcttestbed_version, and thatnpm run gate:reportrenders them without inventing rates. Every token count stays 0 — this is still a dry run and must be labelled as such.Before you open the PR
npm run ciandnpm run test:canarygreenunavailableversions skipped and recorded, not silently droppedexperiments/gate-v1/README.mdanddocs/gate/runner.mdopen questions updatedtrack1/b4-matrix-pins