E1-11: vehicle outbox payload entityType fix - #45
Merged
Conversation
Add VehicleOutboxMapperTest covering the Vehicle snapshot and cascade Fuel Entry tombstone payloads, and extend the create, update and delete repository tests to assert entityType presence. Add coalescence tests proving a cascade delete after (or before) a direct Fuel Entry write yields a payload that still carries entityType. Extend VehicleRepositoryTestScope with seedFuelEntryOutbox to seed an existing FUEL_ENTRY outbox row.
… payloads Add "entityType":"VEHICLE" to LocalVehicle.toVehicleOutboxPayloadOrNull and "entityType":"FUEL_ENTRY" to FuelEntryDatabaseRow.toFuelEntryTombstonePayload so every outbox payload produced by :feature:vehicle conforms to docs/CONTRACTS.md §8.
Merge the two near-identical coalescence tests into a single test that loops over the stale payload variants, keeping the same coverage of a cascade delete preceded by a direct Fuel Entry outbox write.
Apply ktlint formatting to VehicleOutboxMapperTest and add entityType to the outbox payload key set assertion in the shared VehicleFormStateHolderTest so it matches the corrected mapper output.
Complete the handoff with acceptance evidence and files changed, and append the E1-11 story entry to docs/PROJECT_LOG.md.
davidru85
deployed
to
cloud-runtime-verification
September 1, 2026 19:28 — with
GitHub Actions
Active
…enum Replace outbox lookup keys and seeds in :feature:vehicle commonTest with EntityType.*.name (already on the classpath via :core:sync). Keep payload value assertions as exact string literals — the contract wire-value anchor. Add entityTypeEnumNamesMatchTheOutboxWireValues as a characterization pin so an enum rename fails the build instead of silently changing persisted and pushed payloads.
davidru85
deployed
to
cloud-runtime-verification
September 2, 2026 07:09 — with
GitHub Actions
Active
…urce of truth Add E3-13 backlog entry and story index row for the Phase 3 story that centralizes the entityType token. Create GitHub issue #46. Update the E1-11 handoff risks section to reference the follow-up.
davidru85
deployed
to
cloud-runtime-verification
September 2, 2026 07:14 — with
GitHub Actions
Active
Fix five owner-review findings on PR #45 (documentation-only): 1. Restore the accidentally deleted '### 2026-09-01 — E1-10 second-review verification and lifecycle corrections' header in docs/PROJECT_LOG.md. This is a repair of accidentally deleted content, not a rewrite of history. 2. Correct the Human Review Gate record in docs/handoff-E1-11.md to declare the four gated paths touched (AGENTS.md, SPECIFICATION.md, DECISION_BOARD.md, docs/adr/**). 3. Update the In-Progress Checkpoint to the post-fix state. 4. Add missing trailing newlines to ADR-0111 and the handoff. 5. Add 'Closes #36' and check the Gated path line in the PR #45 body. Append a correction entry to docs/PROJECT_LOG.md.
davidru85
deployed
to
cloud-runtime-verification
September 2, 2026 08:18 — with
GitHub Actions
Active
…xcluded Add FirebaseRemoteSyncSourceEntityTypeBoundaryTest proving that: - a valid Vehicle payload with entityType succeeds but the current code leaks entityType into Firestore fields; - a mismatched entityType is not rejected; - a missing entityType is not rejected; - the same applies to Fuel Entry payloads. Make RecordingFirestoreGateway internal so the new test file can reuse it.
…at the boundary Require the outbox payload entityType to match EntitySnapshot.entityType and exclude it from FirestoreWrite.fields, so connected Vehicle and Fuel Entry writes conform to the closed remote schema of docs/CONTRACTS.md §16. A missing, unknown, or mismatched entityType fails as RemoteError.InvalidArgument through the existing closed error API. Update the existing push/pull tests to include entityType in the outbox JSON and compare pull results against the remote (entityType-free) JSON. Add an end-to-end regression test in :shared proving an actual Vehicle outbox payload with entityType reaches RemoteSyncSource as a valid EntitySnapshot.
…cord Finding 2: assert the exact canonical Fuel Entry payload key set in the coalescence test, add cascade-idempotency test, and add a cross-feature parity test in :shared proving the direct Fuel Entry writer and the Vehicle cascade-delete writer produce the same canonical key set. Finding 3: correct ADR-0111 to declare the gated paths touched by E1-11 instead of denying the human review gate. Update handoff, project log, and PR body with the final state.
davidru85
deployed
to
cloud-runtime-verification
September 2, 2026 09:04 — with
GitHub Actions
Active
This was referenced Sep 2, 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.
Summary
docs/CONTRACTS.md §8compliance of every outbox payload produced byVehicleOutboxMapperin:feature:vehicle: the Vehicle snapshot and the cascade Fuel Entry tombstone now emitentityType.EntityTypeenum names to the outbox wire values.Story
E1-11 - :feature:vehicle Outbox Payload entityType FixReady Check
ProposedorPendingIn-Progress Checkpoint
story/E1-11-outbox-entitytype-fixfrommain(68842a2)62c804aAGENTS.mdpasses with 627 actionable tasks;contractCheckandarchitectureCheckpassScope Completed
VehicleOutboxMapper.toVehicleOutboxPayloadOrNullnow emits"entityType":"VEHICLE"as the first key, covering create, update and vehicle tombstone call sites.VehicleOutboxMapper.toFuelEntryTombstonePayloadnow emits"entityType":"FUEL_ENTRY"as the first key of the cascade-delete tombstone payload.VehicleOutboxMapperTestadded with unit coverage of the Vehicle snapshot and cascade Fuel Entry tombstone payloads, includingentityTypeEnumNamesMatchTheOutboxWireValuesanchor.VehicleRepositoryCreateTest.permanentOwnerCreateEnqueuesTheFullVehicleSnapshotexact key-set assertion updated to includeentityType.VehicleRepositoryUpdateTest.updateCoalescesTheOutboxAtTheOriginalSequenceextended to assertentityType.VehicleRepositoryDeleteTest.permanentOwnerDeleteEnqueuesFuelTombstonesBeforeTheVehicleTombstoneextended to assertentityTypein every coalesced Fuel Entry tombstone and in the vehicle tombstone.VehicleRepositoryDeleteTest.cascadeDeleteCoalescesWithAnExistingFuelEntryOutboxRowKeepingEntityTypeadded: parameterized coalescence test.VehicleFormStateHolderTest.saveEnqueuesTheClosedRemoteVehicleSnapshotin:sharedupdated to includeentityTypein the exact key-set assertion.VehicleRepositoryTestScope.seedFuelEntryOutboxhelper added.:feature:vehiclecommonTest files derive their outbox lookup keys and seeds fromEntityType.*.name; payload value assertions stay as exact string literals.Acceptance Evidence
VehicleOutboxMapper.toFuelEntryTombstonePayloademits"entityType":"FUEL_ENTRY":VehicleOutboxMapperTest.fuelEntryTombstonePayloadIncludesEntityTypeFuelEntry.VehicleOutboxMapper.toVehicleOutboxPayloadOrNullemits"entityType":"VEHICLE":VehicleOutboxMapperTest.permanentOwnerVehiclePayloadIncludesEntityTypeVehicle.entityTypeasserted for each write path: Vehicle create, Vehicle update, Vehicle tombstone, cascade Fuel Entry tombstone.(FUEL_ENTRY, entityId)outbox row hasentityTyperegardless of prior write source:VehicleRepositoryDeleteTest.cascadeDeleteCoalescesWithAnExistingFuelEntryOutboxRowKeepingEntityType.entityTypeEnumNamesMatchTheOutboxWireValuespinsEntityType.VEHICLE.name == "VEHICLE"andEntityType.FUEL_ENTRY.name == "FUEL_ENTRY".LOCAL_OWNER + PENDING + no outboxinvariant preserved.docs/CONTRACTS.md §8anddocs/TECHNICAL_PLAN.mdrequire no edit.Out of Scope / Not Done
DatabaseMutations(core/database/.../DatabaseMutations.kt:53,112,152,176,312,428,475), the:feature:fueloutbox mapper literals, the:sharedliterals and the.sqCHECK/SQL literals keep their string literals because:core:databasecannot depend on:core:sync(docs/TECHNICAL_PLAN.md §4) and unification requires a gated relocation ofEntityType. Any centralization is deferred to a separate, explicit, Ready Phase 3 story that must jointly resolve whereEntityTypelives, module dependencies, SQL representation and contract assertions. It is not automatically assigned to E3-03.Files Changed
feature/vehicle/src/commonMain/kotlin/com/ruizurraca/carapp/feature/vehicle/data/VehicleOutboxMapper.ktfeature/vehicle/src/commonTest/kotlin/com/ruizurraca/carapp/feature/vehicle/data/VehicleOutboxMapperTest.kt(new)feature/vehicle/src/commonTest/kotlin/com/ruizurraca/carapp/feature/vehicle/data/VehicleRepositoryCreateTest.ktfeature/vehicle/src/commonTest/kotlin/com/ruizurraca/carapp/feature/vehicle/data/VehicleRepositoryDeleteTest.ktfeature/vehicle/src/commonTest/kotlin/com/ruizurraca/carapp/feature/vehicle/data/VehicleRepositoryTestScope.ktfeature/vehicle/src/commonTest/kotlin/com/ruizurraca/carapp/feature/vehicle/data/VehicleRepositoryUpdateTest.ktshared/src/commonTest/kotlin/com/ruizurraca/carapp/VehicleFormStateHolderTest.ktdocs/handoff-E1-11.md(new)docs/PROJECT_LOG.mddocs/DECISION_BOARD.mddocs/SPECIFICATION.mddocs/TECHNICAL_PLAN.mddocs/adr/README.mddocs/adr/0111-outbox-entity-type-token-ownership.md(new)docs/BACKLOG.mdAGENTS.mdREADME.mdDecisions Made
"VEHICLE","FUEL_ENTRY") in production code. The rejected alternatives are (A) extracting shared constants now and (B) deriving all values from the:core:syncEntityType— B is impossible for:core:databasewithout a gated module-boundary change, and unification must also resolve SQL representation and independent contract assertions. The:feature:vehiclecommonTest files derive their outbox lookup keys and seeds fromEntityType.*.name(the enum is already on their classpath at zero new module cost), while the payload value assertions stay as exact string literals — the contract wire-value anchor. One new test,entityTypeEnumNamesMatchTheOutboxWireValues, pins theEntityTypeenum names to the wire values mandated bydocs/CONTRACTS.md §8and§20; it has no RED phase because it is a characterization pin of an existing invariant. No refactorization is assigned to E3-03.Verification Run
Sharedframework from:composition:ios)Commands or checks run:
Result: BUILD SUCCESSFUL, 627 actionable tasks.
git diff --checkclean.contractCheckproves D-110 and ADR status parity across all four mirrors.Contract Impact
docs/CONTRACTS.md§:Decision Board Impact
docs/DECISION_BOARD.md(D-110) and the related ADR: ADR-0111Shared-Write Modules Touched
core/database— confirm no other story is modifying itProject Log Entry
docs/PROJECT_LOG.mdHuman Review Gate
Gates are defined canonically in
AGENTS.md.docs/SPECIFICATION.md,docs/CONTRACTS.md,docs/DECISION_BOARD.md,AGENTS.md,docs/adr/**,docs/identifiers.md,docs/versions-matrix.md,firestore/**,core/sync/**,core/auth/**,core/database/**, money types)Risks or Follow-ups
E1-06follow-up and the additional Vehicle payload finding folded into this story.DatabaseMutations, the:feature:fueland:sharedliterals, and the.sqCHECK/SQL literals remain independent string literals until a future centralization story.