Skip to content

[Artifacts] Embed a deterministic build identity across all generated outputs #687

Description

@cssbruno

[Artifacts] Embed a deterministic build identity across all generated outputs

Priority

High — deployment coherence, rollback safety, and artifact observability

Context

GOWDK emits multiple coordinated artifacts from one project snapshot:

  • static page and asset output;
  • route and asset manifests;
  • build, OpenAPI, AsyncAPI, audit, and inspection reports;
  • generated application source;
  • one-binary output;
  • split frontend and backend applications/binaries;
  • WASM and generated browser assets;
  • Docker and deployment recipe files.

The deployment documentation correctly requires split frontend and backend artifacts to be deployed and rolled back together when route manifests, endpoint metadata, CSRF policy, or asset paths change. Runtime health currently exposes application/module/instance identity and an asset count, but not the identity of the compiler snapshot from which the process was built.

Build reports and manifests have schema version fields, but they do not provide one shared deterministic identity tying all emitted outputs to the same validated application plan.

Problem

Without a common build identity:

  1. A frontend from generation A can be deployed with a backend from generation B without an immediate, explicit compatibility signal.
  2. Operators cannot reliably correlate a running process with the exact route/asset/application plan that produced it.
  3. Rollback tooling must infer compatibility from filenames, release tags, or deployment timing.
  4. Health checks can report ok even when coordinated artifacts come from different generations.
  5. Logs, traces, audit findings, and bug reports cannot refer to one stable generated-artifact identity.
  6. Cache and artifact stores cannot safely deduplicate or verify complete generations using a canonical plan digest.
  7. Incremental and clean builds lack a common identity that proves convergence to the same semantic plan.

Goal

Generate a deterministic build identity from the canonical validated application plan and embed it consistently in every coordinated artifact and runtime process.

Identity model

Define at least two explicit values:

planID

A deterministic digest of the normalized, output-affecting semantic/application plan before filesystem publication. It should change when behavior or emitted artifact selection changes, including:

  • normalized pages, localized routes, endpoints, bindings, guards, schemas, and render lanes;
  • component/layout/client/WASM plans;
  • asset/CSS logical plans;
  • contracts, realtime subscriptions, and invalidations that affect output;
  • selected modules and target-relevant feature decisions;
  • output-affecting configuration;
  • generator contract/version identifiers.

It must exclude:

  • runtime secret values;
  • timestamps;
  • temporary/output absolute paths;
  • machine-specific cache locations;
  • diagnostic ordering noise;
  • process IDs and runtime instance identity.

buildID

A digest representing the complete committed artifact generation. It may equal planID when emitted artifacts are fully deterministic, or derive from planID plus a canonical sorted list of emitted relative paths, hashes, modes, and artifact kinds.

If both are retained, their semantics must be documented clearly:

  • same planID, different buildID should be exceptional and explainable;
  • equivalent clean and incremental builds should produce both the same planID and buildID.

Use a versioned domain-separated digest format, for example:

gowdk-plan-v1:sha256:<hex>
gowdk-build-v1:sha256:<hex>

Required propagation

Embed the identity in:

  • gowdk-routes.json;
  • gowdk-assets.json;
  • gowdk-build-report.json;
  • compiler manifest and relevant inspection reports;
  • OpenAPI/AsyncAPI extension metadata where appropriate;
  • generated application source/build metadata;
  • frontend and backend binaries;
  • Docker labels or generated metadata where applicable;
  • WASM artifact sidecar metadata;
  • audit/security reports;
  • runtime health/readiness payloads;
  • structured logs, metrics labels only where cardinality policy permits, and trace resource metadata;
  • frontend-to-backend proxy requests for split deployments.

Do not put the full digest into unbounded metric label dimensions. A stable process/resource field or bounded abbreviated display value is preferable.

Split deployment compatibility

For generated split frontend/backend output:

  • the frontend should send its expected plan/build compatibility identity to the generated backend through an internal header;
  • the backend should return its actual identity;
  • mismatch behavior must be explicit and configurable for development versus deployment;
  • health/readiness should report mismatch separately from process liveness;
  • browser-facing responses must not leak unnecessary internal metadata;
  • proxies must prevent clients from spoofing trusted internal compatibility headers.

Potential header names:

X-GOWDK-Expected-Build
X-GOWDK-Build

Exact names and trust rules require a small security review. The default should not trust arbitrary public inbound values as proof of internal deployment identity.

Runtime API

Expose generated metadata through a stable runtime type, for example:

type BuildIdentity struct {
    SchemaVersion int
    Compiler      string
    PlanID        string
    BuildID       string
    Target        string
    Role          string
}

Generated apps should be able to return this from gowdkapp.BuildIdentity() without reading source-tree files.

Health output might include:

{
  "status": "ok",
  "app": "site",
  "module": "frontend",
  "instance_id": "...",
  "build": {
    "plan_id": "gowdk-plan-v1:sha256:...",
    "build_id": "gowdk-build-v1:sha256:...",
    "target": "site",
    "role": "frontend"
  }
}

Canonicalization requirements

  • Canonical serialization must be package-owned and independently testable.
  • Map ordering, source discovery order, filesystem enumeration order, and locale ordering must not affect the digest.
  • Paths included in the identity must use normalized project-relative or artifact-relative forms.
  • Equivalent path separators must hash identically across supported operating systems.
  • Adding non-output-affecting diagnostics or runtime secret values must not change the identity.
  • Generator contract changes that can alter output interpretation must change the domain/version input.

The canonical application plan from #667/#668 should be the preferred source rather than hashing ad hoc output structs from multiple generators.

CLI behavior

Extend machine-readable commands with identity output and add an inspection command such as:

gowdk build-id
gowdk build-id --target site --json
gowdk inspect build-identity
gowdk verify --expect-build <id> dist/site

The exact command should avoid duplicating existing inspect conventions.

Test plan

  • same project built twice produces identical IDs;
  • clean and incremental final builds produce identical IDs;
  • source discovery order does not change IDs;
  • Windows and Unix separators produce identical semantic IDs;
  • changing a page route changes both relevant IDs;
  • changing a runtime-only secret value does not change IDs;
  • changing an output-affecting config field changes IDs;
  • changing a comment/formatting that does not alter semantic output does not change planID;
  • changing generator contract version changes the identity domain;
  • frontend/backend generated from one plan agree;
  • mixed generations report a compatibility mismatch;
  • spoofed public compatibility headers are ignored or overwritten according to policy;
  • identity appears in manifests, binaries, health, and reports;
  • abbreviated display values never become the authoritative comparison value.

Non-goals

  • Replacing release versions, Git commit IDs, or artifact attestations.
  • Hashing runtime secret values.
  • Claiming two builds are bit-for-bit reproducible solely because planID matches.
  • Exposing sensitive source paths or configuration values through health endpoints.
  • Turning build identity into a high-cardinality metric label.

Acceptance criteria

  • A versioned canonical planID algorithm is documented and tested.
  • A complete committed generation has a deterministic buildID, or the decision to equate it with planID is explicit and justified.
  • All coordinated manifests/reports carry the identity.
  • Generated frontend/backend applications and binaries embed the identity.
  • Runtime health exposes safe build identity metadata.
  • Split deployments can detect frontend/backend generation mismatch.
  • Runtime secrets, timestamps, absolute output paths, and machine-local state do not affect the identity.
  • Clean and incremental builds of the same final state produce equal identities.
  • Canonicalization is stable across supported platforms.
  • Logs/traces can correlate to the identity without violating cardinality or disclosure policy.
  • Schema and generator-contract changes have an explicit effect on identity compatibility.

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions