You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit dee5b27
Browse filesBrowse the repository at this point in the historyBrowse files
Bundle 7 on top of shared state/cache. Turns the opaque contract_hash
change into a structured, machine-readable contract diff and gates
promotion on breaking contract changes, computed live.
- contracts.rs: contract_diff classifies SAFE/REVIEW/BREAKING per
change — contract added/dropped, enforcement on/off, column
added/removed/renamed, type changes (numeric widening review,
incompatible breaking), nullability tighten/relax.
- Declared renames: [model.<name>.renames] new = "old" resolves a
removed+added pair into a reviewable rename in both contract and
physical schema diffs. Stale or ambiguous declarations resolve
nothing — they cannot hide a real removal or addition.
- MaterializedRecord persists the full contract (contract_json,
SQLite + Postgres with migration), so base/target comparisons work
against what the environment actually recorded.
- BranchDiffReport gains contract_changes and lineage-aware impacts
naming the downstream models/tests a breaking change affects.
- Promotion: contract breaks join physical schema breaks in the schema
gate, computed live against the target's recorded contracts — a
contract edited after `diff` cannot slip past on a stale artifact.
--allow-breaking-schema waives both.
- plan/explain reasons name the changed columns and breaking count
instead of "contract or assertions changed".
Copy file name to clipboardExpand all lines: SPEC.md
+9-1Lines changed: 9 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -811,6 +811,14 @@ type = "DOUBLE"
811
811
nullable = false
812
812
```
813
813
814
+
Column renames are declared alongside the contract so diffs can classify a
815
+
removed+added pair as a rename rather than a breaking removal:
816
+
817
+
```toml
818
+
[model.assay_results.renames]
819
+
result = "legacy_result"
820
+
```
821
+
814
822
Explicit contract files remain optional.
815
823
816
824
## 32. Inferred tests
@@ -1069,7 +1077,7 @@ phlo transform promote feature/new-assay --to main
1069
1077
phlo transform promote --from feature/new-assay --to main
1070
1078
```
1071
1079
1072
-
Promotion is authorised by named gates, reported identically in human and JSON output: `run` (latest candidate run passed and validated the exact commit being promoted — a passed run is bound to the candidate head **after** its writes land, and a candidate that advanced since its run, or a run recorded before commit binding, fails), `tests` (no failed tests), `blocked` (no blocked/cancelled model, seed or test work), `schema` (a fresh audited diff inspected this pair at these commits and found no unwaived breaking changes — absent or stale evidence fails closed, never reading "no evidence" as "no changes"), `data_diff` (when `--require-diff` is set: a passing `--full` audited diff bound to this candidate→target pair at the commits being promoted — the artifact records both refs' resolved heads and is rejected when they no longer match — still fresh per recorded versions, and never a self-comparison; a single-model `diff.json` is never promotion evidence), `base` (the target still equals the commit the evidence was established against — the hash-bound artifact's recorded base, else the candidate's `created_from` provenance; unknown provenance fails rather than redefining the base as the current head, and the merge asserts the evaluated target hash) and `conflicts` (the merge check is clean). A candidate that advanced between gate evaluation and merge is refused rather than promoted unaudited. `--check` evaluates gates without merging; a passing promotion merges and persists a `PromotionRecord` (refs, hashes, plan/run ids, gate results, timestamp) in the state store.
1080
+
Promotion is authorised by named gates, reported identically in human and JSON output: `run` (latest candidate run passed and validated the exact commit being promoted — a passed run is bound to the candidate head **after** its writes land, and a candidate that advanced since its run, or a run recorded before commit binding, fails), `tests` (no failed tests), `blocked` (no blocked/cancelled model, seed or test work), `schema` (a fresh audited diff inspected this pair at these commits and found no unwaived breaking changes — physical breaks come from the audited diff; contract breaks are computed live from the workspace's desired contracts against the target's recorded contracts, so a post-`diff` contract edit cannot slip past — and absent or stale evidence fails closed, never reading "no evidence" as "no changes"), `data_diff` (when `--require-diff` is set: a passing `--full` audited diff bound to this candidate→target pair at the commits being promoted — the artifact records both refs' resolved heads and is rejected when they no longer match — still fresh per recorded versions, and never a self-comparison; a single-model `diff.json` is never promotion evidence), `base` (the target still equals the commit the evidence was established against — the hash-bound artifact's recorded base, else the candidate's `created_from` provenance; unknown provenance fails rather than redefining the base as the current head, and the merge asserts the evaluated target hash) and `conflicts` (the merge check is clean). A candidate that advanced between gate evaluation and merge is refused rather than promoted unaudited. `--check` evaluates gates without merging; a passing promotion merges and persists a `PromotionRecord` (refs, hashes, plan/run ids, gate results, timestamp) in the state store.
1073
1081
1074
1082
Preconditions may include successful plan, successful execution, required tests passing, no blocking schema changes, no stale state and optional approval.
0 commit comments