Skip to content

Gate canonical Task/Card transactions in DynamoDB Local and trim duplicate browser API specs #183

Description

@alexeygrigorev

Gate canonical Task/Card transactions in DynamoDB Local and trim duplicate browser API specs

Status: blocked on #166 cleanup — Stage A is Tester/PM accepted and committed locally as ae26ba6; Stage C is Tester/PM accepted and committed locally as bf5b39c; only Stage B implementation remains, followed by combined verification
Tags: enhancement, work-engine, backend, frontend, infra, testing, P1
Depends on: #166 successful repaired rollout through post-success cleanup and restoration of the ordinary steady-state deploy workflow; #180 is closed and no longer blocks
Blocks: None
Next owner: #166 orchestrator/On-Call first; after #166 cleanup, Software Engineer adds only the accepted Stage A command to steady-state deploy checks, then Tester and PM perform Stage B/combined acceptance
Resume condition: #166 Phase A/B/C/#182/D and cleanup have production PASS evidence and the normal push/OIDC deploy workflow is restored without transitional mechanisms; then implement Stage B only from accepted descendant bf5b39c

Scope

Close two test-architecture gaps without adding another broad integration suite:

  1. Add one deterministic, deploy-gating DynamoDB Local check for the canonical Task/Card transaction accepted in Complete and archive cards automatically when all tasks are done #168. The check must run the same production TransactWriteItems path that Lambda uses, including Prevent lost Task updates and history with optimistic concurrency #179's Task version/history condition and Complete and archive cards automatically when all tasks are done #168's Card counter/lifecycle/audit writes. The ordinary Dynalite-backed backend and browser suites deliberately use explicit local transaction emulation and cannot provide this proof.
  2. Remove the large Playwright api-* CRUD/validation suites after preserving each meaningful behavior in its proper layer. Backend API/domain tests own request validation, persistence, conflicts, and business rules; Playwright owns a small single-origin routing/auth/deployment-shape smoke plus real operator journeys.

This is test/CI work, not a runtime transaction redesign. Do not add an environment-selected production fallback, general transaction framework, migration/import/restore/export coverage, production data access, or an AWS call.

Accepted local checkpoints

  • Stage A — ae26ba609b84d3dd38608b6adc74ec7a51179ddd. Tester PASS and PM acceptance cover exactly backend/package.json, backend/scripts/test-task-card-transaction.sh, and backend/tests/task-card-transaction.ddb.ts. Evidence: official loopback/ephemeral DynamoDB Local, production mode with emulation disabled, real forwarded TransactWriteCommand, semantic complete/reopen/race atomicity, 1/1 focused pass, test TypeScript config, shell syntax, diff check, and cleanup.
  • Stage C — bf5b39cbfaad3c026caebe5c5ad4bd048b67398c. This descendant contains the accepted Stage A checkpoint and the exact accepted eleven-path browser convergence: seven broad API-spec deletions, independent retained Template-update journeys, two focused backend owners, and one README command correction. Evidence: focused backend owners 71/71, Template-update journeys 2/2, complete remaining browser suite 63/63 with every discovered case accounted for, typecheck, build/runtime boundary, canonical artifact verification, and diff checks.
  • Restore behavior-based browser coverage and fix canonical UI accessibility races #180 closed. The 63/63 Stage C result satisfied Restore behavior-based browser coverage and fix canonical UI accessibility races #180's deferred complete-suite criterion. Restore behavior-based browser coverage and fix canonical UI accessibility races #180 is no longer a dependency or blocker.

Both checkpoints are local and unpushed. Acceptance is not shipment, deploy, or On-Call evidence. Current HEAD is Stage C bf5b39c; origin/main remains behind it.

Staged implementation plan

#183 remains open only for the #166-gated permanent deploy step and final combined verification. Stage A and Stage C are frozen accepted local commits; do not reopen or fold them into Stage B.

Stage A — isolated transaction harness (accepted and committed locally as ae26ba6)

Stage B — permanent deploy gate (blocked on #166 cleanup)

Stage C — browser convergence (accepted and committed locally as bf5b39c)

Stage D — combined verification and closeout

Stage D closes #183 only after #166 unblocks Stage B, the permanent steady-state deploy gate is Tester/PM accepted and committed, and combined verification passes on the descendant integration. #180 is already closed from the accepted Stage C 63/63 cross-post. No local checkpoint claims shipment.

  • Run the full verification listed below only after Stages B and C are integrated.
  • Tester records observed discovery/results without encoding counts, timings, byte values, exact incidental copy, source-text matches, or screenshot pixels as product assertions.

Production transaction gate

Implement the smallest focused harness: one test file, one runner, and one deploy-check step. It must:

  • start an isolated official DynamoDB Local process/container on a loopback ephemeral port, create only the throwaway tables needed by the accepted Task/Card lifecycle, and always clean up its process/container and tables;
  • use synthetic records and final accepted table/key shapes;
  • set the local endpoint and fake local AWS credentials while running application transaction code in production mode;
  • leave usesLocalTransactionEmulation() false and prove that an actual TransactWriteCommand request is accepted by DynamoDB Local; merely inspecting a mocked command or exercising the local emulator is not sufficient;
  • use observable bounded readiness and process-exit diagnostics, not a blind fixed delay;
  • exercise one complete lifecycle journey: attached open Task → final Task completion/Card archive → Task reopen/Card reactivation;
  • prove the Task version/history mutation, Card version/counters/lifecycle fields, and public-safe lifecycle audit are committed together;
  • force a same-version conditional race/failure and prove the loser leaves no partial Task, Card, history, or audit write. Do not pin an implementation-specific command count.

Run this focused command in the deterministic checks job of .github/workflows/deploy-dataops-v1.yml before packaging/deployment. It is a backend correctness gate. Do not add Playwright to that workflow. The runner may share safe container-readiness/cleanup helpers with existing focused DynamoDB Local scripts only when doing so stays smaller and does not turn unrelated transaction suites into ongoing CI.

Browser coverage convergence

Inventory every assertion in:

  • backend/e2e/api-cards.spec.js
  • backend/e2e/api-cron.spec.js
  • backend/e2e/api-files.spec.js
  • backend/e2e/api-instantiation.spec.js
  • backend/e2e/api-recurring.spec.js
  • backend/e2e/api-tasks.spec.js
  • backend/e2e/api-users.spec.js

For each behavior, identify exactly one continuing owner:

Behavior Continuing owner
request validation, CRUD, domain invariants, DynamoDB conditions, concurrency/conflict bodies focused backend/tests/*.test.ts API/domain tests
operator-visible navigation, state, mutation result, recovery, focus, accessibility behavior-based Playwright journey
single-origin dispatch, authenticated/unauthenticated boundary, JSON-vs-SPA routing, static/packaged deployment shape a small Playwright routing/auth/deployment smoke
test setup and cleanup fixture helpers; not duplicated product assertions

Add missing focused backend coverage before deleting its browser duplicate. Move any genuine UI journey out of an api-* file before deleting that file. Fixture API calls may remain inside UI journeys, but Playwright must not recreate full CRUD/validation matrices with its request fixture.

Delete the seven broad api-* specs above once the inventory is satisfied. Keep a compact behavior-based smoke that proves, through the real local HTTP boundary:

  • the health/API namespace is dispatched as API JSON rather than the SPA;
  • an unknown API route does not fall through to frontend HTML;
  • the existing browser-session/auth tests still prove protected single-origin access and safe auth failure;
  • the canonical frontend entry/static module graph loads from the same server shape.

Do not duplicate the product/accessibility repairs, browser diagnostics, fixture isolation, or serial-failure cleanup owned by #180. #183 consumes #180's accepted suite shape and then removes redundant API-contract cases while preserving its meaningful UI journeys.

Acceptance Criteria

  • A focused DynamoDB Local runner executes accepted Complete and archive cards automatically when all tasks are done #168 Task/Card lifecycle code with NODE_ENV=production, the explicit local transaction emulator disabled, and at least one real successful TransactWriteItems request.
  • Final completion and reopen prove atomic Task version/history, Card version/counters/lifecycle metadata, and public-safe lifecycle audit behavior against DynamoDB Local. Assertions identify the semantic history entries and monotonic versions relative to returned state; they do not pin absolute versions or history lengths.
  • A same-version race or failed transaction proves all-or-nothing behavior: the loser cannot partially change Task, Card, history, counters, completion state, or audit, and the accepted conflict contract is preserved.
  • The harness uses isolated synthetic local tables/resources, observable bounded readiness, useful process/container diagnostics, and reliable cleanup on pass, assertion failure, startup failure, and interruption.
  • The focused transaction command is an ordinary deterministic step in the deploy workflow's checks job and fails that job on regression; no AWS credentials, production resource, import, migration, restore, export, seed, or raw operational data is used.
  • No runtime fallback, test-mode branch selected by an environment variable, dual transaction implementation, retry loop, or application-owned table creation is added. Table creation remains test-harness-only.
  • Every meaningful behavior formerly in the seven broad Playwright api-* specs has one documented continuing owner; any missing backend/API or UI coverage is added before the duplicate is removed.
  • The seven broad Playwright api-* specs are deleted. Remaining Playwright API requests are limited to fixture setup/cleanup, compact route/auth/deployment smoke, or actions inside real operator journeys.
  • Meaningful Card/Task, recurring, files, cron/notification, Template instantiation, and user-role behavior remains covered in backend tests and, where operator-visible, behavior-based browser journeys. Coverage is not replaced by exact test-count assertions.
  • The retained browser smoke asserts routes, response class, auth boundary, visible state, and usable behavior—not incidental copy, DOM concatenation, internal IDs, byte/digest values, source text, or screenshot pixels.
  • Browser cases remain independently runnable after Restore behavior-based browser coverage and fix canonical UI accessibility races #180: no file/describe serial failure dependency, cross-test mutation dependency, fixed synchronization sleep, or test-order contract is introduced.
  • .github/workflows/validate-backend-e2e.yml remains the independent, non-deploy-blocking full Playwright workflow and retains failure artifact upload. .github/workflows/deploy-dataops-v1.yml contains no Playwright command or dependency.
  • Backend unit/API tests, the focused real-transaction gate, frontend unit tests, and the complete independent Playwright suite pass with all discovered tests accounted for; Tester records observed counts in evidence rather than pinning counts in code.

Test Scenarios

Scenario: Production transaction path completes and reopens a Card

Given: DynamoDB Local has synthetic canonical Cards, Tasks, and lifecycle-audit tables; transaction emulation is disabled; an active Card has one open attached Task
When: production application code completes that Task and then deliberately reopens it from the returned current version
Then: DynamoDB Local accepts real transaction requests, each mutation advances Task/Card state atomically, completion/reactivation audits are retained once, and no emulator/fallback path runs

Scenario: A transaction condition loses

Given: two mutations start from the same canonical Task/Card versions
When: they race or one deliberately invalidates a transaction condition
Then: only one valid transaction commits; the loser returns the accepted conflict behavior and a strongly consistent read shows no partial losing history, counter, lifecycle, or audit effects

Scenario: Harness startup or assertion fails

Given: the local service exits early or the focused test fails
When: the runner reports the failure
Then: diagnostics identify readiness/process state without exposing record content, and owned containers/processes/tables are cleaned up without touching unrelated local resources

Scenario: Duplicate API contract is removed safely

Given: a browser API assertion tests validation, CRUD, a domain invariant, or a conflict already owned by backend tests
When: the Playwright duplicate is removed
Then: the corresponding backend test still proves the behavior through the handler/repository boundary, and no operator-visible journey is lost

Scenario: An API spec contains real UI behavior

Given: an api-* file also asserts canonical Card navigation or another operator-visible flow
When: that broad file is deleted
Then: the UI behavior lives in an independent behavior-based journey with stable route/role/state assertions, while its API CRUD setup remains only a fixture concern

Scenario: Single-origin smoke distinguishes API from SPA

Given: the local production-shaped HTTP server serves the portal and API from one origin
When: the smoke requests health, an unknown API path, authenticated portal/API behavior, and the canonical frontend entry
Then: API responses retain API routing/response semantics, unknown API paths never return the SPA shell, auth behavior remains safe, and the frontend module graph loads

Scenario: CI boundaries

Given: focused local verification is green
When: the change reaches main
Then: the deploy checks run the deterministic transaction gate before deployment, the independent browser workflow runs the full Playwright suite and retains failure artifacts, and no Playwright outcome blocks or queues deployment

Verification

Engineer and Tester record exact commands, exit codes, and observed test counts for:

npm run typecheck:backend
npm run test:backend
npm --prefix backend run test:task-card-transaction
npm run test:frontend:unit
npm --prefix backend run test:e2e
uv run --with pytest pytest tests/infra/test_template.py

The focused transaction command name may be adjusted during implementation only if the final package script is equally explicit and the issue body is updated. Tester must inspect the test runner and CI job to confirm production mode, disabled emulation, loopback isolation, bounded readiness, cleanup traps, and no production/AWS/data operation. No UI source change or new screenshot acceptance is expected here; #180 owns screenshot-backed acceptance for the UI journeys this issue preserves.

After push, On-Call records both the transaction step result in the deploy checks and the independent browser workflow result. Do not trigger a manual deploy, touch AWS, or run source-data scripts merely to verify this issue.

Out of Scope

  • Changing the canonical Task optimistic-concurrency contract from Prevent lost Task updates and history with optimistic concurrency #179 or the Card aggregate/transaction contract from Complete and archive cards automatically when all tasks are done #168.
  • Generalizing the harness across every existing DynamoDB transaction user, or promoting Sponsor CRM, bookkeeping, Calendar, newsletter, conversational, import, migration, restore, export, or one-off data scripts/tests into ongoing CI.
  • Removing the explicit Dynalite transaction emulator used by ordinary local tests; this issue proves the production path separately and must not make the emulator runtime-selectable.
  • Product/accessibility fixes, broad browser fixture/diagnostic restructuring, retry policy, or serial-suite repair owned by Restore behavior-based browser coverage and fix canonical UI accessibility races #180.
  • A new browser UI journey solely to preserve an API-domain assertion, screenshot goldens, exact suite-size pins, broad text assertions, source-text coverage checks, or longer retries/timeouts.
  • SAM/application-stack redesign, production data writes, AWS mutation, source-repository edits, or private operational knowledge.

Dependencies

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1ImportantbackendBackend/APIenhancementNew or improved functionalityfrontendFrontend UIinfraDeployment and infrastructuretestingTests and QAwork-engineDataTasks task execution engine

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions