provinans / frontend /src /types.ts
reversely's picture
Upload folder using huggingface_hub
7b6e1ea verified
Raw
History Blame Contribute Delete
26.4 kB
export type FieldStatus = "confirmed" | "needs_review" | "flagged";
// One project ("repo") a team labels: a dataset scoped to its own worklist. Served by
// GET /api/projects; an admin creates one through POST /api/projects.
export interface Project {
project_id: string;
name: string;
case_count: number;
}
// GET /api/projects: every project, plus the id the app opens when the reviewer has chosen none.
export interface ProjectList {
projects: Project[];
default: string;
}
// One row of GET /api/fields, mirroring endopath.fields.FieldSpec. `enum_values`
// is non-null for the fields whose value is drawn from a closed vocabulary, so
// the edit path can render a dropdown rather than a free-text box.
export interface FieldSpec {
name: string;
label: string;
value_type: "string" | "number" | "boolean";
enum_values: string[] | null;
}
export type CaseStatus =
| "queued"
| "processing"
| "ready_for_review"
| "in_review"
| "confirmed"
| "exported"
| "flagged";
export interface EvidenceSpan {
quote: string;
char_start: number | null;
char_end: number | null;
page_number: number | null;
source: string;
}
export interface ChecklistField {
value: unknown;
confidence: number | null;
evidence: EvidenceSpan | null;
status: FieldStatus;
applicable: boolean;
not_applicable_reason: string | null;
search_log: string[];
}
export interface WorklistRow {
case_barcode: string;
patient_filename: string | null;
status: CaseStatus;
}
// One field a reviewer routed to the licensed account's queue (#161).
export interface Escalation {
case_barcode: string;
field_name: string;
value: unknown;
escalated_by: string;
role: string;
note: string | null;
escalated_at: string;
}
// One recorded LLM call (#221): metadata only, no prompt or response text. `model` is what the call site
// requested; `response_model` is what the API says handled it; `request_id` is the Anthropic-issued id.
export interface ModelCall {
id: string;
provider: string;
model: string | null;
response_model: string | null;
request_id: string | null;
input_tokens: number | null;
output_tokens: number | null;
cache_creation_input_tokens: number | null;
cache_read_input_tokens: number | null;
latency_ms: number | null;
context: string | null;
created_at: string;
}
export interface TraceSummary {
call_count: number;
input_tokens: number;
output_tokens: number;
cache_creation_input_tokens: number;
cache_read_input_tokens: number;
models: string[];
providers: string[];
mean_latency_ms: number | null;
}
export interface TraceResponse {
calls: ModelCall[];
summary: TraceSummary;
}
// Field coverage (#237): a project's record types and its target-dictionary fields, DB-backed. `source`
// is the record type that fulfils the field; `fill` names how its live confirmed fill is measured.
export interface CoverageRecordType {
record_type_id: string;
name: string;
source_class: string;
blurb: string | null;
}
export interface CoverageField {
name: string;
label: string;
section: string | null;
source: string;
fill: { via: "checklist" | "outcome"; key: string } | null;
}
export interface CoverageExtraction {
case: string;
field: string;
value: string;
evidence: string | null;
}
export interface CoverageResponse {
dictionary_id: string;
record_types: CoverageRecordType[];
fields: CoverageField[];
// record_type_id -> its populated sample extractions (the extracted dictionary in action).
extractions: Record<string, CoverageExtraction[]>;
}
export interface CaseDetail {
case_barcode: string;
patient_filename: string | null;
report_date: string | null;
staging_edition: string;
status: CaseStatus;
page_count: number;
fields: Record<string, ChecklistField>;
}
export interface VisualEvidence {
evidence: EvidenceSpan;
score: number;
}
// A selectable text source (issue #90): how the ingest path reads a report.
export interface TextSourceOption {
id: string;
label: string;
}
// One variable of a target data dictionary. `permitted_values` is null for an
// open vocabulary; `licence_required` marks a variable a licence gates.
export interface DictionaryVariable {
name: string;
label: string | null;
permitted_values: string[] | null;
licence_required: boolean;
}
export interface DataDictionary {
id: string;
title: string;
variables: DictionaryVariable[];
}
export type ReportSourceKind = "prepared_corpus" | "folder";
export interface IngestionRunRequest {
source: { kind: ReportSourceKind; folder_path?: string | null };
dictionary?: DataDictionary | null;
text_source?: string | null;
}
// One enqueued follow-up job: report induction (#92) or dictionary
// compilation (#91). The worker moves status enqueued -> running -> done or
// failed, stamping started_at, finished_at, and any error as it drains it.
export interface IngestionJob {
id: string;
kind: string;
ticket: string;
status: string;
dictionary_id: string;
source_kind: string;
case_count: number;
variable_count: number;
error?: string | null;
created_at: string;
started_at?: string | null;
finished_at?: string | null;
}
// A dictionary a reviewer can open on the mapping screen (#109): the built-in
// CAP checklist, or a submitted one, flagged with whether its crosswalk has been
// drafted yet.
export interface DictionaryOption {
id: string;
title: string;
builtin: boolean;
ready: boolean;
}
export interface IngestionRunResult {
ingested: number;
failures: number;
seeded: { queued: number; flagged: number };
source: { kind: ReportSourceKind; folder_path?: string | null };
text_source: TextSourceOption;
dictionary: {
id: string;
title: string;
variable_count: number;
licence_required_variables: string[];
};
enqueued: IngestionJob[];
}
export interface FieldSummary {
field_name: string;
total: number;
confirmed: number;
needs_review: number;
flagged: number;
avg_confidence: number | null;
}
// The cohort dashboard (#100, prd.md sections 8.1, 4.3, 4.5, 4.7). Beyond the completion summary it
// carries, per field, the confirmed-value and coded-absence-reason distributions as distinct series, the
// absence-versus-grade association, and, per case, the absent variables a re-review would order slides to
// recover. The coded reasons come from the section 4.3 vocabulary (AbsentReason).
export interface ValueCount {
value: string;
count: number;
}
export interface AbsenceCount {
reason: AbsentReason;
count: number;
}
// One stratum of the absence-versus-grade contingency: how many cases carry the field present versus
// coded-absent within that FIGO-grade band.
export interface AssociationRow {
stratum: string;
present: number;
absent: number;
total: number;
absent_rate: number;
}
// Whether a field's absence tracks the grade stratum (prd.md section 4.5). `signal` fires when the
// absence concentrates in one known stratum beyond the other; `detail` names it.
export interface FieldAssociation {
stratifier: string;
rows: AssociationRow[];
signal: boolean;
detail: string | null;
}
// One parsed component of a reported stage (T / N / M), as its own distribution (#165 follow-on), so the
// tile can separate the combined-string "tabs" beside the folded FIGO stage.
export interface FieldComponentDistribution {
dimension: string;
values: ValueCount[];
}
export interface FieldDistribution {
field_name: string;
label: string;
// The JSON-schema type of the field's value: "number"/"integer" render as a histogram, everything
// else as a categorical bar chart (#100).
value_type: string;
confirmed: number;
pending: number;
absent: number;
total: number;
values: ValueCount[];
absence: AbsenceCount[];
association: FieldAssociation;
// Parsed sub-distributions (T/N/M for the reported stage); empty for every other field.
components: FieldComponentDistribution[];
}
export interface RequiresSlidesVariable {
field_name: string;
label: string;
}
// One case's slide order (prd.md section 4.7): the absent variables recovered from the glass slides, the
// ones filled by a join instead, and the FIGO 2023 determinability verdict (#35) for context.
export interface RequiresSlidesCase {
case_barcode: string;
verdict: string | null;
// Whether the verdict rests only on confirmed values or on at least one unreviewed model draft (#224), so
// a draft-based projection renders provisional rather than as established fact.
verdict_basis: "confirmed" | "draft" | null;
stage: string | null;
variables: RequiresSlidesVariable[];
count: number;
join_variables: RequiresSlidesVariable[];
}
export interface DashboardStratifier {
field_name: string;
label: string;
strata: string[];
}
export interface DashboardSummary {
total_cases: number;
done_cases: number;
completion_rate: number;
fields: FieldSummary[];
absence_vocabulary: AbsentReason[];
stratifier: DashboardStratifier;
field_distributions: FieldDistribution[];
requires_slides: RequiresSlidesCase[];
requires_slides_case_count: number;
}
export interface ProvenanceRow {
case_barcode: string;
field_name: string;
value: unknown;
confidence: number | null;
status: FieldStatus;
applicable: boolean;
not_applicable_reason: string | null;
evidence_quote: string | null;
evidence_page: number | null;
evidence_source: string | null;
}
// The cohort export (#101, prd.md sections 3, 8.1). The column spec is the
// canonical concept list (#91): one value column per concept, each paired with
// a parallel absent-reason column so an absent value carries a coded reason
// rather than a blank. The coded reasons come from prd.md section 4.3.
export type AbsentReason =
| "not_applicable"
| "not_stated"
| "indeterminate"
| "determined_by_join"
| "constrained";
export type ExportColumnKind = "identifier" | "value" | "absent_reason";
export interface ExportColumn {
key: string;
label: string;
kind: ExportColumnKind;
// Value columns carry the concept metadata; absent-reason columns carry `of`.
concept_id?: string;
category?: string;
assertion_type?: AssertionType;
cardinality?: Cardinality;
cited_to?: string;
derived?: DerivedRule | null;
absent_reason_key?: string;
of?: string;
// Set on the outcome columns joined from the GDC clinical record rather than read from the report (#176).
sourced_via?: "join";
join_source?: string;
note?: string;
}
export interface ExportBundle {
target_schema: { name: string; concept_count: number; schema_checksum: string };
staging_edition: { selected: string; per_case_editions: string[] };
generated_at: string;
rule_versions: { dependency_graph_checksum: string; named_rules: string[] };
model_versions: { extraction: string };
coding_systems: { stage: string; value_sets: string };
sources: { case_barcode: string; source_document: string | null; evidence_checksum: string }[];
reproduction: string;
}
export interface ExportFile {
filename: string;
media_type: string;
content?: string;
content_base64?: string;
}
export interface ExportResult {
columns: ExportColumn[];
rows: Record<string, unknown>[];
provenance: ProvenanceRow[];
bundle: ExportBundle;
files: { csv: ExportFile; json: ExportFile; xlsx: ExportFile };
}
// A FIGO edition the Export target-schema selector offers (#40), from GET /api/staging_editions.
export interface StagingEditionOption {
id: string;
label: string;
}
// One case's projected FIGO stage under a chosen edition (#40), carried on the export row under
// `figo_stage__projection`. A determined code, a constrained candidate set, or an indeterminate reason,
// each with its confidence and the derivation that produced it.
export interface StageProjection {
kind: "determined" | "constrained" | "indeterminate";
code?: string;
modifier?: string | null;
candidates?: string[];
reason?: string;
system_id?: string | null;
confidence?: number | null;
derivation?: { rule: string; edition: string; inputs: string[] };
}
// The registry browser (#94), served by GET /api/concepts. Its concept spine is
// mapping.concept_list() (#91) with the taxonomy registry (#35) joined on:
// evidence resolved from the citation, dependency relationships from the graph,
// and the decisions that name each concept.
export type AssertionType = "asserted" | "derived";
export type Cardinality = "exactly_one" | "zero_or_one" | "zero_or_more";
export type RuleKind = "formula" | "threshold" | "membership" | "algorithm";
export interface DerivedRule {
inputs: string[];
rule: string;
rule_kind: RuleKind;
}
export interface ConceptSource {
source_id: string;
title: string | null;
year: string | null;
url: string | null;
license: string | null;
}
// Resolved from the concept's `cited_to`. An extraction carries a page-anchored
// verbatim span and its source document; a doc_section is prose-only, the "open"
// evidence state (no value-level extraction row yet, #29).
export interface ConceptEvidence {
kind: "extraction" | "doc_section" | "unresolved";
cited_to: string;
prose_only: boolean;
doc_section?: string;
extraction_id?: string;
source_id?: string;
page?: number | null;
verbatim_text?: string | null;
extracted_by?: string | null;
note?: string | null;
source?: ConceptSource | null;
}
export interface ConceptRef {
concept_id: string;
label: string;
relation: string;
}
export interface ConceptRelationships {
computed_from: ConceptRef[];
feeds_into: ConceptRef[];
gated_by: ConceptRef[];
gates: ConceptRef[];
}
export interface ConceptDecision {
decision_id: string;
date: string | null;
question: string | null;
decision: string | null;
rationale: string | null;
decided_in: string | null;
}
// The SKOS predicate of a crosswalk edge, plus `conflict` for two standards that state
// disagreeing rules for the same question (#59, #85).
export type CrosswalkKind =
| "exactMatch"
| "broadMatch"
| "narrowMatch"
| "relatedMatch"
| "noMatch"
| "conflict";
// One end of a crosswalk edge: a standard's short name and the value's label.
export interface CrosswalkSide {
standard: string;
label: string;
}
// One cross-standard mapping for a concept's clinical dimension (#59), from crosswalk.csv. It reads
// as `<from.standard> <from.label>` -> `<to.standard> <to.label>` with a kind tag; `conflict` edges
// sort first and carry the rationale for the disagreement.
export interface CrosswalkEdge {
from: CrosswalkSide;
to: CrosswalkSide;
kind: CrosswalkKind;
certainty: "certain" | "uncertain";
rationale: string;
}
export interface RegistryConcept {
concept_id: string;
category: string;
label: string;
assertion_type: AssertionType;
cardinality: Cardinality;
derived: DerivedRule | null;
cited_to: string;
evidence: ConceptEvidence;
relationships: ConceptRelationships;
decisions: ConceptDecision[];
crosswalk: CrosswalkEdge[];
}
export interface RegistryCategory {
id: string;
concept_count: number;
open_count: number;
}
export interface ConceptRegistry {
categories: RegistryCategory[];
concepts: RegistryConcept[];
}
// The crosswalk mapping-review surface (#95), served by GET /api/mapping. The
// edges are crosswalk.reference_crosswalk() (the committed CAP-checklist
// reference instance in the #93 edge contract), joined to concept labels and
// categories and to the confirmations a reviewer has recorded.
// One candidate resolution the maieutic loop offers for a queued edge, and that
// POST /api/mapping/confirm accepts. `concept_id` is null for an out-of-scope
// (unresolved) resolution.
export interface MappingResolutionCandidate {
label: string;
concept_id: string | null;
relation: string;
tradeoff: string;
}
// The maieutic draft for one queued edge: the question plus two candidates.
export interface MappingReviewDraft {
question: string;
candidates: MappingResolutionCandidate[];
}
// How a reviewer decided an edge (#103). `confirmed` resolves it; `flagged` and
// `deferred` park it as an open concern without resolving it.
export type MappingDisposition = "confirmed" | "flagged" | "deferred";
// How the confirmed answer was reached, for the decision ledger (#103).
export type MappingDecidedVia = "candidate" | "written" | "chat" | "flag" | "defer";
// Whether an edge reads as settled or needs the reviewer's judgment (#103),
// directed by field type and state rather than a confidence number.
export type MappingAttention = "confident" | "needs_judgment";
export interface MappingConfirmation {
mapping_id: string;
source_field: string;
concept_id: string | null;
relation: string;
predicate: string;
confirmed_by: string;
role: string;
note: string | null;
licence_required: boolean;
confirmed_at: string;
disposition: MappingDisposition;
decided_via: MappingDecidedVia | null;
question: string | null;
options_json: string | null;
}
// One drafted edge from a source field to a canonical concept. `is_unresolved`
// routes the edge to its own lane; `queued` (unresolved or low-confidence) marks
// the reviewer work the maieutic loop resolves. `attention` directs the eye by
// field type and state; the confidence number stays off-screen (#103).
// One canonical concept a source field also resolves to under a confirmed split
// (#103 follow-on), beside the field's headline concept.
export interface MappingEdgeComponent {
concept_id: string;
concept_label: string;
relation: string;
predicate: string;
category: string | null;
}
export interface MappingEdge {
mapping_id: string;
source_std: string;
source_field: string;
source_label: string;
concept_id: string | null;
concept_label: string | null;
category: string | null;
relation: string;
predicate: string;
confidence: number;
note: string;
is_unresolved: boolean;
queued: boolean;
attention: MappingAttention;
review: MappingReviewDraft | null;
confirmation: MappingConfirmation | null;
// Present and non-empty when the field was confirmed as a split.
components: MappingEdgeComponent[];
}
// One decision-ledger record (#103): the question a decision answered, the
// options weighed, the chosen or edited answer, who confirmed it, when, and
// where it is filed. One record per decided edge; amending replaces it.
export interface MappingDecision {
mapping_id: string;
source_field: string;
source_label: string;
disposition: MappingDisposition;
decided_via: MappingDecidedVia | null;
question: string | null;
options: string[];
concept_id: string | null;
concept_label: string | null;
relation: string;
predicate: string;
note: string | null;
confirmed_by: string;
role: string;
confirmed_at: string;
filed_to: { edge: string; table: string };
}
// One component concept a proposed split resolves the field to (#103 follow-on).
export interface MappingProposalComponent {
concept_id: string;
relation: string;
concept_label: string;
}
// One remap the edge chat co-pilot proposes for the open edge (#103), which the
// reviewer applies in a click. `components` is empty for a plain re-target and
// carries the primitives when the proposal splits the field across several
// concepts (with `concept_id`/`relation` as the derived headline).
export interface MappingProposal {
summary: string;
concept_id: string | null;
relation: string;
concept_label: string | null;
components: MappingProposalComponent[];
}
// One prior turn of an edge chat, sent so a follow-up carries its context.
export interface MappingChatTurn {
role: "user" | "assistant";
text: string;
}
export interface MappingChatRequest {
mapping_id: string;
question: string;
history: MappingChatTurn[];
}
// The engine's reply about one edge (#103): a concise answer and, when the
// message points at a better resolution, one remap the reviewer can apply.
export interface MappingChatResponse {
mapping_id: string;
reply: string;
proposal: MappingProposal | null;
}
export interface MappingConcept {
concept_id: string;
label: string;
category: string;
assertion_type: AssertionType;
}
export interface MappingSourceField {
name: string;
label: string;
licence_required: boolean;
}
// One row of the confirmed field set (#96 reads this). A queued edge carries its
// reviewer and time; a high-confidence candidate is ratified by the whole-mapping
// confirmation.
export interface MappingFieldSetRow {
source_field: string;
source_label: string;
concept_id: string | null;
relation: string;
predicate: string;
licence_required: boolean;
confirmed_by: string | null;
confirmed_at: string | null;
origin: "confirmed" | "candidate";
}
// The case-review confirmation surface (#98), served by GET /api/cases/{barcode}/review. The record is
// the stored per-case checklist; each field carries its B1 validation block (#97) and the concept it
// answers, and the payload joins the decision ledger. Every value is served here, never hardcoded.
export type FieldCardKind = "confirmed" | "derived" | "not_applicable";
export type FieldAttention = "confident" | "needs_judgment";
export type FieldPromotion = "confirmed_eligible" | "needs_review";
export type FieldExtractionState =
| "present"
| "not_applicable"
| "not_stated"
| "indeterminate"
| "determined_by_join"
| "constrained";
// One B1 shape check (#97): a type, enum, cardinality, or state check and its outcome.
export interface ValidationCheck {
name: "type" | "enum" | "cardinality" | "state";
status: "pass" | "fail" | "not_applicable";
detail: string;
}
// The recompute of a derived concept (#97), with a human label per primitive input concept.
export interface FieldDerivation {
status:
| "not_derived"
| "matched"
| "mismatched"
| "inputs_absent"
| "rule_not_implemented"
| "not_checked";
rule: string | null;
inputs: string[];
input_labels: { concept_id: string; label: string }[];
recomputed: unknown;
extracted: unknown;
detail: string;
}
// One field's #97 validation block: the shape checks, the derivation recompute, and the promotion it
// earns. The confirmation card renders this beside the value.
export interface FieldValidation {
concept_id: string;
assertion_type: AssertionType;
cardinality: Cardinality;
state: FieldExtractionState;
value: unknown;
evidence: EvidenceSpan | null;
checks: ValidationCheck[];
derivation: FieldDerivation;
promotion: FieldPromotion;
reasons: string[];
}
// One decision-ledger record for a case field (#98): the value filed, how it was reached, who filed it
// and when, and where it is filed. One record per decided field; amending replaces it.
export interface CaseFieldDecision {
field_name: string;
label: string;
value: unknown;
status: FieldStatus;
disposition: string;
decided_via: string | null;
question: string | null;
options: string[];
note: string | null;
confirmed_by: string;
role: string;
confirmed_at: string;
filed_to: { field: string; table: string };
}
// One record card on the confirmation surface: a checklist field with its value, evidence, the concept
// it answers, its validation block, the card archetype that renders it, and its recorded decision.
export interface CaseFieldBlock {
field_name: string;
label: string;
value: unknown;
value_type: "string" | "number" | "boolean";
enum_values: string[] | null;
evidence: EvidenceSpan | null;
status: FieldStatus;
applicable: boolean;
not_applicable_reason: string | null;
concept_id: string | null;
concept_label: string | null;
assertion_type: AssertionType | null;
card_kind: FieldCardKind;
attention: FieldAttention;
validation: FieldValidation;
decision: CaseFieldDecision | null;
}
export interface CaseReviewSection {
title: string;
fields: CaseFieldBlock[];
}
export interface CaseReviewData {
case_barcode: string;
patient_filename: string | null;
report_date: string | null;
staging_edition: string;
status: CaseStatus;
page_count: number;
sections: CaseReviewSection[];
progress: { confirmed: number; applicable: number; confirmed_eligible: number; total: number };
ledger: CaseFieldDecision[];
}
// The reviewer-session context sent with a confirm or edit (#98), drawn from the session so identity is
// not re-entered per value. A ledger row is written only when confirmer and role are present.
export interface FieldDecisionContext {
confirmer: string;
role: string;
note?: string | null;
decided_via?: string | null;
question?: string | null;
options?: string[] | null;
}
// One fact the value chat co-pilot rested its answer on (#98).
export interface FieldChatEvidence {
fact: string;
source: string;
}
export interface FieldChatTurn {
role: "user" | "assistant";
text: string;
}
export interface FieldChatRequest {
question: string;
history: FieldChatTurn[];
}
// The engine's answer about one value (#98): its reasoning, the evidence it read, and, when the question
// points at a correction, the value the reviewer can file.
export interface FieldChatResponse {
field_name: string;
answer: string;
reasoning: string;
evidence: FieldChatEvidence[];
suggested_value: unknown;
suggested_state: string | null;
}
export interface MappingReview {
source_std: string;
source: { std: string; title: string; version: string };
threshold: number;
categories: string[];
concepts: MappingConcept[];
source_fields: MappingSourceField[];
edges: MappingEdge[];
queue: { total: number; resolved: number; remaining: number; parked: number };
confirmed: boolean;
field_set: MappingFieldSetRow[] | null;
ledger: MappingDecision[];
}
export interface MappingConfirmRequest {
mapping_id: string;
concept_id: string | null;
relation: string;
confirmer: string;
role: string;
note?: string | null;
licence_required?: boolean;
disposition?: MappingDisposition;
decided_via?: MappingDecidedVia | null;
question?: string | null;
options?: string[] | null;
// When present, splits the field across these component concepts, with
// concept_id/relation as the derived headline (#103 follow-on).
components?: { concept_id: string; relation: string }[];
}