CES-70 — lock replace mode, resolve remaining decisions, mark READY - #24
Merged
Conversation
Product locked replace over merge and confirmed cross-account imports stay a warning. Spec flips from Draft to Complete (v1); the execution prompt flips from BLOCKED to READY with MODE = replace filled in. Replace forced four follow-on decisions, two of which corrected wrong assumptions in the first draft: - settings is UPDATEd in place, never deleted -- a DELETE would destroy settings.id and violate the identity invariant. - outbox is cleared. Its table CHECK only admits the four replaced tables, so every queued mutation describes a row being destroyed; keeping them would later push replaced data. - photo_refs.draft_id is an FK to drafts, NOT fill_ups, and ttl_expires_at is an absolute stamp -- so replacing fill-ups orphans no photos and changes no TTL. The first draft claimed otherwise. - drafts are keyed by vehicle, so a draft whose vehicle is destroyed is unreachable by construction and would resurface if that vehicle id returned in a later import. Preserve drafts whose vehicle survives; discard the rest with their photos. Photo files are deleted only after commit, which the existing CES-40 orphan-file sweep already covers. Adds the technical rationale for replace (merge cannot express deletions because export omits tombstones; LWW merge would spend the v1.x merge decision ADR 002 deferred), user-facing copy for docs/UI, and a revisit gate on cross-account imports triggered by CES-46 or M3 auth. Error table 13 -> 17 codes, test list 15 -> 17 items. Co-authored-by: JMNofziger <JMNofziger@users.noreply.github.com>
Export code is on main, so client/lib/export/ is available to share from and the prompt has no outstanding prerequisites. Co-authored-by: JMNofziger <JMNofziger@users.noreply.github.com>
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.
Follow-up to PR #22 (already merged). Product locked replace over merge and confirmed cross-account imports stay a warning, so the spec flips from Draft to Complete (v1) and the execution prompt from BLOCKED to READY.
Docs only. No application code, no schema migration, no CES-71 rename.
Mode: replace
Merge is deferred to v1.x — not built, not stubbed, not selectable. The decisive argument: export deliberately omits soft-deleted rows, so a merge sees no tombstones and can never remove anything. Every row deleted on the source device would survive on the destination forever and be re-affirmed by every subsequent import. Row-level LWW would also spend the v1.x field-level merge decision ADR 002 deliberately deferred, on a design no spec defines.
Replace has one deterministic post-state, which makes the golden round-trip test a complete correctness proof rather than a set of encoded guesses.
Revisit gate: merge needs v1.x merge rules and tombstones in export. Both are prerequisites, not nice-to-haves.
Follow-on decisions replace forced
Two of these corrected wrong assumptions in the first draft, found by reading the schema rather than trusting the earlier note:
vehicles,fill_ups,maintenance_rules,maintenance_eventsDELETEthen insertids on the primary keysettingsUPDATEin place, never deletedDELETEwould destroysettings.idand violate the identity invariantoutboxtableCHECK admits only the four replaced tables, so every queued mutation describes a row being destroyeddraftsopenDraftForVehicle), so a draft whose vehicle is gone is unreachable by construction — and would resurface if that vehicle id ever returnedphoto_refs+ JPEGsdraftsphoto_refs.draft_idis an FK todrafts, notfill_ups, andttl_expires_atis an absolute stamp — so replacing fill-ups orphans no photos and changes no TTLPhoto files are deleted only after the transaction commits. An interruption then leaves files with no row, which
PhotoService.sweepalready collects asorphanFilesDeleted; deleting files first would leave rows pointing at missing files on rollback.Also added
install-*.md, a help sheet, or the confirm dialog, plus copy notes for whoever wires the UI.user_key_hashstays a warning, with re-open triggers named: CES-46 landing a real telemetry user key, or M3 (CES-42/43) introducing server accounts.REPLACEwhen local history is non-empty with an inline export-first offer; plain confirm on an empty database, since that is the new-phone path and friction there buys no safety.Error table 13 → 17 codes; test list 15 → 17 items.
Verification
flutter analyzeclean ·python3 ci/telemetry-gate.pyPASS · docs-only (three files) · all relative links and internal anchors resolve. Rebased onto currentmainso CES-41's merged export code is intact — the earlier branch was on a stale base.