@carllee1983/dbcli 1.32.0 → 1.37.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -616,6 +616,46 @@ dbcli assert "SELECT count(*) FROM orders" --expect "value > 100" --no-fail #
616
616
  **Engines:** SQL only (PostgreSQL / MySQL / MariaDB)
617
617
  **Permission:** query-only+
618
618
 
619
+ #### Verification artifact (--write-verification-artifact)
620
+
621
+ Opt-in flag trio that persists a **VerificationArtifact JSON** (schema v1) under `<cwd>/.dbcli/verification/` after the assertion runs. The artifact is always written to `<cwd>/.dbcli/verification/` (relative to the current working directory), regardless of where the `--config` file is located.
622
+
623
+ | Flag | Required | Description |
624
+ | :--- | :--- | :--- |
625
+ | `--write-verification-artifact` | opt-in | Trigger artifact write. No-op when no verdict has been produced. |
626
+ | `--verification-subject <kind:name>` | yes (when flag is set) | Subject identifier. Format: `<kind>:<name>`. Allowed kinds: `recovery`, `task-pack`, `assertion`, `migration`, `backfill`, `manual`. |
627
+ | `--verification-summary <text>` | no | Free-text summary line stored in the artifact. Default when pass: "Assertion verified the expected state." Default when fail: "Assertion did not verify the expected state." |
628
+
629
+ **Output contract:**
630
+
631
+ - `--format json` — `AssertVerdict` gains `verificationArtifactPath: string` pointing to the written file.
632
+ - `--format table` — an extra `Verification artifact: <path>` line is printed after the verdict table.
633
+ - A `--no-fail` assertion that fails still records status `not_verified` and stores `exitCode: 1` in evidence.
634
+
635
+ **Planned vs Result evidence.** `dbcli skill tasks plan safe-backfill-verify --format json` returns a plan containing a `verification` block with `status: "planned"`. That block is the **planned** evidence definition — it describes which check will run. Running `assert --write-verification-artifact` on the actual data produces **result** evidence (`status: "verified"` or `status: "not_verified"`). The two records are distinct; `"planned"` does **not** indicate that verification has run or passed.
636
+
637
+ > **Casting note:** Postgres returns `count(*)` and `sum()` as bigint (a string in the result set). `value ==` uses strict equality, so `"0" == 0` is false. Cast to `::int` (`count(*)::int`) to ensure numeric comparison works correctly.
638
+
639
+ ```bash
640
+ dbcli assert "SELECT count(*)::int FROM orders WHERE status IS NULL" \
641
+ --expect "value == 0" \
642
+ --write-verification-artifact \
643
+ --verification-subject backfill:safe-backfill-verify
644
+
645
+ dbcli assert "SELECT count(*)::int FROM orders WHERE status IS NULL" \
646
+ --expect "value == 0" \
647
+ --write-verification-artifact \
648
+ --verification-subject backfill:safe-backfill-verify \
649
+ --verification-summary "Post-backfill null-status count is zero."
650
+
651
+ # --no-fail: exits 0 but still records not_verified on failure
652
+ dbcli assert "SELECT count(*)::int FROM orders WHERE status IS NULL" \
653
+ --expect "value == 0" \
654
+ --no-fail \
655
+ --write-verification-artifact \
656
+ --verification-subject backfill:safe-backfill-verify
657
+ ```
658
+
619
659
  ### proxy
620
660
 
621
661
  Local-development **observability proxy** for MySQL/MariaDB/PostgreSQL. Inserts dbcli
@@ -1104,6 +1144,304 @@ Output reports: writer enabled/disabled, last write result, file-lock state, rot
1104
1144
 
1105
1145
  **Permission:** n/a
1106
1146
 
1147
+ ### verify
1148
+
1149
+ Run a verification scenario. `verify` **runs** verification scenarios (safe-backfill,
1150
+ migration, rollback) and never executes writes/DDL. `verification` **inspects and manages**
1151
+ the local result artifacts those scenarios produce under `.dbcli/verification/`.
1152
+
1153
+ ```bash
1154
+ # Preflight (default): read-only guards + the exact after-write command. No artifact.
1155
+ dbcli verify safe-backfill \
1156
+ --table users \
1157
+ --query "UPDATE users SET status = 1 WHERE status IS NULL" \
1158
+ --verify-query "SELECT count(*)::int AS n FROM users WHERE status IS NULL" \
1159
+ --expect "value == 0"
1160
+
1161
+ # After-write: re-run guards, run the read-back assertion, write a v1 artifact.
1162
+ dbcli verify safe-backfill ... --after-write
1163
+
1164
+ # JSON for agents.
1165
+ dbcli verify safe-backfill ... --format json
1166
+ ```
1167
+
1168
+ Options: `--table` (req), `--query` (req, analyzed not executed), `--verify-query`
1169
+ (req, **plain SELECT only**), `--expect` (req), `--after-write`, `--format <table|json>`,
1170
+ `--subject-name <name>`, `--summary <text>`.
1171
+
1172
+ Guard constraints (fail closed): `--verify-query` must be a **plain `SELECT`** —
1173
+ `EXPLAIN`/`EXPLAIN ANALYZE`, `SHOW`, `DESCRIBE`, and data-modifying CTEs are rejected
1174
+ (on PostgreSQL `EXPLAIN ANALYZE <write>` actually performs the write). The `--query`
1175
+ **UPDATE target must equal `--table`**, compared schema-aware (`public.users` ≠
1176
+ `audit.users`). The persisted artifact stores only a bounded, literal-free label of the
1177
+ verify-query and `--expect` — string, numeric, and dollar-quoted literals are stripped,
1178
+ so raw SQL/values are never written to disk. The printed after-write
1179
+ command is shell-escaped and carries through `--subject-name`/`--summary`/non-default
1180
+ `--format`. For repeated backfills on the same table, pass a unique `--subject-name` so
1181
+ each operation is independently traceable (the subject defaults to `backfill:<table>`).
1182
+
1183
+ Status: `ready`/`blocked` in preflight (no artifact); `verified`, `not_verified`,
1184
+ `blocked`, or `indeterminate` in after-write (artifact written). `blocked` = a guard
1185
+ failed (blacklist/schema/plan/verify-query-not-plain-SELECT/target-table-mismatch);
1186
+ `not_verified` = the read-back contradicted `--expect`; `indeterminate` = the assertion
1187
+ could not produce a trustworthy verdict. Inspect the result with
1188
+ `dbcli verification show <artifact-id>`.
1189
+
1190
+ #### `verify migration`
1191
+
1192
+ Preflight or after-write verification for a schema migration. **This command never
1193
+ executes DDL** — it analyzes the proposed `ALTER TABLE`, runs read-only guards, and
1194
+ (in after-write mode) records evidence after you apply the migration externally.
1195
+
1196
+ ```bash
1197
+ # Preflight: read-only guards + the exact after-write command. Returns ready or blocked.
1198
+ dbcli verify migration \
1199
+ --table users \
1200
+ --ddl "ALTER TABLE users ADD COLUMN verified_at TIMESTAMPTZ" \
1201
+ --verify-query "SELECT count(*)::int AS n FROM users WHERE verified_at IS NOT NULL" \
1202
+ --expect "value == 0"
1203
+
1204
+ # After the migration is applied externally, record evidence:
1205
+ dbcli verify migration ... --after-write
1206
+
1207
+ # JSON for agents.
1208
+ dbcli verify migration ... --format json
1209
+ ```
1210
+
1211
+ | Option | Required | Description |
1212
+ | --- | --- | --- |
1213
+ | `--table <table>` | yes | Table affected by the migration. |
1214
+ | `--ddl <sql>` | yes | Proposed migration DDL, analyzed but never executed. MVP accepts `ALTER TABLE` only. |
1215
+ | `--verify-query <sql>` | yes | Plain `SELECT` for post-migration read-back verification. |
1216
+ | `--expect <expr>` | yes | Assertion expression for the read-back result. |
1217
+ | `--after-write` | no | Run the post-migration assertion and write a v1 artifact. |
1218
+ | `--format <table\|json>` | no | Output format, default `table`. |
1219
+ | `--subject-name <name>` | no | Artifact subject name. Default is the table name. |
1220
+ | `--summary <text>` | no | Optional artifact summary override. |
1221
+
1222
+ Preflight returns `ready` or `blocked` and prints the exact after-write command;
1223
+ **`ready` is not `verified`** — it only means the guards passed. After-write maps the
1224
+ read-back assertion to `verified` / `not_verified` / `indeterminate`, and a failed
1225
+ guard to `blocked`. `CREATE TABLE`, `DROP TABLE`, `CREATE INDEX`, and multi-statement
1226
+ DDL are blocked in the MVP.
1227
+
1228
+ The `ALTER TABLE` target may be `table`, `schema.table`, or `catalog.schema.table`.
1229
+ Each segment is a simple unquoted name (`[A-Za-z_][A-Za-z0-9_]*`) or a quoted
1230
+ identifier — double-quoted (`"…"`), backtick-quoted (`` `…` ``), or bracket-quoted
1231
+ (`[…]`) — so `"user accounts"` or `"tenant-1"."orders"` are accepted. Targets that
1232
+ cannot be fully parsed under this contract (unterminated quotes, unsupported escapes,
1233
+ or more than three parts) are blocked before the after-write assertion with a
1234
+ "could not be parsed" reason, distinct from the `must match --table` mismatch reason.
1235
+
1236
+ #### `verify rollback`
1237
+
1238
+ (v1.37.0+) Preflight or after-write verification for an **externally-applied rollback** —
1239
+ confirming that after you reverted a change the database is back to the expected prior
1240
+ state. **This command never executes the reverting statement** — it analyzes it, runs
1241
+ read-only guards, and (in after-write mode) records evidence after you apply the rollback
1242
+ externally. One scenario covers both schema and data rollbacks via a required
1243
+ `--kind <ddl|dml>` selector:
1244
+
1245
+ - `--kind ddl` — revert a schema migration. `--statement` is a single `ALTER TABLE`
1246
+ (e.g. dropping a column a forward migration added). Reuses the `migration` DDL gates.
1247
+ - `--kind dml` — revert a data change. `--statement` is a single `UPDATE` that restores
1248
+ prior values. Reuses the `safe-backfill` UPDATE plan gates.
1249
+
1250
+ ```bash
1251
+ # Schema rollback (--kind ddl) — preflight, then record evidence after applying it.
1252
+ dbcli verify rollback \
1253
+ --kind ddl \
1254
+ --table users \
1255
+ --statement "ALTER TABLE users DROP COLUMN verified_at" \
1256
+ --verify-query "SELECT count(*)::int AS n FROM information_schema.columns WHERE table_name = 'users' AND column_name = 'verified_at'" \
1257
+ --expect "value == 0"
1258
+ dbcli verify rollback --kind ddl ... --after-write
1259
+
1260
+ # Data rollback (--kind dml) — revert an UPDATE, then read back.
1261
+ dbcli verify rollback \
1262
+ --kind dml \
1263
+ --table users \
1264
+ --statement "UPDATE users SET status = NULL WHERE status = 1" \
1265
+ --verify-query "SELECT count(*)::int AS n FROM users WHERE status = 1" \
1266
+ --expect "value == 0"
1267
+ dbcli verify rollback --kind dml ... --after-write
1268
+
1269
+ # JSON for agents (both kinds).
1270
+ dbcli verify rollback --kind ddl ... --format json
1271
+ ```
1272
+
1273
+ | Option | Required | Description |
1274
+ | --- | --- | --- |
1275
+ | `--kind <ddl\|dml>` | yes | Reverting-statement grammar: `ddl` (single `ALTER TABLE`) or `dml` (single `UPDATE`). Invalid value fails closed before any DB connection. |
1276
+ | `--table <table>` | yes | Table affected by the rollback. |
1277
+ | `--statement <sql>` | yes | Proposed reverting statement, analyzed but never executed. |
1278
+ | `--verify-query <sql>` | yes | Plain `SELECT` for post-rollback read-back verification. |
1279
+ | `--expect <expr>` | yes | Assertion expression for the read-back result. |
1280
+ | `--after-write` | no | Run the post-rollback assertion and write a v1 artifact. |
1281
+ | `--format <table\|json>` | no | Output format, default `table`. |
1282
+ | `--subject-name <name>` | no | Artifact subject name. Default is the table name. |
1283
+ | `--summary <text>` | no | Optional artifact summary override. |
1284
+
1285
+ A single `--statement` flag is used for both kinds (instead of reusing `--ddl` / `--query`)
1286
+ to keep the dual-kind surface honest. The guard sequence, statuses (`ready`/`blocked` in
1287
+ preflight; `verified` / `not_verified` / `blocked` / `indeterminate` in after-write), and
1288
+ exit codes are identical to the other two scenarios. **MVP restrictions:** DML rollback is
1289
+ `UPDATE`-only (INSERT/DELETE reverts deferred); DDL rollback is single `ALTER TABLE` only,
1290
+ using the same identifier contract as `verify migration`.
1291
+
1292
+ The artifact schema is unchanged: a rollback reuses the existing subject kinds —
1293
+ `--kind ddl` → `migration`, `--kind dml` → `backfill` — and records its provenance via
1294
+ `subject.command = "verify rollback"` plus the summary, so `verification` filters and
1295
+ retention are unaffected.
1296
+
1297
+ ### verification
1298
+
1299
+ (v1.33.0+) Local **VerificationArtifact** inspection and lifecycle surface over
1300
+ `<cwd>/.dbcli/verification/` (always relative to the current working directory,
1301
+ regardless of `--config` location). `list`, `show`, and `summary` are read-only;
1302
+ `prune` is a local lifecycle command — dry-run by default, deleting only with
1303
+ `--execute --force`. Requires no database connection and performs no audit writes.
1304
+
1305
+ **Subcommands:** `list` · `show` · `summary` · `prune`
1306
+
1307
+ #### `verification list`
1308
+
1309
+ List verification artifacts on disk, with optional filters.
1310
+
1311
+ ```bash
1312
+ dbcli verification list --format json
1313
+ dbcli verification list --status verified
1314
+ dbcli verification list --subject backfill
1315
+ dbcli verification list --subject backfill:safe-backfill-verify
1316
+ dbcli verification list --limit 20 --format json
1317
+ dbcli verification list --include-invalid --format json
1318
+ ```
1319
+
1320
+ | Flag | Purpose | Default |
1321
+ |---|---|---|
1322
+ | `--format <json\|table>` | Output format. | `json` |
1323
+ | `--limit <n>` | Maximum number of entries to return. | `20` |
1324
+ | `--status <status>` | Filter by status. One of: `verified`, `not_verified`, `indeterminate`, `blocked`. | all |
1325
+ | `--subject <kind[:name]>` | Filter by subject kind or exact `kind:name`. Allowed kinds: `recovery`, `task-pack`, `assertion`, `migration`, `backfill`, `manual`. | all |
1326
+ | `--include-invalid` | Surface malformed artifact files (normally skipped silently). Invalid files are returned as a separate top-level `invalid` array in JSON output, each entry shaped `{ "path": "...", "filename": "...", "error": "..." }`. When off, `invalid` is `[]`. | off |
1327
+
1328
+ **Missing directory:** if `.dbcli/verification/` does not exist, exits `0` with an
1329
+ empty result (list: `[]`, summary: zero counts).
1330
+
1331
+ **Malformed files:** by default, files that cannot be parsed as valid VerificationArtifact
1332
+ JSON are silently skipped. Pass `--include-invalid` to surface them.
1333
+
1334
+ #### `verification show`
1335
+
1336
+ Print a single verification artifact by its id (the artifact's `id` field) or by
1337
+ the path to the artifact file.
1338
+
1339
+ ```bash
1340
+ dbcli verification show abc123 --format json
1341
+ dbcli verification show abc123 --format table
1342
+ dbcli verification show .dbcli/verification/abc123.json --format json
1343
+ ```
1344
+
1345
+ | Flag | Purpose | Default |
1346
+ |---|---|---|
1347
+ | `<id-or-path>` | Positional. The artifact `id` (format `ver_<base36>_<hex>`), a unique id prefix, the artifact filename, or a path to the file inside `.dbcli/verification/`. | required |
1348
+ | `--format <json\|table>` | Output format. | `json` |
1349
+
1350
+ **Exit codes:**
1351
+ - `0` — artifact found and valid.
1352
+ - `1` — id or path not found, or the artifact file is malformed (parse error).
1353
+
1354
+ #### `verification summary`
1355
+
1356
+ Aggregate verification artifacts into status counts, optionally filtered.
1357
+
1358
+ ```bash
1359
+ dbcli verification summary --format json
1360
+ dbcli verification summary --status not_verified --format json
1361
+ dbcli verification summary --subject migration --format json
1362
+ dbcli verification summary --subject migration:add-status-column --format json
1363
+ ```
1364
+
1365
+ | Flag | Purpose | Default |
1366
+ |---|---|---|
1367
+ | `--format <json\|table>` | Output format. | `json` |
1368
+ | `--status <status>` | Filter to a single status before summarising. | all |
1369
+ | `--subject <kind[:name]>` | Filter by subject kind or exact `kind:name`. | all |
1370
+ | `--latest-only` | Narrow to the latest matching valid artifact plus status counts; the `subjects` breakdown is omitted. Missing artifacts return exit `0` with `latest: null`. | off |
1371
+
1372
+ **Output shape (JSON):**
1373
+ ```json
1374
+ {
1375
+ "storageDir": "/abs/path/.dbcli/verification",
1376
+ "latest": {
1377
+ "path": "...",
1378
+ "id": "ver_...",
1379
+ "createdAt": "2026-06-19T01:02:03.000Z",
1380
+ "status": "verified",
1381
+ "subject": { "kind": "backfill", "name": "safe-backfill-verify" },
1382
+ "summary": "..."
1383
+ },
1384
+ "counts": { "total": 4, "verified": 2, "not_verified": 1, "indeterminate": 0, "blocked": 1, "invalid": 0 },
1385
+ "subjects": [
1386
+ { "subject": { "kind": "backfill", "name": "safe-backfill-verify" }, "total": 3, "latestStatus": "verified", "latestCreatedAt": "2026-06-19T01:02:03.000Z" }
1387
+ ]
1388
+ }
1389
+ ```
1390
+
1391
+ `latest` is `null` when no valid artifacts match the filters.
1392
+
1393
+ #### `verification prune`
1394
+
1395
+ Preview or delete local verification artifacts under `<cwd>/.dbcli/verification/` by
1396
+ explicit retention criteria. **Dry-run by default**; deletes only with `--execute --force`.
1397
+
1398
+ ```bash
1399
+ dbcli verification prune --older-than 30d --format json # preview candidates
1400
+ dbcli verification prune --older-than 30d --execute --force # delete after preview
1401
+ dbcli verification prune --older-than 90d --status verified --keep-latest 50 --execute --force
1402
+ ```
1403
+
1404
+ | Option | Default | Meaning |
1405
+ | --- | --- | --- |
1406
+ | `--format <format>` | `json` | `json` or `table`. JSON is the authoritative contract. |
1407
+ | `--older-than <Nd>` | required | Minimum age in whole days (`7d`, `30d`, `365d`). |
1408
+ | `--keep-latest <n>` | `20` | Always protect the latest N valid artifacts across all subjects/statuses before filters. `0` protects none. |
1409
+ | `--status <status>` | none | Select only valid artifacts with this status. |
1410
+ | `--subject <kind:name>` | none | Select only valid artifacts with this subject. |
1411
+ | `--include-invalid` | `false` | Also select malformed `verification-*.json` files, by file mtime. |
1412
+ | `--execute` | `false` | Delete instead of preview. Requires `--force`. |
1413
+ | `--force` | `false` | Acknowledge deletion; required with `--execute`. |
1414
+
1415
+ Safety: deletion is scoped to regular `verification-*.json` files inside
1416
+ `.dbcli/verification/`; symlinks, directories, and path escapes are skipped with a
1417
+ reason. No database connection is opened and no audit entry is written. JSON output
1418
+ includes `storageDir`, `dryRun`, `cutoff`, `criteria`, `protected`, `candidates`,
1419
+ `deleted`, and `skipped`.
1420
+
1421
+ **Statuses:**
1422
+
1423
+ | Status | Meaning |
1424
+ |---|---|
1425
+ | `verified` | The assertion ran and evidence matched the expected state. |
1426
+ | `not_verified` | The assertion ran and evidence contradicted the expected state. |
1427
+ | `indeterminate` | The assertion ran but evidence was ambiguous (JSON parse failure, missing field, gate skip). |
1428
+ | `blocked` | Verification could not run due to config, permission, schema, placeholder, or safety gates. |
1429
+
1430
+ **Subject kinds:**
1431
+
1432
+ | Kind | Produced by |
1433
+ |---|---|
1434
+ | `recovery` | Post-recovery verification assertions. |
1435
+ | `task-pack` | Assertions generated by task pack plans. |
1436
+ | `assertion` | General-purpose inline assertions. |
1437
+ | `migration` | Schema migration pre/post checks. |
1438
+ | `backfill` | Data backfill verification assertions. |
1439
+ | `manual` | Manually triggered or ad-hoc verification runs. |
1440
+
1441
+ **Storage root:** `<cwd>/.dbcli/verification/` (cwd-relative; independent of `--config`).
1442
+
1443
+ **Permission:** n/a
1444
+
1107
1445
  ### doctor
1108
1446
 
1109
1447
  Run diagnostic checks on environment, configuration, connection, and data.
@@ -0,0 +1,41 @@
1
+ ---
2
+ name: migration-review
3
+ description: Capture pre-change schema evidence and preview a migration's DDL before it is applied.
4
+ tags: [migration, schema, readonly]
5
+ engines: [postgres, mysql]
6
+ params:
7
+ table:
8
+ type: string
9
+ required: true
10
+ description: The table the migration alters (exact name; confirm via `dbcli list`).
11
+ ddl:
12
+ type: string
13
+ required: true
14
+ description: The migration DDL statement to preview (not executed by this task).
15
+ safety:
16
+ mode: plan-only
17
+ requires:
18
+ - blacklist-list
19
+ - schema-check
20
+ steps:
21
+ - type: command
22
+ command: blacklist list
23
+ reason: Confirm the migration's target table and columns are not protected before previewing changes.
24
+ risk: readonly
25
+ - type: command
26
+ command: schema {{table}} --format json
27
+ reason: Capture the pre-change live schema as evidence to diff against after the migration lands.
28
+ risk: readonly
29
+ - type: command
30
+ command: plan "{{ddl}}"
31
+ reason: Preview the migration DDL's risk and scope without executing it.
32
+ risk: readonly
33
+ ---
34
+ # Agent Notes
35
+
36
+ Use this task before applying a schema migration. It only PLANS — it never runs DDL.
37
+ Save the pre-change `schema {{table}} --format json` output as the baseline. After the
38
+ migration is applied (out of band, via your migration tool), re-run
39
+ `schema {{table}} --format json` and diff the two to confirm the change matches intent.
40
+ Always prepare and record an explicit rollback statement before applying. Requires
41
+ data-admin permission to actually run DDL — this task does not grant it.
@@ -0,0 +1,38 @@
1
+ ---
2
+ name: pr-database-review
3
+ description: Review a PR's changed persistence paths, queries and migrations for database risk before merge.
4
+ tags: [review, safety, readonly]
5
+ engines: [postgres, mysql]
6
+ params:
7
+ query:
8
+ type: string
9
+ required: true
10
+ description: The most significant changed SQL/persistence statement to analyze (not executed by this task).
11
+ safety:
12
+ mode: plan-only
13
+ requires:
14
+ - blacklist-list
15
+ - schema-check
16
+ steps:
17
+ - type: command
18
+ command: blacklist list
19
+ reason: Confirm the tables and columns touched by the PR are protected as expected before reviewing changed queries.
20
+ risk: readonly
21
+ - type: command
22
+ command: inspect --format json
23
+ reason: Capture connection, permission tier and schema-cache context for the review.
24
+ risk: readonly
25
+ - type: command
26
+ command: plan "{{query}}"
27
+ reason: Analyze the riskiest changed statement's scope and safety without executing it.
28
+ risk: readonly
29
+ ---
30
+ # Agent Notes
31
+
32
+ Use this task when reviewing a pull request that changes persistence: queries, ORM
33
+ models, migrations, data exports or fixtures. It only PLANS — it never writes. Walk
34
+ the changed files and, for each risky persistence path, re-run `plan "<sql>"` on the
35
+ specific statement. Cross-check the `blacklist list` output against any new columns
36
+ the PR exposes (exports, logs, serializers). For schema/migration changes prefer the
37
+ `migration-review` pack; for index/perf concerns prefer `slow-endpoint-investigation`.
38
+ Do not run write operations or DDL as part of the review.
@@ -0,0 +1,63 @@
1
+ ---
2
+ name: safe-backfill-verify
3
+ description: Plan a safe backfill/UPDATE and a read-back assertion that verifies the write achieved its goal.
4
+ tags: [data, write, safety, verification]
5
+ engines: [postgres, mysql]
6
+ params:
7
+ table:
8
+ type: string
9
+ required: true
10
+ description: The table the backfill writes to (exact name; confirm via `dbcli list`).
11
+ query:
12
+ type: string
13
+ required: true
14
+ description: The backfill UPDATE statement to analyze (not executed by this task).
15
+ verify_query:
16
+ type: string
17
+ required: true
18
+ description: A read-only SELECT (typically count(*)) that proves the backfill's outcome.
19
+ expect:
20
+ type: string
21
+ required: true
22
+ description: The assertion expression for `assert --expect`, e.g. "rows == 0" or "value > 0".
23
+ safety:
24
+ mode: plan-only
25
+ requires:
26
+ - blacklist-list
27
+ - schema-check
28
+ steps:
29
+ - type: command
30
+ command: blacklist list
31
+ reason: Confirm the target table and its columns are not protected before planning a write.
32
+ risk: readonly
33
+ - type: command
34
+ command: schema {{table}} --format json
35
+ reason: Verify the exact column names and types the backfill will touch.
36
+ risk: readonly
37
+ - type: command
38
+ command: plan "{{query}}"
39
+ reason: Analyze the UPDATE's risk and scope without executing it.
40
+ risk: readonly
41
+ - type: command
42
+ command: assert "{{verify_query}}" --expect "{{expect}}"
43
+ reason: Read-back verification — confirm the backfill achieved its goal after the write.
44
+ risk: readonly
45
+ ---
46
+ # Agent Notes
47
+
48
+ Use this task when a backfill must be both safe and provably correct. This task only
49
+ PLANS — the execution sequence the agent runs manually is:
50
+
51
+ 1. Review the `plan "{{query}}"` output and confirm a narrow `WHERE` clause.
52
+ 2. Capture the scope: run `assert "{{verify_query}}" --expect "{{expect}}"` BEFORE the
53
+ write to record the starting count (or run the SELECT directly), so the expected
54
+ delta is known.
55
+ 3. Preview the write with the matching write command, for example
56
+ `dbcli update <table> --where "<predicate>" --set '<json>' --dry-run`. Keep raw
57
+ SQL in `plan "{{query}}"`; `query` does not dry-run arbitrary writes.
58
+ 4. Execute once the dry-run looks correct: re-run the write command without `--dry-run`
59
+ and with the required confirmation/force flag for your environment.
60
+ 5. Verify: re-run `assert "{{verify_query}}" --expect "{{expect}}"` AFTER the write.
61
+ `verified` means the read-back matched; anything else means stop and recover.
62
+
63
+ Requires read-write (or higher) permission to actually execute the write.
@@ -0,0 +1,40 @@
1
+ ---
2
+ name: slow-endpoint-investigation
3
+ description: Connect proxy, explain and missing-index evidence to investigate a slow endpoint's query.
4
+ tags: [diagnostics, performance, readonly]
5
+ engines: [postgres, mysql]
6
+ params:
7
+ query:
8
+ type: string
9
+ required: true
10
+ description: The suspected slow SQL statement behind the endpoint (not executed by this task).
11
+ safety:
12
+ mode: plan-only
13
+ requires:
14
+ - blacklist-list
15
+ steps:
16
+ - type: command
17
+ command: blacklist list
18
+ reason: Confirm sensitive tables and columns are protected before inspecting query internals.
19
+ risk: readonly
20
+ - type: command
21
+ command: proxy analyze --format json
22
+ reason: Aggregate observed slow queries and N+1 patterns from the local proxy event log.
23
+ risk: readonly
24
+ - type: command
25
+ command: explain "{{query}}"
26
+ reason: Inspect the query plan for the suspected statement without running it for effect.
27
+ risk: readonly
28
+ - type: command
29
+ command: guide missing-index-for "{{query}}" --format json
30
+ reason: Get advisory index candidates that could remove the slow scan.
31
+ risk: readonly
32
+ ---
33
+ # Agent Notes
34
+
35
+ Use this task when an endpoint is slow and you want evidence, not guesses. Start from
36
+ `proxy analyze` (requires that the local observability proxy has captured traffic) to
37
+ find the hottest query/table, then `explain` that statement and review
38
+ `guide missing-index-for` candidates. Index advice is ADVISORY: do not create indexes
39
+ directly — route any proposed index through the `migration-review` pack first, then
40
+ verify before/after with `snapshot`/`assert` or `report --section perf` deltas.