Curation Studio
What it is¶
The Curation Studio is the component through which everything the tools apply is meant to be authored, approved, promoted and superseded without a deployment. The governing thought of the product is that a new state, LOB or carrier standard is a curation act, because every rule lives in a versioned, cited record rather than in code. Today that is true of the content and not yet true of the control over the content. This page says so rather than describing the target state as current.
The studio is a running system at elevatenow-rule-layer/CurationStudio: a FastAPI backend (kcs_api.py), a React studio-ui, a six-stage SOP pipeline (Upload, OCR, Segment, Extract, Bind, Diff), lifecycle promotion, an ApprovalQueue, a LayerManager, GKRProof and an immutable AuditLog. It had no design record, which is different from being unbuilt. In the tenant package it is one of the four runtime components and points at the GKR database for the curator persona .
What it governs today¶
The record estate has three families with different physics. Prose chunks (knowledge_chunks) carry citations and ontology anchors: sensitive indicators, subrogation theories, defenses and evidence, coverage exclusions, WC employer defenses. Composite spec records in reference_data are structure only, one per tool per LOB: extraction_spec, coverage_spec, liability_spec, subro_spec, authority_spec, reserve_spec, compensability_spec, complexity_spec, brief_template. Jurisdiction and registry records in reference_data track an external source or declare a vocabulary: sections and obligations, routing, holiday calendars, enum registry, fact precedence, document profiles, valuation schedules, referral policy.
The studio governs knowledge_chunks only, and partially. It has no reference_data surface at all. Every operation on the collection that holds the decision path runs through a seed script or a raw field-level API call, with no lifecycle, no approval, no audit entry and no source link. That is the actual gap, and it makes the studio an extension problem rather than an authoring problem: the lifecycle, approval queue, audit trail and proof harness exist and point at the smaller half of the estate.
The mismatch is structural. The studio's governance model is chunk-shaped, approving and promoting a self-contained unit, while the reference_data estate is spec-shaped: composite records whose parts have different content classes, override directions, verifiers and freshness clocks. The unit of curation, approval, effective dating and verification is not the unit of storage.
Carrier supersession¶
The design is that a carrier overlays its own knowledge on the platform baseline by supersession, and that the overlay is tighten-only. Each parameter carries an override_direction (tighten_only, either_with_record, locked) and states its conservative_direction explicitly, because conservative means fewer referrals for fraud and more escalation for coverage. A locked control cannot be weakened by any overlay, and an attempted removal is rejected and logged as overlay_rejected. Determined content (statutes, form provisions, benefit rates) takes no platform baseline and no carrier override; policy content (thresholds, bands, weights, cadences) takes both. Offering an override control on a statutory value is a design error.
The audit measured the distance between design and code. Every tool uses one store with row-level carrier_id resolved at query time, implemented four different ways (detector, resolver, authority gate, coverage), and in coverage _load_spec pins carrier_id to None so a carrier spec can never be selected while _resolve_overlays reports status resolved. No tool implements override_direction or conservative_direction per parameter. Carrier supersession has never once executed: no carrier-specific claims record exists in either collection, and none of the four tighten checks has run against live carrier data. The manual may state supersession as designed, never as evidenced, until accept, reject with record id and reason, and locked have each been demonstrated.
Constraints the platform already imposes¶
The lifecycle is draft, approved, regression, active, superseded, retired. Records seed as approved and promote to active only on a recorded regression pass. promote_spec.py is the enforcement point: it refuses a failing regression, refuses a non-approved predecessor, and writes an honest promotion_record with a stated reason when overridden. Measured, it covers six table types, excludes extraction_spec and jurisdiction_rule, writes no curation_audit entry, and is invoked by no studio path. Nine paths set a record to active; two write an audit entry; none enforces a predecessor status. Path 9, PUT /api/gkr/reference-data/{table_type}/{record_id}, protects a field list but evaluates only the first segment of field_path, so regression.result, spec_version, effective_from and source_authority are all writable. A caller can write a passing regression and then set curation_status to active, and both land in curation_audit as ordinary field updates. An enforcement point the system routes around is worse than none, because its existence becomes the evidence that the thing is governed.
Every spec carries a common record contract: spec_id, integer spec_version, lob, curation_status, effective_from and effective_to, carrier_id, supersedes_spec_id, regression, source_authority. It is a convention today, not an enforced schema; the studio is the natural place to enforce it. Provenance fields are separate and never merged: source_authority, verified_on, verifier, with domain review recorded distinctly. A domain ruling never supersedes a primary-source verification; it triggers re-verification. See Verification and Curation.
Seed-time validation has been ruled four times and is still unbuilt as one mechanism. Every trigger, applies_when, carve_out_when, rebutted_when, counsel_review_when and state_standard_ref must name something a producer publishes; every obligation anchor must exist in the extraction schema at its declared stages; every governance block parameter must have a verified consumer; no consumer may reference a literal chunk id. Each fails the seed rather than warning. As measured, four validators exist scattered, six of 46 seed scripts validate before writing, and no CI configuration exists.
Generated artifacts are never hand-edited. external_idp_manifest is produced from field_definitions by generate_idp_manifest.py with a --diff gate; the studio edits the source record and regenerates. A value used as a join key is declared once in the enum registry and both sides read it. As measured, the enum_registry record holds zero values and is read by nothing, while the vocabulary validate_spec() enforces is a hardcoded dict of seven keys in seed_authority_spec.py, so a carrier authoring a theory cannot discover which values are legal. That is a studio design requirement, not hygiene.
Baseline audit findings on the control plane¶
The programme's recurring defect family, absence reported as presence, reached the control plane in the read-only baseline audit (outputs CURATION_STUDIO_BASELINE.md and curation_studio_inventory.json, 33 active findings and 10 defects after retractions) .
Authentication exists, is correctly written as Auth0 RS256 middleware in auth_middleware.py, and is switched off by a committed default: IS_DEV = NODE_ENV != production and not ENFORCE_AUTH, with the committed .env setting both permissively, so every request passes unauthenticated. Correcting the file's values fixes nothing, because the hazard is the direction of the default. The product rule: absent configuration must mean the control is on, and disabling it must take an affirmative flag logged at startup.
The companion rule: a control that is on for a reason nobody can name is not a control you can rely on remaining on. The production instance does enforce authentication, verified by unauthenticated 401s on every data route, through a runtime override that no Dockerfile, deploy script or manifest records. Its posture was accidental, and a restart would not reproduce it.
No tenant scoping exists in any route handler; the carrier claim is available in the token and never used to filter. One reference_data collection holds three products with no discriminator: 8,864 records, of which 4,714 are underwriting, 2,905 are a dead sensitive-indicator population no tool reads, and 909 are claims-relevant. The five extraction_spec records carry table_type: null, which makes them invisible to Path 9 routing, to promote_spec.py and to every studio view: not ungoverned, unreachable.
Provenance as measured: 16 of 2,288 chunks carry source_authority; 832 of 8,864 reference_data records do; the basis field is absent everywhere. Tool sync into the studio last succeeded before 2026-07-30 and the studio's tools/ copy lacks the unified SubrogationScreenerGKR, so GKRProof has been validating chunks against code that is not what runs.
Tenant scoping as a release blocker¶
In the tenant package the carrier operates the studio. That makes the authentication default and tenant scoping a release blocker for the package: no route may serve a record without filtering on the carrier claim, and the control must be on unless affirmatively disabled. Carrier-direct curation is gated on these two conditions, not on UI design.
Open items¶
- Who curates, who verifies, who signs; roles attach to the three functions (capture, structure, maintain) rather than to record types.
- Whether carriers curate directly or submit for review, and what a supersession looks like from their side.
- Re-verification cadence: 356 of 760
jurisdiction_rulerecords carryverified_on, all stamped in one week (4 to 11 September 2026), so there has been one verification pass ever; a source registry with a currency model belongs here. - Extending the studio to the
reference_dataestate: structuring and maintenance do not exist, and the 14 spec records and 868 jurisdiction records need two designs, not one. - Seed-time validation as one mechanism with a CI gate.
- Root database credentials in the committed
.envand inAutoSubrogationScreenerGKR.py:43; see How Work Is Run.