Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
279 commits
Select commit Hold shift + click to select a range
3a72858
chore(gaps): run 10:14 exact-head overlay
seonghobae Sep 13, 2026
c4550d2
docs(gaps): refresh exact-head customer-master evidence
github-actions[bot] Sep 13, 2026
4f94c43
chore(docs): stage bounded gap baseline refresh
seonghobae Sep 13, 2026
8e0881a
docs(gaps): refresh exact-head security evidence
github-actions[bot] Sep 13, 2026
cc7b942
chore(docs): stage bounded gap baseline refresh
seonghobae Sep 13, 2026
21fa66d
docs(gaps): refresh exact-head product evidence
github-actions[bot] Sep 13, 2026
a8fd61f
chore(docs): stage live-authority baseline refresh
seonghobae Sep 13, 2026
2a2614f
fix(docs): repair bounded live baseline workflow
seonghobae Sep 13, 2026
3e81a73
docs(gaps): refresh live product authority
github-actions[bot] Sep 13, 2026
38afe0f
chore(gaps): stage bounded authority refresh
seonghobae Sep 13, 2026
c7f25ad
chore(gaps): remove failed bounded refresh helper
seonghobae Sep 13, 2026
f7933a4
chore(docs): stage bounded baseline refresh
seonghobae Sep 13, 2026
015c8ea
docs(gaps): converge release owner authority
seonghobae Sep 13, 2026
d188b85
docs(gaps): refresh current product authority
github-actions[bot] Sep 13, 2026
b21ef49
chore(docs): stage bounded gap baseline refresh
seonghobae Sep 13, 2026
7af1214
fix(docs): repair bounded gap baseline refresh runner
seonghobae Sep 13, 2026
579c4fb
fix(docs): keep refresh payload inside workflow block
seonghobae Sep 13, 2026
e8c9605
docs(gaps): refresh current Customer Master evidence
github-actions[bot] Sep 13, 2026
0dbb05b
chore(docs): stage 20:05 gap baseline refresh
seonghobae Sep 13, 2026
24afee5
chore(docs): remove queued baseline helper
seonghobae Sep 13, 2026
b3dab9e
chore(docs): refresh 20:27 live gap baseline
seonghobae Sep 13, 2026
0c53364
docs(gaps): refresh 20:27 live authority
github-actions[bot] Sep 13, 2026
01e3016
docs(gaps): make current baseline projection explicit
seonghobae Sep 14, 2026
dbc167a
docs(gaps): refresh exact-head acceptance evidence
seonghobae Sep 14, 2026
678c194
docs(gaps): record review-sidecar prerequisite RED
seonghobae Sep 14, 2026
ed6e06d
docs(gaps): record prerequisite exact-head GREEN
seonghobae Sep 14, 2026
deff9ae
docs(gaps): refresh current gate evidence
seonghobae Sep 14, 2026
3dc9330
docs(gaps): record exact-head security green
seonghobae Sep 14, 2026
0b9ded3
docs(gaps): refresh live review execution evidence
seonghobae Sep 14, 2026
0b0146a
docs(gaps): record exact-head full-diff review evidence
seonghobae Sep 14, 2026
105a2a2
docs(gaps): refresh central prerequisite evidence
seonghobae Sep 14, 2026
7c4f24a
docs(gaps): record exact-head review prerequisite approval
seonghobae Sep 14, 2026
c0f0e27
docs(gaps): correct current required-gate inventory
seonghobae Sep 14, 2026
5462b3f
docs(gaps): record terminal review runtime evidence
seonghobae Sep 14, 2026
2d820a5
docs(gaps): record current-main ADR occupancy reconstruction
seonghobae Sep 15, 2026
f761b9d
docs(gaps): refresh central review gate settlement
seonghobae Sep 15, 2026
f811085
docs(gaps): record canonical CodeQL dispatch progress
seonghobae Sep 15, 2026
51e6875
docs(gaps): record reconstructed comparison post repair
seonghobae Sep 15, 2026
04c0919
docs(gaps): record criterion coordinate stack convergence
seonghobae Sep 15, 2026
c01c941
docs(gaps): record current leftover-map stack convergence
seonghobae Sep 15, 2026
cf5454a
docs(gaps): record non-force leftover-map convergence
seonghobae Sep 15, 2026
f999eef
docs(gaps): record comparison-axis repair and stack convergence
seonghobae Sep 15, 2026
09c7e38
docs(gaps): record graphic badge repair and descendant convergence
seonghobae Sep 15, 2026
6a36c32
docs(product): refresh live gap authority after owner and stack repairs
seonghobae Sep 15, 2026
ccb5d68
docs(product): refresh owner ADR authority after review repair
seonghobae Sep 15, 2026
8446506
docs(gaps): record owner-boundary descendant convergence
seonghobae Sep 15, 2026
430d333
docs(gaps): include bounded-operator descendant convergence
seonghobae Sep 15, 2026
e20e92c
docs(gaps): record PostgreSQL timeout compatibility repair
seonghobae Sep 15, 2026
78e5692
docs(gaps): record exact-head PostgreSQL validation admission
seonghobae Sep 15, 2026
b3e8665
docs(gaps): keep PostgreSQL validation admission current
seonghobae Sep 15, 2026
ad9c127
docs(gaps): record report-axis missingness repair and current stack
seonghobae Sep 15, 2026
8af9612
docs(gaps): record live report-axis RED and descendant convergence
seonghobae Sep 15, 2026
74f9cfd
docs(gaps): repair live leftover-map ancestry authority
seonghobae Sep 15, 2026
0cd2d49
docs(gaps): refresh exact-head validation evidence
seonghobae Sep 15, 2026
a37e66b
docs(gaps): refresh leftover-map convergence and repair RCA
seonghobae Sep 15, 2026
b8060d0
docs(gaps): record comparison tick i18n RED
seonghobae Sep 15, 2026
a92be67
docs(gaps): refresh measurement descendant authority
seonghobae Sep 15, 2026
4da1020
docs(gaps): record fail-closed dependency review and queue differential
seonghobae Sep 15, 2026
51d92db
docs(gaps): record CodeQL owner repairs and parser finding
seonghobae Sep 15, 2026
6c08929
docs(gaps): admit exact-head validation for CodeQL repairs
seonghobae Sep 15, 2026
fccf18a
docs(gaps): record post-body CodeQL repair and convergence
seonghobae Sep 15, 2026
99a195e
docs(gaps): record attributed script-tag parser repair
seonghobae Sep 16, 2026
7893fcb
docs(gaps): record unresolved embedded-image parser gap
coderabbitai[bot] Sep 16, 2026
b876eb0
docs(gaps): refresh parser and leftover-map evidence
coderabbitai[bot] Sep 16, 2026
1a48096
docs(gaps): refresh current product and validation authority
seonghobae Sep 16, 2026
257b1aa
docs(gaps): record backend embedded-image parser repair
seonghobae Sep 16, 2026
871e5e5
docs(gaps): advance embedded-image repair authority
seonghobae Sep 16, 2026
38465c1
docs(gaps): record current #1115 provenance repair
seonghobae Sep 16, 2026
4c65962
docs(gap): align owner-boundary lifecycle and stack heads
seonghobae Sep 16, 2026
d12517d
docs(gap): record hosted leftover-map and warning owner evidence
seonghobae Sep 16, 2026
3c138ab
docs(gaps): record #983 hosted coverage evidence
seonghobae Sep 16, 2026
c650ad3
docs(gaps): record repaired tick foundation and converged stack
seonghobae Sep 16, 2026
943dd93
docs(gaps): record comparison tick repair and convergence
seonghobae Sep 16, 2026
aa15ab3
docs(gaps): refresh live report-stack authority
seonghobae Sep 16, 2026
4684e97
docs(gaps): record repaired tick-share stack
seonghobae Sep 16, 2026
8b1b425
docs(gaps): record terminal CodeQL verdict failure
seonghobae Sep 16, 2026
da33df2
docs(gaps): record current #983 coverage evidence
seonghobae Sep 16, 2026
d69fb24
docs(gaps): record hosted parser RED and repair
seonghobae Sep 16, 2026
6d207fe
docs(gaps): record scanner edge coverage convergence
seonghobae Sep 16, 2026
ef86600
docs(gaps): record ontology extension coverage ancestry
seonghobae Sep 16, 2026
98a4a1a
docs(gaps): correct report-axis exact head
seonghobae Sep 16, 2026
ea0f75c
docs(gaps): record image-ingestion security green
seonghobae Sep 16, 2026
dfdd6cd
docs(gaps): record catalog coverage convergence
seonghobae Sep 16, 2026
89008cc
docs(gaps): converge report stack and current receipts
seonghobae Sep 16, 2026
09f60d7
docs(gaps): record current-head cancellation class
seonghobae Sep 16, 2026
5db86ef
docs(gaps): record comparison post accessibility evidence
seonghobae Sep 16, 2026
9bc8a32
docs(gaps): record current CodeQL producer state
seonghobae Sep 16, 2026
b53310b
docs(gaps): record #873 test coverage and descendant convergence
seonghobae Sep 17, 2026
88b4102
docs(gaps): refresh #873 exact queue evidence
seonghobae Sep 17, 2026
ed465dd
docs(gaps): refresh #1115 CodeQL producer progress
seonghobae Sep 17, 2026
5b575b7
docs(gaps): track Customer Master eight-locale review draft
seonghobae Sep 17, 2026
1694d0f
docs(gaps): follow translation draft test repair
seonghobae Sep 17, 2026
15b6e6e
docs(gaps): admit translation candidate validation
seonghobae Sep 17, 2026
cb4bb2d
docs(gaps): record Customer Master seed ownership repair
seonghobae Sep 17, 2026
fa012bf
docs(gaps): scope Customer Master seed ownership lifecycle
seonghobae Sep 17, 2026
f0c4de3
docs(gaps): record translation ownership search-path repair
seonghobae Sep 17, 2026
88fdfb9
docs(gaps): track ledger search-path integrity repair
seonghobae Sep 17, 2026
2520af3
docs(gaps): track seed ownership replay concurrency
seonghobae Sep 17, 2026
c6984b9
docs(gaps): refresh canonical scheduler authority
seonghobae Sep 17, 2026
a454407
docs(gaps): record concurrent Customer Master seed replay repair
seonghobae Sep 17, 2026
b0b323d
docs(gaps): refresh canonical GitHub owner authority
seonghobae Sep 17, 2026
2471774
docs(gaps): track reviewed translation replay preservation
seonghobae Sep 17, 2026
8a24de1
docs(gaps): refresh canonical owner head
seonghobae Sep 17, 2026
6aaf49f
docs(gaps): record completed-seed retirement lifecycle
seonghobae Sep 17, 2026
dfd25c6
docs(gaps): record non-destructive ownership upgrade
seonghobae Sep 17, 2026
3d3e9eb
docs(gaps): track versioned ownership constraint repair
seonghobae Sep 17, 2026
d5000fe
docs(gaps): follow canonical CodeQL owner movement
seonghobae Sep 17, 2026
e3e78b1
docs(gaps): classify terminal CodeQL owner findings
seonghobae Sep 17, 2026
d22ef60
docs(gaps): refresh canonical queue owner
seonghobae Sep 17, 2026
8f54047
docs(gaps): classify executed image CodeQL producer
seonghobae Sep 17, 2026
dce3fab
docs(gaps): settle current-head frontend evidence and queue authority
seonghobae Sep 17, 2026
bf57fdc
docs(gaps): record hosted TLS contract RED and repair
seonghobae Sep 17, 2026
41c050f
fix(a11y): reconstruct leftover-pair name on current report parent
seonghobae Sep 17, 2026
8d78f22
fix(a11y): omit non-finite leftover fallback evidence
seonghobae Sep 17, 2026
fae5df2
docs(gaps): record current-parent leftover-pair a11y repair
seonghobae Sep 17, 2026
ae071b2
test(a11y): exercise leftover pair keyboard names in Storybook
seonghobae Sep 17, 2026
a3497ff
docs(gaps): record current leftover-pair interaction evidence
seonghobae Sep 17, 2026
a73b7e8
test(a11y): expose dense mobile pair-action overflow
seonghobae Sep 17, 2026
b586ea9
fix(a11y): wrap dense leftover pair actions
seonghobae Sep 17, 2026
b041ab7
fix(a11y): apply dense pair-action layout boundary
seonghobae Sep 17, 2026
11e9dbe
docs: track dense mobile leftover-pair repair
seonghobae Sep 17, 2026
55d69eb
test(a11y): align leftover pair selectors with accessible names
seonghobae Sep 17, 2026
5a8deac
test(a11y): exercise pointer and touch pair activation
seonghobae Sep 17, 2026
edb9462
docs(gaps): archive prior overlay and refresh live authority
seonghobae Sep 17, 2026
1463c94
test(a11y): require hosted Storybook browser evidence
seonghobae Sep 18, 2026
ab4108a
test(a11y): add static Storybook browser harness
seonghobae Sep 18, 2026
99235e6
test(a11y): exercise leftover-pair stories in Chromium
seonghobae Sep 18, 2026
fc77115
test(a11y): expose Storybook Chromium acceptance script
seonghobae Sep 18, 2026
0035ecd
fix(a11y): execute Storybook interaction evidence in CI
seonghobae Sep 18, 2026
ae9c000
test(a11y): type Storybook browser page explicitly
seonghobae Sep 18, 2026
464d4bb
test(a11y): isolate Playwright browser spec from Vitest
seonghobae Sep 18, 2026
626a196
test(a11y): keep Playwright spec out of Vitest discovery
seonghobae Sep 18, 2026
d08cb70
test(a11y): scope browser runner to Playwright-only specs
seonghobae Sep 18, 2026
93a6cb2
docs(gaps): record hosted Storybook and release inventory gaps
seonghobae Sep 18, 2026
a2c99dd
docs(gaps): record registry README owner-boundary convergence
seonghobae Sep 18, 2026
f5eddda
docs(gaps): record OIDC smoke dependency repair
seonghobae Sep 18, 2026
e2cbc41
docs(gaps): refresh OIDC smoke operator contract evidence
seonghobae Sep 18, 2026
bd307b4
docs(gaps): serialize OIDC smoke before registry README
seonghobae Sep 18, 2026
a7fb754
docs(gaps): compact current owner chain after OIDC stack convergence
seonghobae Sep 18, 2026
15865f7
docs(gaps): record #974 exact-head GREEN tests
seonghobae Sep 18, 2026
1d3f574
docs(gaps): record #974 security GREEN
seonghobae Sep 18, 2026
d76f021
test(a11y): align app selectors with visible leftover labels
seonghobae Sep 18, 2026
640ee39
chore(test): restore App test fixture before focused selector repair
seonghobae Sep 18, 2026
3435e06
docs(gaps): record hosted leftover selector RED
seonghobae Sep 18, 2026
2a73374
docs(gaps): separate OIDC smoke from browser auth acceptance
seonghobae Sep 18, 2026
c8ce17a
docs(gaps): record ROPC topology removal owner
seonghobae Sep 18, 2026
cf3bc98
ci: run one-shot #977 selector repair
seonghobae Sep 18, 2026
1bd6eff
docs(gaps): record #977 selector repair admission
seonghobae Sep 18, 2026
5842b8a
docs(gaps): correct live translation owner heads
seonghobae Sep 18, 2026
91a66bf
docs(a11y): align leftover-pair ADR with visible labels
seonghobae Sep 18, 2026
b3d844d
docs(gaps): record code-current leftover accessibility ADR
seonghobae Sep 18, 2026
2f5a668
docs(gaps): record executable ROPC security RED
seonghobae Sep 18, 2026
7cb6616
docs(gaps): require PKCE S256 in public-client auth gap
seonghobae Sep 18, 2026
65e15d1
docs(gaps): track queued OIDC causal repair
seonghobae Sep 18, 2026
2c044df
docs(gaps): make ROPC actor migration precede client shutdown
seonghobae Sep 18, 2026
c614d68
test(a11y): align report selectors with visible labels
github-actions[bot] Sep 18, 2026
891c0a1
docs(gaps): record partial OIDC machine-actor migration
seonghobae Sep 18, 2026
8b5eb0b
docs(gaps): converge README onto auth migration
seonghobae Sep 18, 2026
fdfb8ca
docs(gaps): refresh auth stack exact-head evidence
seonghobae Sep 18, 2026
ef2c587
docs(gaps): record OIDC ADR convergence
seonghobae Sep 18, 2026
edfb60f
docs(gaps): record shared JWKS verifier repair
seonghobae Sep 18, 2026
9b5e1f2
docs(gaps): record deterministic machine identity repair
seonghobae Sep 18, 2026
d5baa16
docs(gaps): record terminal translation validation reds
seonghobae Sep 18, 2026
edc5484
docs: record completed #977 selector repair
seonghobae Sep 18, 2026
06ace90
docs: record terminal #974 CodeQL settlement RED
seonghobae Sep 18, 2026
92e68df
docs(gaps): record report-axis contract repair and convergence
seonghobae Sep 19, 2026
102a654
docs(gaps): correct exact Customer Master authority
seonghobae Sep 19, 2026
bede7a7
docs(gaps): record duplicate-kid auth hardening
seonghobae Sep 19, 2026
941474c
docs(gaps): record current auth verifier evidence
seonghobae Sep 19, 2026
da5cdc8
docs(gaps): record RFC 7518 JWKS key floor
seonghobae Sep 19, 2026
5bb9e2f
docs(gaps): record canonical JWK Base64urlUInt repair
seonghobae Sep 19, 2026
abe1d70
docs(gaps): refresh RSA exponent auth evidence
seonghobae Sep 19, 2026
1c409e6
docs(gaps): record minimal JWK integer hardening
seonghobae Sep 19, 2026
b23c41e
docs(gaps): refresh live auth and delivery authority
seonghobae Sep 19, 2026
19d81cf
docs(gaps): record local PU-scope authorization repair
seonghobae Sep 19, 2026
1e7c784
docs(gaps): add mixed-scope fail-closed repair
seonghobae Sep 19, 2026
c4f4f9c
docs(gaps): record RSA exponent bound and auth heads
seonghobae Sep 19, 2026
a3ef969
docs(gaps): record odd-modulus auth boundary
seonghobae Sep 19, 2026
8b3d8ba
docs(gaps): record RFC 7517 key-operations repair
seonghobae Sep 19, 2026
a038cff
docs(gaps): record null-valued JWK metadata repair
seonghobae Sep 19, 2026
f58a14e
docs(gaps): record canonical Base64url pad-bit repair
seonghobae Sep 19, 2026
fdafecc
docs(gaps): record comparison tick root repair and converged stack
seonghobae Sep 19, 2026
1bd658e
docs(gaps): record #861 App acceptance root and telemetry owner
seonghobae Sep 19, 2026
2d3c4c6
docs(gaps): record #861 axis-label clipping acceptance
seonghobae Sep 19, 2026
62c44c7
docs(gaps): record report contract RCA and current owner head
seonghobae Sep 19, 2026
d310efb
docs(gaps): record public-only JWKS boundary
seonghobae Sep 19, 2026
68cca45
docs(gaps): record JWK x5c consistency repair
seonghobae Sep 19, 2026
458bb56
docs(gaps): record full x5c chain validation
seonghobae Sep 19, 2026
d6fde5d
docs(gaps): record x5c key-usage repair and descendant convergence
seonghobae Sep 19, 2026
818b549
docs(gaps): record JWK certificate thumbprint invariant
seonghobae Sep 19, 2026
45c4880
docs(gaps): attach thumbprint exact-head receipts
seonghobae Sep 19, 2026
fcde5db
docs(gaps): record realm-owned service subject boundary
seonghobae Sep 19, 2026
2588bae
docs(gaps): record disjoint machine and user principals
seonghobae Sep 19, 2026
69fa14f
docs(gaps): record service-client boundary repair
seonghobae Sep 19, 2026
2699b57
docs(gaps): record usable machine-auth prerequisite
seonghobae Sep 19, 2026
a8fea34
docs(gaps): refresh auth audiences and report receipt
seonghobae Sep 19, 2026
002292c
docs(gaps): record x5u verifier boundary and auth heads
seonghobae Sep 19, 2026
b68c2ac
docs(gaps): record implicit-flow auth boundary
seonghobae Sep 19, 2026
d40f9e3
docs(gaps): record exact OIDC redirect boundary
seonghobae Sep 20, 2026
75e80f3
docs(gaps): record executable seed auth RED
seonghobae Sep 20, 2026
1887967
docs(gaps): refresh auth repair runner authority
seonghobae Sep 20, 2026
f18aedb
docs(gaps): remove stale auth repair lane authority
seonghobae Sep 20, 2026
5eb824c
docs(gaps): record seed auth repair and remaining ROPC
seonghobae Sep 20, 2026
f22db36
docs(gaps): record backend ROPC executable RED
seonghobae Sep 20, 2026
11f5137
docs(gaps): record exact report-stack failures
seonghobae Sep 20, 2026
96538a5
docs(gaps): record auth helper endpoint repair
seonghobae Sep 20, 2026
6dcac9d
docs(gaps): record PyJWT floor and auth convergence
seonghobae Sep 20, 2026
9119775
docs(gaps): add PyJWT advisory traceability authority
seonghobae Sep 20, 2026
88ab342
docs(gaps): refresh Voice runtime authority
seonghobae Sep 20, 2026
bdfc8e3
docs(gaps): keep baseline head claim immutable
seonghobae Sep 20, 2026
fed6a58
docs(gap): record exact report RED and Voice authority repair
seonghobae Sep 20, 2026
1061d02
fix(a11y): align leftover pair accessible names
seonghobae Sep 20, 2026
bb7cecf
fix(ui): wrap leftover evidence on narrow screens
seonghobae Sep 20, 2026
15c14e5
docs(gaps): refresh exact-head ecosystem authority
seonghobae Sep 20, 2026
85e3d74
docs(gaps): converge report stack after merged intermediate
seonghobae Sep 20, 2026
5cbd477
docs(gaps): correct current OIDC smoke authority
seonghobae Sep 20, 2026
1f9a983
test(ui): align leftover pair accessible names
seonghobae Sep 20, 2026
44befb5
docs(gaps): track auth helper repair and convergence
seonghobae Sep 20, 2026
fd5126a
docs(gaps): refresh auth helper boundary
seonghobae Sep 20, 2026
bfca7e1
docs(gaps): record remote OAuth TLS repair
seonghobae Sep 20, 2026
ecc0c79
docs(gaps): repair acceptance wording and catalog auth owner
seonghobae Sep 20, 2026
6fb0cb0
codex: refresh exact-head gap evidence (#1041)
seonghobae Sep 20, 2026
4e3ca6b
docs(gaps): keep #1041 authority self-reference safe
seonghobae Sep 20, 2026
3e0206d
docs(gaps): record comparison axis repair candidate
seonghobae Sep 20, 2026
1f0d7f3
docs(gaps): record coordinate tick repair
seonghobae Sep 20, 2026
90980a5
docs(gaps): refresh auth exact-head evidence
seonghobae Sep 20, 2026
3b66e5b
docs(gaps): refresh exact-head authority
seonghobae Sep 20, 2026
38f648f
docs(gaps): adopt source-repaired report and auth heads
seonghobae Sep 20, 2026
57989a4
fix(reports): omit unavailable leftover distance
seonghobae Sep 21, 2026
7121a34
test(reports): reject non-finite residual accessibility evidence
seonghobae Sep 21, 2026
61d9d55
fix(reports): omit non-finite residual from accessible evidence
seonghobae Sep 21, 2026
59c8d5c
test(a11y): reject duplicate leftover evidence announcements
seonghobae Sep 21, 2026
d074db6
fix(a11y): announce leftover evidence once
seonghobae Sep 21, 2026
a0be3ca
test(a11y): preserve leftover action guidance while deduplicating evi…
seonghobae Sep 21, 2026
7258b5c
fix(a11y): deduplicate leftover evidence without dropping guidance
seonghobae Sep 21, 2026
d3d1e8c
test(a11y): cover all leftover action evidence branches
seonghobae Sep 21, 2026
61d9ee4
test(a11y): type leftover evidence branch cases explicitly
seonghobae Sep 21, 2026
2a9696b
test(a11y): reject duplicate leftover evidence announcements
seonghobae Sep 21, 2026
57c60f6
fix(a11y): announce leftover action evidence once
seonghobae Sep 21, 2026
5dd4a63
test(a11y): preserve non-finite residual visual disclosure
seonghobae Sep 21, 2026
d162aaf
fix(a11y): keep non-finite residual visual marker
seonghobae Sep 21, 2026
ad5a8ec
chore(a11y): converge gap evidence onto #977 owner lane
seonghobae Sep 21, 2026
73e0b59
docs(gaps): refresh exact-head product evidence (#1041)
seonghobae Sep 21, 2026
5c13fac
docs(gaps): serialize leftover accessibility owner authority
seonghobae Sep 21, 2026
7d05253
docs(gaps): inherit post-merge owner serialization update
seonghobae Sep 21, 2026
ff8adc5
test(docs): pin leftover-pair amendment lineage
seonghobae Sep 21, 2026
724614e
docs(adr): restore leftover-pair segment lineage
seonghobae Sep 21, 2026
7b6ff5b
test(a11y): reproduce omitted rank-zero evidence
seonghobae Sep 21, 2026
bce09c1
fix(a11y): keep rank-zero evidence in action name
seonghobae Sep 21, 2026
9dbb287
docs(gaps): refresh live accessibility and auth authority
seonghobae Sep 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,11 @@ jobs:
- name: Build Storybook
working-directory: frontend
run: pnpm run build-storybook

- name: Install Chromium for Storybook browser acceptance
working-directory: frontend
run: pnpm exec playwright install --with-deps chromium

- name: Exercise Storybook interactions in Chromium
working-directory: frontend
run: pnpm run test:storybook:browser
23 changes: 19 additions & 4 deletions docs/adr/0049-leftover-pair-report-ui.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,22 @@ A hidden post never appears as a leftover pair.
## Consequences

The authorized report payload carries `leftover_pairs` next to
`members` and `selected_items`. Screen-reader names are
`Open leftover closest pair: {title}` and
`Open leftover farthest pair: {title}` so the control announces the
next action, not only the distance.
`members` and `selected_items`.

The button's accessible name begins with the **exact localized label that is
visibly rendered on that button**: `Closest leftover: {title} · {criterion}` or
`Farthest leftover: {title} · {criterion}`. Localized next-action text follows
that visible-label prefix, then only formatter-admitted persisted evidence that
is actually available and finite. Missing or non-finite values are omitted from
the accessible name; they are never announced as `R —`, `d NaN`, or another
placeholder. This keeps the programmatic name aligned with the visible label
required by WCAG 2.2 SC 2.5.3 while still exposing the same buyer evidence to
screen-reader users. The accessible name does not derive, clamp, repair, or
synthesize psychometric values.

The historical `Open leftover closest/farthest pair: …` prefix is not the
screen-reader contract. It may describe the action conceptually, but it must
not replace the rendered label at the start of the accessible name.

## Related

Expand All @@ -136,3 +148,6 @@ coverage of the leftover map is [ADR 0168](0168-leftover-map-complete-case-cover

[ADR 0003](0003-fast-mlsirm-report-integration.md). The grouping
comparison strip reuses this leftover store ([ADR 0149](0149-leftover-pairs-on-comparison-strip.md)).

Accessibility naming follows W3C, *Web Content Accessibility Guidelines (WCAG)
2.2*, Success Criterion 2.5.3, Label in Name.
1,279 changes: 1,279 additions & 0 deletions docs/evidence/product-technical-gap-baseline-history-through-20260913.md

Large diffs are not rendered by default.

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/product-requirements.md
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ current boundary until that repository adopts one.
| `ContextualWisdomLab/keyverse` | `docs/PRD.md` | Production OIDC/JWKS/identity control plane; local demo Keycloak is not Keyverse |
| `ContextualWisdomLab/RankWeave` | No standalone PRD; `README.md`, `ARCHITECTURE.md` | Store-agnostic ranking/fusion dependency; caller owns channels and authorization |
| `ContextualWisdomLab/ThreadWeave` | `docs/PRD.md` | Deterministic reference-thread assembly dependency; LineageWeave owns records and persistence |
| `ContextualWisdomLab/DiskSage` | No standalone PRD; `docs/superpowers/specs/2026-07-10-disksage-design.md` | Prospective storage-policy boundary; no current runtime integration |
| `ContextualWisdomLab/disksage` | No standalone PRD; `docs/superpowers/specs/2026-07-10-disksage-design.md` | Prospective storage-policy boundary; no current runtime integration |
| `ContextualWisdomLab/wardnet` | No standalone PRD; `README.md`, `docs/architecture.md` | Prospective gateway/network-policy boundary; no current runtime integration |
| `ContextualWisdomLab/naruon` | Scoped `docs/topic-intelligence/PRD.md` only | Owns observed calendar/email projections; LineageWeave owns commitments and combined display |
| `ContextualWisdomLab/LineageWeave` | This PRD, with ADRs normative | Evidence BI/orchestration, lineage, semantic projection, API, and UI owner |
1,425 changes: 92 additions & 1,333 deletions docs/product-technical-gap-baseline.md

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"test": "vitest run",
"e2e": "playwright test",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build"
"build-storybook": "storybook build",
"test:storybook:browser": "playwright test --config playwright.storybook.config.ts"
},
"dependencies": {
"oidc-client-ts": "^3.5.0",
Expand Down
28 changes: 28 additions & 0 deletions frontend/playwright.storybook.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { defineConfig, devices } from "@playwright/test";

/** Browser acceptance for the already-built Storybook artifact. */
export default defineConfig({
testDir: "./storybook-e2e",
testMatch: "**/*.pw.ts",
fullyParallel: false,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 1 : 0,
workers: 1,
reporter: [["list"]],
use: {
baseURL: "http://127.0.0.1:6006",
trace: "retain-on-failure",
},
projects: [
{
name: "chromium",
use: { ...devices["Desktop Chrome"], hasTouch: true },
},
],
webServer: {
command: "python3 -m http.server 6006 --directory storybook-static",
url: "http://127.0.0.1:6006",
reuseExistingServer: false,
timeout: 120_000,
},
});
10 changes: 5 additions & 5 deletions frontend/src/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4203,9 +4203,9 @@ describe("App, authenticated", () => {
"Leftover map dropped 0 incomplete criteria",
);
const coverageCaption = screen.getByLabelText("Leftover map coverage");
const closestPair = screen.getByRole("button", { name: /open leftover closest pair: public post/i });
const closestPair = screen.getByRole("button", { name: /^closest leftover: public post · sales-lead /i });
const farthestPair = screen.getByRole("button", {
name: /open leftover farthest pair: specification revision requested/i,
name: /^farthest leftover: specification revision requested · negative /i,
});
expect(closestPair).toHaveTextContent("Closest leftover: Public post · sales-lead");
// Leftover-map coordinates are present, so they name the next action
Expand All @@ -4223,7 +4223,7 @@ describe("App, authenticated", () => {
expect(closestPair).toHaveTextContent("R̂ +0.25");
expect(closestPair).toHaveTextContent("ξ (+0.50, +0.10) ζ (+0.50, −0.02)");
expect(closestPair).toHaveTextContent("d 0.12");
expect(closestPair).toHaveAccessibleName("Open leftover closest pair: Public post · sales-lead");
expect(closestPair).toHaveAccessibleName(/^Closest leftover: Public post · sales-lead /);
expect(farthestPair).toHaveTextContent("Farthest leftover: Specification revision requested · negative");
expect(farthestPair).toHaveTextContent(
"Leftover map places this post at ξ (+0.90, +0.80) and the criterion at ζ (−0.70, −0.40) after IRT main effects. Open this post to read negative.",
Expand Down Expand Up @@ -4438,7 +4438,7 @@ describe("App, authenticated", () => {
render(<App showLabPanels />);

await userEvent.click(
await screen.findByRole("button", { name: /open leftover closest pair: public post/i }),
await screen.findByRole("button", { name: /^closest leftover: public post · sales-lead /i }),
);
await waitFor(() => expect(screen.getByText("The full body text.")).toBeInTheDocument());
expect(await screen.findByRole("heading", { name: "Post quality (IRT)" })).toHaveFocus();
Expand All @@ -4454,7 +4454,7 @@ describe("App, authenticated", () => {
await userEvent.click(screen.getByRole("button", { name: "Close" }));
await userEvent.click(
await screen.findByRole("button", {
name: /open leftover farthest pair: specification revision requested/i,
name: /^farthest leftover: specification revision requested · negative /i,
}),
);
await waitFor(() =>
Expand Down
246 changes: 246 additions & 0 deletions frontend/src/components/LeftoverPairList.accessibleName.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { describe, expect, it, vi } from "vitest";
import type { LeftoverPair } from "../api";
import { LeftoverPairList } from "./LeftoverPairList";

const PAIR: LeftoverPair = {
pair_kind: "closest",
post_id: "post-demo-public",
post_title: "Public post",
criterion_code: "sales_lead_quality",
leftover_distance: 0.12,
leftover_residual: 0.4,
observed_response: 2.4,
expected_response: 2.0,
leftover_map_rank: 1,
};

const ACTION_EVIDENCE_CASES: Array<[string, Partial<LeftoverPair>, string]> = [
[
"rank-only",
{ observed_response: null, expected_response: null, leftover_map_rank: 2 },
"rank 2",
],
["observed/expected", { leftover_map_rank: null }, "Y 2.40"],
["unexplained", { leftover_map_unexplained: 0.05 }, "U +0.05"],
[
"reconstruction",
{ leftover_map_unexplained: 0.05, leftover_map_reconstruction: 0.35 },
"R̂ +0.35",
],
[
"cross share",
{
leftover_map_unexplained: 0.05,
leftover_map_reconstruction: 0.35,
leftover_map_cross_share: 0.13,
},
"0.13",
],
[
"unexplained share",
{
leftover_map_unexplained: 0.05,
leftover_map_reconstruction: 0.35,
leftover_map_cross_share: 0.13,
leftover_map_unexplained_share: 0.23,
},
"0.23",
],
[
"explained share",
{
leftover_map_unexplained: 0.05,
leftover_map_reconstruction: 0.35,
leftover_map_cross_share: 0.13,
leftover_map_unexplained_share: 0.23,
leftover_map_explained_share: 0.76,
},
"0.76",
],
[
"coordinates",
{
leftover_map_unexplained: 0.05,
leftover_map_reconstruction: 0.35,
leftover_map_cross_share: 0.13,
leftover_map_unexplained_share: 0.23,
leftover_map_explained_share: 0.76,
leftover_map_person_axis_1: 0.5,
leftover_map_person_axis_2: 0.1,
leftover_map_item_axis_1: 0.5,
leftover_map_item_axis_2: -0.02,
},
"ξ (+0.50, +0.10)",
],
];

function criterionLabel(code: string): string {
return code === "sales_lead_quality" ? "sales-lead" : code;
}

function occurrences(value: string, token: string): number {
return value.split(token).length - 1;
}

function accessibleNameFor(overrides: Partial<LeftoverPair> = {}): string {
render(
<LeftoverPairList
pairs={[{ ...PAIR, ...overrides }]}
criterionLabel={criterionLabel}
onSelectPost={vi.fn()}
/>,
);
return (
screen
.getByRole("button", { name: /^Closest leftover: Public post · sales-lead / })
.getAttribute("aria-label") ?? ""
);
}

describe("LeftoverPairList accessible action name", () => {
it("starts with the rendered label and carries each finite evidence value once", async () => {
const onSelectPost = vi.fn();
render(
<LeftoverPairList
pairs={[PAIR]}
criterionLabel={criterionLabel}
onSelectPost={onSelectPost}
/>,
);

const action = screen.getByRole("button", {
name: /^Closest leftover: Public post · sales-lead /,
});
expect(action).toHaveTextContent("Closest leftover: Public post · sales-lead");
expect(action).toHaveAccessibleName(/R \+0\.40/);
expect(action).toHaveAccessibleName(/Y 2\.40 · E 2\.00/);
expect(action).toHaveAccessibleName(/rank 1/);
expect(action).toHaveAccessibleName(/d 0\.12/);

const name = action.getAttribute("aria-label") ?? "";
expect(occurrences(name, "rank 1")).toBe(1);
expect(occurrences(name, "Y 2.40")).toBe(1);
expect(occurrences(name, "E 2.00")).toBe(1);
expect(occurrences(name, "R +0.40")).toBe(1);
expect(occurrences(name, "d 0.12")).toBe(1);

await userEvent.click(action);
expect(onSelectPost).toHaveBeenCalledWith(PAIR);
});

it("keeps residual guidance while announcing finite residual evidence once", () => {
const name = accessibleNameFor({
observed_response: null,
expected_response: null,
leftover_map_rank: null,
});

expect(name).toContain(
"Leftover residual R +0.40 after IRT main effects. Open this post to read sales-lead.",
);
expect(occurrences(name, "R +0.40")).toBe(1);
expect(occurrences(name, "d 0.12")).toBe(1);
});

it.each(ACTION_EVIDENCE_CASES)(
"announces %s action evidence once",
(_label, overrides, token) => {
const name = accessibleNameFor(overrides);
expect(occurrences(name, token)).toBe(1);
},
);

it("keeps every finite persisted pair-evidence badge in the same accessible name", () => {
render(
<LeftoverPairList
pairs={[
{
...PAIR,
leftover_map_unexplained: 0.05,
leftover_map_reconstruction: 0.35,
leftover_map_cross_share: 0.12,
leftover_map_unexplained_share: 0.02,
leftover_map_explained_share: 0.76,
leftover_map_person_axis_1: 0.5,
leftover_map_person_axis_2: 0.1,
leftover_map_item_axis_1: 0.5,
leftover_map_item_axis_2: -0.02,
},
]}
criterionLabel={criterionLabel}
onSelectPost={vi.fn()}
/>,
);

const action = screen.getByRole("button", {
name: /^Closest leftover: Public post · sales-lead /,
});
expect(action).toHaveAccessibleName(/R \+0\.40/);
expect(action).toHaveAccessibleName(/Y 2\.40 · E 2\.00/);
expect(action).toHaveAccessibleName(/rank 1/);
expect(action).toHaveAccessibleName(/U \+0\.05/);
expect(action).toHaveAccessibleName(/U²\/R² 0\.02/);
expect(action).toHaveAccessibleName(/R̂²\/R² 0\.76/);
expect(action).toHaveAccessibleName(/2R̂U\/R² 0\.12/);
expect(action).toHaveAccessibleName(/R̂ \+0\.35/);
expect(action).toHaveAccessibleName(/ξ \(\+0\.50, \+0\.10\) ζ \(\+0\.50, −0\.02\)/);
expect(action).toHaveAccessibleName(/d 0\.12/);
});

it("keeps non-finite residual visual disclosure while omitting it and non-finite distance from the accessible name", () => {
render(
<LeftoverPairList
pairs={[
{
...PAIR,
leftover_residual: Number.NaN,
leftover_distance: Number.NaN,
},
]}
criterionLabel={criterionLabel}
onSelectPost={vi.fn()}
/>,
);

const action = screen.getByRole("button", {
name: /^Closest leftover: Public post · sales-lead /,
});
expect(action).toHaveAccessibleName(/rank 1/);
expect(action).not.toHaveAccessibleName(/R —/);
expect(action).not.toHaveAccessibleName(/d NaN/);
expect(action).toHaveTextContent("R —");
expect(action).not.toHaveTextContent("d NaN");
});

it("falls back to the existing localized open action while preserving the visual non-finite residual marker", () => {
render(
<LeftoverPairList
pairs={[
{
...PAIR,
leftover_residual: Number.NaN,
leftover_distance: Number.NaN,
observed_response: null,
expected_response: null,
leftover_map_rank: null,
},
]}
criterionLabel={criterionLabel}
onSelectPost={vi.fn()}
/>,
);

const action = screen.getByRole("button", {
name: /^Closest leftover: Public post · sales-lead /,
});
expect(action).toHaveTextContent(
"Open this post so the leftover criterion is current in Post quality.",
);
expect(action).not.toHaveAccessibleName(/R —/);
expect(action).not.toHaveAccessibleName(/d NaN/);
expect(action).toHaveTextContent("R —");
expect(action).not.toHaveTextContent("d NaN");
});
});
Loading