Lockstep version guard
Contract
| Field |
Bound contract |
| Trigger |
A human explicitly invokes the guard at a release gate. |
| Authority |
Read-only. No file, VCS, credential, paid, published, deployed, or remote mutation. Inspects local release metadata. |
| Side effect |
None; the check writes no project state. |
| Done |
Exit 0 when every checked version equals the canonical version; otherwise exit 1 with a per-file listing. |
Inputs
Supply the release root. The identity ledger catalog/plugins.json under it must provide the canonical releaseVersion and enumerate every ODIN package member, each identifying its version-bearing plugins/<id>/plugin.json via its directory field. No input is optional.
Procedure
Resolve the supplied release root without changing the working tree. Reject a missing, unreadable, or non-directory root. Done when: the release root is resolved and confirmed as a readable directory.
Read the canonical version from the releaseVersion field of catalog/plugins.json. Reject a missing, non-string, or empty version. Done when: the canonical version is read and confirmed as a non-empty string.
Read the entries array of catalog/plugins.json and collect the version-bearing manifest each entry identifies (plugins/<id>/plugin.json resolved from the entry's directory field). Require one distinct manifest per entry; reject duplicate, missing, out-of-root, or non-file paths. Do not discover or add unrelated files to make the check pass. Done when: the manifests for every catalog entry are collected.
Parse every collected file according to its declared data format and extract each release version field. Record the file path, field, parsed value, and whether it matches the canonical version. A missing, malformed, non-string, or empty field is a mismatch, not an assumed value. Done when: every collected file is parsed and its version field is recorded with match status.
Sort records by file path and field so repeated runs produce the same listing. Done when: records are sorted by file path and field.
Exit 0 only if the catalog-coverage check passed (every entry covered) and every record matches. Otherwise exit 1 and print every record, including matching records, so the release gate receives a complete per-file comparison. Done when: exit 0 (all match) or exit 1 (any mismatch) with the complete per-file listing printed.
Failure and recovery
Input-boundary failure, catalog-coverage failure, path-boundary failure, parse failure, and version mismatch all stop the gate with exit 1. Preserve every record obtained before a failure and mark unreadable or invalid entries with their exact error; never substitute a version or report partial agreement as success. Because the procedure is read-only, recovery requires no rollback: correct the release metadata outside this guard, then invoke it again. If a complete per-file listing cannot be produced, return exit 1 with the records available and a blocked entry naming each inaccessible file or unresolved catalog error.
Output
A deterministic per-file listing containing path, version field, observed value or exact error, canonical version, and match status, followed by exit 0 for complete lockstep or exit 1 for any mismatch, invalid input, incomplete catalog coverage, or blocked read.
1---2name: lockstep-version-guard3description: Use when a human invokes the release gate to prove every ODIN plugin shares one canonical version. Not for editing release metadata or remote, credential, publish, deploy, or irreversible changes.4---56# Lockstep version guard78## Contract910| Field | Bound contract |11|---|---|12| Trigger | A human explicitly invokes the guard at a release gate. |13| Authority | Read-only. No file, VCS, credential, paid, published, deployed, or remote mutation. Inspects local release metadata. |14| Side effect | None; the check writes no project state. |15| Done | Exit 0 when every checked version equals the canonical version; otherwise exit 1 with a per-file listing. |1617## Inputs1819Supply the release root. The identity ledger `catalog/plugins.json` under it must provide the canonical `releaseVersion` and enumerate every ODIN package member, each identifying its version-bearing `plugins/<id>/plugin.json` via its `directory` field. No input is optional.2021## Procedure22231. Resolve the supplied release root without changing the working tree. Reject a missing, unreadable, or non-directory root. Done when: the release root is resolved and confirmed as a readable directory.24252. Read the canonical version from the `releaseVersion` field of `catalog/plugins.json`. Reject a missing, non-string, or empty version. Done when: the canonical version is read and confirmed as a non-empty string.26273. Read the `entries` array of `catalog/plugins.json` and collect the version-bearing manifest each entry identifies (`plugins/<id>/plugin.json` resolved from the entry's `directory` field). Require one distinct manifest per entry; reject duplicate, missing, out-of-root, or non-file paths. Do not discover or add unrelated files to make the check pass. Done when: the manifests for every catalog entry are collected.28294. Parse every collected file according to its declared data format and extract each release version field. Record the file path, field, parsed value, and whether it matches the canonical version. A missing, malformed, non-string, or empty field is a mismatch, not an assumed value. Done when: every collected file is parsed and its version field is recorded with match status.30315. Sort records by file path and field so repeated runs produce the same listing. Done when: records are sorted by file path and field.32336. Exit 0 only if the catalog-coverage check passed (every entry covered) and every record matches. Otherwise exit 1 and print every record, including matching records, so the release gate receives a complete per-file comparison. Done when: exit 0 (all match) or exit 1 (any mismatch) with the complete per-file listing printed.3435## Failure and recovery36Input-boundary failure, catalog-coverage failure, path-boundary failure, parse failure, and version mismatch all stop the gate with exit 1. Preserve every record obtained before a failure and mark unreadable or invalid entries with their exact error; never substitute a version or report partial agreement as success. Because the procedure is read-only, recovery requires no rollback: correct the release metadata outside this guard, then invoke it again. If a complete per-file listing cannot be produced, return exit 1 with the records available and a `blocked` entry naming each inaccessible file or unresolved catalog error.3738## Output3940A deterministic per-file listing containing path, version field, observed value or exact error, canonical version, and match status, followed by exit 0 for complete lockstep or exit 1 for any mismatch, invalid input, incomplete catalog coverage, or blocked read.