Skip to content

CES-70 — import spec + CES-71 cadence-units audit (docs only) - #22

Merged
JMNofziger merged 2 commits into
mainfrom
cursor/ces-70-import-spec-40e4
Aug 16, 2026
Merged

CES-70 — import spec + CES-71 cadence-units audit (docs only)#22
JMNofziger merged 2 commits into
mainfrom
cursor/ces-70-import-spec-40e4

Conversation

@JMNofziger

Copy link
Copy Markdown
Owner

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 of export-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_km stores canonical meters on every write path, so CES-71 stays a cosmetic rename.

  • upsertReminderRule is the only writer; it passes cadenceKmMeters through unconverted.
  • maintenance_page._save is the only caller and converts via distanceToMeters(value, prefs); _loadRule round-trips via metersToDisplayWhole.
  • Raw SQL in constraints_test.dart / roundtrip_test.dart writes NULL cadence to exercise the table CHECK — no unit exposure.
  • Repo-test values 10_000_000 / 15_000_000 are 10 000 / 15 000 km — intent matches meters.
  • No cadence references in PWA-lite or tests/client-db/fixtures/.

Runtime confirmation:

km entry 10   -> 10000 m stored        10000 m    -> 10 km shown
km entry 5000 -> 5000000 m stored      16093 m    -> 10 mi shown
mi entry 10   -> 16093 m stored        10000000 m -> 10000 km shown
mi entry 5000 -> 8046720 m stored

One real gap, not a bug: the form-level conversion at maintenance_page._save is untested. maintenance_page_test.dart fills only the months field; the repository test passes meters directly, bypassing distanceToMeters. 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.dart so export and import cannot drift · cadence_km verbatim 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.id never 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 0 in 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 analyze clean · python3 ci/telemetry-gate.py PASS · 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.

Open in Web Open in Cursor 

cursoragent and others added 2 commits August 16, 2026 11:59
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
JMNofziger marked this pull request as ready for review August 16, 2026 12:15
@JMNofziger
JMNofziger merged commit 440ae64 into main Aug 16, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants