midi2-gpu-fabric.git · FCIS_COMPLIANCE_PLAN.md
midi2-gpu-fabric.git / FCIS_COMPLIANCE_PLAN.md
revision b0dfe8c2f39a4152dd199fd35d6d83b08e95b3c0 · complete file
# FCIS_COMPLIANCE_PLAN.md
Remediation for the FCIS v1.1.0 audit (`FCIS_AUDIT.md`). RFC 0001 layering (AGENTS/PLANS/Skills/MCP) is already compliant and is maintained as a checklist; this plan closes the **FCIS-AX (Accessibility)** gap introduced at v1.1.0.
## Goal & Scope
Make the Modernization Studio / Reframe UI accessible per FCIS-AX: every user-facing view — especially the custom CALayer-drawn surfaces — exposes its content to the accessibility tree, so a human (assistive tech), the Copilot (may only claim what it can introspect), and an automated verifier all read the same truth. Scope: `apps/modernization-studio/Sources/ReframeApp/`. Out of scope: FCIS-VRT consolidation, FCIS-AIC preflight (separate tracks).
## Minimal-Change Strategy
- Introduce one reusable accessibility seam; apply it view-by-view, most-opaque-first.
- Add an accessibility layer alongside existing drawing — do not refactor rendering.
- Prove each view through the accessibility tree, never pixels (FCIS-AX-05).
- No new dependencies; keep any how-to in a skill, not AGENTS.
## Phased Plan
### Phase 0: Governance & audit (DONE)
- Files: `.github` `docs/FCIS-AX-Standard.md`, `profile/README.md`; this repo `AGENTS.md`, `apps/modernization-studio/AGENTS.md`, `FCIS_AUDIT.md`.
- FCIS-AX adopted org-wide; FCIS suite → v1.1.0 (`.github` `850188c`, `b3b9450`); repo bound (`27637482`); audit refreshed.
- Acceptance: standard published + announced; repo AGENTS reference it; audit records the AX FAILs. ✔
### Phase 1: Beat surfaces + AX-driven harness (SLICE 1 — pattern-setter)
- Files: `apps/modernization-studio/Sources/ReframeApp/StorifyTimelineChartView.swift`; new AX-driven test.
- Edits:
- Make the view an accessibility container; expose each drawn element as an `NSAccessibilityElement` child tracking `layout.beats`: beat tiles (role/label = title / value = kept·cut·undecided / actions = select·keep·cut), arc regions, gap/coverage tiles.
- Add stable identifiers (FCIS-AX-06).
- Build the reusable **AX-driven harness**: reads the accessibility tree, asserts **pixel parity** (FCIS-AX-03) — beat-element count == reported beat count, labels == beat titles — replacing screenshot state-reading.
- Acceptance: with N beats, the AX tree exposes N beat elements with correct titles/state, asserted by an automated AX check (not a screenshot).
### Phase 2: Sweep remaining LIVE views (re-scoped to governance ch.17 + live-code reachability)
The initial audit over-scoped this as heavy `NSAccessibility` work across 11 views. Grounded in ch.17 ("The Score": the timeline is a lens, the patch-graph Cut canvas is retired) and instantiation reachability, the real Phase 2 is smaller and different:
- **Delete the retired Cut board. — DONE (commit `1fd49b83`).** Removed `CutBoardNSView.swift`, `CutBoardView.swift`, `CutBoardInteraction.swift` + 4 tests (~1,200 lines); `MovieRecorder` recovered into its own file. Build + tests green.
- **Identifier/label sweep on the live `NSTextView`-backed editors — DONE (commit `6510daf3`).** Shared `NSTextView.applyEditorAccessibility(identifier:label:)`; distinct identifiers applied: `editor.manuscript`, `editor.baseline`, `editor.monospace`, `editor.source`, `editor.writing-tools`.
- **Labels/grouping on the SwiftUI Score — DONE (commit `6510daf3`).** `ScoreStageView`: each Text-lane beat is one queryable element with a `scorebeat.<n>` identifier; the STRUCTURE band carries `score.structure` (the parity anchor for "N beats"). `SemanticScoringView` (Music participant) is ch.17 horizon (stubbed) — labeled when it renders a real participant.
- Acceptance: retired board gone ✔; live editors carry distinct stable identifiers ✔; the Score Text-lane exposes identified beats + a count anchor ✔; no opaque custom-drawn beat surface remains unexposed (the only one, the timeline, was closed in Phase 1) ✔. Per-editor/Score end-to-end AX-tree verification is deferred to the Phase 3 running-app harness (SwiftUI `Context`/`makeNSView` not unit-constructible).
### Phase 3: Enforcement & definition-of-done
- Files: copilot claim-grounding path; `Scripts/verify`; repo FCIS-AX Declaration.
- Edits: ground Copilot claims in accessible elements (FCIS-AX-04); wire the AX harness into `Scripts/verify` so new UI is gated on accessibility (complements FCIS-VRT); add the FCIS-AX Declaration (surfaces, custom views, identifiers, harness location, known gaps); adopt FCIS-AX-07 as definition-of-done.
- Acceptance: verify runs the AX check; FCIS-AX-04 grounded; declaration present.
## "B" — the empty-BEATS-lane report: RESOLVED — it was the verify HARNESS, not the app (commit `2e6194fb`)
The Phase 3 AX self-check reported `[VERIFY-STATE] beats=1` / `[VERIFY-AX] timelineBeats=0`. Instrumentation (driver vs shell model identity, per-render logging, a beat-loss diagnostic through cfg→layout→AX) proved the real cause: **two `ReframeViewModel` instances.** The app spins up a launcher model, then the manuscript's model (normal lifecycle); the verify **driver** had latched onto the early instance and segmented a *ghost* while the visible shell was bound to the live one — so the on-screen timeline stayed empty. `driverModelId` ≠ shell `modelId`; when they diverged, `main[cfgWin=0 ...]`; when the driver re-targeted the live model, `main[cfgWin=1 cfgBeats=1 layoutBeats=1 axBeats=1]`.
**Two earlier fix theories (drawing mismatch; `objectWillChange` reactivity) were WRONG and reverted** — they chased a bug that wasn't in the app. The actual fix is in the harness: `ReframeVerifyDriver` now re-targets the current model instance (a superseded drive bails). With the driver segmenting the model the shell shows — the same one a user's Segment button drives — the beat flows draw→layout→AX and **verify PASSES with real AX parity** (`timelineBeats == beats`). The app's beat→timeline→accessibility pipeline is proven sound end-to-end.
**Residual note (not a reproduced bug):** the launcher→manuscript dual-model lifecycle is normal, but any code path that reads/segments the non-visible instance would show an empty lane. The compact `[VERIFY-AX-DBG]` diagnostic (model id + cfg/layout/AX beat counts) stays in place so a recurrence is pinpointed instantly. See [[project_state_coherence_audit]].
## Rollback Plan
Each phase is additive (an accessibility layer beside existing drawing), independently revertible per view. No rendering/data changes in Phases 1–2; the data-path fix is a separate revertible commit.
## Status
RFC 0001: COMPLIANT. FCIS-AX: **Phase 1 DONE** (`dab07878`); **Phase 2 DONE** (`1fd49b83`, `6510daf3`); **Phase 3 (b) DONE + GREEN** — running-app AX self-check wired into `Scripts/verify` (`5375b35b`, `6c88f55c`); it caught a real parity failure that instrumentation traced to a verify-harness ghost-model bug, now fixed (`2e6194fb`). **`Scripts/verify` PASSES with real AX parity** (`timelineBeats == beats`), proving the beat→timeline→accessibility pipeline end-to-end. **Phase 3 (a) DONE** — FCIS-AX-04 enforced: the Copilot's structural claim is read from one accessor and `Scripts/verify` asserts `claimBeats == beats produced/accessible` (green; commit `4ca9967b`). **All FCIS-AX phases complete; `Scripts/verify` gates every run on claim == surface == production.** See `FCIS_AUDIT.md`.
### Chapter 36 addressed navigator (2026-07-31)
The generic address/rack/map/inspector seam is released upstream in `UncertaintyScoreKit v0.8.3` and pinned by
Modernization Studio. Reframe retains typed wants, reference acts, retrieval receipts, and writer decisions in its
adapter context; the kit receives none of those domain types. The navigator's searchable rack, state filters,
producer-order preservation, shared viewport controls, stable selection, drag provider, and AX identifiers are covered
by the upstream test suite plus `UncertaintyLedgerTests`. The remaining evidence item is the final governed running-app
drive against this exact resolved dependency. That drive reached the persisted Romeo-and-Juliet beats, selected a
composite-address note, and read the full inspector content through AX (address, state, span, detail, and closure cue).