Architecture governance

MMCA.Store — Architecture Remediation Backlog

Derived from ArchitectureScorecard.md (two-axis: Maturity 98.4% / Implementation 83.6%, full re-score 2026-07-17, framework pin v1.117.0). Items are categories scoring below 4 (maturity) or with a notable implementation gap, ranked by priority = (4 − maturity) × weight (and impl-gap items called out separately). This is Store's first in-repo remediation ledger; the scorecard is the source of truth for scores, ../MMCA.Common/FACTS.md for framework-wide facts, and ../Docs/Architecture/ArchitectureRemediation.md for the cross-repo [C→A] roll-up.

Status legend: ☐ open · ◐ in progress · ☑ done


🔴 Priority — a11y / E2E merge gate (#21, #28, #22)

The former single biggest maturity lever: #28 cleared 2026-07-03; #22 cleared on the 2026-07-17 re-score (the gate flip verified live). Only #21 remains open (priority (4-3)×3 = 3, the highest open lever), pending a recorded screen-reader pass.

  • [~] #21 Accessibility, maturity 4 corrected back to 3 (2026-07-11, drift plan D6); impl 7 → 8 DONE. The axe + Playwright suite gates the deploy (e2e-gate, chromium, workflow_call into e2e.yml, in deploy.yml's needs), and the axe scans broadened 10 → 22 pages (public, shopper, and Catalog/Sales/Identity admin surfaces), lifting impl 7 → 8. The prior maturity-4 was an over-claim: the rubric pairs axe-in-CI with a recorded manual screen-reader pass, so honest maturity is 3, matching ADC on the same rubric. A new ACCESSIBILITY-SCREENREADER-PASS.md runbook shipped, but its results log is still empty. Maturity 3 → 4 lever: record a dated manual SR pass in the new runbook (needs a human + NVDA/VoiceOver against the running Aspire app; cannot be done headless).
  • #28 Front-End Testing, maturity 3 → 4 DONE (2026-07-03) / impl 6 → 8 DONE (2026-07-11, drift plan D7). The E2E + axe deploy gate shipped with #21; bUnit breadth grown to 214 [Fact]/[Theory] across 40 files (Catalog 63 / Sales 126 / Identity 25) with loading/empty/error/edge state coverage, the full CI gate green at 1393/1393.
  • #22 Responsive & Cross-Browser, maturity 3 → 4 DONE (GRANTED on the 2026-07-17 re-score; adversarially verified against live workflow files: e2e.yml:76 scopes continue-on-error to scheduled non-chromium runs only, deploy.yml:315 invokes all three engines, deploy.yml:429 puts e2e-gate in deploy needs). Scorecard §22 is M4/I8; moved to the protect list. History of the reopen-and-fix below. The wave-5 change passed browsers: ["chromium", "firefox", "webkit"] into the e2e-gate call, so all three engines RUN in the gate, but the non-chromium legs cannot FAIL it: e2e.yml:71 still sets continue-on-error: ${{ matrix.browser != 'chromium' }}, and deploy.yml:433's own inline comment describes e2e-gate as chromium-only. The 2026-07-16 re-score held maturity 3 on exactly this evidence and the candidacy was declined. The green-soak history (2026-07-09 through 2026-07-11, plus the d057afc three-engine catch) still stands as soak evidence. Maturity 3 → 4 lever: remove the continue-on-error conditional for the gate-invoked firefox/webkit legs (or gate them behind their own required jobs) once the soak is judged sufficient; nightly-matrix legs may stay advisory. Lever SHIPPED same day (2026-07-16): continue-on-error is now github.event_name == 'schedule' && matrix.browser != 'chromium', so all three engines the gate invokes (deploy.yml:315) CAN fail a deploy while nightly non-chromium legs stay advisory flake alarms; the stale chromium-only comments in e2e.yml/deploy.yml corrected. Soak judged sufficient: job-level green nightly matrices 2026-07-09 through 2026-07-16, with the sole 2026-07-12 red being the all-three-engines product defect fixed in d057afc (a true positive, not flake). Maturity 3 → 4 candidacy recorded for the next re-score.

🟠 Priority — execution-quality gaps (impl, not maturity)

  • #14 Testability, impl 6 → 9. DONE (2026-07-01 wave, re-scored 2026-07-02). The floor step now measures Store's own code (reportgenerator +MMCA.Store.*;-*.Tests) at floor 42.0 with 46% actual (deploy.yml:82-86), the ADC-parity self-filtered gate; bUnit page-level breadth reached ADC parity (8 files). Unit-coverage program (2026-07-05): floor ratcheted 42.0 to 51.6 (54% measured) after Stripe money-path, Sales UI, and GDPR-handler unit tests. Integration-coverage expansion (2026-07-06): ~100 new integration tests over real SQL closed the money-path gaps (Stripe webhook signature contract, order state machine, deliberate 404-not-403 order ownership), GDPR erasure/export end-state, refresh-token rotation, preferences, cross-service ProductVariantChanged consistency, checkout concurrency, contract guards (OpenAPI + RFC 9457) for Sales/Identity, and the ProductImages/PUT leftovers; [Idempotent] was wired onto the Sales money POSTs with a replay contract test. The Catalog+Sales fixtures were consolidated onto SqlServerIntegrationTestFixtureBase. Cross-service broker tier (2026-07-11, drift plan D5): a non-gating nightly MMCA.Store.CrossService.IntegrationTests (Testcontainers RabbitMQ + SQL, cross-service-tests.yml) now exercises the genuine outbox-to-broker-to-consumer round-trip (Catalog ProductVariantChanged to Sales' zero-stock InventoryItem); the first run needs a manual workflow_dispatch (done 2026-07-11, green). Gated by recency same day (remediation wave 6): a cross-service-freshness job in deploy.needs fails a deploy when the latest successful nightly is older than 3 days (mirrors ADC TD-02; the Testcontainers workflow itself stays out of the deploy chain). Deliberately skipped: dedicated rate-limit fixtures (the WAFs neutralize the limiter; a tight-limit variant is low value for the volume, revisit only if abuse is observed).
  • #23 Front-End Performance, impl 6 → 8. DONE (2026-07-03, drift plan D4 + D10). Public CatalogBrowse moved to server-side paging (GetPagedAsync + bounded MobileInfiniteScrollList); cart enrichment resolves names via the targeted products/variant-lookup batch endpoint (CartStateService.cs:282-296); Core Web Vitals (LCP/CLS/TTFB/FCP) are measured per E2E run and uploaded as CI artifacts (Workflows/WebVitalsTests.cs). Accepted trade-offs (2026-07-02 approval): price sorts fall back to Newest; search is Name-contains.

🟡 Priority — minor / accept-or-polish

  • #32 Dependency & Supply-Chain, impl 7 → 8. DONE (2026-07-03, drift plan D8 + D9). Vulnerability gate is NuGetAudit + TreatWarningsAsErrors at restore, which fails build-and-test (a needs: of deploy) and every Docker image build; accepted advisories are the documented NuGetAuditSuppress set (Directory.Build.props:16,8-12,38-40). The SBOM became a hard gate in 43d733f with supply-chain added to deploy's needs. All three CI restores now run --locked-mode (committed-lock drift fails the build) and the vuln report is promoted to the suppress-aware gating audit mirroring ADC.
  • [~] #20 Design System, impl 7 → 8 lever OPEN (marker corrected 2026-07-17: the wave-6 done-claim over-reached; the 2026-07-16 and 2026-07-17 re-scores both hold §20 at M4/I7 because the recorded MudBlazor Style=/CellStyle= residuals below still hold impl at 7, ProductList.razor:118). Maturity 4 stands (2026-07-01). The brand-color token guard BrandColorTokenTests shipped in 5fbd003 (CI-enforced, both UI hosts' home CSS repointed to var(--mmca-primary)). The remaining impl lever landed: every plain-HTML inline style= in Catalog.UI and Sales.UI moved verbatim into 17 new scoped .razor.css files as semantic classes (cart drawer, product images/variants, catalog cards, order/inventory pages; classes only added, DOM structure unchanged). Recorded residuals: MudBlazor Style=/CellStyle= parameters on components with no plain-HTML ancestor in their own markup, which Blazor CSS isolation cannot target without a DOM-changing wrapper (list in the wave-6 commit); no hard-coded brand hex anywhere. CI.slnf 1397 green incl. all fitness gates.
  • #9 API & Contract, impl 8 → 9. DONE (2026-07-03, drift plan D16). The v2 demonstration shipped: ServiceInfoController carries [ApiVersion("1.0", Deprecated = true)] + [ApiVersion("2.0")] mirroring ADC, and the two deploy-gating contract-guard integration tests (Contract/ApiVersioningTests + Contract/OpenApiContractTests, mirroring MMCA.ADC.Conference.IntegrationTests/Contract/) run in the integration-tests job. (Scorecard §9 refreshed to M4/I9 on 2026-07-11, drift plan D12.)
  • [~] #24 Forms, maturity 3 → 4 DONE (2026-07-11, drift plan D11); impl 8 → 9 lever OPEN (marker corrected 2026-07-17: the wave-6 done-claim over-reached; the 2026-07-16 and 2026-07-17 re-scores both hold §24 at M4/I8 because client validation stays MudForm-level, not full FluentValidation parity with the server rules). Maturity 4 is earned by the CI-gated FormsConventionTests (MinimumCreateForms=4) machine-enforcing the four create forms' guard/dirty/validated-MudForm/Required markers, matching ADC. The impl lever landed: client-side parity added where server rules were genuinely unmirrored: email-format validation (mirroring CustomerEmailRules' exact algorithm) on CustomerCreate + CustomerDetail, and per-field NewPassword min-length/128-cap plus confirm-match on Profile change-password (localized en+es keys). Audited-and-already-covered rules (Product/Category/Inventory lengths, ranges, SKU cap) and deliberately server-only rules (SKU uniqueness needs the DB) recorded in the wave-6 commit. No FormsConventionTests markers weakened.
  • #7 Microservices / single shared DBNOT A GAP (corrected): Store runs database-per-service (Store_Catalog/Store_Sales/Store_Identity); the legacy MMCAStore DB is a retained read-only archive only.

🐞 Defect-fix wave (2026-07-05)

Four reviewed product defects fixed in one wave; every behavior change flipped its pinning test in the same change.

  • S-1 Stripe network errors escaped the Result pattern. StripePaymentService now handles HttpRequestException in both resilience predicates (retry + circuit breaker) and maps it to Payment.Stripe.SessionCreationFailed / Payment.Stripe.SessionRetrievalFailed instead of letting it propagate past the catch blocks.
  • S-2 Zero-decimal currency guard. Checkout-session creation validates the currency against a deliberate two-decimal allow-list (USD, EUR; must be extended together with Currency.All) before the * 100 smallest-unit conversion, returning the new Payment.Stripe.UnsupportedCurrency error, and rounds AwayFromZero instead of truncating fractional cents.
  • S-3 BuyNow drawer half-failure parity. CheckoutAndPayAsync now returns CheckoutOutcome(StripeUri, OrderId); on a payment-session failure it also persists the orphan-recovery token (previously only the success path did) and CartDrawer navigates to /orders/{id} with the order-id warning, matching Catalog's BuyNow fallback.
  • S-4 Case-sensitive Admin check in the GDPR handlers. DeleteUserHandler/ExportUserDataHandler use the new case-insensitive UserRole.IsAdmin instead of != UserRole.Admin, so a lowercase admin role claim authorizes the cross-user path.
  • Reviewed, not fixed (deliberate): CartStateService.InitializeAsync loading the cart without raising OnChange stays pinned intended behavior (initialization is silent; only user-visible mutations notify). OrderDetail's missing [Authorize] remains a recorded deliberate choice (E2E gap program review), out of scope for this wave.

Deliberate / accepted (record the choice; don't silently leave low)

  • ADR-042 device capability abstraction (latent, drift plan D8). The core seam is converged (Store wires browser + MAUI capabilities via UseMauiDeviceCapabilities/AddBrowserDeviceCapabilities and renders the shared OfflineBanner), but Store consumes no further capability in its own product UI: no ExternalLink, no DeviceUIModule/DeepLinkListener, no app actions. Because no Store product page carries an external anchor today, the WebView dead-end risk is LATENT, not a live defect, so there is nothing to convert now. Adopt ExternalLink on any future Store product page that grows an external anchor, and register a Store IUIModule with DeepLinkListener (the way ADC's DeviceUIModule does) if a Store MAUI feature surface is ever wanted. The framework side is complete in Common (18 capability contracts + the MMCA.Common.UI.Maui package), so this is consumer-side only, not [C→A].
  • #5 Vertical Slice (M3) RESOLVED (2026-07-17 re-score): §5 is M4/I8, granted on the CI-gated SliceCohesionTests (sealed subclass of the shared non-vacuous base, in the deploy-gating MMCA.Store.CI.slnf:52), the identical gate ADC credits at M4/I8. The layered-by-project hybrid remains a deliberate design choice, now correctly recorded as an implementation-axis cap (holds impl at 8), not a maturity deduction. Moved to the protect list.
  • #27 Internationalization N/A RETIRED (2026-07-02): ADR-027 superseded ADR-011; Store ships full en-US + es localization with the CI-gated TranslationCompletenessTests. §27 is scored and included in the indices. Updated 2026-07-03 (i18n completion sweep): §27 is M4/I8 with zero residual hard-coded literals (35 snackbars incl. cart/checkout/Stripe, 33 breadcrumb labels, nav items, both StoreHome hosts), a second CI gate (LocalizedTextConventionTests), the completeness floor raised 20→25, and MudBlazor chrome localized via the framework's ResxMudLocalizer. Impl 8→9 lever DONE (2026-07-11, remediation wave 6): Tests/E2E/MMCA.Store.E2E.Tests/Workflows/PseudoLocalizationTests.cs extends the pseudo-loc text-expansion evidence to Store's own public pages (/, /catalog, /login): activates qps-Ploc via the production /culture/set cookie mechanism (the circuit handshake carries cookies, not query strings), asserts the [!! sentinel, Common's exact no-horizontal-overflow expression, and a per-page resx-owned en-US leak probe, plus a default-culture sentinel guard. No host/AppHost change needed; rides the deploy-gating chromium e2e-gate (first genuine run in CI). §27 Implementation 8→9 candidacy recorded for the next re-score. Candidacy GRANTED on the 2026-07-17 re-score (user-adjudicated: the lever's test is real and rides the deploy-gating chromium e2e-gate): §27 is M4/I9.
  • Single-region deployment — accepted in infra/DISASTER-RECOVERY.md (real load doesn't justify multi-region cost).
  • All per-service DBs on one physical SQL server — logical isolation complete; shared server for cost (minor §7/§8).
  • 2026-07-16 re-verification note: #9 (M4/I9) and #32 came back FLAG on the full re-score (first-pass scorers proposed regressions that the adversarial verify pass disproved against committed evidence). #9 stands at M4/I9. #32 was re-adjudicated the same day by the drift-analysis fold: a capability-level ADC comparison (adversarially verified) found no mechanism behind ADC's I9 that Store lacks, so §32 is now M4/I9; the earlier FLAG had reasoned from stale scorecard text (including a stale 49 lock-file count, actual 55).
  • ADR-043 adoption (mobile deep links / app association / native OAuth callback): recorded DEFERRED (2026-07-16 drift fold). The drift analysis lands this in Store, but adoption is feature-scale (Store-scheme deep links, iOS/Android manifest entries, associated domains) and rides the same trigger as the recorded ADR-042 latency: adopt when a Store MAUI surface is actively wanted. Not scheduled; revisit with the ADR-042 entry above.
  • #33 broker-parity tier SHIPPED (2026-07-16, mirrors ADC): Tests/Integration/MMCA.Store.ServiceBusEmulator.IntegrationTests runs MassTransit v8 against the official Service Bus emulator (pinned 2.0.1) with the real ProductVariantChanged contract, proving admin-plane topology creation + the AMQP round-trip nightly in cross-service-tests.yml (new job, same cross-service-freshness deploy gate). Closes the local-RabbitMQ vs prod-Service-Bus red flag with automation instead of documentation; §33 I8→9 candidacy recorded for the next re-score.
  • ADR-044 adoption (native push, third notification channel): recorded DEFERRED (2026-07-16 drift fold). Store has no user-notification pipeline at all (no ADR-024 inbox, no SignalR channel), so ADR-044 adoption means adopting the whole notification stack first: a product decision, not remediation. Record here so the gap is conscious; schedule only if Store wants user notifications.

🟠 Below-maturity-4 tracking (inclusion policy: categories scoring < 4 maturity)

These categories score maturity 3; the ledger records them per its own line-4 inclusion policy (mirrors ADC's equivalent entries).

  • #19 · State Management & Data Flow · maturity 3 → 4 (weight 3). DONE (2026-07-11, remediation wave 2). The §19 fitness gate now runs in the CI.slnf arch tier: StateManagementConventionTests (sealed subclass of the shared v1.115.0 StateManagementConventionTestsBase) reflects over the three module UI assemblies (now registered as Layer.Ui in StoreArchitectureMap) failing the build on any mutable static field or settable static property, plus a source scan forbidding singleton *StateService/*StateContainer registrations. Verified non-vacuous: a seeded mutable static in Catalog.UI failed the gate with the exact offender name, then green after removal. Maturity 4 GRANTED on the 2026-07-16 re-score (two-pass, adversarially verified; the proposed impl bump to 9 was rejected as an enforcement gain, not substance). Scorecard §19 is M4/I8; moved to the protect list.
  • #18 · UI Architecture & Components · maturity 3 → 4 (weight 3). DONE (2026-07-11, remediation wave 2). The §18 fitness gate now runs in the CI.slnf arch tier: UIArchitectureConventionTests (sealed subclass of the shared v1.115.0 UIArchitectureConventionTestsBase) caps every *.razor.cs under Source/ at 400 lines and inline @code blocks at 120 lines. Conformance shipped with the gate: OrderDetail.razor.cs 500 → 361 (extracted OrderSummaryPanel + OrderLinesPanel) and ProductDetail.razor.cs 491 → 340 (extracted ProductVariantsPanel), markup moved verbatim (DOM identical for the E2E selectors), all bUnit suites green. Verified non-vacuous via a seeded 402-line file. Maturity 4 GRANTED on the 2026-07-16 re-score (two-pass, adversarially verified; the proposed impl bump to 9 was rejected, impl holds 8 on the residual inline-style logic). Scorecard §18 is M4/I8; moved to the protect list.
  • #12 · Performance & Scalability · maturity 3 → 4 (weight 2). DONE (2026-07-11, remediation wave 3). Both halves of the lever are now enforced deploy preconditions: (a) a load-freshness job in deploy.yml's needs fails the deploy when the latest successful monthly load-test.yml run is older than 35 days (the dr-freshness pattern; latest run 2026-07-01, green), and (b) the WebVitals budgets were tightened from catastrophic-only (LCP 8000) to the Core Web Vitals "good" band (LCP 2500 / FCP 1800 / TTFB 800 / CLS 0.1 / INP 500), calibrated against measured CI maxima (LCP 172ms, 10-30x headroom), asserted inside the deploy-gating chromium e2e-gate. Maturity candidacy DECLINED on the 2026-07-16 re-score: the k6 load test itself runs monthly/on-demand, so it is capacity-planning evidence rather than a merge gate; the freshness gate bounds staleness but does not gate regressions. §12 stays M3/I8, lever OPEN: either record the monthly cadence as the accepted posture (ADC's stance) or add a latency-regression check to the merge path. §23 split out and RESOLVED same day (drift-analysis fold, adversarially verified): its CWV budget assertions are per-deploy enforcement independent of k6's cadence, the identical evidence ADC's twentieth cycle credited, so scorecard §23 is M4/I8 and moves to the protect list.
  • #13 · Observability & Operability · maturity 3 → 4 (weight 2). DONE (2026-07-11, remediation wave 6). The dashboard half already existed (the saved store-slo-workbook Azure Monitor workbook mirrors the three SLO alerts per service); the missing runbook half landed as infra/OPERATIONS.md: each provisioned alert (failed-requests, server-response-time, dependency-failures) mapped to concrete triage steps (workbook pane, App Insights drill path, container logs, the Stripe/gRPC/outbox failure classes) plus fast-reference recovery moves (revision rollback, PITR restore, the freshness gates) and a pair-with-sloAlertSpecs governance note. Split verdict on the 2026-07-16 re-score: Implementation 8 → 9 GRANTED (both prior deductions closed: workbook infra/main.bicep:274 + runbook infra/OPERATIONS.md), but the maturity candidacy was DECLINED: dashboards/runbooks are IaC/review-enforced, and nothing in CI fails when an alert loses its runbook pairing. §13 stays M3/I9, lever OPEN: add a CI gate asserting the sloAlertSpecs-to-OPERATIONS.md pairing (mirrors ADC's reopened #13; one shared gate design can serve both repos). Gate SHIPPED same day (2026-07-16): Tests/Architecture/MMCA.Store.Architecture.Tests/ObservabilityConventionTests.cs (mirror of ADC's) machine-enforces the pairing in the CI.slnf arch gate: every sloAlertSpecs key needs a ### ...-alert-<key> runbook section carrying the alert's current (sev N), orphans fail, 3-spec non-vacuity floor, both files embedded. Verified red on a seeded severity drift, green on the real files. Maturity 3 → 4 candidacy recorded for the next re-score. Maturity 4 GRANTED on the 2026-07-17 re-score (ObservabilityConventionTests.cs:24,34 verified live in the CI.slnf arch gate, MMCA.Store.CI.slnf:52): §13 is M4/I9; moved to the protect list.

🟢 Resolved this cycle (2026-07-11 drift-convergence, drift plan D1-D13)

  • #29 DR gates (drift plan D3). dr-freshness is now in deploy.needs (fails a deploy when the last successful dr-drill is stale), dr-drill.yml gained a weekly cron, and GracefulShutdownTests (in MMCA.Store.Gateway.Tests, MMCA.Store.CI.slnf) is CI-gated, so scorecard §29 legitimately holds M4 and lifts Implementation 8 → 9. The former honest residual (stale 2026-06-22 drill) is resolved: the weekly dr-drill.yml cron runs green, most recently 2026-07-13, so dr-freshness is satisfied.
  • #31 cost-guard deploy gate (drift plan D4). cost-guard.yml gained a workflow_call trigger and is invoked as a cost-guard job in deploy.needs, so an un-reverted surge blocks the deploy (previously weekly-cron-only). Prerequisite for a clean first gated deploy: a green latest scheduled cost-guard run.
  • #1 SOLID, impl 8 → 9 (drift plan D9). Scorecard §1 refreshed to cite the CI-gated ConstructorDependencyCountTests (ceiling 7, the 8+-dependency red flag cleared) + TimeProvider injection.
  • #17 DevOps, MI-SQL ACTIVATED in prod (2026-07-12; wiring landed inert 2026-07-11 as drift plan D2). The full infra/SQL-MANAGED-IDENTITY.md sequence is complete: Stage 1 Entra admin live on the server (SQL_AAD_ADMIN_* repo vars), Stage 2 grants verified in all three DBs (mmca-prod-apps-identity as EXTERNAL_USER + db_owner in Store_Catalog/Store_Sales/Store_Identity), Stage 3 USE_MANAGED_IDENTITY_SQL=true deployed green (run 29192048197, full gate chain + post-deploy smoke). All three services now run passwordless Authentication=Active Directory Managed Identity; the SQL password path remains only as the documented dual-auth rollback. Mirrors ADC's 2026-06-28 activation; §17 Implementation 8→9 BANKED on the 2026-07-16 re-score (repo variable USE_MANAGED_IDENTITY_SQL=true + green run 29192048197 re-verified directly; the scorecard's stale inert claim corrected). The SQL public-network-access acceptance (no VNet) stands as documented.

✅ Already at level 4 (protect, don't regress)

SOLID (#1), Design Patterns (#2), Clean Architecture (#3), DDD (#4), Vertical Slice (#5), CQRS (#6), Microservices (#7), Data (#8), API (#9), Cross-Cutting (#10), Security (#11), Observability (#13), Testability (#14), Code Quality (#15), Maintainability (#16), DevOps (#17), UI Architecture (#18), State Management (#19), Design System (#20), Responsive (#22), Front-End Performance (#23), Forms (#24), Navigation (#25), Front-End Security (#26), i18n (#27), Front-End Testing (#28), Resilience (#29), Compliance/Privacy (#30), FinOps (#31), Dependency & Supply-Chain (#32), DevEx (#33), Architecture Governance (#34): all maturity 4. (#18 and #19 reached maturity 4 on the 2026-07-16 re-score via the CI-gated convention fitness tests; #5, #13, and #22 reached maturity 4 on the 2026-07-17 re-score, leaving only #12 and #21 below 4.) Most also score impl 8-9; preserve via the shared fitness functions + CI gates. (#28 reached maturity 4 on 2026-07-03 via the E2E/axe deploy gate, and #24 reached maturity 4 on 2026-07-11 via FormsConventionTests (D11); #21 Accessibility was corrected back to maturity 3 on 2026-07-11 (D6), pending a recorded screen-reader pass; #16/#20/#25/#27 reached maturity 4 in the 2026-07-02 docs re-score on gates shipped 2026-07-01; #32 and #34 reached maturity 4 on 2026-06-26.)

#34 caveat realized (2026-07-02): both governance ledgers are committed and kept current per release (§34 impl re-scored 7 → 9), and the arch fitness suite has grown to 22 test classes. Record future tactical deferrals here as TD-NN sub-items under their category rather than in a separate file (the single-ledger model ADC adopted 2026-06-26).