Skip to content

refactor(build): separate dashboard preparation from provenance rebuilds and embed an immutable bundle #1056

Description

@ScriptedAlchemy

Priority: P2 build ownership, reproducibility and edit/compile cost. Source-confirmed repeated work and a shared-output race window; no corrupted release or benchmark reproduced.

Evidence at #707 3d955ff998eef120cd398f163c613a54e3383ccb

  • crates/tracedecay-cli/build-support/source_provenance.rs::watch_paths correctly watches the Git identity and repository-wide source inputs so the product commit/dirty state stays current.
  • crates/tracedecay-cli/build.rs::main/embed_dashboard invokes npm run build on every ordinary checkout-mode build-script run, not only after a frontend input changes. A Rust/test/docs/source-provenance edit can therefore rerun the frontend build. The opt-in skip path verifies an explicitly supplied output digest; it does not change the default invalidation coupling.
  • Preparation runs npm ci only when node_modules is absent. A directory left from an older lockfile satisfies this condition even after Cargo notices a changed package-lock.json; normal compilation does not prove the dependency installation matches the current lockfile.
  • dashboard/rsbuild.config.ts writes one checkout-global app-dist with cleanDistPath: true.
  • Build.rs validates that directory and computes its digest, then generates include_bytes! expressions pointing back into ../../dashboard/app-dist. rustc opens those paths later. A separate Cargo target directory/build or direct frontend build can clean/replace them between validation and inclusion. Cargo's lock for one target directory is not an owner for all writers of this shared frontend output. dashboard_manifest.rs checks paths and symlinks but does not retain a snapshot of their bytes.

Smaller ownership model

Separate frontend dependency preparation/building from the CLI's frequently invalidated provenance step. Reuse the existing npm scripts, manifest, bundle digest and distribution staging; do not invent another build daemon, global cache manager, source inventory or redundant manifest format.

The producer should build the intended frontend inputs/dependency lock once into an owned output. The consumer should embed one immutable bundle for the lifetime of its Rust compilation. An output owned by that build (for example a staged OUT_DIR subtree) is sufficient; a new workspace crate is not required. Compute/verify the digest of the actual staged bytes and generate includes to those same bytes. Merely copying from an actively rewritten directory file-by-file is not a coherent source snapshot: use producer completion/exclusion or an immutable producer artifact while staging.

Keep exact source-provenance invalidation. Do not 'fix' repeated npm work by omitting Git/tracked-input watches, lying about the dirty bit, removing the frontend from the binary, or silently accepting stale/empty assets. Bundle-byte integrity and provenance of the frontend source used to generate those bytes are distinct: an expected output digest must come from the applicable build/distribution owner, not from hashing whatever old directory happens to exist.

Provide one explicit dependency preparation path that honors package-lock changes. It need not run npm ci on every Rust edit. Honor the existing locked package manager workflow and fail clearly when preparation is missing/inconsistent rather than introducing network access as a fallback in a reproducible consumer build.

Keep deterministic cold/warm frontend output requirements. The current disabled Rsbuild persistent cache has a documented reproducibility reason; enabling it blindly is not this fix. Packaged crates must still embed their staged bundle without requiring a source checkout or npm installation.

Acceptance

  • A Rust-only/provenance-only change updates the compiled product identity without invoking a frontend rebuild when its actual inputs are unchanged. Measure process invocations and clean/incremental build time separately.
  • A frontend source/configuration/lockfile change prepares the new bundle and embeds its matching digest; a stale node_modules directory alone cannot attest the new dependency closure.
  • Pause one build after bundle validation/staging, rebuild/clean the producer directory from another target, then resume rustc: the first build either consumes its original complete staged bundle or refuses; never mixed bytes under the old cache tag.
  • Two isolated CARGO_TARGET_DIR builds cannot delete or rewrite each other's compiler inputs through shared app-dist cleanup.
  • Missing files, invalid paths, symlink escapes, digest mismatch and incomplete production assets still fail closed. Preserve the existing good manifest tests; add one real preparation-to-embedding boundary test instead of a duplicate path-validator suite.
  • Normal packaged/offline consumption remains independent of Node tooling, with the advertised installed dashboard available.

Related #1055 removes logo generation from the same build script; #1053 owns the vendor diff split. This issue is authored build-graph simplification, not vendored code or a claim that moving files alone saves executable bytes. No repository builds, browser tests or concurrent-build reproduction were executed during this review. Keep #707 draft.

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