State Machines

On this page

CRAIG uses explicit state machines with validated transitions for all stateful entities. Invalid transitions return HTTP 400 with a descriptive error message. Each diagram below is derived directly from the transitions.rs source code in the corresponding service.

Case Management (craig-cases)

Investigation Status

Investigations track the lifecycle from intake through disposition.

created
open
pending_review
closed

Case Status

Cases represent the ongoing management of a child welfare matter.

created
open
closed
transferred

Case Plan Status

Case plans define permanency goals and associated tasks. Only one plan should be active per case; activating a new plan typically supersedes the previous one.

created
approved
replaced
replaced
draft
active
superseded
completed

Case Plan Task Status

Tasks within a case plan track action items for workers and families.

created
direct completion
pending
in_progress
completed

Placement (craig-placement)

Placement Status

Placements track a child’s physical location in care. Creating an active placement increments the foster home’s occupancy counter; ending it decrements.

created
child placed
cancelled
child moved
planned
active
ended

Terminal facts are immutable (#1112). Placements are born planned or active; the create endpoint refuses ended outright, since a birth-ended row would freeze NULL terminal facts forever and never emit placement.ended, and this closes the previously-unvalidated status vocabulary. ended_at and end_reason are writable only in the request that transitions the placement to ended, and that transition must carry ended_at: an end recorded without its instant could never be repaired under immutability. end_reason stays optional there, since whether a reason is mandatory is jurisdiction policy, not structure. A request that tries to decouple either fact from the ending transition is refused with the typed terminal-facts-end-transition problem, and because ended admits no further transition, not even to itself, the facts recorded at the end are permanent. Consumers that snapshot them, such as the #1070 SG activation’s transfer_on derivation and the financial placement.ended void handler, can no longer be desynchronized through the API. Non-terminal record-keeping (ctw_finding, reasonable_efforts, permanency_goal) stays writable after the end. A post-hoc correction path, audited, re-emitting a typed event, with financial reconciliation, is deliberately not provided; if the domain ever demands one, it is its own designed feature, not an edit. The placement_ended_missing_ended_at blocking invariant backstops raw writes that strip the end instant, but a raw rewrite of the fact values falls outside any invariant’s reach, since the columns carry no history to compare against. The store remains the single legitimate writer.

Foster Home License Status

License status controls whether a home can receive new placements. The matching algorithm only returns homes with active licenses.

application
approved
reinstated
pending
active
suspended
revoked
expired

Data Exchange (craig-exchange)

Data Sharing Agreement Status

Agreements govern the legal basis for exchanging data with external partners.

created
executed
draft
active
expired
terminated

Exchange Transaction Status

Transactions represent individual data exchange operations with partners. Failed transactions can be retried, which re-queues them as pending.

initiated
re-queued
pending
success
failed
retry

ICPC Request Status

ICPC (Interstate Compact on the Placement of Children) requests follow a complex multi-step workflow. Requests can be withdrawn from early stages but not after a home study is in progress.

created
draft
submitted
withdrawn
received
home_study_in_progress
approved
conditional
denied
completed

Reporting (craig-reporting)

AFCARS Submission Status

AFCARS (Adoption and Foster Care Analysis and Reporting System) submissions follow a review and approval workflow before transmission to the federal Administration for Children and Families (ACF).

created
draft
validated
reviewed
approved
transmitted

NCANDS Submission Status

NCANDS (National Child Abuse and Neglect Data System) submissions follow the same review workflow as AFCARS.

created
draft
validated
reviewed
approved
transmitted

Financial (craig-financial)

Payment Status

Foster care maintenance and assistance payments track the forward chain pending → approved → issued → cleared. Each step has been a supervisor-gated REST transition since #978 (PUT …/approve, /issue, /clear), implemented as one atomic UPDATE … WHERE status = <expected> that stages its lifecycle event (financial.payment_approved / payment_issued / payment_cleared) in the same transaction. voided is permitted from every state by the transition predicate, but the production writers only ever void undisbursed (pending/approved) rows: the placement.ended consumer’s placement-scoped set-based void (#776), and, since #1068, the subsidy generator’s reconcile pass, which voids an agreement-month whose derivation went stale (backdated status/terms) and regenerates it under the voided-exclusive unique key (ADR-053). Disbursed rows are frozen instead, and surface through the subsidy_disbursed_derivation_mismatch invariant. A deliberate manual-void path is a tracked follow-up (#1028).

generated from placement.activated
supervisor approval
disbursement recorded
reconciliation clearance
placement ended (undisbursed)
placement ended (undisbursed)
permitted, no production writer
permitted, no production writer
pending
approved
issued
cleared
voided

Adjustment Status

Payment adjustments (recoupment, underpayment correction, allocation change) require the same supervisor approval as the originating payment.

created
supervisor approval
withdrawn
posted against payment
draft
approved
cancelled
applied

Claiming Record Status

Title IV-E claiming records are aggregated into quarterly federal financial participation (FFP) claims (CB-496 / CB-250) for submission to ACF.

records accumulating
quarter-end cutover
CB-496/CB-250 filed with ACF
payment received / reconciled
correction needed
corrections applied
open
closed
submitted
settled
reopened

Subsidy Agreement Status

Kinship-subsidy agreements (ADR-052, #1067) are governed by the Georgia DFCS Policy Manual’s chapter 22.8, covering the ERR and SG/NRSG programs, and chapter 22.9, the review workflow (ADR-054, #1081). SG (Subsidized Guardianship) pays a relative caregiver after a permanent-guardianship transfer; NRSG is its non-relative counterpart. The statuses below label business-effective intervals (subsidy_agreement_status_intervals), not a mutable row state: subsidy_agreements.current_status is a projection of the interval head, maintained single-writer by craig_financial::subsidy::store under a parent FOR UPDATE and verified by blocking invariants. pending exists because SG/NRSG agreements are signed before the guardianship transfer. Since #1070 (ADR-056) the witnessed activation (POST …/subsidy-agreements/{id}/activate) is the only native pending → active mint: it runs at the derived transfer date, the guardianship-ending date of the agreement’s anchoring placement (the specific placement record whose ACTIVE state justifies the agreement), confirmed by a service-to-service read from craig-placement rather than operator-entered, and under a county-floor proof. The generic transition endpoint refuses that same transition for native SG/NRSG agreements, naming this path instead. Imported agreements never enter native activation, and since #1071/ADR-057 an open-pending import is unrepresentable, so the refusal is belt-only. suspended is distinct from termination: a missed review causes suspension, and three suspended months cause termination, automated by the #1081 knob-consented review-enforcement sweep. terminated → active is reinstatement under chapter 22.8, on the same identity, with cause-specific approval enforced by #1081; a post-closure re-application is instead a new agreement row with a predecessor_agreement_id link. withdrawn and declined are pending-terminal paths.

two-step guardianship create (#1070)
one-shot ERR create (#1069)
witnessed activation (#1070)
family withdrew (terminal)
agency declined (terminal)
e.g. missed review (22.9)
reinstated
closure cause (22.8)
incl. 3 suspended months
22.8 reinstatement (approval-gated)
pending
active
withdrawn
declined
suspended
terminated

Security & Compliance (craig-security)

Security Review Status

Biennial security reviews (45 CFR § 95.621(f)) are scheduled and tracked on the security_reviews table with the three-state workflow below.

review planned
assessment started
report filed with findings
scheduled
in_progress
completed

NIST Control Implementation Status

NIST SP 800-53 controls tracked on nist_controls follow a three-state implementation lifecycle. Each control records last_assessed_at, assessed_by, and free-text implementation notes.

control identified
some artifacts in place
fully evidenced
regression discovered
rework required
planned
partial
implemented

Security Alert Acknowledgement

Detection rules create alerts on security_alerts. An alert begins unacknowledged; an admin (or the system on webhook response) acknowledges with a note.

Invariant (#1156, DB-enforced since #1172): at most one unacknowledged alert exists per rule. The partial unique index uq_security_alerts_standing_rule is the arbiter, so overlapping scans, from the scheduler and on-demand alike, insert exactly one. The standing alert is the operator’s signal for a sustained breach; acknowledging it re-arms the rule, and a still-breached condition fires a fresh alert on the next scan.

rule breached (one standing alert per rule)
admin ack (re-arms the rule)
terminal for THIS row - a still-breached rule fires a NEW row
unacknowledged
acknowledged

Public Intake (craig-intake)

Public Report Status

Public abuse/neglect reports submitted via /report move through screening to either a formal referral (converted) or a screen-out decision.

report submitted
intake worker opens
referral created in craig-cases
does not meet criteria
re-routed to another agency
pending
screening
converted
screened_out
forwarded

Signer Key Status (Partner JWS)

Partners registering signer keys for JWS-signed intake submissions go through an admin approval step. Keys can be revoked at any time after approval; revoked keys are permanent (submissions fail JWS verification).

partner registers JWK
admin review + approval
admin denies
compromise / policy violation / rotation
pending
approved
rejected
revoked
Edit this page · latest