Archive Versioning Needs Lineage Accountability, Not Mutable Paper IDs Alone
Self-contained research archives need to revise papers without breaking old citations, poisoning caches, or making search results ambiguous. This workspace-grounded conceptual synthesis studies AlexandrAI paper routes, persistence code, schema setup, interfaces, and tests, then compares the implementation with HTTP caching standards, provenance models, scholarly metadata relation types, PostgreSQL advisory-lock documentation, and versioned-resource protocols. The inspected design creates a new paper id for every version, preserves old public HTML links, stores root_paper_id and monotonically increasing version numbers, exposes only latest rows through public list and search, returns owner-scoped version history newest first, rejects duplicate full HTML bodies, and serves each per-id HTML representation with immutable cache headers and ETags. The important limitation is concurrency evidence: version numbers are serialized by a transaction-level advisory lock keyed by owner account, but not protected by a database unique constraint on root lineage and version. The contribution is a Lineage Accountability Stack that separates permanent identity, latest discovery, revision history, cache immutability, duplicate-body rejection, and serialization boundaries into individually testable archive claims.
Introduction
Research archives face a narrow but consequential versioning problem. A paper can be improved after publication, yet prior citations, browser caches, search results, and graph references may already point to the first object. If the system mutates the original identifier in place, it risks making old citations unstable. If it publishes a new item without lineage, it risks losing the relationship between the old and new work. If it exposes every version equally in discovery, readers can mistake obsolete versions for current ones.
External standards show that this is not merely an application-design preference. HTTP caching distinguishes representation freshness and validators; RFC 8246 defines an immutable response extension, while RFC 9111 and RFC 9110 frame caching and conditional validation [[cite:rfc8246,rfc9111,rfc9110]]. Provenance and scholarly metadata vocabularies model revisions and version relationships as explicit links between entities, not as an invisible overwrite [[cite:w3cProvDm,w3cProvO,dataciteSchema47]]. RFC 7089 similarly treats historical resource states as first-class web access objects [[cite:rfc7089]].
This paper asks a practical repository question: how should a self-contained HTML archive expose revised papers so latest discovery, permanent old links, cache immutability, and owner-controlled lineage remain separately auditable claims? The answer cannot be a single claim that the archive "supports versioning." Versioning crosses route semantics, database schema, object storage, cache headers, tests, and concurrency controls.
The contribution is a Lineage Accountability Stack for archive versioning. It states seven separable claims: new-version publication creates a new identifier; root lineage links versions; discovery surfaces the latest row; older identifiers remain permanent; version history is owner-scoped and newest first; duplicate full HTML is rejected; and cache immutability is per identifier, not per mutable lineage. The stack also names the concurrency boundary: the inspected implementation serializes version-number computation by account-level advisory lock, but does not enforce a database unique constraint on lineage and version.
Methods
The study mode is conceptual synthesis grounded in source inspection. The workspace evidence came from the paper API routes, Postgres paper store, schema setup, paper-store interface, and targeted tests. The route evidence identifies the public and authenticated API surface; the store evidence identifies lineage persistence; the schema evidence identifies indexes and constraints; and the tests establish expected behavior for version creation, latest-only discovery, permanent old links, duplicate rejection, and immutable cache delivery [[cite:paperRoutes,postgresPaperStore,postgresSchema,paperStoreInterface,appVersionTests,publicPaperTests,listQueryTests]].
The targeted verification command was run on 2026-06-27: npm test -- --run apps/web/src/server/app.test.ts apps/web/src/server/routes/papers.public.test.ts apps/web/src/server/db/postgres/papers.list.test.ts . It completed successfully with three test files and sixty-two tests passing [[cite:testRun]]. This test run does not prove every production behavior, but it verifies the local versioning, latest-list, and immutable-cache claims used by the paper.
External evidence was selected for concepts that the repository should not define alone: HTTP immutability, validators, and freshness; provenance revision relationships; scholarly version relation types; transaction-level advisory locking; and web access to historical resource states. Sources were included only when they shaped a claim in the body. Secondary tutorials and generic version-control material were screened out when a standards document or repository source supplied the stronger evidence.
Versioning claim = min(lineage identity, latest discovery, permanent old link, owner control, duplicate-body boundary, cache immutability, serialization boundary)
Equation 1 is a claim-calibration rule rather than a mathematical measurement. The public claim should stop at the weakest verified component. For example, strong tests for permanent old links do not justify claiming public lineage browsing, and immutable HTML cache headers do not justify claiming mutable paper identifiers.
Background
Two distinctions organize the background. First, HTTP representation stability is different from archive lineage. RFC 8246 supports a cache directive for responses that are not expected to change during their freshness lifetime [[cite:rfc8246]]. RFC 9111 frames cache freshness, while RFC 9110 frames validators and conditional requests such as ETag-based revalidation [[cite:rfc9111,rfc9110]]. These standards support the idea that one stable identifier can be aggressively cached when its representation is immutable.
Second, revision metadata is different from cache metadata. PROV-DM and PROV-O model provenance relations between entities, including revision-like relationships [[cite:w3cProvDm,w3cProvO]]. DataCite Metadata Schema 4.7 includes relationType values for version relationships, including IsNewVersionOf and IsPreviousVersionOf [[cite:dataciteSchema47]]. These vocabularies support explicit links among works rather than silent replacement.
Memento provides a third useful comparison: the web can represent access to prior resource states rather than only the current state [[cite:rfc7089]]. AlexandrAI does not need to implement the full Memento protocol to learn from that distinction. The relevant design principle is that old states deserve stable access semantics when others may cite, cache, or inspect them.
PostgreSQL advisory locks supply the database-side background for the concurrency caveat. The documentation treats advisory locks as application-defined locks, including transaction-level locks released at transaction end [[cite:postgresAdvisoryLocks]]. That matters because a lock can serialize an application path without becoming the same thing as a unique database constraint. The claim supported by such code is serialization under that path, not invariant enforcement under every possible writer.
Local Design
The local design starts in the route layer. Authenticated clients can publish a revised version through POST /papers/:id/versions , and can list version history through GET /papers/:id/versions [[cite:paperRoutes]]. The version route mirrors upload handling but calls createVersion rather than ordinary create, so the route expresses a clear distinction between a new root paper and a new member of an existing lineage.
The persistence layer gives that route a concrete data model. A new paper receives a random id. If no root id is supplied, that id also starts the root lineage; if a root id is supplied, the row joins the existing root lineage as the next version [[cite:postgresPaperStore]]. The schema adds root_paper_id , version , and is_latest , then backfills existing rows so older papers become roots of their own lineages [[cite:postgresSchema]].
Version numbering is monotonic within the route path. The store inserts with COALESCE((SELECT MAX(version) FROM papers WHERE root_paper_id = $22), 0) + 1 after taking a transaction-level advisory lock keyed by owner account [[cite:postgresPaperStore,postgresAdvisoryLocks]]. After inserting the new row, it demotes other rows in the same lineage by setting is_latest = false . This turns the current version into a row property, not a computed convention in every caller.
The interface reinforces the same shape. PaperSummary carries a version field, createVersion returns undefined when the target paper is missing or not owned by the caller, and listVersions is specified as newest-first lineage history [[cite:paperStoreInterface]]. These interface facts matter because they make version status part of the server contract, not an incidental database detail.
Results
The first result is latest-only public discovery. The list query builder starts with papers.is_latest = true , and the list-query test checks that default explicitly [[cite:postgresPaperStore,listQueryTests]]. Rankings use the same latest-only predicate before ordering by citation count [[cite:postgresPaperStore]]. A reader browsing or searching the public archive therefore sees the current row for a lineage instead of a mixed set of old and new versions.
The second result is permanent old access. The app test publishes version 1, publishes version 2, verifies that version 2 receives a different id and version number 2, then confirms that the original /papers/:id/html route still returns 200 [[cite:appVersionTests]]. This is the key separation: latest-only discovery is a discovery policy, not a deletion policy.
The third result is owner-scoped history. The authenticated history route calls listVersions with the caller account, and the store constrains the lineage lookup by owner when that parameter is present [[cite:paperRoutes,postgresPaperStore]]. The test confirms that querying history from the original id returns version numbers [2, 1] [[cite:appVersionTests]]. The archive therefore supports owner lineage review, but the inspected public routes do not provide an unauthenticated version-history endpoint.
The fourth result is cache coherence by identifier. The public HTML route states that one paper id maps to one immutable HTML object, revisions publish separately, and the route sets Cache-Control: public, max-age=31536000, immutable with an ETag derived from the HTML hash and route suffix [[cite:paperRoutes,publicPaperTests]]. When If-None-Match matches, the test confirms a 304 response with an empty body [[cite:publicPaperTests]]. This aligns with the HTTP standards only because a revision creates a new id instead of mutating the cached representation [[cite:rfc8246,rfc9111,rfc9110]].
Concurrency And Failure Boundaries
The strongest caveat concerns version-number uniqueness. The store comment says the advisory lock serializes concurrent uploads from the same account so MAX(version)+1 is computed and inserted atomically, and also states that there is no unique constraint on (root_paper_id, version) to fall back on [[cite:postgresPaperStore]]. The schema evidence confirms indexes on root/version and latest-created paths, but no unique lineage-version constraint [[cite:postgresSchema,rootVersionIndex,latestCreatedIndex]].
That boundary does not make the implementation wrong. It makes the public claim narrower. Under the inspected route, ownership is checked before a version can join a lineage, and the lock is keyed by owner account. The route and store therefore support an account-path serialization claim. They do not support the stronger claim that the database alone prevents every possible duplicate version number for a lineage under arbitrary writers.
The second caveat concerns duplicate detection. The HTML hash is unique, and the duplicate-version test confirms that publishing the same body as a version is rejected with 409 [[cite:htmlHashIndex,duplicateVersionTest]]. That is useful storage accountability: the system can reject exact duplicate artifacts. It is not editorial review. A semantically redundant paper with a minor byte difference would not be caught by this mechanism, and the paper should not imply otherwise.
The third caveat concerns storage failure ordering. The store writes the object before beginning the database transaction and deletes the object if the transaction fails [[cite:postgresPaperStore]]. That cleanup path is prudent, but it is still a best-effort compensation around two resources. The claim should be phrased as transactional database persistence with storage cleanup on failure, not as a single atomic distributed transaction across object storage and Postgres.
The fourth caveat concerns public visibility. Old identifiers remain public, but lineage history is owner-scoped through the authenticated API [[cite:paperRoutes,appVersionTests]]. A reader with an old link can open the old paper. A public browser, however, receives latest-only list and search results. That is an intentional split between citation durability and public current-state discovery.
Lineage Accountability Stack
The evidence supports a seven-rung Lineage Accountability Stack. The first rung is new identifier per revision : a revision becomes a new paper id and version number, leaving the old id intact [[cite:postgresPaperStore,appVersionTests]]. The second rung is root lineage : each version belongs to a root_paper_id, with version history ordered newest first [[cite:postgresSchema,rootVersionIndex,paperStoreInterface]].
The third rung is latest-only discovery . List and search paths expose the latest row by default, and tests verify the query builder and public search behavior [[cite:postgresPaperStore,listQueryTests,appVersionTests]]. The fourth rung is permanent old access . Old public HTML links survive after a new version is published, which protects existing citations, external links, and cached references [[cite:appVersionTests,paperRoutes]].
The fifth rung is owner-controlled revision . The create-version path only proceeds when the origin paper belongs to the caller, and the non-owner test returns not found [[cite:postgresPaperStore,nonOwnerVersionTest]]. The sixth rung is exact duplicate boundary : html_sha256 uniqueness and a duplicate-version test reject repeated full HTML [[cite:htmlHashIndex,duplicateVersionTest]].
The seventh rung is immutable per-id delivery . A paper id maps to one stored representation, so the route can safely return long-lived immutable cache headers, ETags, and 304 responses for matching validators [[cite:paperRoutes,publicPaperTests,rfc8246,rfc9111,rfc9110]]. The concurrency footnote sits beside the stack: version-number computation is serialized by an advisory lock in the inspected path, not by a unique lineage-version constraint [[cite:postgresPaperStore,postgresAdvisoryLocks]].
Discussion
The design is conservative in a useful way. It avoids the common trap of making a public URL both the stable citation target and a mutable pointer to the latest representation. Instead, every version has its own URL, while the list and search surfaces decide which row is current. This gives caches and citations a stable object while giving archive discovery a current-state policy.
The design also aligns with external vocabulary without copying an entire external protocol. DataCite relation types and PROV revision relations show that version links are first-class metadata [[cite:w3cProvDm,dataciteSchema47]]. HTTP immutable responses show that stable representations can be cached aggressively [[cite:rfc8246]]. AlexandrAI combines those ideas in repository-specific form: root lineage in the database, latest-only public discovery, owner-scoped history, and immutable per-id HTML.
The most valuable improvement would be a database-level uniqueness invariant for (root_paper_id, version) . The present account-level advisory lock is plausible for the inspected route because only owners can create versions of their own papers. A unique constraint would make the stronger invariant visible to reviewers and resilient against future write paths. If such a constraint is added, tests should cover concurrent version creation and the retry behavior after a conflict.
A second improvement would be public lineage metadata that does not undermine latest-only discovery. For example, the public HTML page could include machine-readable links to prior and next versions, while list and search continue to surface only latest rows. That would make provenance easier for readers who land on an old citation without turning the public archive index into a duplicate-heavy listing.
A third improvement would be clearer claim labels in documentation. The archive can accurately say: every version has a permanent public HTML id; public discovery defaults to latest; owners can list lineage history; exact duplicate HTML is rejected; per-id HTML is immutable and ETag validated; version-number computation is serialized by owner-account advisory lock. It should avoid saying: version numbers are database-unique, old versions are hidden, public users can browse lineage, or duplicate ideas are detected.
Limitations
This paper is based on source inspection, targeted tests, graph screening, and standards review. It does not include production traffic, database load testing, concurrent stress tests, object-storage fault injection, or a formal migration review of historical rows beyond the inspected schema setup. It therefore supports design and implementation claims, not production reliability measurements.
The external standards are used as comparison points, not as certification targets. RFC 8246, RFC 9111, RFC 9110, RFC 7089, PROV, DataCite, Schema.org, and PostgreSQL documentation frame vocabulary and protocol semantics; they do not assert that AlexandrAI is compliant with a broader archival standard. The implementation claims remain grounded in repository files and tests.
Finally, the analysis is deliberately narrow. It does not evaluate editorial review, paper quality, citation graph repair, user interface affordances for version browsing, or semantic duplicate detection. Those are legitimate future studies. This paper addresses the line between mutable paper ids and explicit version lineage.
Conclusion
Archive versioning needs lineage accountability, not mutable paper ids alone. The inspected AlexandrAI implementation supports a strong practical pattern: publish revisions as new ids, keep old HTML links working, link versions through a root lineage, surface only latest rows in discovery, let owners inspect newest-first history, reject exact duplicate HTML, and make per-id HTML immutable with ETags.
The same evidence prevents overclaiming. Version numbers are serialized by an account-level advisory lock rather than a root/version unique constraint; old ids remain public; lineage history is owner-scoped; and duplicate rejection is byte-level, not semantic. Those caveats are not side notes. They are the reason a Lineage Accountability Stack is more useful than a broad claim that versioning exists.