Skip to content

Latest commit

 

History

History
143 lines (115 loc) · 7.23 KB

rootform-lock.md

File metadata and controls

143 lines (115 loc) · 7.23 KB

rootform.lock contract

Current format version: 1.

rootform.lock is deterministic JSON recording the project's non-embedded selections: local or OCI Dialects, local or OCI Policy Pack sources, excluded owners, and explicit replacements. Embedded units (the RF Vocabulary and the embedded Dialects in the Rootform binary) are never lock fields: they change with the binary, not per project. Terraform and OpenTofu provider versions remain owned by source code and .terraform.lock.hcl; they never enter this file.

The lock is not a semantic pin. Derived linking pins live in linked artifacts. It records no toolchain pin, no release-set pin, no embedded unit version or digest, and no unsupported-provider evidence.

Who writes this file

rootform add, rootform remove, and rootform update are the only commands that write rootform.lock. They resolve and verify every operand, validate the resulting Dialects and Policy Packs, and write canonical format 1 JSON in a fixed order. An identical change leaves the existing bytes and modification time untouched. Other commands only read the lock.

Rootform creates rootform.lock.new exclusively beside the lock while a writer runs; rootform vendor holds it too while it writes .rootform/. Another writer stops if that file exists. If a command was interrupted, remove the sentinel only after confirming no Rootform writer is running. Before replacing the lock, Rootform checks that its bytes have not changed since the command started. The new lock becomes visible through an atomic rename. An editor save between that final check and the rename may still be lost, so avoid editing the lock during a Rootform write. If a crash leaves vendored content ahead of the lock, normal commands fail closed; rootform vendor restores the selected bytes.

Use add, update, and remove for normal selection changes. Manual edits remain an advanced escape hatch when the strict reader validates them. An invalid lock stops every command that reads it with exit 3 and is never repaired automatically. Commit the lock and review its diff with the source or dependency change. See Where Rootform stores external content for the storage and vendor guarantees.

Top-level fields

  • format_version: exact string 1;
  • dialects: required array of local or OCI Dialect selections;
  • policy_packs: required array of local or OCI Policy Pack source selections;
  • excluded_owners: required array of excluded Dialect owners;
  • replacements: required array of replaced Dialect owners.

An empty lock is valid. A project with no non-embedded selection, exclusion, or replacement does not need a lock for a normal run; the lock file may be absent. run --locked requires an existing valid lock, including an empty one. Absence is never transformed into an empty selection.

rf is reserved and may never appear as an excluded or replaced owner.

Dialect selections

An OCI Dialect entry carries its owner, exact x.y.z version, exact compiled-content content_digest, and complete artifact pin: tagless OCI repository, manifest_digest, layer_digest, positive download_size, and positive install_size. Digests use lowercase sha256:<64 hex>.

A local Dialect entry carries its owner, exact x.y.z version, exact content_digest, and a relative local.path. Local authoring locks omit acquisition artifacts.

An excluded owner removes that unit's knowledge from the effective catalog without removing resource bases. A replacement names the replaced owner; the replacement unit is itself a selected Dialect with its own origin, versions, and digests. A collision of owners without an explicit replacement is an error. rf is neither replaceable nor excludable.

Policy Pack source selection

Each selected pack source carries lowercase pack name, exact x.y.z version, content content_digest, and its local or oci source. The source declares no semantic dependency versions; RF Vocabulary and Dialect dependencies are derived at linking and recorded in the linked artifact, never as independent project selections.

Pack selection is never automatic: only pack sources recorded in this section or named explicitly are evaluated. rootform check evaluates the selected Policy Packs and rootform run never evaluates them, so governance selection never changes a Form's architectures.

Validation and identity

  • one entry per Dialect owner and one pack source per pack name;
  • Dialects, packs, exclusions, and replacements use strict canonical order;
  • unknown fields, duplicate JSON keys, trailing values, invalid names, versions, digests, sizes, paths, and noncanonical order are rejected;
  • whitespace and object-field order are insignificant;
  • content and artifact digests verify independently;
  • acquisition metadata never changes semantic identity;
  • selected OCI content with another digest is never substituted;
  • a local or OCI source whose current digest drifts from a locked digest is a selection/integrity error; a relink never adopts it silently;
  • any missing, extra, changed, or differently versioned locked selection makes locked execution incoherent and refuses --locked.

Current shape is format 1. rootform init --locked never creates, normalizes, or modifies lock. Unknown formats, malformed input, and current code incompatible with locked selection fail before acquisition and are never overwritten.

Preparation and mutation

run and explicit init use the same preparation service. run never acquires packages, creates or rewrites the lock, and never mutates a selection to resolve an incompatibility. Its only implicit preparation writes are local deterministic linking and the derived linked artifact cache; explicitly requested outputs remain separate.

Preparation of external contents is an explicit operation. rootform init verifies every exact existing selection and may acquire a missing OCI package only from the immutable repository and manifest digest already recorded in the lock. rootform vendor materializes those same exact selections under the project. With --offline, init can verify a vendor tree, while vendor needs verified local sources or installed OCI content. Neither acquires content. --locked requires the lock and freezes its bytes; it does not prevent exact acquisition by init. Automatic linking stays local and never changes locked sources.

rootform init prepares exact existing selections; it does not detect providers, resolve versions, create a lock, or modify one. A missing lock means an empty selection unless --locked requires the file.

Canonical project marker is rootform.lock directly beneath the selected project root. No parent search occurs.

Canonical vendor paths are .rootform/dialects and .rootform/policy-packs. Vendor materializes only selected non-embedded Dialects and Policy Pack sources, with licenses and notices. It never materializes toolchain, RF Vocabulary, embedded Dialects, or linked-artifact cache. When used, each vendored tree is exclusive for its selected kind; missing or divergent content never falls back silently to the Rootform home or a registry. Vendor preserves exact pins without discovery, upgrade, or lock mutation.

Machine schema: ../schemas/rootform-lock.schema.json.