A3 Aggregator · Tutors release confidence

Built 2026-10-19 11:06 UTC by harness 1.49.0 from 54 kept runs and the kaizen register · home · overnight readiness · scoreboard · a3.json

This sheet compares main at sha-2bff81a (Main to RC forecast) against production 17.0.0, run 2026-10-19 10:46 UTC.

Gate · Main to RC forecastFAILsha-2bff81a beside 17.0.0 · 2026-10-19 10:46 UTC
full report · the run · scorecard 40 (D) · 2 glance items
FAIL because 8 differences have no claim and no PR declared them (#501's CHANGELOG line says (image-hardening, image-manifest, metrics); startup moved; #481's CHANGELOG line says (network); #505's CHANGELOG line says (dom, focus); persistence moved). The other 84 are declared in its PR's CHANGELOG line (#505: 82, #501: 2): nothing is owed on main, and the release author claims them from those lines when the release is cut. A CHANGELOG line that names what moved, a Rule that claims it, or a fix on main turns this to PASS; the gap below says where each came from.
Release Confidence ScorenoneThe Gate wins: no number talks a FAIL back on
The eight dimensions (for the root cause, not a decision)
  • Claim coverage0
  • Noise health80
  • Statistical margin100
  • Rehearsals100
  • Test signal10
  • Requirements traceabilityn/m
  • Change risk0
  • Post-deploy historyn/m
Quality · a reading aid beside the Gate, never an input to it
Speed lookp95 2.03 ms on production, 2.01 ms on main; 0 of 600 requests failed; 4 slowdowns to look at, advice only: catalogue: ready slower on b: median 2366 ms → 5471 ms (+131%), p=0.012, n=5/5; live: ready slower on b: median 2362 ms → 5342 ms (+126%), p=0.012, n=5/5; reader: ready slower on b: median 2370 ms → 5392 ms (+128%), p=0.012, n=5/5; and 1 moreWithin reason when: No journey, page or startup significantly slower (advice: timing never fails the Gate); k6 failure rate 0 on mainstartup:catalogue/ready:105 · startup:live/ready:106 · startup:reader/ready:107 · the load
Metrics look2 unclaimed metrics hunks: time: new series on b: http_request_duration_seconds_count; time: new series on b: http_requests_totalWithin reason when: No unclaimed metrics hunkmetrics:http_request_duration_seconds_count:54 · metrics:http_requests_total:55
Tests lookharness half: within reasonmonorepo half: lookHarness: within reason. Monorepo (record for the judged commit, 68m old): 3 changed packages below 80%: @tutors/ui-navigators 55.11%, @tutors/i18n 72.73%, @tutors/metrics 75.93%; the Nightly within reason.Within reason when: Harness: every journey completed on both sides, the A/A clean and at most 2 days old, every mutant caught. Monorepo: the Nightly green on the commit, no changed package below 80% mutation scorethe A/A · self-test of 2026-10-19 · quality.json · the Nightly run

Tests read the monorepo's quality record for the judged commit, generated 2026-10-19 (68m before the forecast). The strip is a reading aid: it never changes the Gate, the score or an exit code.

What each light read
LightCheckStateReading
SpeedNo journey or startup significantly slower, or outside production's control limitslook4 slowdowns (advice, not a failure): catalogue: ready slower on b: median 2366 ms → 5471 ms (+131%), p=0.012, n=5/5; live: ready slower on b: median 2362 ms → 5342 ms (+126%), p=0.012, n=5/5; reader: ready slower on b: median 2370 ms → 5392 ms (+128%), p=0.012, n=5/5; and 1 more; control chart: every journey's median on main inside production's limits (18)
startup:catalogue/ready:105 · startup:live/ready:106 · startup:reader/ready:107
Speedk6 failure rate 0 on mainwithin reasonp95 2.03 ms on production, 2.01 ms on main; 0 of 600 requests failed
the load
MetricsNo unclaimed metrics hunklook2 unclaimed metrics hunks: time: new series on b: http_request_duration_seconds_count; time: new series on b: http_requests_total
metrics:http_request_duration_seconds_count:54 · metrics:http_requests_total:55
Tests (harness)Every journey completed on both sideswithin reasonevery journey completed on both sides
Tests (harness)The A/A it relied on clean, at most 2 days oldwithin reasonA/A clean (0 differences), 58m before the run
the A/A
Tests (harness)The newest weekly mutants self-test caught every mutantwithin reason16 of 16 mutants caught, 2026-10-19
self-test of 2026-10-19
Tests (monorepo)The Nightly green on the commitwithin reasonNightly green on 2bff81a
quality.json · the Nightly run
Tests (monorepo)No changed package below 80% mutation scorelook3 changed packages below 80%: @tutors/ui-navigators 55.11%, @tutors/i18n 72.73%, @tutors/metrics 75.93%
quality.json · the Nightly run
Last release gateWARN17.0.0-rc.1 beside 16.2.2, 2026-10-15 · report
Post-deploy · 17.0.0green32 runs since 17.0.0 was deployed 2026-10-15 · newest run · why · rollback #131
Nightly A/APASS2026-10-19 · report
Countermeasures open2fixes a 5 Whys asked for: 2 built, waiting on a release to show they work · 1 verified · each one
Fixed on main · good news, never a failure0% with a note2 console errors production shows and main does not, none with a claim saying why yet. These count for main, not against it. A claim is an optional note that the fix was meant; nothing waits on it · which ones

No RCS: Gate FAIL. The Gate wins: no number talks a FAIL back on. The dimensions are shown for the 5 Whys, not for a decision.

The gap, explained every difference main at sha-2bff81a (Main to RC forecast) against production 17.0.0, run 2026-10-19 10:46 UTC found, in one row each

103 differences: claims explain 11; #505 declared 82 in its CHANGELOG line; #501 declared 2 in its CHANGELOG line; #501 contributed 4 (#501's CHANGELOG line says (image-hardening, image-manifest, metrics); startup moved); #478 most likely contributed 4 (#481's CHANGELOG line says (network); #505's CHANGELOG line says (dom, focus); persistence moved); 0 unexplained.

Explained byDifferencesShareWhat changed (kinds)First seen
Claimed: a Rule or CHANGELOG entry says so1111%
Rule 0330: When a student opens a learning object, the reader shall send the learning event to the reader's server without publishing it over Realtime from the browser. — Rule 0330: the reader sends each learning event to its own server (POST /api/live/activity) instead of broadcasting it from the browser (#481)88%
Rule 0330: When a student opens a learning object, the reader shall send the learning event to the reader's server without publishing it over Realtime from the browser. — Rule 0330: moving learning events from browser Realtime to the reader's server adds one immutable chunk on reference:course and reference:note (#478, #481)22%
Rule 0331: When the reader's server receives a learning event, the reader shall publish it only to the activity feeds a live dashboard has watched in the last 90 seconds. — Rule 0331: the reader's server claims the topics to publish to, and charges the day's Live budget, through realtime_claim_live_publish (#481)11%
Declared by its PR: the CHANGELOG line names it, claimed when the release is cut8482%
#505
#505 fix(a11y): button names contain their visible text
(dom, focus): Screen readers announce the Preferences button as "Preferences", and the search and close buttons announce their keyboard shortcuts
8280%dom: semantic DOM differs (+# −# lines at line #) (41)
focus: keyboard order changed (# stops on a, # on b) (41)
2026-10-17
#501
#501 feat(image): declare a HEALTHCHECK and expose request SLIs from start (image-hardening, image-manifest, metrics)
(image-hardening, image-manifest, metrics): feat(image): declare a HEALTHCHECK and expose request SLIs from start
22%metrics: new series on b (2)2026-10-19
Contributed by a PR: first seen the night it merged88%
#501
#501 feat(image): declare a HEALTHCHECK and expose request SLIs from start (image-hardening, image-manifest, metrics)
#501's CHANGELOG line says (image-hardening, image-manifest, metrics); startup moved: fix the line, or claim it
44%startup: ready slower on b (4)2026-10-19
#478 most likely
#478 Route every Realtime channel through a budgeted port
also merged those nights: #481, #476, #483, #505, #480 and 1 more

#481's CHANGELOG line says (network); #505's CHANGELOG line says (dom, focus); persistence moved: fix the line, or claim it
44%persistence: RPC realtime_claim_live_publish — # row(s) on a, # on b (3)
persistence: RPC realtime_watch — # row(s) on a, # on b (1)
2026-10-18, 2026-10-18
Unexplained: the record cannot say who00%

The behaviour behind these Rules moved: Rule 0582 (exercises 0011, 0250, 0252, 0260, 0303, 0330): 9 differences in dom, focus, persistence; Rule 0591 (exercises 0319): 8 differences in dom, focus; Rule 0584 (exercises 0047, 0049, 0050): 6 differences in dom, focus; Rule 0588 (exercises 0052, 0053, 0054): 6 differences in dom, focus; Rule 0589 (exercises 0330, 0335): 6 differences in dom, focus, persistence; Rule 0590 (exercises 0319): 6 differences in dom, focus; Rule 0585 (exercises 0037, 0038, 0039): 4 differences in dom, focus; Rule 0586 (exercises 0011, 0267): 4 differences in dom, focus; Rule 0583 (exercises 0046, 0064, 0280): 3 differences in dom, focus, persistence; Rule 0587 (exercises 0042, 0284): 2 differences in dom, focus; Rule 0592 (exercises 0275, 0276): 2 differences in dom, focus.

A PR is named when the difference first appeared in the forecast after it merged and its files touch what changed; several PRs merged the same night stay one row ("one of"), never split by guesswork. A PR whose CHANGELOG line names the artefact that moved, as CONTRIBUTING.md asks ((axe, dom)), declared it: nothing is owed on main, and the release author claims it from that line. Read from 15 earlier forecasts beside the same production, 2026-10-15 to 2026-10-19.

Timing on control charts advice, never a failure: an outlier against production's own variation is something to investigate

1 of 18 journeys outside production's limits: investigate it, starting with "what to check" in the report.

JourneyMain's median night by night (dots), production's limits (band)Reading
anonymous-student-searches2026-10-15: main 2614ms, production 2829ms2026-10-16: main 2843ms, production 2999ms2026-10-17: main 2839ms, production 2898ms2026-10-17: main 2681ms, production 2620ms2026-10-17: main 2744ms, production 2843ms2026-10-17: main 2870ms, production 2814ms2026-10-17: main 2862ms, production 2688ms2026-10-18: main 2526ms, production 2695ms2026-10-18: main 2963ms, production 2949ms2026-10-18: main 2957ms, production 2991ms2026-10-19: main 3094ms, production 2981ms2026-10-19: main 2925ms, production 2882ms2026-10-19: main 2107ms, production 2232ms2026-10-19: main 2313ms, production 2276msmain 2,313msUCL 3,180mscentre 2,764msLCL 2,348msspecial cause: below LCL
main 2313ms is below the limits from production's last 14 nights (2348–3180ms): a special cause to investigate, not a failure
Limits from production's median on each of the last 14 nights: centre 2,764ms is their mean; the average jump from one to the next (mR̄) is 156ms; UCL = 2,764ms + 2.66 × 156ms = 3,180ms; LCL = 2,764ms − 2.66 × 156ms = 2,348ms.
anonymous-student-reads-course2026-10-15: main 4895ms, production 4902ms2026-10-16: main 5133ms, production 5101ms2026-10-17: main 5032ms, production 4956ms2026-10-17: main 4781ms, production 4776ms2026-10-17: main 4850ms, production 4896ms2026-10-17: main 4894ms, production 4925ms2026-10-17: main 4873ms, production 4894ms2026-10-18: main 4720ms, production 4730ms2026-10-18: main 5079ms, production 5435ms2026-10-18: main 5299ms, production 5050ms2026-10-19: main 5257ms, production 5247ms2026-10-19: main 5141ms, production 5356ms2026-10-19: main 4096ms, production 4125ms2026-10-19: main 4447ms, production 4463msmain 4,447msUCL 5,703mscentre 4,918msLCL 4,134mscommon cause
main 4447ms is inside the limits from production's last 14 nights (4134–5703ms): common cause, nothing to investigate
Limits from production's median on each of the last 14 nights: centre 4,918ms is their mean; the average jump from one to the next (mR̄) is 295ms; UCL = 4,918ms + 2.66 × 295ms = 5,703ms; LCL = 4,918ms − 2.66 × 295ms = 4,134ms.
catalogue-loads2026-10-15: main 1310ms, production 1564ms2026-10-16: main 1626ms, production 1526ms2026-10-17: main 1411ms, production 1564ms2026-10-17: main 1434ms, production 1426ms2026-10-17: main 1343ms, production 1415ms2026-10-17: main 1457ms, production 1521ms2026-10-17: main 1410ms, production 1386ms2026-10-18: main 1360ms, production 1359ms2026-10-18: main 1568ms, production 1577ms2026-10-18: main 1474ms, production 1514ms2026-10-19: main 1429ms, production 1537ms2026-10-19: main 1486ms, production 1557ms2026-10-19: main 1063ms, production 1154ms2026-10-19: main 1227ms, production 1227msmain 1,227msUCL 1,717mscentre 1,452msLCL 1,187mscommon cause
main 1227ms is inside the limits from production's last 14 nights (1187–1717ms): common cause, nothing to investigate
Limits from production's median on each of the last 14 nights: centre 1,452ms is their mean; the average jump from one to the next (mR̄) is 99ms; UCL = 1,452ms + 2.66 × 99ms = 1,717ms; LCL = 1,452ms − 2.66 × 99ms = 1,187ms.
live-loads2026-10-15: main 1520ms, production 1535ms2026-10-16: main 1608ms, production 1397ms2026-10-17: main 1658ms, production 1501ms2026-10-17: main 1536ms, production 1415ms2026-10-17: main 1522ms, production 1535ms2026-10-17: main 1482ms, production 1524ms2026-10-17: main 1562ms, production 1405ms2026-10-18: main 1465ms, production 1420ms2026-10-18: main 1634ms, production 1657ms2026-10-18: main 1688ms, production 1668ms2026-10-19: main 1749ms, production 1681ms2026-10-19: main 1748ms, production 1580ms2026-10-19: main 1223ms, production 1150ms2026-10-19: main 1317ms, production 1295msmain 1,317msUCL 1,796mscentre 1,483msLCL 1,170mscommon cause
main 1317ms is inside the limits from production's last 14 nights (1170–1796ms): common cause, nothing to investigate
Limits from production's median on each of the last 14 nights: centre 1,483ms is their mean; the average jump from one to the next (mR̄) is 118ms; UCL = 1,483ms + 2.66 × 118ms = 1,796ms; LCL = 1,483ms − 2.66 × 118ms = 1,170ms.
reference-course-reads2026-10-15: main 7065ms, production 7069ms2026-10-16: main 7789ms, production 7828ms2026-10-17: main 7461ms, production 7452ms2026-10-17: main 7087ms, production 7624ms2026-10-17: main 7285ms, production 7344ms2026-10-17: main 7759ms, production 7711ms2026-10-17: main 7319ms, production 6857ms2026-10-18: main 6742ms, production 7264ms2026-10-18: main 8017ms, production 8238ms2026-10-18: main 7732ms, production 7685ms2026-10-19: main 7688ms, production 8019ms2026-10-19: main 7802ms, production 7809ms2026-10-19: main 6028ms, production 6191ms2026-10-19: main 6157ms, production 5762msmain 6,157msUCL 8,847mscentre 7,347msLCL 5,846mscommon cause
main 6157ms is inside the limits from production's last 14 nights (5846–8847ms): common cause, nothing to investigate
Limits from production's median on each of the last 14 nights: centre 7,347ms is their mean; the average jump from one to the next (mR̄) is 564ms; UCL = 7,347ms + 2.66 × 564ms = 8,847ms; LCL = 7,347ms − 2.66 × 564ms = 5,846ms.
replay-course-urls2026-10-15: main 14999ms, production 23572ms2026-10-16: main 23220ms, production 19943ms2026-10-17: main 7692ms, production 8332ms2026-10-17: main 15080ms, production 11765ms2026-10-17: main 26997ms, production 20270ms2026-10-17: main 8017ms, production 26907ms2026-10-17: main 18903ms, production 7592ms2026-10-18: main 18903ms, production 26998ms2026-10-18: main 27400ms, production 9712ms2026-10-18: main 27077ms, production 23230ms2026-10-19: main 22750ms, production 27596ms2026-10-19: main 26962ms, production 14835ms2026-10-19: main 6581ms, production 7325ms2026-10-19: main 7250ms, production 7804msmain 7,250msUCL 43,133mscentre 16,849msLCL 0mscommon cause
main 7250ms is inside the limits from production's last 14 nights (0–43133ms): common cause, nothing to investigate
Limits from production's median on each of the last 14 nights: centre 16,849ms is their mean; the average jump from one to the next (mR̄) is 9,881ms; UCL = 16,849ms + 2.66 × 9,881ms = 43,133ms; LCL = 16,849ms − 2.66 × 9,881ms = 0ms.
rule-0582-signed-in-lab2026-10-18: main 4615ms, production 4531ms2026-10-18: main 5057ms, production 5354ms2026-10-18: main 4981ms, production 4945ms2026-10-19: main 5074ms, production 5106ms2026-10-19: main 4907ms, production 5027ms2026-10-19: main 3878ms, production 3922ms2026-10-19: main 4192ms, production 4083msmain 4,192msUCL 5,924mscentre 4,710msLCL 3,496mscommon cause
main 4192ms is inside the limits from production's last 7 nights (3496–5924ms): common cause, nothing to investigate; provisional limits, 7 nights
Limits from production's median on each of the last 7 nights: centre 4,710ms is their mean; the average jump from one to the next (mR̄) is 456ms; UCL = 4,710ms + 2.66 × 456ms = 5,924ms; LCL = 4,710ms − 2.66 × 456ms = 3,496ms. Provisional: under 10 points, so they will move as more are added.
rule-0583-presence2026-10-18: main 10716ms, production 11131ms2026-10-18: main 4702ms, production 4701ms2026-10-18: main 4501ms, production 4487ms2026-10-19: main 4446ms, production 4586ms2026-10-19: main 4351ms, production 4465ms2026-10-19: main 3120ms, production 3028ms2026-10-19: main 3269ms, production 3237msmain 3,269msUCL 8,863mscentre 5,091msLCL 1,318mscommon cause
main 3269ms is inside the limits from production's last 7 nights (1318–8863ms): common cause, nothing to investigate; provisional limits, 7 nights
Limits from production's median on each of the last 7 nights: centre 5,091ms is their mean; the average jump from one to the next (mR̄) is 1,418ms; UCL = 5,091ms + 2.66 × 1,418ms = 8,863ms; LCL = 5,091ms − 2.66 × 1,418ms = 1,318ms. Provisional: under 10 points, so they will move as more are added.
rule-0584-quiz-notebook-talk2026-10-18: main 5187ms, production 4917ms2026-10-18: main 12944ms, production 13039ms2026-10-18: main 12996ms, production 13067ms2026-10-19: main 13088ms, production 13209ms2026-10-19: main 13123ms, production 13162ms2026-10-19: main 12684ms, production 12642ms2026-10-19: main 12880ms, production 12967msmain 12,880msUCL 15,929mscentre 11,858msLCL 7,786mscommon cause
main 12880ms is inside the limits from production's last 7 nights (7786–15929ms): common cause, nothing to investigate; provisional limits, 7 nights
Limits from production's median on each of the last 7 nights: centre 11,858ms is their mean; the average jump from one to the next (mR̄) is 1,531ms; UCL = 11,858ms + 2.66 × 1,531ms = 15,929ms; LCL = 11,858ms − 2.66 × 1,531ms = 7,786ms. Provisional: under 10 points, so they will move as more are added.
rule-0585-preferences2026-10-18: main 12024ms, production 12060ms2026-10-18: main 6497ms, production 6879ms2026-10-18: main 6264ms, production 6789ms2026-10-19: main 6695ms, production 6628ms2026-10-19: main 6237ms, production 6139ms2026-10-19: main 4006ms, production 4250ms2026-10-19: main 4606ms, production 4804msmain 4,606msUCL 10,501mscentre 6,793msLCL 3,085mscommon cause
main 4606ms is inside the limits from production's last 7 nights (3085–10501ms): common cause, nothing to investigate; provisional limits, 7 nights
Limits from production's median on each of the last 7 nights: centre 6,793ms is their mean; the average jump from one to the next (mR̄) is 1,394ms; UCL = 6,793ms + 2.66 × 1,394ms = 10,501ms; LCL = 6,793ms − 2.66 × 1,394ms = 3,085ms. Provisional: under 10 points, so they will move as more are added.
rule-0586-private-course2026-10-18: main 4141ms, production 4199ms2026-10-18: main 10196ms, production 10173ms2026-10-18: main 10182ms, production 10279ms2026-10-19: main 10537ms, production 10090ms2026-10-19: main 10329ms, production 10846ms2026-10-19: main 10917ms, production 10753ms2026-10-19: main 10604ms, production 10679msmain 10,604msUCL 12,763mscentre 9,574msLCL 6,386mscommon cause
main 10604ms is inside the limits from production's last 7 nights (6386–12763ms): common cause, nothing to investigate; provisional limits, 7 nights
Limits from production's median on each of the last 7 nights: centre 9,574ms is their mean; the average jump from one to the next (mR̄) is 1,199ms; UCL = 9,574ms + 2.66 × 1,199ms = 12,763ms; LCL = 9,574ms − 2.66 × 1,199ms = 6,386ms. Provisional: under 10 points, so they will move as more are added.
rule-0587-calendar-llm2026-10-18: main 12255ms, production 12177ms2026-10-18: main 4847ms, production 4832ms2026-10-18: main 4642ms, production 4671ms2026-10-19: main 4859ms, production 4584ms2026-10-19: main 4439ms, production 4630ms2026-10-19: main 3018ms, production 3191ms2026-10-19: main 3382ms, production 3362msmain 3,382msUCL 9,450mscentre 5,350msLCL 1,249mscommon cause
main 3382ms is inside the limits from production's last 7 nights (1249–9450ms): common cause, nothing to investigate; provisional limits, 7 nights
Limits from production's median on each of the last 7 nights: centre 5,350ms is their mean; the average jump from one to the next (mR̄) is 1,542ms; UCL = 5,350ms + 2.66 × 1,542ms = 9,450ms; LCL = 5,350ms − 2.66 × 1,542ms = 1,249ms. Provisional: under 10 points, so they will move as more are added.
rule-0588-content-lock2026-10-18: main 13784ms, production 10192ms2026-10-18: main 10106ms, production 17255ms2026-10-19: main 17099ms, production 13263ms2026-10-19: main 16939ms, production 17023ms2026-10-19: main 15162ms, production 15132ms2026-10-19: main 15667ms, production 15687msmain 15,667msUCL 23,942mscentre 14,759msLCL 5,576mscommon cause
main 15667ms is inside the limits from production's last 6 nights (5576–23942ms): common cause, nothing to investigate; provisional limits, 6 nights
Limits from production's median on each of the last 6 nights: centre 14,759ms is their mean; the average jump from one to the next (mR̄) is 3,452ms; UCL = 14,759ms + 2.66 × 3,452ms = 23,942ms; LCL = 14,759ms − 2.66 × 3,452ms = 5,576ms. Provisional: under 10 points, so they will move as more are added.
rule-0589-live2026-10-18: main 12631ms, production 12509ms2026-10-18: main 12812ms, production 6426ms2026-10-19: main 6697ms, production 12584ms2026-10-19: main 6149ms, production 6607ms2026-10-19: main 4008ms, production 4154ms2026-10-19: main 4717ms, production 4691msmain 4,717msUCL 19,111mscentre 7,829msLCL 0mscommon cause
main 4717ms is inside the limits from production's last 6 nights (0–19111ms): common cause, nothing to investigate; provisional limits, 6 nights
Limits from production's median on each of the last 6 nights: centre 7,829ms is their mean; the average jump from one to the next (mR̄) is 4,242ms; UCL = 7,829ms + 2.66 × 4,242ms = 19,111ms; LCL = 7,829ms − 2.66 × 4,242ms = 0ms. Provisional: under 10 points, so they will move as more are added.
rule-0590-time-calendar2026-10-18: main 7198ms, production 7787ms2026-10-18: main 7605ms, production 7127ms2026-10-19: main 7510ms, production 7263ms2026-10-19: main 6910ms, production 7129ms2026-10-19: main 4741ms, production 4705ms2026-10-19: main 5482ms, production 5237msmain 5,482msUCL 8,609mscentre 6,541msLCL 4,474mscommon cause
main 5482ms is inside the limits from production's last 6 nights (4474–8609ms): common cause, nothing to investigate; provisional limits, 6 nights
Limits from production's median on each of the last 6 nights: centre 6,541ms is their mean; the average jump from one to the next (mR̄) is 777ms; UCL = 6,541ms + 2.66 × 777ms = 8,609ms; LCL = 6,541ms − 2.66 × 777ms = 4,474ms. Provisional: under 10 points, so they will move as more are added.
rule-0591-time-labs2026-10-18: main 8555ms, production 9095ms2026-10-18: main 8434ms, production 8538ms2026-10-19: main 8482ms, production 8587ms2026-10-19: main 8348ms, production 8782ms2026-10-19: main 5465ms, production 5885ms2026-10-19: main 6245ms, production 6602msmain 6,245msUCL 10,264mscentre 7,915msLCL 5,566mscommon cause
main 6245ms is inside the limits from production's last 6 nights (5566–10264ms): common cause, nothing to investigate; provisional limits, 6 nights
Limits from production's median on each of the last 6 nights: centre 7,915ms is their mean; the average jump from one to the next (mR̄) is 883ms; UCL = 7,915ms + 2.66 × 883ms = 10,264ms; LCL = 7,915ms − 2.66 × 883ms = 5,566ms. Provisional: under 10 points, so they will move as more are added.
rule-0592-whiteboard2026-10-18: main 13985ms, production 13837ms2026-10-19: main 13918ms, production 13658ms2026-10-19: main 13746ms, production 13907ms2026-10-19: main 13643ms, production 13668ms2026-10-19: main 13925ms, production 13863msmain 13,925msUCL 14,360mscentre 13,787msLCL 13,213mscommon cause
main 13925ms is inside the limits from production's last 5 nights (13213–14360ms): common cause, nothing to investigate; provisional limits, 5 nights
Limits from production's median on each of the last 5 nights: centre 13,787ms is their mean; the average jump from one to the next (mR̄) is 216ms; UCL = 13,787ms + 2.66 × 216ms = 14,360ms; LCL = 13,787ms − 2.66 × 216ms = 13,213ms. Provisional: under 10 points, so they will move as more are added.
student-signs-in2026-10-15: main 3934ms, production 4023ms2026-10-16: main 4290ms, production 4173ms2026-10-17: main 4002ms, production 4001ms2026-10-17: main 3739ms, production 3915ms2026-10-17: main 4131ms, production 3930ms2026-10-17: main 4174ms, production 4005ms2026-10-17: main 3885ms, production 4106ms2026-10-18: main 3795ms, production 3789ms2026-10-18: main 4225ms, production 4359ms2026-10-18: main 4466ms, production 4335ms2026-10-19: main 4186ms, production 4243ms2026-10-19: main 4242ms, production 4418ms2026-10-19: main 3078ms, production 3205ms2026-10-19: main 3381ms, production 3253msmain 3,381msUCL 4,604mscentre 3,983msLCL 3,361mscommon cause
main 3381ms is inside the limits from production's last 14 nights (3361–4604ms): common cause, nothing to investigate
Limits from production's median on each of the last 14 nights: centre 3,983ms is their mean; the average jump from one to the next (mR̄) is 234ms; UCL = 3,983ms + 2.66 × 234ms = 4,604ms; LCL = 3,983ms − 2.66 × 234ms = 3,361ms.

How to read it: the band is how much production's own time for the journey varies when nothing has changed. The UCL (upper control limit) is the top of that band and the LCL (lower control limit) the bottom, each the centre ± 2.66 times the average jump between consecutive points (an XmR chart; 2.66 puts the limits about three standard deviations out, so a point beyond one happens by chance well under 1 time in 100). A dot inside the band is ordinary variation; a red dot outside it is a special cause, something changed, worth investigating. Limits come from production's nightly medians beside the same production, or from its runs in the newest forecast until there are two nights.

1Background why this matters

Tutors ships four apps (reader, catalogue, live, time) as signed images. The release harness runs each candidate beside production, diffs everything a student can observe, and stops the line unless every difference is claimed by a Rule or a changelog entry.

This A3 reads every run the harness has kept: 54 runs from 2026-09-26 to 2026-10-19 (Release candidate 5, Main to RC forecast 35, Nightly A/A 14), the kaizen register (3 filled 5 Whys), and the workflows' own history on GitHub. It is rebuilt with the site, so it always describes the newest evidence.

Why it matters: production is 17.0.0; main (sha-2bff81a) is what the next release would ship. Every unclaimed difference is a claim or a fix that release will need, and every red check after a deploy is a question about what students are running.

  • Comparing main at sha-2bff81a (Main to RC forecast) against production 17.0.0, run 2026-10-19 10:46 UTC. 103 differences: claims explain 11; #505 declared 82 in its CHANGELOG line; #501 declared 2 in its CHANGELOG line; #501 contributed 4 (#501's CHANGELOG line says (image-hardening, image-manifest, metrics); startup moved); #478 most likely contributed 4 (#481's CHANGELOG line says (network); #505's CHANGELOG line says (dom, focus); persistence moved); 0 unexplained.
  • Gate FAIL on the Main to RC forecast sha-2bff81a beside 17.0.0, so no RCS.
  • Last release candidate kept: 17.0.0-rc.1 beside 16.2.2, WARN on 2026-10-15.
  • Post-deploy since 17.0.0 was deployed: green, rollback issue #131 open.
  • A/A: PASS on 2026-10-19.
  • Quality: Speed look, Metrics look, Tests look.
  • Real courses: 1 of 5 real courses load on main sha-2bff81a, 1 on production 17.0.0; none is broken by main alone.

3Goal the target condition

MeasureNowTarget
Gate on the newest forecast
confidence.json
FAILPASSgap
Unclaimed differences
report.json
920gap
Claims: known and gaps
report.json
11 claimed, 92 unclaimed (10% covered)every difference claimed or fixedgap
Real courses load on main (course corpus)
course-capture.yml, course-check.json
1 of 5 courses, 155 of 161 pages (production: 1 of 5)every corpus coursegap
Nothing a student uses is worse on main (real courses)
course-check.json, both sides (src/course/compare.ts)
2 page(s) and 0 journey(s) worse, 0 page(s) better0 worsegap
Release Confidence Score
docs/lean.md, bands
none (Gate wins)75 or more (Amber), on the way to 90 (Green)gap
Post-deploy
post-deploy.yml
greengreen on a confirmed buildmet
Releases scored (C0 evidence gate)
scoreboard branch
13gap
Countermeasures verified closed (C4 evidence gate)
kaizen/README.md
1 of 3every one, in a releasegap

2Current condition go and see: the value stream, and where the problems pile up

Value stream map: commit to productionprocess times are medians of each workflow's runs on GitHub; waits from the images' and runs' own timestamps
push: every merge to main flows downstream; nothing pulls a release but a person cutting a tagMerge to main (monorepo pull requests): review and merge: people's time, not measured here. Process time not measured Merge to main monorepo pull reques… P/T not measured FPY not measured Build and sign images (monorepo image-build.yml): four images to Quay, signed with cosign, SBOM attested. Process time 4m (median of 85), 85 of 87 runs green Build and signimages monorepo image-build… P/T 4m · n 85 FPY 98% (85/87) Nightly A/A (nightly-noise.yml): production against itself: the noise floor. Process time 11m (median of 40), 40 of 48 runs green Nightly A/A nightly-noise.yml P/T 11m · n 40 FPY 83% (40/48) Main to RC forecast (main-preview.yml): main judged as if it were a candidate. Process time 13m (median of 43), 43 of 44 runs green Main to RCforecast main-preview.yml P/T 13m · n 43 FPY 98% (43/44) Release gate (Jidoka) (release.yml): stops the line on any unclaimed difference. Process time 12m (median of 2), 2 of 5 runs green Release gate(Jidoka) release.yml P/T 12m · n 2 FPY 40% (2/5) Promote and deploy (monorepo deploy.yml, and today Netlify): 1 deploy(s) announced to the harness. Process time not measured Promote anddeploy monorepo deploy.yml,… P/T not measured FPY not measured Post-deploy verify (post-deploy.yml): production against the recorded release. Process time 71s (median of 75), 75 of 100 runs green Post-deployverify post-deploy.yml P/T 71s · n 75 FPY 75% (75/100) 16 PRs merged since v17.0.0, not in productionI1692 unclaimed differences the next release owesI922 open countermeasuresI2waitprocessn/m4m11m13m12mn/m71smerge to image build: 3s3simages ready to forecast: 2.3h2.3hsince the last release gate: 4.0d4.0dproduction 17.0.0 unchanged: 5.0d5.0d
Lead time4.1doldest merge to main not in production
Process time29mbuild + forecast + gate, machine time
Flow efficiency0.48%process time / lead time
Inventory16PRs merged since v17.0.0, not in production
Inventory92unclaimed differences the next release owes
Inventory2open countermeasures
Numbers
StageWhereProcess timeFirst passNote
Merge to mainmonorepo pull requestsnot measured–review and merge: people's time, not measured here
Build and sign imagesmonorepo image-build.yml4m (n 85)85/87four images to Quay, signed with cosign, SBOM attested
Nightly A/Anightly-noise.yml11m (n 40)40/48production against itself: the noise floor
Main to RC forecastmain-preview.yml13m (n 43)43/44main judged as if it were a candidate
Release gate (Jidoka)release.yml12m (n 2)2/5stops the line on any unclaimed difference
Promote and deploymonorepo deploy.yml, and today Netlifynot measured–1 deploy(s) announced to the harness
Post-deploy verifypost-deploy.yml71s (n 75)75/100production against the recorded release
Wait: merge to image build3s
Wait: images ready to forecast2.3h
Wait: since the last release gate4.0d
Wait: production 17.0.0 unchanged5.0d
Unclaimed differences, by causeMain to RC forecast sha-2bff81a: report.json
  1. dom: semantic DOM differs 4145%
  2. focus: keyboard order changed 4189%
  3. startup: ready slower on b1 distinct, once in each of 4 images 493%
  4. persistence: RPC realtime_claim_live_publish — N row(s) on a… 397%
  5. metrics: new series on b 299%
  6. persistence: RPC realtime_watch — N row(s) on a, N on b 1100%

2 causes of 6 carry 89% of the 92 unclaimed differences. dom: semantic DOM differs alone is 45%.

Numbers
CausedifferencesCumulative
dom: semantic DOM differs4145%
focus: keyboard order changed4189%
startup: ready slower on b493%
persistence: RPC realtime_claim_live_publish — N row(s) on a…397%
metrics: new series on b299%
persistence: RPC realtime_watch — N row(s) on a, N on b1100%
Why the line stops, every red run about the monorepo40 kept runs of the monorepo (index.json of the release and forecast streams; the harness's own A/A and failures left out) · 18 failed post-deploy runs since the deploy of 2026-10-15 (GitHub Actions)
  1. Main to RC forecast: unclaimed differences 3351%
  2. Post-deploy: production differs from the recorded release 1878%
  3. Main to RC forecast: stale claims 891%
  4. Release candidate: unclaimed differences 497%
  5. Release candidate: stale claims 2100%

65 stops over the kept runs and the post-deploy runs since the current release was deployed, about the monorepo and production only: the harness's own A/A and its failures are not counted. 3 causes carry 91%: Main to RC forecast: unclaimed differences; Post-deploy: production differs from the recorded release; Main to RC forecast: stale claims.

Numbers
CausestopsCumulative
Main to RC forecast: unclaimed differences3351%
Post-deploy: production differs from the recorded release1878%
Main to RC forecast: stale claims891%
Release candidate: unclaimed differences497%
Release candidate: stale claims2100%
Where confidence is lost, points of 100confidence.json
  1. Claim coverage5 deductions, e.g. unclaimed: dom /: reader:home: semantic DOM differs (+1 −1 lines at line 10) 2030%
  2. Change risk19 deductions, e.g. PR #476 changed Reader, Development but no changelog entry under v2bff81a779424d44aab12c4e4074a75c4457eac8 names it 1553%
  3. Test signal3 deductions, e.g. mutation score 72.73% on @tutors/i18n, below 80% 13.573%
  4. Requirements traceability (not measured)up to 10: needs the changelog, the EARS files and the claims side by side: pass --traceability <json>; changes.json already reports 13 orphan changes between the tags (a changelog entry with no diff, or a diff with no entry), a floor breach once it is measured 1088%
  5. Post-deploy history (not measured)up to 5: needs the last release's post-deploy record: pass --post-deploy <its run dir or report.json> 595%
  6. Noise health4 deductions, e.g. mask realtime-rest-fallback-warning fired nothing in this run (a mask that never fires is a mask to delete) 3100%

52 points lost on the dimensions measured, and 15 more are not measured on this run (hatched: a ceiling, never scored). The vital few: Claim coverage, Change risk, Test signal, Requirements traceability (not measured).

Numbers
CausepointsCumulative
Claim coverage2030%
Change risk1553%
Test signal13.573%
Requirements traceability (not measured)1088%
Post-deploy history (not measured)595%
Noise health3100%
Change risk findings, by rulechanges.json (v17.0.0..2bff81a)
  1. a diff and its changelog entry disagree130 points 1368%
  2. a hotspot file touched9 points 384%
  3. churn above the app's median5 points 189%
  4. dependency5 points 195%
  5. production lines with too few test lines10 points 1100%

19 findings over 16 PRs; a diff and its changelog entry disagree: 13 of 16.

Numbers
CausefindingsCumulative
a diff and its changelog entry disagree1368%
a hotspot file touched384%
churn above the app's median189%
dependency195%
production lines with too few test lines1100%

Real courses: what a student would notice if main were released the course corpus, each page read in production's reader and main's, then compared page by page

1 of 5 real courses load on main sha-2bff81a, 1 on production 17.0.0; none is broken by main alone.

CourseProduction 17.0.0Main sha-2bff81aPages on mainMedian time to titletutors.json schema
Database
databases-2024
fails 39 of 40 pages
/lab/localhost:8194/topic-01-Conceptual/unit-1-Introduction/book-a/01: title "Download Visual Paradigm" not shown: locator.waitFor: Timeout 30000ms exceeded.
fails 39 of 40 pages
/lab/localhost:8194/topic-01-Conceptual/unit-1-Introduction/book-a/01: title "Download Visual Paradigm" not shown: locator.waitFor: Timeout 30000ms exceeded.
1 worse · 0 better
of 40 pages compared
journeys: 0 worse, 0 better of 2
691 ms → 586 ms (−105 ms)168 problems
/ must have required property 'authLevel'
/los/[topic-00-Assignments] must have required property 'authLevel'
/los/[topic-00-Assignments]/los/[unit-0-repeat-ca] must have required property 'authLevel'
…
fails on both
Computer Systems & Networks
setu-hdip-comp-sci-2024-comp-sys
fails 39 of 40 pages
/lab/localhost:8193/topic-08-week8/unit-1/book-3/01: title "Raspberry Pi OS" not shown: locator.waitFor: Timeout 30000ms exceeded.
fails 39 of 40 pages
/lab/localhost:8193/topic-08-week8/unit-1/book-3/01: title "Raspberry Pi OS" not shown: locator.waitFor: Timeout 30000ms exceeded.
0 worse · 0 better
of 40 pages compared
journeys: 0 worse, 0 better of 2
691 ms → 622 ms (−69 ms)164 problems
/ must have required property 'authLevel'
/los/[topic-00-Assessment_Details] must have required property 'authLevel'
/los/[topic-00-Assessment_Details]/los/[talk-1] must have required property 'authLevel'
…
fails on both
Higher Diploma in Computer Science 2024
wit-hdip-comp-sci-2024
loads 1 of 1 pagesloads 1 of 1 pages0 worse · 0 better
of 1 pages compared
551 ms → 744 ms (+193 ms)28 problems
/ must have required property 'authLevel'
/los/[unit-1] must have required property 'authLevel'
/los/[unit-1]/los/[web-0-workshop-4] must have required property 'authLevel'
…
loads on both
Full Stack Web Development
wit-hdip-comp-sci-2024-full-stack-1
fails 38 of 40 pages
/lab/localhost:8192/unit-1-node/topic-02-hapi/unit-2/book-1-playtime-0-2-0/04: title "Sessions" not shown: locator.waitFor: Timeout 30000ms exceeded.
/lab/localhost:8192/unit-6-sveltekit/topic-19-svelte-routing/side-unit/book-2-donation-svelte-1/05: title "Signup" not shown: locator.waitFor: Timeout 30000ms exceeded.
fails 38 of 40 pages
/lab/localhost:8192/unit-1-node/topic-02-hapi/unit-2/book-1-playtime-0-2-0/04: title "Sessions" not shown: locator.waitFor: Timeout 30000ms exceeded.
/lab/localhost:8192/unit-6-sveltekit/topic-19-svelte-routing/side-unit/book-2-donation-svelte-1/05: title "Signup" not shown: locator.waitFor: Timeout 30000ms exceeded.
1 worse · 0 better
of 40 pages compared
journeys: 0 worse, 0 better of 2
843 ms → 847 ms (+4 ms)conformsfails on both
Programming Fundamentals
wit-hdip-comp-sci-2024-programming
fails 38 of 40 pages
/topic/localhost:8191/topic-00-assignments/hold-unit-2/previous assignments/2022: title "Constraints" not shown: locator.waitFor: Timeout 30000ms exceeded.
/lab/localhost:8191/topic-02-selection_and_iteration/unit-02a-if-stmt-and-events/book/05: title "Mouse events" not shown: locator.waitFor: Timeout 30000ms exceeded.
fails 38 of 40 pages
/topic/localhost:8191/topic-00-assignments/hold-unit-2/previous assignments/2022: title "Constraints" not shown: locator.waitFor: Timeout 30000ms exceeded.
/lab/localhost:8191/topic-02-selection_and_iteration/unit-02a-if-stmt-and-events/book/05: title "Mouse events" not shown: locator.waitFor: Timeout 30000ms exceeded.
0 worse · 0 better
of 40 pages compared
journeys: 0 worse, 0 better of 2
590 ms → 666 ms (+76 ms)265 problems
/ must have required property 'authLevel'
/los/[topic-00-assignments] must have required property 'authLevel'
/los/[topic-00-assignments]/los/[unit-1] must have required property 'authLevel'
…
fails on both
Database: 1 worse on main, 0 better

Worse on main

  • Assignment Two Video talk · /video/localhost:8194/topic-00-Assignments/unit-2-assignment-2/talk-1/vNzjCvOApCA?start=5244
    new accessibility violation(s): button-name
Full Stack Web Development: 1 worse on main, 0 better

Worse on main

  • 01: Node topic · /topic/localhost:8192/unit-1-node/topic-01-node
    new console error: Permissions policy violation: compute-pressure is not allowed in this document.

Checked 2026-10-19 11:06 UTC by course-capture.yml. Worse on main: a page that does not load, more broken course images, a course file failing, a new console error, a link to a page that does not exist, a lost heading, a quarter less text or a new serious accessibility violation; or a journey main clicks less far through. One check per side: times are a reading, not a benchmark, and nothing here is an input to the Gate. tutors.json schema: 1 of 5 courses conform to the schema the generator on main promises (mono-repo 55f3aff); reported only, since the reader opens courses older generators wrote.

4Root cause analysis each question as deep as the evidence goes

  1. Q1

    Why does main (sha-2bff81a) stop the line?

    92 unclaimed differences. 2 causes of 6 carry 89% of the 92 unclaimed differences. dom: semantic DOM differs alone is 45%.

    Pareto · report.html · the run

    5 Whys to the root: sha-185e87f, Gate FAIL on the Main to RC forecast, chain ends at Why 4 in a process
  2. Q2

    Why is post-deploy red?

    Post-deploy is green on its latest run (32 runs since 17.0.0 was deployed (2026-10-15 09:07 UTC)).

    newest post-deploy run · post-deploy runs · issue #131

    5 Whys to the root: 16.2.2, post-deploy red on every run, chain ends at Why 4 in a process
  3. Q3

    Which differences were decisions, not failures, and why were they made?

    2 fixes on b across 1 page (console). A fix never gates: it is a decision, and a claim is where its why is written. None has a claim saying why yet. Fixed with no note yet: catalogue:home (Cannot read properties of undefined (reading 'from')). That is good news; a claim is an optional note that the fix was meant, and it switches the glance item off.

    report.html, differences · src/claims/decisions.ts

    5 Whys to the root: sha-185e87f, claimed fixes read as unclaimed and their claims as stale, chain ends at Why 3 in a tool
  4. Q4

    Where is confidence lost?

    52 points lost on the dimensions measured, and 15 more are not measured on this run (hatched: a ceiling, never scored). The vital few: Claim coverage, Change risk, Test signal, Requirements traceability (not measured). The Gate is FAIL, so none of this is a score: it is where the next release has to earn its points.

    Pareto · confidence.json · docs/lean.md, visual management

    Evidence stops: 2 dimensions not measured on this run: Requirements traceability (needs the changelog, the EARS files and the claims side by side: pass --traceability <json>; changes.json already reports 13 orphan changes between the tags (a changelog entry with no diff, or a diff with no entry), a floor breach once it is measured); Post-deploy history (needs the last release's post-deploy record: pass --post-deploy <its run dir or report.json>)
  5. Q5

    Why is change risk 0 of 100?

    19 findings over 16 PRs. 0 of 16 were merged with no approving review, and any one of them breaches the floor, so change risk cannot rise above it until review coverage does. The points themselves go to a diff and its changelog entry disagree (13), a hotspot file touched (3), churn above the app's median (1), dependency (1), production lines with too few test lines (1).

    Pareto · changes.json

    Evidence stops: the next why is the monorepo's branch rules and review load, which the kept reports do not carry; open a 5 Whys with harness why --finding two-of-three-below-75:change-risk once the scoreboard fires it
  6. Q6

    Can the A/A be trusted to say the harness sees clearly?

    20 of 37 A/A nights were clean, 9 noisy (2 on 2026-09-22, 13 on 2026-09-23, 1 on 2026-09-24, 1 on 2026-09-27, 1 on 2026-10-01, 2 on 2026-10-03, 1 on 2026-10-16, 1 on 2026-10-19, 1 on 2026-10-19) and 8 degraded. 2 clean nights ran on a harness older than 1.4.4, which could not tell a clean night from a blind one (a journey failing on both sides), so their clean cannot be counted as seeing. 4 of 28 masks fired nothing on the latest night: each is a blind spot to review.

    noise-history.json · PR #22

    Evidence stops: the detection that answers it shipped in 1.4.4; every night since says degraded when it is
  7. Q7

    How long does a change wait to reach production, and where?

    The oldest merge to main not yet in production has waited 4.1d, while the machine time of the whole stream is 29m: flow efficiency 0.48%. The wait is inventory: 16 PRs merged since v17.0.0, not in production; 92 unclaimed differences the next release owes; 2 open countermeasures.

    the value stream map below

    Evidence stops: release cadence is a decision, not a defect: the map shows the batch, the team chooses its size

Fixed on main present on production, gone on main: never a failure; a claim records whether it was meant

PageFixed on bStateWhy (the claim)
console catalogue:homeCannot read properties of undefined (reading 'from')fixedno note yet (optional: a claim records that the fix was meant)

5Countermeasures to the system, never to a person

A countermeasure is a fix to the system that a 5 Whys asked for. It moves from open (not built) to in place (built, with a link) to closed, and it closes only when a release shows it working: its check is read in that release's report and the release goes in Verified by.

CountermeasureBuiltHow a release shows it worksStatus
claim guidance claims/README.md gains "A tool removed from an image": one narrow `sbom` claim per removed tree, its scope a brace list of the removed packages generated from report.json, citing the CHANGELOG entry, so the next release claims all 708 SBOM hunks without a broad claim.
its 5 Whys · answers gate · kaizen/2026-09-29-sha-185e87f-gate.md
claims/README.mdthe release gate's SBOM differences are all claimed by narrow claims: none unclaimed, and claim hygiene flags no sbom claim. 17.0.0 did not show it (release gate 2026-10-15 12:02): 212 SBOM differences unclaimed, and one sbom claim covers 696.waiting on a release
SOP change release/SOP.md's deploy step records the build production serves (the pinned digest, or while Netlify serves tutors.dev a /version naming the commit) and post-deploy judges only a confirmed build, reporting any other as "not the tested build" instead of a rollback.
its 5 Whys · answers post-deploy · kaizen/2026-09-29-16.2.2-rollback.md
src/modes/production-build.tspost-deploy names the build production serves and judges only that one: its report reads "production build: match" for the deployed release. 17.0.0 showed it: post-deploy run 38791747525 (2026-10-15 19:11) read "production build: match (production serves the recorded candidate's commit 432d46864626)".verified in 17.0.0
glance rule a claim that names an info hunk is recorded as matching it, without gating it, so the glance's fixed-on-b rule reads "claimed" and the claim is no longer reported stale.
its 5 Whys · answers decisions · kaizen/2026-09-29-sha-185e87f-fixed-on-b.md
src/claims/matcher.tsa release with a claim that names a fix on b (an info hunk) reports that claim as matching, not stale, and the glance's fixed-on-b item reads "claimed". Not yet shown: 17.0.0 claimed no fix on b.waiting on a release

6Plan who, what, when

WhatWhoWhenStatus
claims/README.md gains "A tool removed from an image": one narrow `sbom` claim per removed tree, its scope a brace list of the removed packages generated from report.json, citing the CHANGELOG entry, so the next release claims all 708 SBOM hunks without a broad claim.Leigh Griffin2026-10-06in place
a claim that names an info hunk is recorded as matching it, without gating it, so the glance's fixed-on-b rule reads "claimed" and the claim is no longer reported stale.Leigh Griffin2026-10-06in place
Score 3 real releases so the weights can be judged against the team's view (C0)the release captainthe next three releases1 of 3
Record 2 reviewer's glances (C3)the reviewerthe next two releases0 of 2

7Follow-up how we will know it worked

CheckNow
Every countermeasure closed in a release (Verified by)1 of 3 closednot yet
Open countermeasures not rising (run rule)2 open, 0 overdueyes
The next forecast's Pareto: the top bar shrinksdom: semantic DOM differs: 41not yet
Post-deploy green on a build it can confirmgreenyes

This sheet is rebuilt with the site after every kept run. A countermeasure closes only when a release names it in Verified by; until then it stays on the plan.

4The 5 Whys from the kaizen register, as written and checked by harness why check: each answer checkable, each chain ending at the first process or tool

sha-185e87f, Gate FAIL on the Main to RC forecastTrigger: Gate FAIL · kaizen/2026-09-29-sha-185e87f-gate.md
  1. Why 1

    Why did the Gate FAIL on sha-185e87f?

    The harness's own trace (facts, each one a link or a file):

    the evidence
    • Gate: FAIL (sha-185e87f beside 16.2.2): 893 unclaimed diff(s); 4 claim(s) matched nothing and should be removed from the changelog
    • Report: report.html, report.json compare.unclaimed
    • Unclaimed differences: 893 of 986 hunks (93 more are info: fixes, never gating)
    • The same Gate on the two forecasts before it: 892 unclaimed (2026-09-28T03:45Z, sha-017ceb6), 865 (2026-09-27T09:14Z, sha-54a8f83): the line has stopped on every forecast since the Main to RC stream began.
  2. Why 2

    Why are there 893 unclaimed differences?

    Because one kind of difference is most of them. By artefact and change (the A3 Aggregator's Pareto, from report.json): 696 are sbom "package removed" and 12 are sbom "package bumped", so 708 of 893 (79%) are the images' software bill of materials. The 696 removals are 174 distinct packages (npm, corepack, yarn, node-gyp, @npmcli/*, @sigstore/*, tar 7.5.11 and the rest of npm's own dependency tree) counted once in each of the four images. The 12 bumps are node 22.23.2 to 22.23.3, tar and tzdata, again once per image. The next bars are the Paper UI rebuild (network 85, dom 33, screenshot 16, focus 15, logs 15): 185 in all.

  3. Why 3

    Why did 174 packages leave every image?

    The monorepo's runtime image stopped shipping a package manager. Commit 4070315 "build: patch Debian and drop package managers from the runtime image" removes npm, npx, corepack and yarn from the runtime stage of the Dockerfile (the Trivy gate failed on npm's bundled tar and brace-expansion). It reached main with #143 on 2026-09-19 and is not in v16.2.2 (caa53d0, git merge-base --is-ancestor says no). It is an intended, security-positive change: the same run reports 72 advisories gone on b (18 per image, vulns info hunks), and the Debian patch is the 12 bumps.

  4. Why 4

    Why is an intended change like that unclaimed?

    Because nothing tells the release how to claim a removed tool. release/claims.yaml on main holds 4 claims, all for the accessibility fixes of #313 (mono-repo #364), and a claim is written in the release PR (SOP step 4), so the forecast shows the claims the next release still owes. For this change the owed claim is awkward to write: claims/README.md shows how to claim one bumped package and a framework bump by glob (*/@sveltejs/*), but a removed tool takes its whole dependency tree with it, 174 packages with unrelated names, one hunk per package per image. The precise claim is not obvious and the easy one (*/**) is a broad claim that needs an approver.

    Root cause, in a process.

claim guidance claims/README.md gains "A tool removed from an image": one narrow `sbom` claim per removed tree, its scope a brace list of the removed packages generated from report.json, citing the CHANGELOG entry, so the next release claims all 708 SBOM hunks without a broad claim.

Owner Leigh Griffin · due 2026-10-06 · in place

Built: claims/README.md · Check: the release gate's SBOM differences are all claimed by narrow claims: none unclaimed, and claim hygiene flags no sbom claim. 17.0.0 did not show it (release gate 2026-10-15 12:02): 212 SBOM differences unclaimed, and one sbom claim covers 696.

16.2.2, post-deploy red on every runTrigger: rollback · kaizen/2026-09-29-16.2.2-rollback.md
  1. Why 1

    Why did post-deploy FAIL against 16.2.2?

    The harness's own trace (facts, each one a link or a file):

    the evidence
    • Verdict: FAIL: 5 new difference(s) between production and the recorded candidate; open a rollback issue
    • The differences: network GET {{course}}/course.png on reference:lab; console new messages on reference:course, reference:lab and reference:note; focus keyboard order changed on reference:course (#38)
    • Production build: NOT CONFIRMED: /version did not answer; production was built at 2026-09-18T08:06:22Z from an unnamed build (run log)
    • History: post-deploy.yml concluded failure on all 64 of its runs from 2026-09-17 to 2026-09-29: 36 found no recorded release run to compare with (before the first release gate passed on 2026-09-27), 17 could not start on a push (2026-09-17 to 2026-09-21), and 11 found production different, each adding to the one open rollback issue.
  2. Why 2

    Why does production differ from the recorded 16.2.2?

    Because production is not the build the harness recorded. The recording is the signed image quay.io/tutors-sdk/tutors-reader:16.2.2 (digest sha256:7567d59…, created 2026-09-19T18:07Z from caa53d0). tutors.dev was built at 2026-09-18T08:06Z, three minutes after the release PR #264 merged caa53d0 (08:03Z), by Netlify from source (apps/reader/netlify.toml: pnpm --filter tutors-reader... build). Same commit, a different build and a different host, so the two can differ without any change to the code.

  3. Why 3

    Why is production built outside the image the harness gates?

    Because the deploy path that ships the gated image is built but does not serve tutors.dev yet. The monorepo's deploy.yml pins signed digests into deploy/k8s/overlays and release/deployed.json (16.2.2, deployedAt 2026-09-21T10:57Z) for OpenShift, and the OpenShift and AWS migration that would make those overlays production is planned, not done. So the "deployed" dispatch that tells the harness what production serves has never been sent: none of the 64 runs was a repository_dispatch, every judged one was the 15-minute schedule.

  4. Why 4

    Why has a red check not stopped anything for twelve days?

    Because the release SOP has no step that says which build production serves before post-deploy is trusted. The monitor finds the same five differences every quarter hour, the rollback issue deduplicates them by signature, and a standing difference with no confirmed build reads as a standing alarm rather than a stop. The Jidoka rule holds for the gate before a release; after it, nothing in the standard work says what to do when production is not the tested artefact.

    Root cause, in a process.

SOP change release/SOP.md's deploy step records the build production serves (the pinned digest, or while Netlify serves tutors.dev a /version naming the commit) and post-deploy judges only a confirmed build, reporting any other as "not the tested build" instead of a rollback.

Owner Leigh Griffin · due 2026-10-13 · closed

Built: src/modes/production-build.ts · Check: post-deploy names the build production serves and judges only that one: its report reads "production build: match" for the deployed release. 17.0.0 showed it: post-deploy run 38791747525 (2026-10-15 19:11) read "production build: match (production serves the recorded candidate's commit 432d46864626)".

sha-185e87f, claimed fixes read as unclaimed and their claims as staleTrigger: finding · kaizen/2026-09-29-sha-185e87f-fixed-on-b.md
  1. Why 1

    Why is this a place to look: reader-auth:sign-in: 2 axe violations fixed on b, unclaimed?

    The harness's own trace (facts, each one a link or a file):

    the evidence
    • Glance item: rank 2 of 7 (fixed on b; novelty 1.00 × exposure 0.17): reader-auth:sign-in: 2 axe violations fixed on b, unclaimed; a fix nobody claimed can be a behaviour change
    • Hunks: axe:reader-auth:sign-in:158 color-contrast (serious) and axe:reader-auth:sign-in:159 document-title (serious), both severity info
    • Nearest claim: axe reader-auth:sign-in: Rule 0216: The reader shall show the sign-in page with no critical or serious WCAG 2.1 AA violations; why it did not cover: it is info-only (the claim matched nothing in this run: stale)
    • The same run's Gate reasons: "4 claim(s) matched nothing and should be removed from the changelog"; glance items 2 to 5 say the same of reference:course, reference:note and reference:topic
  2. Why 2

    Why do a fix and the claim written for it both read as unmatched?

    Because the matcher never offers an info hunk to a claim. The four claims in the monorepo's release/claims.yaml (Rules 0216, 0051 twice and 0036, added by #364) name exactly the five axe hunks, and all five are severity info ("axe violation fixed on b"). src/claims/matcher.ts assigns only failing hunks ("Info hunks are reported but never need a claim"), so the four claims are never used and staleClaims lists them, and compare.matches carries no claim for the fixes.

  3. Why 3

    Why does the glance repeat it?

    Because the glance reads the same matches. fixedOnB in src/glance/rank.ts looks for the claim of each fixed hunk in compare.matches, finds none, and words the item "unclaimed; a fix nobody claimed can be a behaviour change". The tool asks for a claim on a fix, then calls the claim stale: the Contributor who follows the SOP is told by the Gate to remove it and by the glance to add it.

    Root cause, in a tool.

glance rule a claim that names an info hunk is recorded as matching it, without gating it, so the glance's fixed-on-b rule reads "claimed" and the claim is no longer reported stale.

Owner Leigh Griffin · due 2026-10-06 · in place

Built: src/claims/matcher.ts · Check: a release with a claim that names a fix on b (an info hunk) reports that claim as matching, not stale, and the glance's fixed-on-b item reads "claimed". Not yet shown: 17.0.0 claimed no fix on b.

Lean terms on this sheet

Jidoka
the Gate stops the line on an unclaimed difference; no score talks it back on
Andon
the red marks: a stopped gate, a red post-deploy, a stage that is not the tested artefact
Gemba
every number links to the report, the hunk or the run it came from
Pareto
the vital few causes (80% of the effect) above the dashed line
5 Whys
asked until the answer is a process or a tool, never a person
VSM
process time (P/T), first-pass yield (FPY), waits and inventory (I) from merge to verify
Flow efficiency
process time as a share of lead time
Decision
a fix on b is a choice, not a failure: orange, beside the traffic lights, and switched off by the claim that says why
Kaizen
every finding ends in one of seven countermeasure kinds, closed in a release (docs/lean.md)