Disciplines · Proposals

YSD-18107 — What becomes of the seven finished panels no route reaches

inward, which files the application actually renders.

8sections11 minread

On this page
  • Status: proposed
  • Priority: EXT — blocking for YSD-18107 and, through it, for YSD-16005 and the Section 22.3 completion audit. Four of the twenty-three study surfaces are reached in part or not at all, six required (flow, surface) instrument pairs are open because of it, and no accessibility work of any kind can close them: no lane can open a page the application does not compose.
  • Decision owner: @GreyChimp
  • Drafted: 2026-08-19 by Claude Code (Opus 5)
  • Approval: pending

Question#

accessibility/surface-mounting.ts measures, from the route entry points inward, which files the application actually renders. Seven finished panels — 6,600 lines across four surfaces — are reached by nothing in the repository but their own component tests:

Panel Surface Lines
EvidenceReviewQueue.tsx lens-and-review 494
SourceSetInspectionPanel.tsx lens-and-review 896
RetrievalSetInspectionPanel.tsx lens-and-review 551
CitationValidationPanel.tsx notebooks-and-reports 676
GroundedReportPromotionPanel.tsx notebooks-and-reports 1460
EvidenceExportBundlePanel.tsx evidence-export 1542
AuthoringDraftWorkbenchPanel.tsx authoring-drafts 981

Each is declared in accessibility-surface-map.json with a reason, and the gate refuses both directions — an undeclared unreachable path, and a declaration for a path a route has since started reaching. That keeps the list honest. It does not answer the question a reader is left with, which is: mount them, or retire them?

The question is EXT because neither answer is the accessibility lane's to give. Mounting means building producers, schemas or domains in another initiative's code; retiring means moving files that another initiative's checklist marked complete.

What was measured#

Three premises decide the cost, and all three are now re-derived on every run by accessibility/unmounted-backing.ts rather than written down once — the same correction this register has already made twice. The prose written on 2026-08-17 said the seven split into "a BFF projection over a store that exists" and "the domain itself", citing EvidencePack as real "across contracts, the persistence registry and a Veritas API client". Measured on 2026-08-19, that was wrong three ways.

There are two EvidencePack contracts. The one under contracts/common declares the object all three evidence panels cite — slug, excerpts, retrievalTrace, consumers. The one under contracts/veritas declares a different object of the same name — storyId, claimIds, evidenceItems — and it is the Veritas one the API client serves at /veritas/evidence-packs. The reach cited belonged to the other contract.

A table with no writer is not a store. The common contract does have a table: the persistence registry derives v1_cross_cutting_evidence_pack, and it is in schema.prisma and in the 20260527184417_v1_initial migration. Nothing outside the generated Prisma client has ever named its accessor crossCuttingEvidencePack. Zero writers, zero readers.

No panel imports the contract it cites. Every one of the seven declares its own view type — enums, statuses, field shapes — copied by hand from a contract it never references, so a contract change cannot break a panel and typecheck cannot report a divergence.

All thirty of their string-literal unions were held against every z.enum in the cited contracts and in the modules those contracts import, on 2026-08-19:

  • 23 are exact copies, member for member and almost all in the same order. Two of the twenty-three are copied from a module the panel's header does not name at all — SourceCredibilityTier from common/source.ts, GroundedReportReviewPriority from common/grounded-answer.ts — and one is copied from an enum the contract does not export: AuthoringDraftFactCheckStatus reproduces factCheckStatus: z.enum(['pending', 'partially_checked', 'checked', 'blocked']), declared inline inside an object in authoring-job.ts. A vocabulary that cannot be imported is a vocabulary that gets retyped.
  • 1 has already diverged. GroundedReportGroundingLevel declares four levels — grounded, partially_grounded, synthesis_only, ungrounded. GroundedReport.groundingSummary.level is GroundedAnswerGroundingLevelSchema and carries six: weakly_grounded and unknown are missing. The panel's readiness evaluator branches on that field three times, faithfully mirroring the three refinements the contract itself keys on the same four values — so the logic is right and the type cannot hold two of the six states a real report can be in. Nothing is wrong today, because nothing produces the view; it is wrong on the first day a producer meets a weakly_grounded report.
  • 1 is a deliberate subset. AuthoringDraftHandoffTarget offers six of the contract's eight checkpoint kinds plus an added revise; outline_approval and draft_checkpoint are not offerable as handoff targets.
  • 5 have no counterpart anywhere in libs/contracts: RetrievalCandidateStatus, EvidenceExportFormat, EvidenceExportRedaction, EvidenceExportScopeFlag, EvidenceExportAudience. These are vocabularies the panels invented — export formats, redaction levels, audit audiences, the ten include_* scope flags — and a producer would have to give each one a canonical home before it could assemble the projection at all. That is work the cost table below does not count, and all five sit on the same panel.

This half is a hand measurement made once, on the date above, and deliberately not a rule: a gate over seven files that this decision may retire is a gate written for a world that may not exist. If the ruling is to mount, it should become one.

With those corrected, the seven do split — into three groups, not two:

Panel Contract Consumers outside libs/contracts Table Cost
EvidenceReviewQueue common/evidence-pack persistence registry yes producer-over-an-empty-store
RetrievalSetInspection common/evidence-pack persistence registry yes producer-over-an-empty-store
EvidenceExportBundle common/evidence-pack persistence registry yes producer-over-an-empty-store
SourceSetInspection common/source-set libs/oshun/evidence-sophia (2) no store-first
CitationValidation common/citation none no domain-first
GroundedReportPromotion common/grounded-report none no domain-first
AuthoringDraftWorkbench common/authoring-job none no domain-first

SourceSet is the one with a live consumer: libs/oshun/evidence-sophia validates it, hashes it and computes readiness over it, and no table holds one. That is a different job from the other six and a different team to ask.

Two facts about the citation row are worth stating because getting either wrong inverts it. common/citation.ts declares both CanonicalCitation, whose verification field the panel writes, and CitationTrail, which the registry registers as v1_cross_cutting_citation_trail. A table for a sibling object in the same file is not a table for this one, and asking the question at module granularity made the registry a consumer of both. AuthoringJob is likewise named in prose by four contract files that import nothing; outside its own module and spec it is imported by exactly one non-test file in the repository — publication-release-gate.ts, itself a contract.

Where they came from#

None of the seven is a surface the Yemaya study proposal asks for. Eight vocabulary probes over YEMAYA_STUDY_AND_DECONSTRUCTION_WORKSPACE_PROPOSAL.md — review queue, evidence pack, citation validation, grounded report, export bundle, authoring draft, source set, retrieval set — return zero hits.

Every one was delivered under a V1-SOP item in docs/releases/v1/specs/todos.md, and every one of those items is marked complete:

text
[x] V1-SOP-015 Add evidence review queues backed by Sophia contracts.
[x] V1-SOP-016 Add source-set inspection views for research integrity review.
[x] V1-SOP-017 Add retrieval-set inspection tooling for grounded outputs.
[x] V1-SOP-018 Add citation validation tooling for operator review.
[x] V1-SOP-019 Add grounded report promotion workflows.
[x] V1-SOP-020 Add evidence export tooling for investigations and audits.
[x] V1-SOP-036 Build operator workbench surfaces for draft inspection, …

Their verification notes are careful and specific — V1-SOP-015's runs to twenty-four lines, names every field of the view model, counts ten passing tests and records a clean adversarial stub-grep. What no note claims is a route. The acceptance was that a component exists, is tested, and typechecks, and under that acceptance all seven are genuinely done.

Six of the seven sit beside a study surface the application does reach, doing an operator-facing version of an act the study workspace already performs: DetectionReviewPanel beside EvidenceReviewQueue, StudyReportsWorkspace beside GroundedReportPromotionPanel, ProjectHandoffPanel beside EvidenceExportBundlePanel. authoring-drafts is the exception and the reason it is a whole unrendered surface: nothing in the study workspace does authoring-draft promotion at all.

Recommendation#

Retire all seven from the Yemaya study scope, and re-open the mounting debt against V1-SOP, where the panels and the decision both belong.

Retiring here means moving each file out of apps/oshun/web/src/components/ studio/ into an operator directory of V1-SOP's choosing. The study surface map's scope is that directory; a file that leaves it stops being a study surface and the map self-corrects. Nothing is deleted and no test is lost.

Three things make this the answer rather than mounting:

  1. The study workspace was never asked for them. Putting a Sophia operator queue on a learner's study route would be a product mistake made to satisfy a scope boundary that is a directory name.
  2. Mounting is V1-SOP work whichever panel you start with — a producer for an empty table, a persistence design, or a domain — and V1-SOP is where the requirement, the contracts and the acceptance all live.
  3. Six of the seven would arrive beside a study surface that already performs their act, which is a duplication a person has to rule on before any of it is worth building.

Declining them is not available, and it is the answer that would otherwise look cheapest. The map's declined list carries twenty-six entries and the established form of its reason is "not a Yemaya study surface: it belongs to X, which owns its own accessibility evidence" — Isis, Aja, the AI operations workspace, the Phase-180 bridge. Writing that for these seven would be false: accessibility-surface-map.json is the only accessibility surface map in the repository, and there is no Sophia or V1-SOP register to pick them up. Declining would file a hole in the product as a scoping decision and record, in writing, that somebody else holds evidence nobody holds.

The move must not go before the debt lands. Moving a file out of the study scope removes the only measurement in the repository that says these panels have no route. The map already refuses to let that happen quietly — a declaration for a path no surface claims is a finding, so the move forces an edit to accessibility-surface-map.json, and that edit is exactly where the debt would be dropped. The approval should therefore carry, as one act: the destination directory, the re-opened V1-SOP entries, and the deletion of the seven unmounted declarations.

Options considered#

  • Build the crossCuttingEvidencePack producer and mount the three evidence panels. Not rejected on merit — it is the single highest-yield piece of work in the table, lighting three panels at once over a schema and a migration that already exist. Rejected as this checklist's call: the producer writes Sophia evidence packs, the panels are Sophia operator tooling, and neither the requirement nor the acceptance for either lives in the Yemaya study proposal. If V1-SOP wants them mounted, this is where to start — and two of the three are cheaper than the third: EvidenceExportBundlePanel carries all five of the invented vocabularies, so a producer for it has to canonicalize export formats, redaction levels, audit audiences and ten scope flags before it can assemble anything.
  • Mount authoring-drafts because it is the smallest hole. Rejected. It is the smallest by file count and the largest by cost: one file, one surface, four flows, and AuthoringJob is inert — no table, no consumer, one importer and that a sibling contract. It is the only one of the seven where mounting means building the domain.
  • Re-file all seven as declined. Rejected for the reason above: the reason string would be false, and the falsehood is the whole content of the entry.
  • Leave them declared unmounted indefinitely. Rejected as an answer and adopted as the interim state. It is what holds today, it is now measured every run rather than asserted once, and it is honest — but it leaves 6,600 lines of finished panel that nobody can reach and four surfaces that cannot be evidenced, with no owner and no date.
  • Delete the seven panels. Rejected. They are complete, tested work against real contracts; the fault is in where they were filed and what was accepted as done, not in the code.
  • Retire all seven to an operator directory, re-open the V1-SOP entries, and drop the declarations in the same change — recommended.

Consequences#

  • Four surfaces stop being partly- or wholly-unrendered, because three of them stop claiming paths the product does not present and authoring-drafts ceases to be a study surface at all. lens-and-review, notebooks-and-reports and evidence-export become fully mounted.
  • Two of the six open instrument gaps close as a consequence rather than by any harness work: contrast and zoom on authoring-drafts were reported as instrument debt for a page that does not exist.
  • The study scope drops from 137 files to 130, and 23 surfaces to 22.
  • V1-SOP-015 through 020 and V1-SOP-036 re-open. Their acceptance form — a component that exists, is tested and typechecks — is the thing that produced seven route-less panels, and it will produce more until it asks for a route.
  • The Yemaya register loses its measurement of these panels, which is the cost of the move and the reason the destination has to carry one before the files go.
  • YSD-18107's remaining machine slice closes. What remains on the item is the manual assistive-technology pass it shares with YSD-16005, whose actor is participants nobody has recruited.

Machine-enforced outcome#

On approval, the seven paths move out of apps/oshun/web/src/components/studio/ and the seven unmounted declarations are deleted in the same change. The surface map's scope resolver then accounts for 130 files rather than 137, assertSurfacesAreMounted reports every claimed path reached from a route, and assertBackingStillHolds has nothing left to measure. A move that deletes the declarations without moving the files fails assertScopeAccountedFor — a scope file that no surface claims and nobody declined; a move that takes the files without deleting the declarations fails mountingFindings — a declaration aimed at a path no surface claims. Neither half can ship alone.

If the decision instead goes to mounting, the same rule reports it: a route that reaches one of the seven turns its declaration into a finding, and the panel's surface starts answering for its flows again on the next run.

Pending control#

The seven panels are declared unmounted in docs/proposals/yemaya-study-workspace/accessibility-surface-map.json, and libs/yemaya/study-workspace/src/accessibility/surface-mounting.ts measures the declaration against the import graph on every run of the accessibility gate, in both directions. Beside it, libs/yemaya/study-workspace/src/accessibility/unmounted-backing.ts measures what each panel is waiting for — the projection, the contract's consumers, the table's callers — and fails while any write-off has stopped being true or any declared cost no longer matches the repository. Until this decision is made, the gate reports four surfaces reached in part or not at all, six instrument pairs with no possible instrument, and 0 of 10 accessibility flows evidenced; no change to any harness can move those numbers, because the gap is in what the product composes.