Author: Claude Opus for jmpicnic | Date: 2026-05-19 | Status: Draft
Bidirectional traceability between the requirements and the acceptance criteria that verify them. Each acceptance criterion specifies a verification method (code review, unit test, integration test, EXPLAIN ANALYZE, pg_stat_statements comparison, Sentry rolling-window measurement, or the dev synthetic-failover gate). The Status column tracks verification progress during implementation; the implementer updates each row from Pending to Verified (or Blocked with a note) as each criterion is exercised.
Note on AC numbering: acceptance criteria are numbered sequentially within sections (AC-JDBC-1, AC-IDX-1, etc.) so the prefix carries the domain. Where an AC covers more than one requirement, multiple REQs are listed.
| AC | REQ | Acceptance Criterion | Verification Method | Status |
|---|
| AC-JDBC-1 | REQ-PDEV490-001 | common-module/gradle/libs.versions.toml declares the aws-jdbc-wrapper version (4.0.1) and library; the persistence module’s build.gradle.kts declares api(libs.aws.jdbc.wrapper). | Code review of gradle/libs.versions.toml + build.gradle.kts. | Pending |
| AC-JDBC-2 | REQ-PDEV490-002 | common-module/lib/src/main/kotlin/cards/arda/common/lib/persistence/DataSource.kt reads dbConfig.url as authoritative and computes an isWrapperScheme flag via dbConfig.url.toString().startsWith("jdbc:aws-wrapper:"). URL construction is not performed inside common-module. | Code review. | Pending |
| AC-JDBC-3 | REQ-PDEV490-003 | DataSource.kt sets driverClassName = "software.amazon.jdbc.Driver" if and only if isWrapperScheme is true. A unit test constructs DataSource with each scheme and asserts the conditional. | Code review + unit test. | Pending |
| AC-JDBC-3b | REQ-PDEV490-002, REQ-PDEV490-003, REQ-PDEV490-004, REQ-PDEV490-005, REQ-PDEV490-006 | A unit test (DataSourceTest) constructs DataSource with a legacy jdbc:postgresql: URL and asserts: no driverClassName override, no wrapperPlugins property, no exceptionOverrideClassName override, no Aurora tuning properties. Confirms strict additivity — zero behavior change for legacy consumers. | Unit test. | Pending |
| AC-JDBC-4 | REQ-PDEV490-004 | DataSource.kt sets wrapperPlugins = "auroraInitialConnection,failover2,efm2,readWriteSplitting" on the HikariCP dataSourceProperties if and only if isWrapperScheme is true. | Code review + unit test + pod startup log inspection on dev (confirm the plugin pipeline appears in wrapper-emitted log lines when the operations consumer opts in). | Pending |
| AC-JDBC-5 | REQ-PDEV490-005, REQ-PDEV490-006 | When isWrapperScheme is true, DataSource.kt sets exceptionOverrideClassName = "software.amazon.jdbc.util.HikariCPSQLException" AND the five Aurora-tuning properties (failoverClusterTopologyRefreshRateMs = 2000, failoverReaderConnectTimeoutMs = 5000, failoverWriterReconnectIntervalMs = 2000, loadBalanceReadOnlyTraffic = true, readerInitialConnectionHostSelectorStrategy = leastConnections). | Code review + unit test. | Pending |
| AC-JDBC-6 | REQ-PDEV490-007 | operations/gradle/libs.versions.toml has the commonModule pin updated to the Phase-2 release tag, and the operations build succeeds against that release. | Code review + make -C operations clean build exit code 0. | Pending |
| AC-JDBC-7 | REQ-PDEV490-008 | operations/src/main/resources/application.conf has dataSource.jdbcUrl matching the jdbc:aws-wrapper:postgresql://… scheme. | Code review. | Pending |
| AC | REQ | Acceptance Criterion | Verification Method | Status |
|---|
| AC-RW-1 | REQ-PDEV490-010 | During a representative items-page workload exercised against dev, pod-side wrapper logging shows read-only transactions (transaction(readOnly = true)) connecting to an Aurora reader instance. | Pod log inspection on Alpha002-dev after Wave 3 deploy. | Pending |
| AC-RW-2 | REQ-PDEV490-011 | During the same workload, write-transactions land on the Aurora writer instance. | Pod log inspection on Alpha002-dev. | Pending |
| AC-RW-3 | REQ-PDEV490-012 | The application-level HikariCP pool size, eviction policy, and caller-facing API surface are unchanged. The existing operations integration-test suite continues to pass without modification. | Code review of DataSource.kt’s HikariCP pool block + existing test suite pass. | Pending |
| AC | REQ | Acceptance Criterion | Verification Method | Status |
|---|
| AC-IDX-K1 | REQ-PDEV490-020, REQ-PDEV490-021, REQ-PDEV490-022, REQ-PDEV490-023 | operations/src/main/resources/resources/kanban/database/migrations/V007__kanban_card_bitemporal_indexes.sql declares the three indexes using CREATE INDEX CONCURRENTLY with no WHERE retired = FALSE predicate. Sidecar .conf sets executeInTransaction=false. | Code review of migration + sidecar file. | Pending |
| AC-IDX-K2 | REQ-PDEV490-020, REQ-PDEV490-021 | Post-deploy on dev, EXPLAIN ANALYZE on the bitemporal SELECT for kanban_card (cardsForItem-shaped query) shows Index Scan using idx_kanban_card_tenant_item_temporal on kanban_card sq (not Seq Scan, not Bitmap Index Scan on idx_kanban_card_eid). | EXPLAIN ANALYZE against Alpha002-dev after Wave 1 migration. | Pending |
| AC-IDX-K3 | REQ-PDEV490-022 | \d kanban_card (or equivalent pg_indexes query) on dev shows idx_kanban_card_tenant_id. | psql introspection on Alpha002-dev. | Pending |
| AC | REQ | Acceptance Criterion | Verification Method | Status |
|---|
| AC-IDX-I1 | REQ-PDEV490-025, REQ-PDEV490-026 | operations/src/main/resources/reference/item/database/migrations/V015__item_bitemporal_indexes.sql (or next-available V* number) declares the composite index(es) using CREATE INDEX CONCURRENTLY with no WHERE retired = FALSE predicate. Sidecar .conf sets executeInTransaction=false. | Code review. | Pending |
| AC-IDX-I2 | REQ-PDEV490-025 | Post-deploy on dev, EXPLAIN ANALYZE on the bitemporal SELECT for item (listWithDetails-shaped query) shows Index Scan using idx_item_tenant_eid_temporal on item sq. | EXPLAIN ANALYZE against Alpha002-dev. | Pending |
| AC | REQ | Acceptance Criterion | Verification Method | Status |
|---|
| AC-K12-1 | REQ-PDEV490-030, REQ-PDEV490-031, REQ-PDEV490-032 | operations/src/main/kotlin/.../ServiceImpl.kt:276-293 matches the “After” shape in specification.md § Task 1a.2: withTotal = false, no flatMap/when block, bare inTransaction { universe.list(…)() }. Both changes appear in a single commit (git log shows one commit touching both the flag and the block). | Code review + git-log inspection of the Wave 1 kanban PR. | Pending |
| AC-K12-2 | REQ-PDEV490-033 | Integration test cardsForItem on an item with zero cards returns HTTP 200 with Page(records = [], totalCount = null). | Integration test in operations/src/test/kotlin/.../ServiceImplTest.kt. | Pending |
| AC-K12-3 | REQ-PDEV490-030, REQ-PDEV490-031 | Integration test cardsForItem on an item with multiple cards returns HTTP 200 with Page(records = [...N cards...], totalCount = null). | Integration test. | Pending |
| AC-K12-4 | REQ-PDEV490-NFR-022 | Post-deploy on dev, pg_stat_statements ranked by call frequency on the kanban DB no longer shows the COUNT statement formerly issued by cardsForItem in the top entries (it was previously near the top). | pg_stat_statements snapshot on Alpha002-dev before/after Wave 1. | Pending |
| AC | REQ | Acceptance Criterion | Verification Method | Status |
|---|
| AC-TX-1 | REQ-PDEV490-040 | common-module/lib/src/main/kotlin/.../AppError.kt declares AppError.Transient sealed branch under AppError.Internal with three subtypes (FailoverSucceeded, TransactionStateUnknown, FailoverFailed). | Code review. | Pending |
| AC-TX-2 | REQ-PDEV490-041 | common-module/lib/src/main/kotlin/cards/arda/common/lib/lang/errors/AppError.kt:192 Throwable.normalizeToAppError() has new branches that classify each of the three wrapper exception classes (raw and ExposedSQLException-wrapped) to the corresponding AppError.Transient subtype. Unrelated throwables continue to map to the existing AppError.Implementation / AppError.GeneralValidation branches. | Code review + unit tests on normalizeToAppError. | Pending |
| AC-TX-3 | REQ-PDEV490-042, REQ-PDEV490-044 | Forced-transient integration test (TransientFailureContractTest — Test A): a forced FailoverSuccessSQLException produces HTTP 503 with Retry-After: 2 header and response body matching ErrorResponse(code = 503, …). | Integration test on ContainerizedPostgres harness with maxAttempts = 1. | Pending |
| AC-TX-4 | REQ-PDEV490-043 | Existing tests for HTTP 500 rendering on AppError.Internal subtypes other than Transient (e.g., IncompatibleState) continue to pass without modification. | Existing test suite pass. | Pending |
| AC | REQ | Acceptance Criterion | Verification Method | Status |
|---|
| AC-RT-1 | REQ-PDEV490-050 | common-module/lib/src/main/kotlin/.../PoolConfig.kt has new fields maxAttempts: Int = 2 and backoffMs: Long = 300. | Code review. | Pending |
| AC-RT-2 | REQ-PDEV490-051, REQ-PDEV490-053 | Retry-absorbed integration test (TransientFailureContractTest — Test B): a one-shot FailoverSuccessSQLException followed by a healthy connection produces HTTP 200 with the normal happy-path response. | Integration test on ContainerizedPostgres harness with default maxAttempts = 2. | Pending |
| AC-RT-3 | REQ-PDEV490-052 | Unit test: a non-transient throwable (e.g., IllegalStateException) surfaces immediately without retry. | Unit test on the retry wrapper. | Pending |
| AC-RT-4 | REQ-PDEV490-054 | operations/src/main/resources/application.conf declares dataSource.pool.maxAttempts = 2 and dataSource.pool.backoffMs = 300. | Code review. | Pending |
| AC | REQ | Acceptance Criterion | Verification Method | Status |
|---|
| AC-DEC-1 | REQ-PDEV490-060 | common-module/lib/src/main/kotlin/.../AbstractScopedUniverse.kt:27 declares the tenantId column as uuid(ScopedMetadata.COLUMN_TENANT_ID) with no chained .index(…). | Code review. | Pending |
| AC-DEC-2 | REQ-PDEV490-061 | grep -rn '\.index(' common-module/lib/src/main/kotlin/.../universe/ against the post-change tree returns no new declarations (no Exposed-level index declarations added or modified anywhere else under universe/). | Code review + grep. | Pending |
| AC-DEC-3 | REQ-PDEV490-062 | common-module/lib/src/main/kotlin/.../persistence/rdbms/DbMigration.kt:31 FluentConfiguration chain includes .mixed(true) alongside .group(true). The operations test container (which has all migrations V001..V007 pending) applies the migration tree without raising FlywayMigrateException: Detected both transactional and non-transactional migrations. | Code review + green operations build after the operations PR’s commonModule pin bumps to the Wave 2 release. | Pending |
| AC-DEC-4 | REQ-PDEV490-063 | common-module/lib/.../persistence/rdbms/DataSource.kt companion has internal val allCreatedPools registering each HikariDataSource returned by newSqlDataSource(). common-module/lib/.../testing/persistence/PoolRegistry.kt provides closeAllPoolsForTests() (test-only helper with explicit “DO NOT CALL FROM PRODUCTION CODE” KDoc). ContainerizedPostgres.stop() invokes PoolRegistry.closeAllPoolsForTests(). Verification: the operations full test suite (make -C operations build) completes without hanging under Gradle’s default parallel test execution on a multi-core developer machine; CI continues to pass. | Code review + green local make -C operations build end-to-end without manual --max-workers=1 workaround. | Pending |
| AC | REQ | Acceptance Criterion | Verification Method | Status |
|---|
| AC-FO-1 | REQ-PDEV490-070, REQ-PDEV490-NFR-012 | During the Wave 5 dev synthetic-failover test, the wrapper’s topology log shows the new writer instance is detected within ~2-5 seconds of the failover trigger. | Pod log inspection during Wave 5 test. | Pending |
| AC-FO-2 | REQ-PDEV490-071, REQ-PDEV490-NFR-010 | During the Wave 5 test, the steady-load probe shows the HTTP 5xx window lasts ≤ 5 seconds (down from ~30 seconds today). | Sentry transaction log + probe-side metrics during Wave 5. | Pending |
| AC-FO-3 | REQ-PDEV490-072, REQ-PDEV490-NFR-011 | During the Wave 5 5xx window, HTTP 503 dominates the distribution and HTTP 500 is essentially zero. | Sentry transaction log during Wave 5. | Pending |
| AC-FO-4 | REQ-PDEV490-073 | The Wave 4 helm chart diff (no chart change beyond common-module consumer wiring) confirms the JVM-level networkaddress.cache.ttl setting is unchanged. | Code review of operations helm chart (src/main/helm/values*.yaml). | Pending |
| AC | REQ | Acceptance Criterion | Verification Method | Status |
|---|
| AC-AUD-1 | REQ-PDEV490-080 | grep -rnE 'SQLException|ExposedSQLException|PSQLException' src/main/kotlin/ on the operations worktree (Wave 3 PR branch) returns zero hits. Audit recorded in the operations Wave 3 PR description. | Grep snapshot included in PR body. | Pending |
| AC-AUD-2 | REQ-PDEV490-085 | The tenant_id audit table from analysis.md § Current state / Index coverage is referenced from the operations PR description (or its CHANGELOG entry) as the source of REQ-PDEV490-022’s scope. | PR description review. | Pending |
| AC | REQ | Acceptance Criterion | Verification Method | Status |
|---|
| AC-DOC-1 | REQ-PDEV490-090 | documentation/src/content/docs/current-system/architecture/patterns/persistence/aurora-jdbc-wrapper.md exists with frontmatter and content; rendered preview accessible via make -C documentation preview. | Doc-PR review + make pr-checks. | Pending |
| AC-DOC-2 | REQ-PDEV490-091 | documentation/src/content/docs/current-system/architecture/patterns/persistence/bitemporal-indexes.md exists with frontmatter and content. | Doc-PR review + make pr-checks. | Pending |
| AC-DOC-3 | REQ-PDEV490-092 | documentation/src/content/docs/process/craft/database/flyway-authoritative-for-indexes.md exists with frontmatter and content. | Doc-PR review + make pr-checks. | Pending |
| AC-DOC-4 | REQ-PDEV490-093 | documentation/src/content/docs/current-system/architecture/patterns/api-design.md has a Transient failures and retry contract section documenting the HTTP 503 + Retry-After: 2 surface. | Doc-PR review. | Pending |
| AC-DOC-5 | REQ-PDEV490-094 | Runbooks present under documentation/src/content/docs/process/operation-notes/: 20260519-aurora-synthetic-failover-test.md (Wave 5 acceptance test), 20260519-aurora-wrapper-troubleshooting.md, and 20260514-aurora-parameter-group-and-operations-bump-rollout.md (rollout runbook, already on this branch). | Doc-PR review. | Pending |
| AC-DOC-6 | REQ-PDEV490-095 | The Wave 4 documentation PR merges before the Wave 5 dev synthetic-failover test is executed (Wave 3 and Wave 4 can be developed in parallel; the runbook is drafted from the spec and may be refined post-Wave-3-deploy if the deployed shape diverges). | Doc-PR review + git-log timing inspection. | Pending |
| AC | REQ | Acceptance Criterion | Verification Method | Status |
|---|
| AC-PERF-1 | REQ-PDEV490-NFR-001 | Seven days after PDEV-490 has been promoted to Alpha001-prod, Sentry platform-be transaction-duration p50 for GET /v1/kanban/.../kanban-card/for-item/{item-eid} ≤ 250 ms and p95 ≤ 1,000 ms on a rolling seven-day window. Baseline (2026-05-19): p50 = 1,113 ms, p95 = 2,911 ms. | Sentry rolling-window query on platform-be post-rollout. | Pending |
| AC-PERF-2 | REQ-PDEV490-NFR-002 | Seven days after PDEV-490 has been promoted to Alpha001-prod and the PDEV-489 front-end consolidation has migrated the items-page consumer off this route (out of scope for PDEV-490), Sentry platform-be transaction-duration p50 for POST /v1/kanban/.../kanban-card/details ≤ 250 ms and p95 ≤ 1,000 ms on a rolling seven-day window. Baseline (2026-05-19): p50 = 289 ms, p95 = 2,035 ms. The conditional dependency on PDEV-489 is explicit; this criterion may be deferred until both projects have shipped. | Sentry rolling-window query. | Pending (conditional on PDEV-489) |
| AC | REQ | Acceptance Criterion | Verification Method | Status |
|---|
| AC-SQL-1 | REQ-PDEV490-NFR-020 | EXPLAIN ANALYZE on the post-Wave-1 kanban_card bitemporal SELECT (representative cardsForItem-shaped query) shows index scan / index-only scan on the inner correlated subquery. Captured before-and-after in the Wave 1 kanban PR description. | EXPLAIN ANALYZE on dev. | Pending |
| AC-SQL-2 | REQ-PDEV490-NFR-021 | EXPLAIN ANALYZE on the post-Wave-1 item bitemporal SELECT (representative listWithDetails-shaped query) shows index scan / index-only scan on the inner correlated subquery. | EXPLAIN ANALYZE on dev. | Pending |
| AC-SQL-3 | REQ-PDEV490-NFR-022 | Covered by AC-K12-4 above (pg_stat_statements confirms the COUNT statement disappears from top-N). | (cross-reference) | Pending |
| AC | REQ | Acceptance Criterion | Verification Method | Status |
|---|
| AC-BLD-1 | REQ-PDEV490-NFR-030 | make -C common-module clean build exit code 0 on the Wave 2 release PR; all existing tests pass. | Build output on Wave 2 PR. | Pending |
| AC-BLD-2 | REQ-PDEV490-NFR-031 | make -C operations clean build exit code 0 on each of the three operations PRs (Wave 1 kanban, Wave 1 item, Wave 3 consumer); all existing tests pass. | Build output on each PR. | Pending |
| AC-BLD-3 | REQ-PDEV490-NFR-032 | Coverage thresholds in the Gradle build scripts continue to be met on both common-module and operations. | Coverage report from ./gradlew build. | Pending |
| AC-BLD-4 | REQ-PDEV490-NFR-033 | make -C documentation pr-checks exit code 0 on the Wave 4 PR. | Documentation build output on Wave 4 PR. | Pending |
| AC-CHG-1 | REQ-PDEV490-NFR-040, REQ-PDEV490-NFR-041, REQ-PDEV490-NFR-042 | Each PR carries the CHANGELOG entry specified in specification.md Tasks 1a.4 / 1b.3 (combined into the operations PR), 2.9, 3.5 (combined into the operations PR), and 4.3. common-module’s entry presents the wrapper integration and mixed=true enablement as Added (strictly additive — consumers on jdbc:postgresql: URLs see zero behaviour change). The operations PR entry calls out the 500→503 status-code remap (which only takes effect after the consumer opts in to the wrapper scheme) as Changed. | PR description / CHANGELOG review. | Pending |
Each requirement maps to at least one acceptance criterion.
| Requirement | ACs | Covered |
|---|
| REQ-PDEV490-001 | AC-JDBC-1 | Yes |
| REQ-PDEV490-002 | AC-JDBC-2 | Yes |
| REQ-PDEV490-003 | AC-JDBC-2 | Yes |
| REQ-PDEV490-004 | AC-JDBC-3 | Yes |
| REQ-PDEV490-005 | AC-JDBC-4 | Yes |
| REQ-PDEV490-006 | AC-JDBC-5 | Yes |
| REQ-PDEV490-007 | AC-JDBC-6 | Yes |
| REQ-PDEV490-008 | AC-JDBC-7 | Yes |
| REQ-PDEV490-010 | AC-RW-1 | Yes |
| REQ-PDEV490-011 | AC-RW-2 | Yes |
| REQ-PDEV490-012 | AC-RW-3 | Yes |
| REQ-PDEV490-020 | AC-IDX-K1, AC-IDX-K2 | Yes |
| REQ-PDEV490-021 | AC-IDX-K1, AC-IDX-K2 | Yes |
| REQ-PDEV490-022 | AC-IDX-K1, AC-IDX-K3 | Yes |
| REQ-PDEV490-023 | AC-IDX-K1 | Yes |
| REQ-PDEV490-025 | AC-IDX-I1, AC-IDX-I2 | Yes |
| REQ-PDEV490-026 | AC-IDX-I1 | Yes |
| REQ-PDEV490-030 | AC-K12-1, AC-K12-3 | Yes |
| REQ-PDEV490-031 | AC-K12-1, AC-K12-3 | Yes |
| REQ-PDEV490-032 | AC-K12-1 | Yes |
| REQ-PDEV490-033 | AC-K12-2 | Yes |
| REQ-PDEV490-040 | AC-TX-1 | Yes |
| REQ-PDEV490-041 | AC-TX-2 | Yes |
| REQ-PDEV490-042 | AC-TX-3 | Yes |
| REQ-PDEV490-043 | AC-TX-4 | Yes |
| REQ-PDEV490-044 | AC-TX-3 | Yes |
| REQ-PDEV490-050 | AC-RT-1 | Yes |
| REQ-PDEV490-051 | AC-RT-2 | Yes |
| REQ-PDEV490-052 | AC-RT-3 | Yes |
| REQ-PDEV490-053 | AC-RT-2 | Yes |
| REQ-PDEV490-054 | AC-RT-4 | Yes |
| REQ-PDEV490-060 | AC-DEC-1 | Yes |
| REQ-PDEV490-061 | AC-DEC-2 | Yes |
| REQ-PDEV490-062 | AC-DEC-3 | Yes |
| REQ-PDEV490-063 | AC-DEC-4 | Yes |
| REQ-PDEV490-070 | AC-FO-1 | Yes |
| REQ-PDEV490-071 | AC-FO-2 | Yes |
| REQ-PDEV490-072 | AC-FO-3 | Yes |
| REQ-PDEV490-073 | AC-FO-4 | Yes |
| REQ-PDEV490-080 | AC-AUD-1 | Yes |
| REQ-PDEV490-085 | AC-AUD-2 | Yes |
| REQ-PDEV490-090 | AC-DOC-1 | Yes |
| REQ-PDEV490-091 | AC-DOC-2 | Yes |
| REQ-PDEV490-092 | AC-DOC-3 | Yes |
| REQ-PDEV490-093 | AC-DOC-4 | Yes |
| REQ-PDEV490-094 | AC-DOC-5 | Yes |
| REQ-PDEV490-095 | AC-DOC-6 | Yes |
| REQ-PDEV490-NFR-001 | AC-PERF-1 | Yes |
| REQ-PDEV490-NFR-002 | AC-PERF-2 | Yes (conditional on PDEV-489) |
| REQ-PDEV490-NFR-010 | AC-FO-2 | Yes |
| REQ-PDEV490-NFR-011 | AC-FO-3 | Yes |
| REQ-PDEV490-NFR-012 | AC-FO-1 | Yes |
| REQ-PDEV490-NFR-020 | AC-SQL-1 | Yes |
| REQ-PDEV490-NFR-021 | AC-SQL-2 | Yes |
| REQ-PDEV490-NFR-022 | AC-K12-4, AC-SQL-3 | Yes |
| REQ-PDEV490-NFR-030 | AC-BLD-1 | Yes |
| REQ-PDEV490-NFR-031 | AC-BLD-2 | Yes |
| REQ-PDEV490-NFR-032 | AC-BLD-3 | Yes |
| REQ-PDEV490-NFR-033 | AC-BLD-4 | Yes |
| REQ-PDEV490-NFR-040 | AC-CHG-1 | Yes |
| REQ-PDEV490-NFR-041 | AC-CHG-1 | Yes |
| REQ-PDEV490-NFR-042 | AC-CHG-1 | Yes |
Every functional and non-functional requirement is covered by at least one acceptance criterion. No requirement is uncovered.
| Category | Criteria | Code Review | Unit / Integration Test | EXPLAIN / pg_stat | Sentry / Operational | Build / CI |
|---|
| JDBC connectivity | 7 | 7 | 0 | 0 | 1 (pod log) | 1 |
| Read / write splitting | 3 | 1 | 1 | 0 | 2 (pod log) | 0 |
Bitemporal indexes — kanban_card | 3 | 1 | 0 | 2 | 0 | 0 |
Bitemporal indexes — item | 2 | 1 | 0 | 1 | 0 | 0 |
cardsForItem cleanup | 4 | 1 | 2 | 1 | 0 | 0 |
| Transient error contract | 4 | 2 | 1 | 0 | 0 | 1 |
| Retry policy | 4 | 2 | 1 | 0 | 0 | 1 |
| Decorative declaration removal | 2 | 2 | 0 | 0 | 0 | 0 |
| Failover behaviour | 4 | 1 | 0 | 0 | 3 (Wave 5) | 0 |
| Operations audit | 2 | 2 | 0 | 0 | 0 | 0 |
| Documentation | 6 | 6 | 0 | 0 | 0 | 0 |
| Performance — post-rollout | 2 | 0 | 0 | 0 | 2 | 0 |
| Performance — SQL plan | 3 | 0 | 0 | 3 | 0 | 0 |
| Build / test / CHANGELOG | 5 | 1 | 0 | 0 | 0 | 4 |
| Total | 51 | 27 | 5 | 7 | 8 | 7 |
Verification mix favours code-review-based gates (53%, mostly mechanical checks against the specification), followed by operational measurements (Sentry + pod log inspection during Wave 5 — 16%), EXPLAIN ANALYZE / pg_stat_statements checks (14%), build / CI gates (14%), and unit / integration tests (~10%). Few code-side tests is consistent with a project that is mostly additive (indexes, new error branch, new wiring) on top of an existing well-tested persistence layer.
During implementation, each row’s Status column is updated:
Pending — not yet exercised.
In Progress — implementation underway; verification artefact not yet produced.
Verified — verification artefact present; AC satisfied.
Blocked — verification cannot proceed; note inline (e.g., depends on Wave 5).
Failed — verification artefact present; AC not satisfied. Implementation must address.
The implementer or sub-agent updates this file as each AC is exercised. A final verification pass (driven by the verify-operations-project skill) reads the matrix and confirms every AC has reached Verified before the project promotes to roadmap/completed/.
- PDEV-490 goal — project goal and success criteria.
analysis.md — entry-state analysis (where each AC’s “before” measurement comes from).
requirements.md — EARS requirements (the source of every REQ-PDEV490-* ID).
specification.md — phased implementation plan (where each REQ-PDEV490-* is realised, including the tasks each AC validates).
Copyright: (c) Arda Systems 2025-2026, All rights reserved