CES-70 — import spec + CES-71 cadence-units audit (docs only) - #22
Merged
Conversation
Audits the shipped CES-41 export contract from the assembler and its tests (headers.dart, snapshot.dart, manifest.dart, readme.dart) rather than the 2026-04 body of export-v1.md, and turns it into an executable import spec. Locks the engineering decisions: canonical INT64 only (derived columns present but ignored), strict A1 headers imported from the export constants, cadence_km read verbatim as meters, photos fail closed, imported rows stay never-synced (row_version NULL, no outbox enqueue), ids preserved never remapped, single-transaction atomicity, FK-parent apply order with orphan rejection, and identity as advisory only so settings.id is never overwritten. Merge vs replace is left explicitly unlocked per CES-70 with both options, a recommendation (replace behind typed confirmation), and the cost of a wrong guess. Records the blocking cadence_km audit: every write path already stores meters, so CES-71 stays a cosmetic rename. Notes the one real gap -- the form-level conversion in maintenance_page._save is untested. Co-authored-by: JMNofziger <JMNofziger@users.noreply.github.com>
Same shape as ces-41-export.md, with all 13 engineering decisions locked up front. Held at BLOCKED rather than READY because Decision 0 (merge vs replace) is a product lock; naming a mode on that one line flips it to READY without further editing. Co-authored-by: JMNofziger <JMNofziger@users.noreply.github.com>
JMNofziger
marked this pull request as ready for review
August 16, 2026 12:15
This was referenced Aug 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Spec / discovery pass for CES-70. No application code, no schema migration, no CES-71 rename.
What
docs/specs/export-import.md— normative import spec, audited from the shipped CES-41 assembler (PR #21) rather than the 2026-04 body ofexport-v1.md.docs/product/prompts/ces-70-import.md— execution prompt, held at BLOCKED.docs/specs/README.md— index row.Cadence audit (blocking) — CLEAN
maintenance_rules.cadence_kmstores canonical meters on every write path, so CES-71 stays a cosmetic rename.upsertReminderRuleis the only writer; it passescadenceKmMetersthrough unconverted.maintenance_page._saveis the only caller and converts viadistanceToMeters(value, prefs);_loadRuleround-trips viametersToDisplayWhole.constraints_test.dart/roundtrip_test.dartwritesNULLcadence to exercise the table CHECK — no unit exposure.10_000_000/15_000_000are 10 000 / 15 000 km — intent matches meters.tests/client-db/fixtures/.Runtime confirmation:
One real gap, not a bug: the form-level conversion at
maintenance_page._saveis untested.maintenance_page_test.dartfills only the months field; the repository test passes meters directly, bypassingdistanceToMeters. CES-71 renames exactly that path and should add the assertion.Locked in the spec
Canonical INT64 only (derived columns must be present but are never read) · strict A1 headers imported from
client/lib/export/headers.dartso export and import cannot drift ·cadence_kmverbatim meters · photos fail closed via the CES-40 guard · imported rows stay never-synced (row_version NULL, no outbox enqueue) ·ids preserved, never remapped · single-transaction atomicity · FK-parent apply order with orphan rejection · identity advisory only,settings.idnever overwritten · foreground-only UX.Plus a 15-code error table and a 15-item test list.
Deliberately NOT decided
Merge vs replace is a product lock (CES-70 says so). The spec gives both options, a recommendation — replace, behind a typed confirmation, because a merge can never express deletions and LWW merge pre-empts the v1.x rules ADR 002 deferred — and the cost of guessing wrong in either direction.
Decision 0in the prompt is the one line that unblocks implementation.Also flagged for product: cross-account imports are permitted by design (hash mismatch is a warning, not a rejection) — confirm or override.
Verification
flutter analyzeclean ·python3 ci/telemetry-gate.pyPASS · 247 client tests green · change set is docs-only (tracked and filesystem Dart counts both 90, unchanged).One forward-reference link in the prompt points at
client/lib/export/, which resolves when PR #21 merges — the prompt already lists that merge as a prerequisite.