Work Order State Machine — Guard Specification
Status: Accepted | Version: 2.0 | Date: 2026-02-13
Scope: Master WO + Linked WO Lifecycle with 21 CFR Part 11 Guards
1. State Inventory
Both Master and Linked Work Orders share the same 9-state lifecycle. The distinction lies in guard conditions and aggregation rules, not in the states themselves.
| State | Category | Description | Editable Fields |
|---|---|---|---|
DRAFT | Initial | WO created, metadata incomplete | All fields |
PLANNED | Planning | Requirements defined, awaiting scheduling | Job plan, priority, requirements |
SCHEDULED | Planning | Resources allocated, timeline set | Schedule only |
IN_PROGRESS | Execution | Active work underway | Time entries, execution notes |
PENDING_REVIEW | Review | Work complete, awaiting approval | None (locked) |
APPROVED | Approval | System Owner + QA (if reg) signed off | None (locked) |
REJECTED | Terminal† | Review found deficiencies | None (clone to rework) |
COMPLETED | Terminal | All post-approval tasks confirmed | None (immutable) |
CANCELLED | Terminal | WO abandoned with justification | None (immutable) |
†REJECTED is terminal for that WO version — rework requires a DRAFT clone with lineage reference.
2. Transition Map
┌──────────────────────────────────────────────┐
│ CANCELLED │
│ (from any non-terminal) │
└──────────────────────────────────────────────┘
▲ ▲ ▲ ▲
│ │ │ │
┌───────┐ T1 ┌────────┐ │T2 ┌──────────┐ T3 ┌─────────────┐
│ DRAFT │─────▶│PLANNED │──┼──▶│SCHEDULED │───▶│IN_PROGRESS │
└───────┘ └────────┘ │ └──────────┘ └──────┬──────┘
│ │ T4
│ ▼
│ ┌──────────────┐
│ │PENDING_REVIEW│
│ └───┬──────┬───┘
│ T5a │ │ T5b
│ ▼ ▼
│ ┌─────────┐ ┌────────┐
│ │APPROVED │ │REJECTED│
│ └────┬─────┘ └────────┘
│ T6 │
│ ▼
│ ┌──────────┐
└──────────────│COMPLETED │
└──────────┘
3. Guard Conditions by Transition
T1: DRAFT → PLANNED
interface T1Guards {
// Data completeness
originator_set: boolean; // originator_id NOT NULL
item_set: boolean; // item_id NOT NULL, ChangeItem exists
summary_present: boolean; // summary.length > 0
detail_present: boolean; // detail.length > 0
// RBAC
performed_by_role: 'ORIGINATOR' | 'ASSIGNER';
// Audit
audit_action: 'STATUS_CHANGE';
audit_previous: 'DRAFT';
audit_new: 'PLANNED';
}
Rationale: Minimum viable record completeness before resource planning begins. No schedule or job plan required yet — those come at PLANNED→SCHEDULED.
Part 11 implication: Audit trail entry captures who planned it and when. The version field increments.
T2: PLANNED → SCHEDULED
interface T2Guards {
// Resource readiness
job_plan_assigned: boolean; // job_plan_id NOT NULL
schedule_assigned: boolean; // schedule_id NOT NULL
minimum_requirements_defined: boolean; // ≥1 WorkOrderMinimumRequirement row
// Job plan validation
job_plan_has_tools: boolean; // ≥1 JobPlanToolRequirement
job_plan_has_experience: boolean; // ≥1 JobPlanExperienceRequirement
// Assignee
assignee_set: boolean; // assignee_id NOT NULL
assignee_meets_experience: boolean; // PersonExperience.rating ≥ JobPlanExperienceRequirement.minRating
// RBAC
performed_by_role: 'ASSIGNER' | 'SYSTEM_OWNER';
}
Rationale: Cannot schedule work without knowing what tools, skills, and people are needed. The experience match check prevents under-qualified assignments.
Part 11 implication: Job plan linkage creates traceability from execution method to the change record.
T3: SCHEDULED → IN_PROGRESS
interface T3Guards {
// Acknowledgment
assignee_acknowledged: boolean; // Assignee confirms start via authenticated action
// E-signature (optional per tenant config)
start_signature_required: boolean; // Tenant config: require_start_signature
signature_valid: boolean; // If required: ElectronicSignature.signerId === assignee.personId
// Time tracking
time_entry_created: boolean; // TimeEntry with actual_start_at set
// Dependencies (for Linked WOs)
predecessor_dependencies_met: boolean; // All predecessor WOs in COMPLETED|IN_PROGRESS|APPROVED
// RBAC
performed_by_role: 'ASSIGNEE';
}
Rationale: Assignee must explicitly start — prevents phantom work orders that show progress without actual execution. Dependency check for Linked WOs prevents out-of-order execution.
Part 11 implication: Login-bound action establishes who started the work. First TimeEntry.actual_start_at becomes the official execution start timestamp.
T4: IN_PROGRESS → PENDING_REVIEW
interface T4Guards {
// Execution completeness
all_time_entries_closed: boolean; // All TimeEntry rows have actual_end_at set
// Master WO aggregation
is_master_wo: boolean; // master_id IS NULL AND has children
children_ready_for_review: boolean; // If master: ALL children in PENDING_REVIEW|APPROVED|COMPLETED|CANCELLED
// Linked WO
execution_notes_present: boolean; // Detail field updated with execution results
// Regulatory artifacts (if regulatory_flag)
regulatory_evidence_attached: boolean; // IQ/OQ docs, golden image, WI updates linked
// RBAC
performed_by_role: 'ASSIGNEE' | 'SYSTEM_OWNER';
}
Rationale: Work must actually be done (time entries closed) before review. Master WOs cannot enter review while children are still executing — this prevents premature sign-off.
Part 11 implication: Regulatory evidence requirement ensures validation documentation is attached before any approval workflow begins. This is the "complete before you review" principle.
T5a: PENDING_REVIEW → APPROVED
interface T5aGuards {
// Approval chain
system_owner_approved: boolean; // Approval row: role=SYSTEM_OWNER, decision=APPROVED
qa_approved_if_required: boolean; // If regulatory_flag: Approval row: role=QA, decision=APPROVED
// E-signature (mandatory for approval)
system_owner_signature: boolean; // Approval.signatureId links to valid ElectronicSignature
qa_signature_if_required: boolean; // If regulatory: QA Approval.signatureId valid
// Signature validation
signature_signer_matches_approver: boolean; // sig.signerId === approval.approverId
signature_is_recent: boolean; // sig.signedAt within configurable window (e.g., 30 min)
signature_auth_method_valid: boolean; // authMethod in tenant-allowed methods
// No open child WOs (for Master)
all_children_terminal_or_approved: boolean;
// Separation of duties
approver_not_assignee: boolean; // approval.approverId !== wo.assigneeId
// RBAC
performed_by_role: 'SYSTEM_OWNER' | 'QA';
}
Rationale: This is the critical compliance gate. Dual approval (System Owner + QA for regulatory changes) with e-signatures is the Part 11 cornerstone. Separation of duties prevents self-approval.
Part 11 implication: §11.50 — Signature manifestation (signer identity, date/time, meaning). §11.10(e) — Authority checks. §11.70 — Signature/record linking.
T5b: PENDING_REVIEW → REJECTED
interface T5bGuards {
// Rejection record
rejection_decision_recorded: boolean; // Approval row: decision=REJECTED
rejection_comment_present: boolean; // comment.length > 0 (must explain deficiency)
// E-signature
rejection_signature_valid: boolean; // Valid ElectronicSignature linked
// RBAC
performed_by_role: 'SYSTEM_OWNER' | 'QA';
}
Post-transition action: System creates a DRAFT clone WO with previous_version_id pointing to the rejected WO, preserving lineage.
T6: APPROVED → COMPLETED
interface T6Guards {
// Post-approval verification
asset_state_updated: boolean; // Asset status reflects change (e.g., IN_PRODUCTION)
golden_image_captured: boolean; // If applicable: evidence document linked
work_instructions_updated: boolean; // If applicable: Document version linked
// Master WO aggregation
all_children_completed_or_cancelled: boolean; // No child in APPROVED (must progress to COMPLETED)
cancelled_children_justified: boolean; // Cancelled children have cancellation reason
// RBAC
performed_by_role: 'SYSTEM_OWNER' | 'ASSIGNER';
}
Rationale: APPROVED ≠ COMPLETED. The gap between these states captures post-approval tasks: updating asset registers, capturing golden images, updating controlled documents. This is frequently missed in naive implementations.
TC: Any Non-Terminal → CANCELLED
interface TCGuards {
// Authorization
cancellation_authorized: boolean; // Role = SYSTEM_OWNER | QA | ADMIN
// Justification
cancellation_reason_present: boolean; // reason.length > 0
// E-signature (if IN_PROGRESS or later)
cancellation_signature: boolean; // Required if status >= IN_PROGRESS
// Child WO cascade
children_cancellation_handled: boolean; // All active children also cancelled or completed
// Impact assessment (if regulatory_flag)
regulatory_impact_assessed: boolean; // For reg WOs: impact statement attached
}
4. Master ↔ Linked WO Aggregation Rules
Master WO Cannot Advance Past Children
| Master Target State | Required Child State(s) |
|---|---|
| PLANNED | No restriction |
| SCHEDULED | ≥1 child WO exists |
| IN_PROGRESS | ≥1 child IN_PROGRESS |
| PENDING_REVIEW | All children: PENDING_REVIEW | APPROVED | COMPLETED | CANCELLED |
| APPROVED | All children: APPROVED | COMPLETED | CANCELLED |
| COMPLETED | All children: COMPLETED | CANCELLED (with justification) |
Child WO Constraints
- Child cannot move to COMPLETED if Master is CANCELLED (unless explicitly overridden by SYSTEM_OWNER with justification).
- Child CANCELLED does not automatically cancel Master — Master requires its own cancellation decision.
- Child WO dependency graph must be a DAG (no cycles). Validated at JobPlan creation.
5. Guard Implementation Pattern
// Composable guard pattern — each guard is a pure function
type Guard = (wo: WorkOrder, context: TransitionContext) => GuardResult;
interface GuardResult {
passed: boolean;
violation?: string;
part11_ref?: string; // e.g., "§11.10(e)"
}
// Guard composition
function composeGuards(...guards: Guard[]): Guard {
return (wo, ctx) => {
for (const guard of guards) {
const result = guard(wo, ctx);
if (!result.passed) return result;
}
return { passed: true };
};
}
// Transition registry
const TRANSITION_GUARDS: Record<string, Guard> = {
'DRAFT→PLANNED': composeGuards(
requireField('originatorId'),
requireField('itemId'),
requireField('summary'),
requireField('detail'),
requireRole('ORIGINATOR', 'ASSIGNER'),
),
'PLANNED→SCHEDULED': composeGuards(
requireField('jobPlanId'),
requireField('scheduleId'),
requireField('assigneeId'),
requireMinimumRequirements(),
requireExperienceMatch(),
requireRole('ASSIGNER', 'SYSTEM_OWNER'),
),
'SCHEDULED→IN_PROGRESS': composeGuards(
requireAssigneeAcknowledgment(),
requireDependenciesMet(),
requireRole('ASSIGNEE'),
),
'IN_PROGRESS→PENDING_REVIEW': composeGuards(
requireTimeEntriesClosed(),
requireChildrenReady('PENDING_REVIEW'),
requireRegulatoryEvidence(),
requireRole('ASSIGNEE', 'SYSTEM_OWNER'),
),
'PENDING_REVIEW→APPROVED': composeGuards(
requireApproval('SYSTEM_OWNER'),
requireApprovalIfRegulatory('QA'),
requireESignatures(),
requireSeparationOfDuties(),
requireChildrenTerminalOrApproved(),
requireRole('SYSTEM_OWNER', 'QA'),
),
'PENDING_REVIEW→REJECTED': composeGuards(
requireRejectionWithComment(),
requireESignature(),
requireRole('SYSTEM_OWNER', 'QA'),
),
'APPROVED→COMPLETED': composeGuards(
requirePostApprovalTasks(),
requireAllChildrenTerminal(),
requireRole('SYSTEM_OWNER', 'ASSIGNER'),
),
};
6. Audit Trail Event Schema
Every transition generates an immutable audit event:
interface AuditTrailEvent {
id: string; // UUID
entity_type: 'WORK_ORDER';
entity_id: string; // work_order.id
action: 'STATUS_CHANGE';
performed_by: string; // person.id
performed_at: string; // ISO 8601
previous_value: {
status: WorkOrderStatus;
version: number;
};
new_value: {
status: WorkOrderStatus;
version: number;
transition_guards_evaluated: GuardResult[];
signature_id?: string;
};
// Part 11 metadata
part11_context: {
regulatory_flag: boolean;
approval_chain: ApprovalRef[];
signature_refs: SignatureRef[];
};
}
7. CODITECT Agent Mapping
| State Transition | CODITECT Pattern | Agent(s) Involved |
|---|---|---|
| DRAFT → PLANNED | Prompt Chaining | WO Orchestrator → Task Classifier |
| PLANNED → SCHEDULED | Orchestrator-Workers | WO Orchestrator → Scheduling Agent, Experience Matching Agent |
| SCHEDULED → IN_PROGRESS | Routing | WO Orchestrator → Asset Mgmt Agent, Vendor Coordinator |
| IN_PROGRESS → PENDING_REVIEW | Evaluator-Optimizer | WO Orchestrator → Documentation Agent, QA Review Agent |
| PENDING_REVIEW → APPROVED | Human Checkpoint | QA Review Agent → Human (System Owner, QA) |
| APPROVED → COMPLETED | Parallelization | Asset Mgmt Agent ∥ Documentation Agent ∥ WO Orchestrator |
| Any → CANCELLED | Circuit Breaker | WO Orchestrator (with cascade to all active children) |
The critical insight: PENDING_REVIEW → APPROVED is always a human checkpoint in CODITECT. No autonomous agent can approve regulatory changes — this is a hard architectural constraint derived from Part 11 §11.10(e) (authority checks) and §11.50 (signature manifestation).
Copyright 2026 AZ1.AI Inc. All rights reserved. Developer: Hal Casteel, CEO/CTO Product: CODITECT-BIO-QMS | Part of the CODITECT Product Suite Classification: Internal - Confidential