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

01

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.

02

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.

03

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.

04

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.

05

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

Schema document_versions binary_id PK; document_id FK; version_number int
Per-version surface content_hash, signature, timestamp SHA-256 + PKCS #7 + RFC 3161 token
Sequence Monotonic per document Strictly serial; no gaps, no decimal versions
Mutation API None Versions module exposes only insert + read; no update path
Working draft The document itself Editable; document_versions captures only sealed states
Latest version get_latest_version/1 Single-query lookup; canonical "current" pointer
Version listing list_versions/1 Ordered by sequence; full timeline of seals
Verification surface Per-version Each version has its own verification code; old codes never expire

The full picture

What is built, what is being built, and what we chose not to build

Live today

Immutable per-version records

Live

DocumentVersion schema with content_hash, signature, timestamp; no update path exists.

Per-document monotonic version sequence

Live

Strict serial numbering; the version that was sealed at v3 is permanently v3.

Working-draft editing

Live

The document itself stays editable; sealing snapshots it into a new immutable version.

Per-version verification

Live

Every sealed version has its own verification code that resolves to that exact byte sequence.

Full version timeline API

Live

list_versions/1 and get_latest_version/1 power the UI; no client-side reconstruction needed.

Building now

Visual version-history UI

Building now

Side-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 now

Optional org-defined tags on each version (e.g. 'IFC', 'permit', 'final') without changing the immutable seal.

Version-pinned share links

Building now

Share a link that always resolves to a specific version, never the current draft.

Roadmap

Cross-document version dependencies

Roadmap

A specification that references a drawing version explicitly, so updating the spec re-seals against the right drawing.

Diff-aware re-sealing

Roadmap

An assistive workflow that surfaces what changed between draft and last seal before you commit the new seal.

Version retention policies

Roadmap

Per-org rules for archiving very old versions to cold storage while keeping the verification surface live.

Considered & rejected

"Edit a seal" workflow

Considered & rejected

The 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 & rejected

Decimal 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 & rejected

Storage 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 & rejected

A 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

SOC 2 PI1.1

Processing Integrity — Inputs

Per-version content hash + signature confirms input integrity

ISO 27001 A.12.1.4

Separation of dev / test / production

Working drafts and sealed versions live in different states with different controls

21 CFR Part 11 11.10(c)

Protection of records

Immutable per-version records; no update path exists

21 CFR Part 11 11.10(d)

Limiting system access

Sealing requires MFA + current credential; drafts are scoped to org members

HIPAA §164.312(c)(1)

Integrity

Verifiable per-version hash; tampering breaks the seal

ESIGN Act §101(d)(2)

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?
No. The Versions module exposes only insert and read operations. There is no update path; database write access by EngineeringID employees would still produce a new row, not a modification.
What happens if the working draft is deleted?
Sealed versions are independent rows. Deleting the document soft-deletes the working-draft state; sealed versions remain intact and verifiable per your retention policy.
How is "current version" determined?
By the highest version_number in the per-document sequence. There is no "active" or "default" flag — the latest sealed version is canonical by definition.
Can two sealings collide on version_number?
No. Per-document version_number is enforced by a unique constraint plus serial allocation in the sealing transaction. Concurrent seal attempts serialize through the document row.
Are old verification codes still active?
Yes — and they always will be. Each version carries its own verification code that resolves to that exact byte sequence. A code from a v3 seal in 2024 verifies the v3 bytes regardless of how many later versions exist.
Can we tag versions with internal milestone names?
Tagging is in active development. Tags are metadata on top of the sealed version; they do not change the immutable seal or its hash.

A version timeline that is permanent and unambiguous

Every seal is its own row, its own hash, its own legal artifact.