Versioning
Every revision is preserved, every seal is immutable
On a long project, drawings go through dozens of iterations. Without strict version control, a contractor builds from a superseded set, an inspector reviews a draft, a court asks which version was actually approved — and the answer is "we are not sure." We make the answer unambiguous: the version that was sealed is the version that exists, forever, by hash.
Executive summary
Each document has one working draft and any number of sealed versions. The draft is editable. Sealed versions are not. Each sealed version is a row in document_versions with its own SHA-256 content hash, its own X.509 signature, its own RFC 3161 timestamp.
The version system is intentionally unforgiving: there is no "edit this seal" — only "seal a new version." Every revision creates a new row; the old row is never modified. A v3 sealed in 2024 will hash and verify identically in 2034, regardless of how many drafts came after.
Our commitments
Five rules for the version timeline
Sealed versions are immutable, period
No update_seal API exists. The sealing pipeline only inserts; it never modifies. Even EngineeringID employees cannot edit a sealed version.
Drafts are editable, sealed versions are not
The working draft is yours to revise. Sealing snapshots the current state into a new immutable version with its own hash, signature, and timestamp.
Version sequence is strictly serial
Per-document monotonically increasing version numbers. There is no version 3.5 between 3 and 4 — only 3, 4, 5.
Old versions are reachable forever
Every sealed version remains addressable by version number, content hash, or verification code — for as long as your retention policy keeps the record.
The current version is unambiguous
The latest sealed version is the canonical one. We do not guess which version is current; we point at the most recent seal and say so.
Implementation — the version model
How versions are stored
The full picture
What is built, what is being built, and what we chose not to build
Live today
Immutable per-version records
LiveDocumentVersion schema with content_hash, signature, timestamp; no update path exists.
Per-document monotonic version sequence
LiveStrict serial numbering; the version that was sealed at v3 is permanently v3.
Working-draft editing
LiveThe document itself stays editable; sealing snapshots it into a new immutable version.
Per-version verification
LiveEvery sealed version has its own verification code that resolves to that exact byte sequence.
Full version timeline API
Livelist_versions/1 and get_latest_version/1 power the UI; no client-side reconstruction needed.
Building now
Visual version-history UI
Building nowSide-by-side comparison of any two sealed versions; revision-mark overlay highlighting differences.
The data model is complete; the UI surface is the build target.
Version-tag annotations
Building nowOptional org-defined tags on each version (e.g. 'IFC', 'permit', 'final') without changing the immutable seal.
Version-pinned share links
Building nowShare a link that always resolves to a specific version, never the current draft.
Roadmap
Cross-document version dependencies
RoadmapA specification that references a drawing version explicitly, so updating the spec re-seals against the right drawing.
Diff-aware re-sealing
RoadmapAn assistive workflow that surfaces what changed between draft and last seal before you commit the new seal.
Version retention policies
RoadmapPer-org rules for archiving very old versions to cold storage while keeping the verification surface live.
Considered & rejected
"Edit a seal" workflow
Considered & rejectedThe seal is the legal artifact; an editable seal is not a seal.
Why we rejected it: every "edit this seal in place" is a way to silently change history. The right answer is: seal a new version. The old version stays exactly as it was; the new version is its own seal with its own timestamp.
Decimal versioning (v2.5, v3.1.7)
Considered & rejectedDecimal versions invite ambiguity about which is "the real" version.
Why we rejected it: a strictly serial integer sequence eliminates "is 2.10 newer than 2.9?" arguments. Org-defined tags handle the human-readable layer; the underlying sequence stays unambiguous.
Auto-prune old versions to save space
Considered & rejectedStorage is cheap; replacing a court-admissible record is not.
Why we rejected it: every old sealed version is potentially the version someone built from. Auto-pruning is an availability incident waiting to happen — the cost is per-MB storage, the loss is irrecoverable evidence.
Optimistic re-sealing without re-verification
Considered & rejectedA re-seal that does not re-verify the credential is a re-seal that can run against an expired license.
Why we rejected it: every seal goes through the full credential gate. Skipping it for "trusted re-seals" creates a path where a lapsed license still produces valid-looking seals. We do not have a fast path that bypasses the gate.
Compliance mappings
Controls this surface satisfies
Processing Integrity — Inputs
Per-version content hash + signature confirms input integrity
Separation of dev / test / production
Working drafts and sealed versions live in different states with different controls
Protection of records
Immutable per-version records; no update path exists
Limiting system access
Sealing requires MFA + current credential; drafts are scoped to org members
Integrity
Verifiable per-version hash; tampering breaks the seal
Accuracy of retention
Sealed versions reproduce the document exactly as sealed
For compliance teams
Questions you do not need to call to ask
Can a sealed version be modified after the fact?
What happens if the working draft is deleted?
How is "current version" determined?
Can two sealings collide on version_number?
Are old verification codes still active?
Can we tag versions with internal milestone names?
A version timeline that is permanent and unambiguous
Every seal is its own row, its own hash, its own legal artifact.