Release Construction
Release construction turns repository-controlled records and immutable Entry histories into one resolved model for every Stage 1 public consumer. This page is for maintainers, technical users, and coding agents changing loading, validation, routing, Changelog, or export behavior.
Purpose and Ownership
The system prevents pages, components, and exports from assembling their own interpretation of the evidence ledger. It owns:
- Read-only loading of canonical JSON records and Entry publication snapshots.
- Validation of complete record collections, histories, relationships, Stage 1 content, and release inputs.
- Selection of each Entry's newest valid published snapshot, with v2
publication_stateinterpreted explicitly and legacy v1 state derived compatibly. - Deterministic public ordering of a copied source array on each resolved current Entry.
- Resolution of Topic Trail membership, resolved trail descriptions, current and historical Methodology references, About links, dates, activity, and counts.
- Construction of canonical paths, absolute URLs, and permanent alias-redirect descriptors.
- Derivation of material public Changelog events.
- Registration of the Schema, stable-latest dataset, and immutable release-specific artifact routes.
- Read-only loading and validation of persisted production release metadata at the application boundary.
- Strict production failure and diagnostic-rich private preview results.
It does not own:
- Authoring or editing canonical content.
- Creating or persisting Entry snapshots.
- Generating release IDs or timestamps.
- Creating, rewriting, or silently substituting a persisted release descriptor.
- Projecting or serializing the dataset, writing generated artifacts, or emitting deployment redirect files.
- Rendering the Stage 1 pages or a private preview interface.
- Terminal logging, persistent logs, process exit behavior, or the current clock.
Repeatable Release Publication owns those production orchestration responsibilities. It supplies explicit metadata to this system and consumes either one complete release or its blocking diagnostics.
Inputs and Outputs
The canonical loader receives an injectable repository root and reads the approved locations under data/canonical-records/ and data/publication-snapshots/entries/. It returns located source records and loader diagnostics. Invalid JSON retains its filename and raw source text so a private preview can explain the failure.
constructReleaseModel receives:
- The loader result.
- Explicit
ReleaseMetadatawhen available. - An explicit public site origin.
- Either
productionorpreviewmode.
A successful production call returns one immutable ReleaseModel. It contains current public Entries, Methodology, Topic Trails, About content, material Changelog events, and route and permanent-alias redirect descriptors. That validated model feeds public pages, including the Stage 1 About Page, Stage 1 Changelog Page, Stage 1 Export JSON Page, Stage 1 Topic Trail Page, and Stage 1 Methodology Page, and is the input to Dataset Generation. A failed production call returns diagnostics and no release.
Preview always returns a PreviewReleaseModel. Valid sections remain available when they can be resolved without relying on invalid input; invalid records remain separate from authoritative values.
The application boundary exposes two named release sources. loadPersistedProductionApplicationRelease reads the exact production descriptor path, requires the validated production origin, and constructs a strict release. loadFixedMetadataDevelopmentApplicationRelease injects stable non-production metadata for development and test mode without writing it anywhere.
Normal Flow
- The application adapter reads canonical files through the project-owned loader. The loader enumerates filenames deterministically, parses JSON, and checks snapshot storage paths without changing any file.
- The application supplies release metadata and a site origin. Production reads metadata from the persisted descriptor; development and explicit test mode inject fixed non-production metadata. The framework-independent constructor does not read environment variables or files.
- Record schemas validate Entry v1/v2 records, Topic Trails, versioned Methodologies, About content, version-aware Methodology publication events, v1/v2 snapshots, and release metadata. Aggregate validation checks the release UUIDv7 in the same durable-ID namespace as records and snapshots, then checks slug namespaces and relationships.
- Snapshots are grouped by Entry ID. Each history is ordered by validated revision number and checked for numbering, chronology, v1/v2 materiality rules, publication-state transitions, Methodology references, and retained historical slugs.
- The newest valid public snapshot becomes the current Entry. Release resolution clones that Entry, orders its copied source array for public display, and keeps the immutable snapshot and editable canonical Entry unchanged.
- The constructor selects the highest validated Methodology semantic version as current, retains all version references, and resolves routes, Topic Trail membership and descriptions, Methodology and About links, derived dates, latest meaningful activity, trail counts, and trail Last Activity. Each trail receives its own copied Entry list in latest-update order.
- Material snapshots and the Methodology publication event form the public Changelog.
- Production returns the release only when no blocking diagnostic remains. Preview returns trustworthy partial results, invalid source records, and all diagnostics. Dataset projection happens only after a successful production result.
The operation is deterministic. Identical records, snapshots, release metadata, and site origin produce the same result because the constructor does not generate IDs, read the clock, or inspect filesystem timestamps.
Persisted Release Metadata Boundary
PersistedReleaseDescriptor is the validated ReleaseMetadata shape stored at generated/release-data/release.json. The read-only adapter resolves that exact path beneath an injected repository root, parses JSON, and validates it with releaseMetadataSchema.
Production loading fails closed when the descriptor is missing, unreadable, malformed, or schema-invalid. It never falls back to the fixed development/test metadata. Ordinary builds, development starts, page renders, and tests do not create a UUID, read the clock, or write the descriptor.
The fixed adapter is explicitly non-production. Its constants make local and automated output reproducible, but they are not genuine release state and must not be written into canonical records or persisted as a production descriptor. The Stage 1 Release Gate (Historical) was the sole creator of the initial genuine descriptor. It validated a candidate release before exclusive creation, preserved the winning descriptor during a creation race, and never rewrote an existing descriptor.
Production and Private Preview
Production requires a root-only HTTPS origin, valid release metadata, one complete About record, at least one complete Methodology version and matching publication event per version, at least one public Entry, and no empty Topic Trail. The highest validated semantic version is current; when v2 is present it supplies the current Methodology and Dataset v2 route while v1 remains available at its immutable version route. The application adapter fails clearly when PUBLIC_SITE_ORIGIN is absent or invalid. A missing or invalid requirement blocks the complete release.
Preview may use an explicitly supplied HTTPS origin or HTTP localhost. The application adapter defaults an omitted preview origin to http://localhost:4321, even when a production origin exists in the environment. Missing release metadata keeps release-independent information available, but the preview is non-promotable and cannot expose a release-specific dataset artifact path or enter dataset generation.
This diagnostic preview mode is separate from a Cloudflare Pages preview deployment. Git-integrated Pages previews run a production-shaped static build with the committed descriptor and PUBLIC_SITE_ORIGIN=https://vydex.pages.dev, so their temporary preview hostnames never become canonical URLs. Cloudflare Pages Deployment owns that hosting behavior.
Invalid preview records are not repaired. The preview keeps their record type, recoverable ID, filename, raw or partial value, field diagnostics, and unresolved relationship diagnostics. The Topic Trail page may present Missing Required Field and Last Activity: Unknown, but the constructor never inserts those fallbacks into records, resolved release values, routes, Changelog events, or exports.
Any blocking diagnostic sets promotable: false. A loader-invalid source may appear in diagnostics, but it cannot contribute to public selection, counts, ordering, routes, Changelog events, or export records.
Snapshot Authority and Material Activity
Every canonical Entry must have a valid snapshot history, and every history must match one canonical Entry by stable ID. The current public state comes from the newest snapshot, not the editable Entry. This allows unpublished edits to exist without leaking into a release.
Date Added comes from the first publication timestamp. Date Updated and latest meaningful activity come from the newest material revision. Latest meaningful activity also retains the Entry title from that material snapshot.
Resolved public Entries sort by latest meaningful activity timestamp descending, Date Added descending, then immutable Entry ID ascending. The shared pure comparator is used by the Stage 1 Homepage and Entry route neighbor projection, so a non-material correction or title-only change cannot move an Entry in either list or change its Previous/Next neighbors.
Each resolved Topic Trail has a separate latest-update comparator. It uses latest meaningful activity timestamp descending, Date Added descending, the retained material title alphabetically in English, then immutable Entry ID ascending. This extra title key applies only inside Topic Trail lists. A later non-material title correction may change the displayed current title but cannot change trail order or Last Activity.
Stage 1 production uses the newest snapshot's publication state to determine whether an Entry is public. A v2 removed snapshot is historical lifecycle state and must not become a current public route or export record; legacy v1 snapshots derive the equivalent state from entry_state. Removal and restoration remain represented in immutable history and Changelog data.
Routes and Redirects
Route collision checks operate on normalized root-relative pathnames before the constructor creates absolute URLs. The registry owns the homepage and #latest anchor, current Entry and Topic Trail routes, current and versioned Methodology routes, About, Changelog, export landing, dataset Schema, stable-latest dataset, and release-specific dataset artifact paths. Artifact paths use the Release ID directory and a basename dated from the validated UTC generated_at value through the shared route derivation function.
The resolved Methodology pairs the highest validated canonical record with separate current and immutable absolute URLs, and retains version-specific references for every loaded Methodology. The Methodology Page consumes those URLs directly for route-specific canonical metadata; Entry records continue to carry the immutable version URL assigned by their published snapshot.
Entry and Topic Trail aliases produce permanent 301 redirects. The stable-latest dataset path is not an alias and does not use that contract; Dataset Generation returns a separate 302 descriptor whose destination changes with each release.
Current slugs create canonical routes. Historical aliases create 301 redirect descriptors that point directly to the current route. Redirect sources must be unique, cannot collide with current routes, and cannot form loops or chains. This system returns descriptors only; the release gate translates them into the staged Cloudflare _redirects file and verifies the emitted rules.
About content authors provide titles and descriptions for its related links, while the route registry supplies the destinations. Authored About data therefore cannot drift from the canonical Methodology, Changelog, or export routes.
The About Page consumes the resolved record directly. It uses the registered About route and validated site origin for its self-canonical URL, while its Related Links use the absolute destinations already attached by release construction.
Changelog and Dataset Input
Entry Changelog events come only from material snapshots:
initial_publicationbecomesadded.material_updatebecomesupdated.removalbecomesremovedwhen historical data contains one.
The separately authored Methodology publication events become methodology_change. Legacy v1 events resolve their Methodology version through methodology_id; v2 events also carry methodology_public_version, which is checked against the referenced record. Every resolved event exposes the same required published_at field and a public calendar date derived from it. Events sort uniformly by published_at newest first, then the approved event-type order, public title alphabetically in English, and stable source_identity. Entry events use the immutable revision ID; the Methodology event uses the affected Methodology ID. Exact timestamps and tie-breakers are internal ordering data rather than public display fields.
Methodology effective_date is not an event-ordering field. The canonical v1 event uses the one-time migrated timestamp 2026-07-24T19:21:21.438Z; the v2 event carries its explicit public version and genuine publication timestamp. Future Methodology publication events must author their genuine timestamp at publication rather than infer it from a UUID, Git history, or the effective date.
Release construction retains the selected snapshot, derived revision activity, canonical URL, resolved Topic Trail name and description, resolved version-specific Methodology reference, and publicly ordered copied sources for every current Entry. It does not create public export records. The Stage 1 Entry Page renders that resolved order and trail description directly, while the separate dataset generator uses the same resolved state so pages and exports cannot disagree about which revision or relationship is current.
The source-ordering module owns one pure comparator: Source Role follows the approved evidence-role cascade, and an English alphabetical title comparison breaks ties. Its ordering helper sorts a copied array. Dataset generation defensively reapplies that same helper to copied input, derives labels and Evidence Types, validates the serialized result against its Schema, and returns immutable artifact metadata. Domains retain their validated order. The filesystem writer remains a separate adapter.
Failure Behavior
Diagnostics identify the record type, field or rule, recoverable record ID, filename, invalid value, and related record when those values exist. Production does not return a partial release when any blocking error remains.
Blocking conditions include malformed JSON, invalid snapshot paths, invalid records, missing or orphan histories, broken relationships, duplicate or colliding routes, incomplete required content, missing or invalid material-event timestamps, wrong Methodology references, removed current Entries, empty Topic Trails, invalid origins or release metadata, and permanent-alias redirect failures.
The loader and constructor return diagnostics without writing to standard output or standard error. The release gate enriches them with affected generated surfaces, formats the private report, and returns a non-zero command result.
Internal Edge Cases
- Missing canonical directories load as empty collections, allowing release validation to report the absent Stage 1 requirements.
- Only
.jsonauthoring files are loaded. Snapshot discovery is recursive only under the snapshot Entry root. - Snapshot directory and filename metadata must agree with the parsed snapshot, but revision ordering comes from validated contents.
- Standard URL parsing can normalize invalid-looking paths; origin validation also checks the supplied syntax so query delimiters, fragments, and non-root paths remain invalid.
- An invalid record with a recoverable ID remains visible in preview but cannot make an incomplete aggregate appear authoritative.
- Topic Trail membership includes both primary and secondary relationships. Every loaded trail must contain at least one selected public Entry, and sorting a trail does not reorder
current_entries. - The current Entry title and retained material title may differ after a non-material correction. Trail ordering uses the retained material title; public Entry content continues to use the selected current snapshot.
- Public source ordering never mutates the canonical Entry, an immutable snapshot, or its source objects. Source labels, Evidence Types, URLs, publishers, and
used_forvalues remain attached to the same citation after sorting.
Cross-System Edge Cases
- Canonical Records owns stored shapes and record-local rules. Release construction consumes those schemas rather than widening or repairing them.
- Publication Revisions owns snapshot creation, history semantics, and material activity. Release construction validates complete stored histories and selects their current state.
- Dataset Generation owns versioned public export projection, Schema validation, deterministic serialization, immutable artifact descriptors, and the dataset filesystem writer boundary.
- The Entry Preview consumes a typed subset of
ResolvedPublicEntry. It must use resolved dates, Topic Trail data, and canonical URLs rather than load, infer, or repair authoring records. - The Stage 1 Entry Page consumes the complete
ResolvedPublicEntry, including its publicly ordered sources. It must not introduce a page-local comparator. - The Stage 1 Methodology Page consumes
ResolvedMethodology, including its current and version-specific canonical URLs. It must not reconstruct those URLs from the request pathname. - The Stage 1 About Page consumes
ResolvedAboutRecord. It must not load authoring JSON, repair missing content, or reconstruct Related Link destinations. - The Stage 1 Changelog Page consumes the ordered material-event collection, validates its display projection, and groups derived dates without adding a second comparator or exposing exact times.
- The Stage 1 Export JSON Page prepares Dataset
2.0.0for the current v2 release, or the retained Dataset1.0.0contract for a legacy release, from this same release. It must not load a second descriptor or reconstruct the artifact route. - The Stage 1 Homepage consumes
current_entriesand reuses the release comparator. It does not add filtering, title ordering, or a second material-activity field. - The Stage 1 Topic Trail Page consumes one resolved non-empty trail with its ordered Entries, count, Last Activity, and canonical URL. It verifies consistency but does not rebuild membership or ordering.
- Static Application Foundation owns the Astro build and dependency direction. Astro pages must consume the shared application release adapter instead of parsing authoring files.
- Release metadata persistence remains outside the canonical loader and domain constructor. Rebuilding the same release with the same persisted descriptor preserves its ID, generation timestamp, and deterministic output.
- Cloudflare preview URLs are hosting addresses, not release-construction inputs. Pages preview builds must pass the production origin into the strict application adapter.
- The repository contains the complete Stage 1 seed record set and initial production descriptor. Tests and development page builds inject fixed metadata through the named non-production adapter without creating or persisting genuine release state. Ordinary production builds require the persisted descriptor and never generate a replacement.
- The release gate caches one production application-release load during its Astro build so every generated route consumes the same in-memory model. Ordinary builds retain their existing uncached behavior.
Invariants
- One release model is the source for homepage, Entry, Topic Trail, Methodology, About, Changelog, Export JSON, route, redirect, and dataset consumers.
- Invalid records are never silently omitted, repaired, or promoted into authoritative derived values.
- Public Entry state and relationships come from immutable snapshots; editable differences remain unpublished.
- Resolved current Entries expose sources in deterministic public order without changing canonical records or immutable snapshots.
- Non-material revisions do not change material activity ordering, Topic Trail ordering, Trail Last Activity, or public Changelog events.
- Stable IDs resolve relationships; filenames and slugs do not.
- Canonical URLs come from a validated explicit origin and the route registry.
- Release metadata is supplied unchanged and is never generated or inferred.
- Production release metadata comes only from
generated/release-data/release.json; fixed development/test metadata is never a fallback. - Production returns either one complete internally consistent release or no release.
- Loader and domain code remain free of logging and write side effects.
Implementation Landmarks
src/adapters/canonical-record-loader/— Read-only repository JSON loading and path diagnostics.src/adapters/application-release/— Environment-facing origin configuration and the single application release call.src/adapters/public-site-origin/— Root-only absolute HTTPS production-origin validation.src/adapters/persisted-release-descriptor/— Exact-path descriptor reading, JSON parsing, and Schema validation.src/adapters/stage-one-release-descriptor/— Exclusive creation and immutable reuse of the initial Stage 1 descriptor.src/domain/release-construction/— Validation orchestration, preview handling, and resolved release models.src/release/stage-one-release/— Production orchestration that consumes this domain boundary.src/domain/release-construction/compare-resolved-public-entries.ts— Shared material-activity ordering comparator.src/domain/release-construction/compare-resolved-topic-trail-entries.ts— Topic Trail latest-update comparator with the material-title tie-breaker.src/domain/release-construction/derive-changelog.ts— Material-event projection, derived calendar dates, and uniform timestamp/type/title/identity ordering.src/domain/source-ordering/— Shared public source comparator and copied-array ordering helper.src/domain/route-generation/— Origin, route-registry, canonical URL, and redirect contracts.src/domain/json-export-generation/— Post-release Dataset v1/v2 projection, Schema, validation, and serialization.tests/adapters/andtests/domain/— Loader, production, preview, routing, Changelog, dataset, and writer coverage.
Before Changing Release Construction
Check:
- Whether a value is authored, stored in a snapshot, supplied as release metadata, or derived for one release.
- Whether preview output remains honest when an invalid record could change membership, counts, ordering, routes, or exports.
- Whether public Entry selection still ignores unpublished editable differences.
- Whether material activity remains separate from the current revision after a non-material update.
- Whether release resolution and Homepage selection still share the same material-activity, Date Added, and immutable-ID comparator.
- Whether Topic Trail resolution still uses material activity, Date Added, the retained material title, and immutable Entry ID without mutating
current_entries. - Whether release resolution and Dataset generation still share the public source comparator while canonical and snapshot arrays remain untouched.
- Whether the selected current Methodology is the highest validated semantic version and every Entry keeps its exact Methodology reference.
- Whether v2 publication state keeps removed history out of current public routes and exports while preserving legacy v1 state compatibility.
- Whether production descriptor loading still uses the exact reserved path and fails instead of falling back to fixed metadata.
- Whether production and Pages preview builds still require an explicit validated production origin while diagnostic previews retain their localhost default.
- Whether the release UUIDv7 still participates in the global durable-ID collision check.
- Whether route and alias checks run before absolute URL generation.
- Whether every page-facing value still comes from the shared release model.
- Whether dataset behavior belongs in Dataset Generation rather than the release constructor.
- Whether a proposed filesystem, environment, clock, logging, or output side effect belongs in an adapter or the release gate instead of the domain constructor.
- Whether tests cover both strict production rejection and diagnostic preview behavior.