Statuses
Every enumeration is a text column with a named CHECK (column IN (...)) constraint built by
enum_check() in api/app/db/models/_enums.py (ADR 0006). Values are lower-case snake_case and appear
in API bodies exactly as listed here; the web app renders them as sentence-case labels (“Under review”)
and the docs keep the database spelling in code. Coloured chips always carry a text label, and agent-origin
content never uses the pass tone until a person has accepted it.
The five status words and the illustrative label
Products, providers, tools and capabilities carry exactly one of five release statuses: available
(released and in use), preview (released to a private preview for design partners
after its gates passed), designed (specified and under construction; nothing is
available), planned (sequenced for a named release) and
roadmap (intended, not sequenced). No other status word is used on the site, in
these docs or in the deck; the words come from RELEASE_STATUSES in code, never from hand-written copy. Records
that exist only to show the product (the seeded program trv-101, its people and its data, every HTML mock and
every console screenshot) carry the label “Illustrative” (illustrative on the record; “Console build,
illustrative data” inside a screenshot frame) so that no example is read as a customer, a result or a live
system.
Enumerations
Organisation, access and connections
| Enumeration | Constant | Values |
|---|---|---|
| Release status (products, providers, tools, capabilities) | RELEASE_STATUSES | available, preview, designed, planned, roadmap |
| Program status | PROGRAM_STATUSES | active, paused, completed, archived |
| Stage id | STAGE_IDS | discovery, preclinical, clinical, manufacturing |
| Scope kind | SCOPE_KINDS | org, program |
| Subject type | SUBJECT_TYPES | user, group |
| Connection status | CONNECTION_STATUSES | pending, connected, error, disabled |
| Credential class | CREDENTIAL_CLASSES | service, delegated |
| Write policy | WRITE_POLICIES | read_only |
| Sync trigger | SYNC_TRIGGERS | test, webhook, manual, scheduled |
| Sync run status | SYNC_RUN_STATUSES | queued, running, succeeded, partial, failed, skipped |
| Webhook delivery outcome | WEBHOOK_OUTCOMES | enqueued, ignored, rejected |
| Rate budget scope | BUDGET_SCOPES | platform, organization, connection |
Audit and signatures
| Enumeration | Constant | Values |
|---|---|---|
| Actor kind (audit envelope) | ACTOR_KINDS | human, agent, system |
| Signature meaning (server-derived) | SIGNATURE_MEANINGS | authored, reviewed, approved, acknowledged |
| Signature authentication method | SIGNATURE_AUTH_METHODS | idp_reauth, dev_token |
| Signature target type | SIGNATURE_TARGET_TYPES | protocol, report, requirement_set (R5 adds stage_gate; moved from R4 by ADR 0032) |
Agent runs, versions and the console
| Enumeration | Constant | Values |
|---|---|---|
| Agent run kind | AGENT_RUN_KINDS | evidence_compare, evidence_gaps, evidence_hypotheses, plans_draft_protocol, plans_draft_report, review_check, console_turn, progress_propose, review_extract_requirements, review_sop_impact, review_check_batch, twin_cycle, twin_handoff |
How a twin run was started (agent_runs.initiated_by, null for other runs) | RUN_INITIATORS | schedule, event, handoff, user |
| Agent run status | AGENT_RUN_STATUSES | queued, running, awaiting_input, succeeded, failed, cancelled |
| Agent run mode | AGENT_RUN_MODES | interactive, background |
| Worker lane | AGENT_RUN_LANES | interactive, background |
| Agent event level | AGENT_EVENT_LEVELS | debug, info, warning, error |
| Public run error code | AGENT_ERROR_CODES | runtime_unavailable, session_lost, budget_exhausted, timed_out, cancelled_by_user, attribution_leak, internal_error, gate_expired, policy_denied, plan_violation, config_mismatch, runtime_updating, rate_limited |
| Agent key (roles) | AGENT_KEYS | console, evidence, plans, review, progress, reader |
| Agent version status | AGENT_VERSION_STATUSES | candidate, active, retired |
| Capability risk class | RISK_CLASSES | operational, evidence_generating |
Model check outcome (run_snapshots.model_check) | MODEL_CHECK_OUTCOMES | match, config_mismatch, unverified |
| Thread status | THREAD_STATUSES | open, archived |
| Thread visibility | THREAD_VISIBILITIES | private, program |
| Message role | MESSAGE_ROLES | user, agent, system, tool |
| Message status | MESSAGE_STATUSES | streaming, complete, failed |
| Message feedback | MESSAGE_FEEDBACK | none, helpful, corrected, dismissed |
| Interrupt kind | INTERRUPT_KINDS | plan_approval, write_approval, consent, question, batch_approval |
| Interrupt status | INTERRUPT_STATUSES | pending, resolved, expired, cancelled |
| Tool call status | TOOL_CALL_STATUSES | proposed, approved, declined, running, succeeded, failed, policy_denied |
| Artifact kind | ARTIFACT_KINDS | plan, comparison_table, finding_set, hypothesis_set, protocol_draft, report_draft, deviation_table, sop_diff, milestone_view, summary, persona_brief (R4 adds skill_result, run_id NULL allowed; 11 -> 12) |
| Notification kind | NOTIFICATION_KINDS | approval_requested, needs_input, run_finished, run_failed, sop_changed, batch_completed, connector_reauth, handoff_received, digest, twin_paused, mention, decision_reminder |
Run mode (users.settings.console_run_mode) | RUN_MODES | approve_each_write, auto_reads_gated_writes, keep_planning |
Stream event kind (GET .../threads/{thread_id}/stream) | STREAM_EVENT_KINDS | state, text_delta, citation, tool_call_proposed, tool_call_result, interrupt, artifact_delta, message_complete, run_finished, keepalive |
Documents and Evidence
| Enumeration | Constant | Values |
|---|---|---|
| Assertion kind | ASSERTION_KINDS | observation, interpretation, assumption, suggestion |
| Origin | ORIGINS | human, agent |
| Licence code (documents, chunks, sources) | LICENCE_CODES | cc0, cc_by, cc_by_sa, cc_by_nd, cc_by_nc, publisher_copyright, customer_internal, unknown |
| Document status | DOCUMENT_STATUSES | pending, ready, error, archived |
| Question status | QUESTION_STATUSES | open, answered, parked |
| Source kind | SOURCE_KINDS | publication, eln_entry, protocol, report, dataset, sop_document, registry_record, preprint, other |
| Source status | SOURCE_STATUSES | pending, ready, error, archived |
| Source link target | SOURCE_LINK_TARGETS | question, finding, hypothesis |
| Hypothesis status | HYPOTHESIS_STATUSES | proposed, under_review, accepted, rejected, retired |
| Hypothesis decision | HYPOTHESIS_DECISIONS | accepted, rejected |
| Gap status | GAP_STATUSES | open, addressed, dismissed |
| Evidence agent run kind | EVIDENCE_AGENT_RUN_KINDS | evidence_compare, evidence_gaps, evidence_hypotheses |
Plans
| Enumeration | Constant | Values |
|---|---|---|
| Research plan status | PLAN_STATUSES | draft, review, approved, archived |
| Protocol status | PROTOCOL_STATUSES | draft, review, approved, superseded, archived |
| Protocol format | PROTOCOL_FORMATS | markdown, usdm_json |
| Experiment status | EXPERIMENT_STATUSES | planned, running, completed, aborted |
| Report status | REPORT_STATUSES | draft, review, approved, archived |
| Tool invocation status | TOOL_INVOCATION_STATUSES | queued, running, succeeded, failed |
| Tool invocation mode | TOOL_INVOCATION_MODES | sync, async |
| Plans agent run kind | PLANS_AGENT_RUN_KINDS | plans_draft_protocol, plans_draft_report |
Review
| Enumeration | Constant | Values |
|---|---|---|
| SOP status (local SOPs) | SOP_STATUSES | draft, review, approved, superseded, archived |
| SOP source kind | SOP_SOURCE_KINDS | local, connector |
| SOP version lifecycle state (mapped per connection) | SOP_LIFECYCLE_STATES | draft, in_review, effective, superseded, obsolete, unmapped |
| Requirement set status | REQUIREMENTS_STATUSES | none, proposed, accepted, rejected |
| Requirement modality | REQUIREMENT_MODALITIES | MUST, SHOULD, MAY |
| Check target type | CHECK_TARGET_TYPES | protocol, experiment, report, eln_entry |
| Check status | CHECK_STATUSES | queued, running, succeeded, partial, failed |
| Check binding rule | BINDING_RULES | auto, manual |
| Review finding kind | REVIEW_FINDING_KINDS | missing_metadata, unsupported_conclusion, inconsistent_entry, undocumented_deviation, other |
| Review severity | REVIEW_SEVERITIES | info, minor, major |
| Review finding decision | REVIEW_DECISIONS | open, accepted, dismissed, resolved |
| Review decision choice (request body) | REVIEW_DECISION_CHOICES | accepted, dismissed, resolved |
| Deviation status | DEVIATION_STATUSES | suspected, confirmed, not_a_deviation, closed |
| Proposed deviation classification (agent-proposed, person-confirmed) | DEVIATION_CLASSIFICATIONS | minor, major, critical |
Progress
| Enumeration | Constant | Values |
|---|---|---|
| Milestone status | MILESTONE_STATUSES | planned, in_progress, blocked, completed, cancelled |
| Dependency kind | DEPENDENCY_KINDS | blocks, informs |
| Open item status | OPEN_ITEM_STATUSES | open, answered, closed |
| Approval target type | APPROVAL_TARGET_TYPES | milestone, plan, protocol, report, hypothesis (R5 adds stage_gate; moved from R4 by ADR 0032) |
| Approval status | APPROVAL_STATUSES | requested, approved, rejected, withdrawn |
| Approval decision | APPROVAL_DECISIONS | approved, rejected |
Persona twins (R3)
| Enumeration | Constant | Values |
|---|---|---|
| Twin status | TWIN_STATUSES | active, paused, retired |
| Why a twin is paused | TWIN_PAUSED_REASONS | user, manage, budget, high_decline_rate, permission_lost, membership_lost, user_inactive, migrated |
| Trigger kind | TWIN_TRIGGER_KINDS | schedule, event, handoff, mention |
| Trigger priority | TWIN_TRIGGER_PRIORITIES | now, digest |
| Audit actions a trigger may name (closed) | TRIGGERABLE_ACTIONS | connector_object.update, hypothesis.decision, sop_version.update, milestone.update, handoff.accept, experiment.update, approval.create |
| Audit actions that pause a twin | PAUSE_ACTIONS | role_assignment.delete, user.deactivate |
| Inbox item kind | INBOX_ITEM_KINDS | decision, signature, question, handoff, mention, information (R5 adds stage; moved from R4 by ADR 0032) |
| Inbox item status | INBOX_ITEM_STATUSES | open, snoozed, done, dismissed, expired |
| Inbox feedback | INBOX_FEEDBACK | none, helpful, not_useful |
| Hand-off kind | HANDOFF_KINDS | review, data, decision, information |
| Hand-off status | HANDOFF_STATUSES | sent, accepted, declined, done, withdrawn |
| Delegation status | DELEGATION_STATUSES | active, expired, revoked |
Phase 4: workbench, memory, pins, assets and skills (R4, designed)
Every value below is fixed in PRODUCT-CONTRACT.md section 12 and mirrored in docs/lib/content.ts; none exists
in code until the R4 migration 0006_workbench lands, and every count is an R4 target re-derived on
release: tables 60 -> 63 (evidence_pins, document_assets, memory_records; EXPECTED_TABLE_COUNT = 63),
routes 189 -> 206 (EXPECTED_ROUTE_COUNT = 206), harness keys 20, workbench roles 15, artifact kinds
12; run kinds stay 13, interrupt kinds 5, notification kinds 12, USER_SETTING_* 7 -> 8
(USER_SETTING_WORKBENCH_ROLE), permissions 87 and persona version 3 unchanged.
| Enumeration | Constant | Values |
|---|---|---|
Workbench role key (users.settings.workbench_role[program_id], agent_runs.harness_key) | WORKBENCH_ROLE_KEYS | medicinal_chemist, biologist_pharmacologist, dmpk_tox_scientist, cmc_process_scientist, clinical_pharmacologist, regulatory_strategist, medical_writer, qa_reviewer, program_manager, analytical_qc_scientist, formulation_scientist, computational_biologist, biostatistician, ip_analyst, portfolio_head |
Neutral persona harness key (the other five of the 20 HARNESS_KEYS) | NEUTRAL_HARNESS_KEYS | scientist, quality_reviewer, program_lead, program_owner, manufacturing_specialist |
Memory tier (memory_records.tier) | MEMORY_TIERS | individual, person, role |
| Memory kind | MEMORY_KINDS | episodic, preference, vocabulary, rubric_adjustment, lesson, rubric_version (tier 2 admits preference, vocabulary, rubric_adjustment only) |
| Memory status | MEMORY_STATUSES | proposed, kept, promotion_requested, promoted, forgotten |
| Memory origin | MEMORY_ORIGINS | human, agent |
Pin target type (evidence_pins.target_type) | PIN_TARGET_TYPES | chunk, asset, record |
Asset kind (document_assets.kind) | ASSET_KINDS | figure, table, page, supplement, attachment, rendition, dataset |
| Asset status | ASSET_STATUSES | pending, mirrored, caption_only, failed |
Document integrity status (documents.integrity_status) | INTEGRITY_STATUSES | ok, corrected, retracted |
Licence statement class (chip_class on pins and assets; one enum, two names) | LICENCE_STATEMENT_CLASSES | public_domain, cc_by, cc_by_sa, acknowledgement, internal, third_party_suspected, locator, no_derivatives (eight; the last added 2026-09-16 for cc_by_nd) |
Provider status on the role home (SourceStatusOut.status) | SOURCE_CONNECTION_STATUSES | connected, not_connected, degraded, terms_changed (R5; the terms probe is designed and the value cannot occur in R4, contract 12.4) |
| Skill class | SKILL_CLASSES | A (numeric and checklist, server-side read tool), B (library, worker job) |
Skill reference status (references.json) | SKILL_REFERENCE_STATUSES | verified, to_verify |
| Rubric level (rendered as words; no verdict word exists) | RUBRIC_LEVELS | no_evidence, weak, moderate, strong |
| Tool-call denial | check_allowed | unknown_tool, policy_denied, plan_violation (existing), harness_denied (R4) |
Audit actions added in R4 (registry style <target>.<verb>): workbench_role.set, workbench_role.assign,
workbench_role.default_applied, pin.create, pin.delete, pin.share, memory.keep, memory.forget,
memory.oversight_read, memory.promote, document.gather, document.blob_read,
document.third_party_flag, asset.capture, skill_run.start, agent_run.harness_denied; none joins
TRIGGERABLE_ACTIONS or PAUSE_ACTIONS. Worker jobs added: documents_gather, jats_normalise,
assets_extract, assets_mirror, memory_expire, provider_probe, retraction_watch, skill_library_job.
The asset statuses mirrored and caption_only and the memory statuses kept, promotion_requested,
promoted and forgotten have no tone in the pinned 61-value map and render neutral (recorded as a
follow-up for the contract owner; the map grows only at R5).
Transition rule for plans, protocols, reports and local SOPs: POST .../transition accepts any value of the
resource’s status enum other than approved (422 Invalid transition otherwise, 409 Conflict when the
row already has that status); approved is set only by the /approve route, which refuses rows that are
already approved, archived or superseded. Protocols and reports that carry a signature refuse every
further update with 409 record_signed: a change is a new version with supersedes_id. The diagrams below
show the intended path through each lifecycle.
Thread
open
archived
Visibility is a second axis: private by default, program only after the owner’s explicit Share with
program action. Promote, approve and export never change it.
Message
streaming
complete
failed
Agent run
queued
running
awaiting_input
succeeded
failed
cancelled
Interrupt
pending
resolved
expired
cancelled
A detached interrupt (run_interrupts.detached = true, R3) never changes its run’s status: the twin cycle
files it and ends succeeded, approval executes the write server-side, and expiry writes nothing (“Expired,
nothing written”). Interrupts on a twin run are resolvable only by the bound person or, for write approvals,
an active delegate holding the write’s permission (403 bound_user_only otherwise).
Tool call
proposed
approved
declined
running
succeeded
failed
policy_denied
Read tools skip the approval step: they start as running when the run mode allows automatic reads. A
proposal filed by a twin also carries basis_hash; when the linked record changed since the proposal the
approval is refused with 409 stale_proposal, the row stays proposed and the card reads “Changed since
proposed”.
Twin (R3)
active
paused
retired
One active twin per person and program (409 twin_active_exists). “Paused. Nothing runs until you resume.”
Inbox item (R3)
open
snoozed
done
dismissed
expired
An item is a pointer, never a copy: it closes when its source resolves and carries delegated_from_user_id
when it was routed. Items past due_at raise one decision_reminder per day to holders of program.twins.read.
Hand-off (R3)
sent
accepted
declined
done
withdrawn
There is no proposed state: the row exists only after the sending person approved. A duplicate of the same
kind to the same persona on the same record is refused while one is sent or accepted (409 handoff_exists).
Delegation (R3)
active
expired
revoked
Signature and stage items are never routed by delegation; the audit row cannot carry both a delegation and a signature. Twins do not follow the delegate.
Document
pending
ready
error
archived
Requirement set (SOP version)
none
proposed
accepted
rejected
SOP version lifecycle state
draft
in_review
effective
superseded
obsolete
unmapped
States are read from the QMS and mapped per connection, never hard-coded. Only effective versions bind
checks; unmapped versions are ineligible and appear in the connection’s health. superseded_at comes from
the source or from the successor’s effective_at.
Agent version
candidate
active
retired
Program
active
paused
completed
archived
Programs are archived, never deleted: audit and signature rows reference them with ON DELETE NO ACTION.
Source
pending
ready
error
archived
Hypothesis
proposed
under_review
accepted
rejected
retired
Plan
draft
review
approved
archived
Protocol
draft
review
approved
superseded
archived
Experiment
planned
running
completed
aborted
Report
draft
review
approved
archived
Check
queued
running
succeeded
partial
failed
A check never changes its binding: a different (sop_version_id, requirements_hash, check_logic_version)
triple creates a new check with supersedes_check_id.
Review finding decision
open
accepted
dismissed
resolved
Deviation
suspected
confirmed
not_a_deviation
closed
Milestone
planned
in_progress
blocked
completed
cancelled
Approval
requested
approved
rejected
withdrawn
Sync run
queued
running
succeeded
partial
failed
skipped
Connection
pending
connected
error
disabled
Tone map
One function, mirrored in web/lib/status.ts (toneFor, TONE_STATUS_COUNT = 61) and docs/lib/content.ts
(TONE_STATUS_COUNT = 61). Unknown values are neutral, so nothing renders without a tone. Release words
use info for available and preview and neutral for the rest. Phase 2 grew the map from 40 to 56:
pass gained effective and complete; review gained awaiting_input, interrupted_input_required,
in_review, candidate and enqueued; fail gained policy_denied; info gained streaming; neutral gained
declined, obsolete, expired, gate_expired, ignored, none and archived_pending_purge. Phase 3 R3
grows it from 56 to 61: pass gains enabled (a duty or trigger), review gains sent (a hand-off waiting for
its addressee), neutral gains done, snoozed and revoked. A lint on both sides asserts that every value of
every *_STATUSES enumeration rendered as a chip has a tone; the R3 enumerations TWIN_STATUSES,
INBOX_ITEM_STATUSES, HANDOFF_STATUSES and DELEGATION_STATUSES are covered in full. R4 leaves the map at
61 (TONE_STATUS_COUNT = 61, contract 12.7); R5 adds reviewed (pass, 62) with the stage gates (ADR 0032).
| Tone | Count | Statuses |
|---|---|---|
| pass | 12 | connected, succeeded, approved, accepted, completed, ready, resolved, answered, active, effective, complete, enabled |
| review | 16 | pending, queued, draft, review, proposed, under_review, requested, suspected, planned, open, awaiting_input, interrupted_input_required, in_review, candidate, enqueued, sent |
| fail | 7 | error, failed, rejected, blocked, confirmed, aborted, policy_denied |
| info | 4 | running, in_progress, partial, streaming |
| neutral | 22 | disabled, skipped, archived, retired, dismissed, parked, cancelled, withdrawn, superseded, not_a_deviation, closed, paused, declined, obsolete, expired, gate_expired, ignored, none, archived_pending_purge, done, snoozed, revoked |
interrupted_input_required is the agent container’s job state while a gate waits; the API stores the run
as awaiting_input and the composer prints “Paused, waiting for a decision”. archived_pending_purge is the
label the web app shows for a customer_internal document that is archived and inside its hold period. The
gap status addressed and the SOP lifecycle state unmapped are not in the map and render neutral.
Source: api/app/db/models/_enums.py, api/app/db/models/_agentic.py, api/app/db/models/twin.py, api/app/db/models/inbox.py, api/app/db/models/handoff.py, api/app/db/models/delegation.py, api/app/db/models/org.py, api/app/db/models/rbac.py, api/app/db/models/connection.py, api/app/db/models/connectors.py, api/app/db/models/agent.py, api/app/db/models/agents.py, api/app/db/models/audit.py, api/app/db/models/conversation.py, api/app/db/models/documents.py, api/app/db/models/evidence.py, api/app/db/models/plans.py, api/app/db/models/review.py, api/app/db/models/progress.py, api/app/db/models/signatures.py, api/app/worker.py, web/lib/status.ts, web/lib/api/types.ts, docs/lib/content.ts (TONE_STATUS_COUNT = 61, R4_TARGETS, the phase-4 enumerations), PRODUCT-CONTRACT.md sections 10.4, 10.6, 11.4, 11.7, 12.6 and 12.7, decisions/0032-release-renumbering-stage-gates-to-r5.md