Core Contract Change Guide¶
Change bijux-gnss-core only when several packages need one stable meaning.
Every public type, invariant, diagnostic, conversion, or serialized record can
affect signal, navigation, receiver, infrastructure, and command consumers.
Start with ownership and compatibility before editing code.
Trace The Blast Radius¶
flowchart TD
proposal["proposed shared change"]
shared{"same meaning required by<br/>multiple packages?"}
family["identify contract family"]
public["public API impact"]
serialized["serialized meaning"]
validation["invariants and diagnostics"]
consumers["downstream readers<br/>and writers"]
evidence["focused and consumer proof"]
proposal --> shared
shared -- no --> owner["keep with stronger owner"]
shared -- yes --> family
family --> public
family --> serialized
family --> validation
public --> consumers
serialized --> consumers
validation --> consumers
consumers --> evidence
The cheapest safe outcome is often leaving a local concept with its existing owner. Shared convenience is not enough to justify a core contract.
Choose The Maintenance Route¶
| change | operational route | required decision |
|---|---|---|
| New or changed shared type, identifier, unit, time, coordinate, or diagnostic | Change sequence | prove identical cross-package meaning and invalid states |
| Public export | Common workflows | name consumers, feature exposure, and compatibility burden |
| Artifact envelope, payload, validator, or conversion | Fixture and regression care | define version, reader policy, semantic validation, and fixture provenance |
| Numerical or timekeeping behavior | Verification commands | use independent references, properties, edge cases, and derived tolerances |
| Change spanning several contract families | Review scope | separate shared meaning from downstream runtime or scientific behavior |
| Published compatibility | Release and versioning | explain source, data, validation, and downstream impact |
| Focused local work | Local development | run the narrowest proof that can fail for the moved invariant |
Evolve Persisted Meaning Explicitly¶
flowchart LR
old["existing payload meaning"]
change{"can old and new readers<br/>assign the same meaning?"}
additive["compatible additive change"]
version["new payload version<br/>or reader policy"]
validator["semantic validation"]
fixture["independent fixture"]
consumer["old and new consumers"]
old --> change
change -- yes --> additive --> validator
change -- no --> version --> validator
validator --> fixture --> consumer
Do not change old serialized meaning in place. Parsing old bytes with a new struct is not compatibility if units, defaults, status, or validity semantics changed.
Treat Fixtures As Evidence, Not Output¶
The retained timekeeping regression corpus is active property-test evidence. The checked-in observation record is currently not referenced by tests or source. It is dormant data, not an active serialization guarantee. Do not cite it as round-trip or backward-compatibility proof until a reader test deserializes and validates it.
When an active fixture changes:
- state which contract meaning made the old bytes wrong;
- preserve the old record when compatibility still matters;
- generate expectations independently of the writer under test;
- update validator, reader, and consumer evidence in the same coherent change.
Commit And Review Boundary¶
A core commit is coherent when one contract family, its public and serialized meaning, validators, documentation, focused proof, and necessary downstream adaptations agree. Do not combine unrelated contract families merely because they share a release version.
Before completion, confirm that no higher-package algorithm, runtime state, repository layout, or command presentation leaked into core.
Sources Of Truth¶
The change rules define ownership and evolution discipline. The serialization guide, contract map, and test guide provide the compatibility and evidence routes.