# Migration Guide
This guide covers breaking changes between releases of `odcs` and `pyodcs`.
## 0.9.x → 1.0.0 { #09x-100 }
### Deprecated strict API removed
**Before (0.9.x):** `--strict` (CLI), `strict=True` (Python), `validate_strict()`, `ValidationOptions`, and `validate_with_options()` were deprecated no-ops.
**After (1.0.0):** Removed. JSON Schema validation always runs in `validate()` — no flag required.
**Action:**
```bash
# Remove --strict from CI scripts
odcs validate contract.yaml
```
```python
# Remove strict= keyword
pyodcs.validate(contract)
pyodcs.parse_and_validate(content, "yaml")
pyodcs.parse_and_validate_paths(primary, deps=[...])
```
```rust
// Use validate() instead of validate_strict() / validate_with_options()
use odcs::validate;
let report = validate(&contract);
```
**Unchanged:** `parse_strict()` — still means parse + validate + return `DataContract` (not related to the old CLI flag).
### API stability
See [API stability policy](../implementation/api-stability.md). Root re-exports in `odcs` are stable; `#[doc(hidden)]` internal modules are not.
## 0.8.x → 0.9.0
### Local contract registry
**After (0.9.0):** Index a directory of contracts and resolve cross-file FQNs without listing every dependency:
```bash
odcs registry index ./contracts/
odcs validate consumer.yaml --registry ./contracts/
```
Python:
```python
pyodcs.registry_index_and_save("./contracts/")
pyodcs.parse_and_validate_paths("consumer.yaml", registry="./contracts/")
```
Lookup helpers: `registry_lookup`, `registry_list`, `registry_load`.
**Action:** Run `odcs registry index` after adding or changing contracts under your registry root. Re-index explicitly when files change (no auto-reindex on validate).
## 0.7.x → 0.8.0
### Section semantics
**After (0.8.0):** Additional business rules in the sections validation phase:
- Unique non-empty `roles[].id` values
- `support[].url` required when `tool` is `slack`, `teams`, `discord`, `googlechat`, `ticket`, or `other`
- Non-empty `slaProperties[].scheduler` requires non-empty `schedule`
- `price.priceAmount` requires `price.priceCurrency`; negative amounts rejected
**Action:** Run `odcs validate contract.yaml --json` and fix section semantics violations.
### Cross-file references
**After (0.8.0):** Fully-qualified relationship endpoints resolve when dependency contracts are loaded:
```bash
odcs validate consumer.yaml --dep provider.yaml --include ./contracts/
```
Python: `pyodcs.parse_and_validate_paths(primary, deps=[...])`
### Compatibility analysis
**After (0.8.0):** Compare contracts with `odcs diff old.yaml new.yaml` (exit `1` when breaking changes exist). Python: `pyodcs.diff(old_dict, new_dict)`.
## 0.6.x → 0.7.0 { #06x-070 }
### Structural cross-field validation
**Before (0.6.x):** Cross-field rules (duplicate schema object names, duplicate server identifiers, dangling SLA element references) were not enforced.
**After (0.7.0):** The structural validation phase checks:
- Unique non-empty `schema[].name` values (`odcs:invalid-schema`, `validationPhase: structural`)
- Unique non-empty `servers[].server` values (`odcs:invalid-schema`)
- `slaProperties[].element` tokens must reference existing `schema[].name` values (`odcs:unresolved-reference`)
- `slaDefaultElement`, when set, must reference an existing `schema[].name` (deprecated field; same element-path semantics)
**Action:** Run `odcs validate contract.yaml --json` and fix contracts with duplicate names or dangling SLA element references. If you use `slaDefaultElement`, ensure it names a schema object (not an SLA `property` name).
## 0.5.x → 0.6.0
### `validationPhase` on validation diagnostics
**Before (0.5.x):** Validation diagnostics included `stage: validation` but no pipeline phase metadata.
**After (0.6.0):** Every validation-stage diagnostic includes `validationPhase` (camelCase JSON) identifying the validator module (`document`, `schema`, `quality`, `jsonSchema`, …). Parse-stage diagnostics omit the field. CLI text output adds a `phase:` line when set.
**Action:** CI filters that relied on parsing `message` text can use `validationPhase` instead. Python consumers can use `pyodcs.VALIDATION_PHASES`. No changes required for well-formed contracts; diagnostic `id` values are unchanged.
## 0.4.x → 0.5.0 { #04x-050 }
### Nested duplicate keys fail parse
**Before (0.4.x):** Duplicate YAML keys at nested depths were silently overwritten by `serde_yaml` and never reported. JSON duplicate keys reported `object_ref` as the bare key name only.
**After (0.5.0):** Duplicate mapping keys at any depth fail parse with `odcs:duplicate-key` and a path-style `object_ref` (e.g. `schema[0].name`). JSON nested duplicates use the same path format.
**Action:** If CI previously accepted YAML contracts with nested duplicate keys, fix those contracts or expect parse failures (exit code `2`).
No API removals or changes to validation semantics for well-formed documents.
## 0.3.x → 0.4.0
### JSON Schema validation is always on
**Before (0.3.x):** JSON Schema validation ran only with `--strict` (CLI) or `strict=True` (Python).
**After (0.4.0):** `validate()` always runs JSON Schema validation against the pinned ODCS v3.1.0 schema. Deprecated `--strict` / `strict=True` aliases were removed in **1.0**.
**Action:** Remove `--strict` from CI scripts if you added it only for schema checks. Expect more validation failures on contracts that passed semantic checks but violate JSON Schema.
### `version` vs `apiVersion`
**Before:** Some examples and tooling conflated `version` with the ODCS specification release.
**After:** `version` is your contract document revision (e.g. `1.0.0`). Only `apiVersion` gates spec support (`v3.1.0`).
```yaml
version: "1.0.0" # your contract semver
apiVersion: "v3.1.0" # ODCS specification version
```
**Action:** Audit contracts using `version: "3.1.0"` — change to a contract revision and keep `apiVersion: "v3.1.0"`.
### Stricter default validation
0.4.0 adds default checks for:
- Quality rule dimensions and library comparison operators
- `logicalType` enums
- Server `type` enums and type-specific required fields
- Relationship `type` enum (`foreignKey`)
**Action:** Run `odcs validate contract.yaml --json` and fix new `odcs:invalid-quality`, `odcs:invalid-schema`, or `odcs:json-schema-violation` diagnostics.
### `odcs schema` default output
**Before:** Default printed upstream repository URL only.
**After:** Default prints the full pinned JSON Schema. Use `--url-only` for URL-only output.
### Library API changes
| `validate_strict()` | Alias for `validate()` | **Removed** — use `validate()` |
| `ValidationOptions::strict()` | No additional effect | **Removed** |
| `validate_with_options()` | `strict` flag ignored | **Removed** |
## 0.2.x → 0.3.0
### Unknown fields rejected
**Before (0.2.x):** Extra fields at the root or in nested objects might be ignored.
**After (0.3.0):** Unknown fields produce `odcs:unknown-field`. Use `customProperties` for extensions.
```yaml
customProperties:
- property: myExtension
value: value
```
### Quality rules moved under `schema[]`
**Before:** Root-level `quality` may have been accepted.
**After:** Quality rules must be nested under `schema[]` objects or properties per ODCS v3.1.0.
### Library metric names
v3.1.0 library metrics: `nullValues`, `missingValues`, `invalidValues`, `duplicateValues`, `rowCount`. Legacy names like `not_null` fail validation.
### Canonical Object Model
0.3.0 introduced the full ODCS v3.1.0 object model (SLA, team, servers, roles, pricing, support, relationships). Parsing uses `deny_unknown_fields` on model types.
## 0.1.x → 0.2.0
0.2.0 added CI/release workflows, PyO3 bindings, and the `pyodcs` package. The CLI gained `validate`, `inspect`, `diagnostics`, `schema`, and `version` commands with standardized exit codes.
## Getting help
- [FAQ](faq.md) — common validation errors
- [Diagnostics](diagnostics.md) — error code reference
- [CHANGELOG](../changelog.md) — full release notes