Chapter 5
A protocol record is not a document you write once and file away. This chapter defines, as a single profile, the states a record passes through from draft to retention, the approval gates that sit between them, and the audit trail that makes every change reconstructable afterwards.
The preceding chapters dealt with static structure. Chapter 2 defined the CRISPRProtocol aggregate root and its child structures, Chapter 3 defined serialization and identifiers, and Chapter 4 defined the call contracts that produce and validate those records. What actually breaks in an institution, however, is not structure but time. The same protocol record must obey different rules while it is a working draft, after the institutional biosafety committee has approved it, and after execution has begun. A field that could be edited freely before approval must not change after approval without going through an amendment procedure. Written down in a policy document, that rule is not kept. Software has to enforce it, and to enforce it the state must be stored explicitly.
One thing should be said plainly here. WIA-BIO-014 v1.0 does not define a lifecycle state field. The aggregate root carries id, version, created and updated; the validation result carries a validated timestamp. Approval is expressed as a boolean, SafetyChecks.ethicsApproval, and regulatory compliance as a string array, regulatory[]. In other words the standard's records imply a state machine but never name one. The state model defined in this chapter is therefore not a normative requirement of the specification; it is a profile that an implementation declares for itself. The profile-manifest mechanism in Annex I of the PHASE documents exists for exactly this purpose. An implementation states in its manifest which state model it enforces, and then produces evidence for that declaration in the manner of Chapter 7.
Where the state is stored is also a design decision, and there are two options. The first is to add a status field to the record body. Queries become trivial, but this collides with the immutability principle of Chapter 3: the body changes on every state change, so versions proliferate. The second is to treat state as a projection of an append-only event log. The record body stays immutable and the state is computed from the transition events recorded against it. A registry table may cache the current state for query performance, but that cache must be reconstructable from the log at any time. This book recommends the second option, because it makes the audit trail the single source of state rather than a side feature.
The profile defines eight states: six on the normal path and two terminal ones.
| State | Entry condition | Fields frozen | Required record |
|---|---|---|---|
draft |
Record created | None (except id, created) |
Author identity, creation event |
under_review |
Submission event + required fields complete + at least one validation[] entry |
target, guideRNA, casSystem, delivery, strategy |
Submission event (who, when), schema-validation pass record |
approved |
Reviewer decision + valid approval reference present | The above + safety.biosafety, safety.riskLevel |
Approval reference record (issuing body, scope, validity) |
in_execution |
Within approval validity + execution-start event | Whole protocol record (changes only by amendment) | Opening entry of the execution record, responsible person |
validated |
At least one validation record + stored result snapshot | All of the above + the relevant validation[] entries |
Validation record rows, ValidationResult snapshot |
archived |
Active work closed + retention decision | Everything (read-only) | Retention decision event, retention start point |
superseded |
A successor version reaches approved |
Everything + supersededBy |
Successor version identifier, transition event |
withdrawn |
Withdrawal request + authorized approval | Everything + withdrawal reason | Withdrawal reason, approver identity |
The permitted transitions are shown below; any transition not drawn is rejected. Two features matter most: no arrow leaves archived, and withdrawn is reachable from every active state.
draft ──submit──> under_review ──approve──> approved ──start──> in_execution
^ | |
| | | record
└────return─────────┘ v
validated
|
archive
v
archived
(any active state) ──withdraw──> withdrawn (terminal, not deletion)
approved | in_execution | validated ──amend──> superseded
└─ supersededBy ─> new version
The return path from under_review back to draft is deliberately kept open. Reviewers asking for revisions is routine, not exceptional, and without a return path users simply create a new record instead — which scatters one project across several orphaned records. A return must always be recorded with a reason, and the earlier submission and review events remain in the log after it. The fact that a protocol was once sent back is itself auditable.
The approval gate is the most important mechanism in this chapter. Without it the rest of the state model is decoration. And it must be said clearly that the raw material the standard provides is not sufficient to build one. SafetyChecks.ethicsApproval is a boolean. A boolean is an assertion that an approval exists; it is not the approval. It cannot carry who approved, when, for what scope, whether that approval is still valid, or where the underlying document lives. regulatory[] is a free-text array, so typing "LMO notification filed" into it passes schema validation. Chapter 2 flagged this as a modelling pitfall; this section defines the structure that fills the gap.
The profile separates approval into its own approval reference record. The protocol record holds only the reference identifiers, and the boolean is demoted to a derived value the system computes when at least one valid reference exists. The path in which a human writes the boolean directly is closed. An approval reference must carry the following attributes.
approvalId — the issuing body's own document number, never replaced by an internal serial.bodyType — IBC | IRB | regulator | other: the kind of issuer, fixed as a controlled vocabulary.issuingBody — the issuer's name, stored together with its identifier in the organizational directory.scope — what the approval actually covers: a protocol identifier, an institution, a facility, or a class of work.issuedAt / expiresAt — issue and expiry instants. If an approval genuinely has no expiry, store an explicit null together with the justification.documentUri / documentDigest — location and hash of the underlying document. Reference it; do not copy the document into the protocol store.recordedBy — who entered the reference. The person who approved and the person who typed it in are different, and both are needed.Gate rules attach to transitions. The profile enforces four.
under_review → approved: at least one approval reference of each type institutional policy requires must exist, and each reference's scope must cover this protocol.approved → in_execution: at the moment of transition, every required approval reference must have an expiresAt in the future. Execution cannot begin on an expired approval.approved without a separate higher-level approval reference. An override must be possible, but it must carry an approval reference and a reason, and the fact of the override must appear in the log.
One observation about the reference implementation belongs here. The SDK's validateCRISPRProtocol looks only at booleans. When checkEthics is set and ethicsApproval is false it adds an error — except where the purpose is knockout, in which case it downgrades to a warning. An empty regulatory[] yields a warning only. The SDK validator is therefore a structural checker, not an approval gate. The gate has to live in the record store's policy layer, and the manifest must say honestly that policy checks are performed by the store. A manifest that claims gate conformance on the strength of a successful SDK call is exactly the false claim Chapter 7 warns about.
An approval reference block looks like this. All values are placeholders.
{
"protocolId": "<PROTOCOL-ID-PLACEHOLDER>",
"protocolVersion": "4",
"approvals": [
{
"approvalId": "<IBC-DOCUMENT-NUMBER-PLACEHOLDER>",
"bodyType": "IBC",
"issuingBody": {
"name": "<INSTITUTION-BIOSAFETY-COMMITTEE-PLACEHOLDER>",
"directoryId": "<ORG-ID-PLACEHOLDER>"
},
"scope": {
"kind": "protocol",
"value": "<PROTOCOL-ID-PLACEHOLDER>"
},
"issuedAt": "2026-03-02T00:00:00Z",
"expiresAt": "2027-03-01T23:59:59Z",
"documentUri": "dms://<DOCUMENT-STORE-PLACEHOLDER>/approval/0001",
"documentDigest": {
"alg": "SHA-256",
"value": "<HEX-DIGEST-PLACEHOLDER>"
},
"recordedBy": "<STAFF-ID-PLACEHOLDER>",
"recordedAt": "2026-03-03T01:14:22Z"
}
],
"derived": {
"safety.ethicsApproval": true,
"computedAt": "2026-03-03T01:14:22Z",
"computedBy": "record-store-policy-engine/1.4.0"
}
}
The derived block is the point of the example. The boolean does not go away — the standard's schema requires it, so it must still be there. What changes is that how its value was decided is stored alongside it. When an auditor asks where that true came from, the answer has to be inside the record.
The audit trail is the append-only event log that lets a protocol store answer "who changed what, when, and on whose authority". Since state is a projection of that log (§5.1), the log is not an add-on but the centre of the store. If the log cannot be written, the record change must not take effect either: the record write and the event write belong to one transaction. Break that and you create entries where "the change landed but the log has nothing", and no later audit can explain them.
A single event must answer six questions: actor (who), action (what), subject (where), change (from what to what), time (when), and authority (on what basis). The last one is what separates an audit trail from ordinary application logging. The authority field points either to the actor's role or to the approval reference that justifies the action.
| Event type | Required attributes | Effect on state |
|---|---|---|
record.created |
Actor, protocol identifier, initial version | Enters draft |
field.changed |
Field path, old-value hash, new-value hash, reason | None (accepted only in permitted states) |
state.transitioned |
Previous state, new state, gate evaluation results | State change |
approval.attached |
Approval reference id, issuing body, validity | Input to G1 and G2 |
approval.expired |
Approval reference id, expiry instant, notified parties | Blocking flag (no automatic transition) |
record.corrected |
New version, corrected field, correction reason | Version increment, state unchanged |
record.migrated |
Source and target schema versions, migration tool and version | Version increment, state unchanged |
record.superseded |
Successor version identifier | Enters superseded |
record.withdrawn |
Withdrawal reason, approver | Enters withdrawn |
Tamper evidence comes from hash chaining. Each event carries the hash of the preceding event (prevHash) and a hash over its own canonical serialization (hash), using the canonical JSON rules of Chapter 3 and naming SHA-256 as the hash function. Remove or alter an intermediate entry and every later link stops matching, so deletion becomes visible. A chain alone cannot catch a store that was rewritten wholesale, so the head hash should be anchored externally at intervals. The evidence package of Chapter 7 is the natural anchor point: put the head hash into the signed package and you can later prove what the log contained up to that signature.
Correction and replacement are different events. Blur the distinction and the audit trail loses its meaning. A correction (record.corrected) fixes an error in the record itself — a mistyped gene symbol, a typo in a description. The plan did not change; only the record was brought into line with the facts. A replacement (record.superseded) means the plan changed, and the prior version must survive not as a "wrong record" but as "the plan that was valid at that time". Log both as the same event and an auditor can no longer answer why a field differs between versions. Keeping the reason field free-text while fixing the event type as a controlled vocabulary is the practical way to preserve the distinction.
What must not go into the log also needs deciding. Personally identifying information should never sit in it as plain text: record actors as institutional identifiers and resolve names and contact details from the identity system. Value changes are likewise safer as hashes than as full payloads. Long string fields in particular — sequence strings among them — turn the log into a second copy of the data if old and new values are written out verbatim. Store the hash and the length, and let the reader find the content in the versioned record. An audit trail exists to prove that something changed, not to duplicate what it was.
A single event looks like this.
{
"eventId": "01JH8Z4K5N7Q9R2T4V6X8Y0A2C",
"seq": 4412,
"recordedAt": "2026-03-11T04:22:09.481Z",
"actor": {
"id": "<STAFF-ID-PLACEHOLDER>",
"role": "reviewer",
"authMethod": "oidc+mfa"
},
"type": "state.transitioned",
"subject": {
"protocolId": "<PROTOCOL-ID-PLACEHOLDER>",
"version": "4"
},
"change": {
"field": "lifecycle.state",
"from": "under_review",
"to": "approved"
},
"authority": {
"kind": "approvalRef",
"approvalId": "<IBC-DOCUMENT-NUMBER-PLACEHOLDER>",
"gateResults": [
{ "gate": "G1", "result": "pass" },
{ "gate": "G4", "result": "not-applicable" }
]
},
"reason": "<REVIEW-DECISION-NOTE-PLACEHOLDER>",
"prevHash": "<HEX-DIGEST-PLACEHOLDER>",
"hash": "<HEX-DIGEST-PLACEHOLDER>"
}
Why seq sits next to recordedAt is the subject of the next section: timestamps alone cannot establish order.
Annex E of the PHASE documents states that a seven-year retention window is sufficient to satisfy ISO/IEC 17065:2012 audit expectations in most jurisdictions. Citing that figure means carrying its caveats with it. First, Annex E is a non-normative implementation note, not a requirement. Second, the text itself says that some regulators require longer retention, in which case the deployment policy must extend the window rather than rely on the PHASE defaults. Seven years is a reference floor, and stricter local rules always win. This book does not present it as a legal obligation; which rules bind a given institution is a question for that institution's legal and regulatory function.
What retention policies usually omit is not the length but the start point. Seven years from when? Record creation, approval expiry, the last validation record, or the declared end of the project? Without a defined start event a retention policy is an unexecutable sentence. The profile requires a start event to be named per class of material.
| Material retained | Retention owner | Start event | At end of period |
|---|---|---|---|
| All versions of the protocol record | Research administration | Entry into archived |
Transfer or deletion after an approved disposition event |
| Approval reference records | IBC / IRB secretariat | Later of approval expiry and project closure | Follows the source document's retention policy |
| Audit event log | Information security and QA jointly | End of the related record's retention | Must never be deleted before the record |
| Validation records and result snapshots | QA | Snapshot creation | Evidence-package policy wins where included |
The third row is the one most often violated in practice. Set log retention shorter than record retention and you create a span in which a retained record exists with no way to say who changed it. The log must outlive the record it explains.
Deletion must never happen quietly. Running an automatic purge on the strength of an elapsed retention period is how a record under active audit disappears. The profile requires disposition to be an explicit event: a candidate list is assembled, the retention owner reviews it, deletion executes only against the approved list, and the deletion itself is logged. The log must retain an entry saying that the record with this identifier was removed at this time under an approved disposition procedure. If a deleted record leaves no trace at all, an auditor cannot even establish that it once existed.
Clock synchronization is a precondition for the audit trail. Events that cannot be ordered are useless for audit. Annex E notes that NTPv4 with stratum-2 servers suffices for most of the deadlines in the PHASE documents and recommends PTP only for sites that require deterministic interlocks. A protocol record store is not in the latter category: work that humans approve and humans execute does not need sub-millisecond precision. What it needs is not precision but trustworthy ordering, and that rests on three rules.
clientTimestamp field as a claimed value and let the store write recordedAt. A large gap between the two is a reportable condition.seq to each event. Order then survives identical timestamps and backwards clock adjustments, and the hash chain fixes it in place.Chapter 3 set a simple principle: a corrected record is a new version, and there is no in-place edit. This section deals with the judgement that principle demands once a protocol is live. The question is always the same — is this change an amendment to the same protocol, or a different protocol?
The test is the scope of the approval. Does the approval already issued still cover this change? If it does, the change is an amendment. If it does not, re-approval is required, and depending on the size of the change the right answer may be a separate protocol. The table below organizes that judgement by type of change. The real boundaries are set by the institution's IBC/IRB policy; the table shows which questions the software has to ask.
| Type of change | Handling | Re-approval | Existing validation evidence |
|---|---|---|---|
| Description wording, typo correction | Amendment (editorial) | Not required | Carried forward as-is |
Adding a validation[] entry |
Amendment (minor) | Not required; notification | Carried forward + new evidence rows |
Change to delivery or strategy |
Amendment (minor or major per institutional policy) | Required | Cannot be carried forward — revalidate |
Raising safety.biosafety or riskLevel |
Amendment (major) | Required | Cannot be carried forward |
Change to target |
New protocol (new identifier) | Required | Cannot be carried forward |
| Change of responsible person or affiliation | Amendment (editorial) | Institutional policy | Carried forward |
Carrying validation evidence forward deserves particular care. A validation record is bound to the version that produced it. Saying that a validation performed on version 4 still holds for version 5 is defensible only when the changes in version 5 do not touch that validation's premises. Carrying forward must therefore take the form of an assertion rather than a copy of a value: this result was produced at version 4, and this named person judged on this date that the scope of the version 5 change does not include its premises. Recorded that way, an auditor can review the judgement. Copy the value alone and there is nothing left to review.
The version chain must be walkable in both directions. The new version points back with supersedes, and the old version points forward with supersededBy. With only one direction, a reader arriving from an old link or citation cannot answer whether the document still holds. What gets cited in papers and regulatory filings is usually the version current at the time, so in practice the back-pointer that announces a successor is more useful than the forward one. Retired versions remain, signed, in place. Annex H keeps a parallel window for superseded standard versions for the same reason, and the profile applies that principle to institutional records.
Once states and logs exist, institutional reports come for free: the lists a coordinator used to assemble by hand each quarter from mail threads and spreadsheets fall out of a single query. That is the practical return on adopting the state model of §5.1. One rule attaches, though. Reports read stored fields only. Presenting success rates or efficiency statistics derived from stored values as institutional performance indicators is contrary to this book's facts policy, because the records contain no basis for such numbers.
The reports that can be built from stored fields alone — and that turn out to be genuinely useful — are these; the fields each one reads are noted after it.
under_review is a review-capacity problem.expiresAt on approval references. The only report that prevents expiry during execution (G3), and in practice the one most often requested.in_execution state plus absence of validation[] evidence rows. Catches missing records.safety.ethicsApproval is true but no valid approval reference exists. A data-quality check; anything other than zero must be investigated.archived or withdrawn.The report definitions themselves are worth storing as records. When a query hides in code it is hard to answer "what exactly did this number count". Store the definition as data and version it, and you can confirm that last quarter's report and this quarter's were produced by the same definition.
{
"reportId": "approvals-expiring",
"definitionVersion": "1.1.0",
"reads": ["approvals[].expiresAt", "lifecycle.state"],
"filter": {
"state": ["approved", "in_execution"],
"expiresWithinDays": 60
},
"outputs": ["protocolId", "version", "state", "approvalId", "expiresAt", "owner"],
"derivedMetrics": [],
"note": "Stored fields only. No derived performance metrics."
}
That derivedMetrics is an empty array is stated explicitly. The empty array is not an oversight; it is the policy, written down.
This section collects the failure patterns seen repeatedly in systems that implement a lifecycle. Each is given as a symptom and a remedy.
recordedAt) separately from the instant the event occurred (occurredAt), and surface entries whose gap exceeds a threshold in their own report. Forbidding retrospective entry is unrealistic, so the goal is to make it visible.withdrawn, and deletion may pass only through the disposition procedure of §5.4.What this chapter defined is a layer the specification does not contain. For that reason an implementation must write down in its profile manifest what it actually enforces, and produce evidence for what it wrote. How that evidence is assembled, signed and published is the subject of Chapter 7. Before that, Chapter 6 covers where these states and logs sit inside real institutional systems, and how far each role is allowed to see.
On scientific and laboratory-safety content: this book covers the record and data standard only. Laboratory technique, the actual requirements attached to a biosafety level, and the interpretation of regulation are matters for your institutional biosafety committee (IBC) and institutional review board (IRB), and for the official biosafety and regulatory authorities (the KDCA and the authorities responsible for the LMO Act, the WHO, the NIH Guidelines, and your national regulator).