@carllee1983/dbcli 1.52.1 → 1.54.0

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.
@@ -110,8 +110,8 @@ still stop where those gates require human confirmation.
110
110
  term, or relationship/join intent instead of a physical table or field name, first run
111
111
  `dbcli skill context --format json`. If it includes `semantic`, treat that reviewed
112
112
  section as the governed vocabulary; use `dbcli semantic search <terms> --format json`
113
- to look up a specific term. If no semantic section exists or search returns no result,
114
- fall back to `blacklist` → `schema` mapping and tell the user that optional
113
+ to look up a specific term. If `contracts` is present, use only its approved terms and
114
+ their descriptive evidence policy; it never authorizes an assertion or query. If no semantic section exists or search returns no result, fall back to `blacklist` → `schema` mapping and tell the user that optional
115
115
  `dbcli.semantic.json` can make future requests consistent. Never create, update, or
116
116
  migrate that file without an explicit human request; semantic vocabulary never replaces
117
117
  schema confirmation or the normal query/write safety gates.
@@ -159,6 +159,7 @@ in **How to use dbcli** still applies.
159
159
  | ORM or migration work | `schema --format json` → `diff --against-orm <orm-schema>` → review error-level drift → proposals via `migrate` (dry-run) → `migration-review` task pack → `diff --against <snapshot>` after applying. |
160
160
  | Schema design, no database yet | `design init --output ./dbcli.design.json` → edit → `design validate` → `design render --format mermaid`. With existing ORM models, reconcile via `design diff --against-orm <path>` first. |
161
161
  | Design drift on a live database | `blacklist list` → `schema --format json` → `design diff --against-cache` → `design propose --against-cache`, then hand the plan to a human before any migration. |
162
+ | PR schema-change review | `blacklist list` → `impact assess --design ./dbcli.design.json --against-cache --output ./impact.json --fail-on warn`; optionally add explicit `--events ./.dbcli/proxy/events.jsonl` for advisory redacted workload table evidence (never SQL/log rendering or a blocker), then review declared findings, coverage gaps, and the optional reviewed `dbcli.data-access.json` (declared operations only; never source parsing). |
162
163
  | PR database review | Review changed persistence paths, then propose concrete `schema` / `plan` / `dry-run` / `report` / `guide` commands per material claim. |
163
164
  | Slow endpoint or query | `report --section perf` → task pack `analyze-table-perf` → `lint "<query>"` → `guide missing-index-for "<query>"`; use `proxy analyze` when logs exist. |
164
165
  | Safe data backfill | `blacklist list` → `schema <object>` → count/scope query → `update … --dry-run` → read-back or snippet `--verify`. |
@@ -201,7 +202,9 @@ Guardrails:
201
202
  - Durable evidence: `assert … --write-verification-artifact --verification-subject <kind:name>`;
202
203
  inspect with `verification summary` / `list` / `show <id>`. The `verify safe-backfill` /
203
204
  `migration` / `rollback --kind <ddl|dml>` / `constraint --check <fk|not-null|unique|custom>`
204
- family runs preflight + `--after-write` checks and **never executes the write**. Full flags
205
+ family runs preflight + `--after-write` checks and **never executes the write**. Add
206
+ `--evidence-receipt <workspace-relative-path>` only after after-write for a safe provenance
207
+ receipt; it is never approval to execute a write. Full flags
205
208
  and the per-command blocks are in [reference.md](../skills/dbcli/reference.md#commands).
206
209
 
207
210
  ## Audit log
@@ -415,6 +418,7 @@ Full flags and edge cases: see [reference.md](../skills/dbcli/reference.md#init)
415
418
  | `shell` | (same as query+) | Interactive REPL. SQL engines, MongoDB, and Redis (single-line; `.no-limit on/off`). Elasticsearch opens a Kibana Dev Tools-style REPL (`<METHOD> /<path>` + optional JSON body, blank line submits). |
416
419
  | `skill` | n/a | Generate / install AI skill docs (`--install <claude\|gemini\|antigravity\|copilot\|cursor\|codex\|windsurf>`); `skill tasks list/show/plan` for Agent Task Packs; `skill context` for an LLM prompt-context payload (for injecting into another LLM, not needed for normal operation). |
417
420
  | `semantic` | n/a | Validate, search, inspect drift, migrate to v2, or print the optional project-root `dbcli.semantic.json`. Give its reviewed context to an external agent, but keep provider credentials, prompts, and agent context outside dbcli. `semantic draft validate --input <file|-> [--format text\|json]` validates only the explicit untrusted `QueryDraft` offline against local semantic/schema/saved-query metadata; it returns safe hashes/references/violation codes, never executes or echoes candidate SQL. Review the original draft, then invoke `explain` or `query` separately if intended. |
421
+ | `contract` | n/a | Validate, inspect approved context, search, or inspect drift for optional project-root `dbcli.contracts.json`. Contracts add ownership and a descriptive evidence policy to canonical semantic references; they are offline, never execute SQL, and cannot create verification or query authority. `skill context` includes only valid approved contracts. |
418
422
  | `migrate` | admin | SQL only. **DDL; dry-run by default** — needs `--execute`. |
419
423
 
420
424
  Use root-level `dbcli --use <name> <command>` for any command; `query`, `schema`, `list`,
@@ -601,4 +605,4 @@ schema. Raw `query` / `export` invocations render a sortable table only.
601
605
  - Blacklisted tables and columns are redacted from query output.
602
606
  - `schema` reports `estimatedRowCount` and `sizeCategory` (small / medium / large / huge). For large/huge tables add `WHERE` or `LIMIT` — bands in [reference.md](../skills/dbcli/reference.md#schema).
603
607
  - `doctor` on `mongodb+srv://` reports whether SRV resolves natively or through the DoH fallback — useful when the runtime restricts DNS.
604
- - **Global flags:** `--version`, `--config <path>`, `--global`, `--use <name>`, `--timeout <ms>`, `-v` / `--verbose` / `-vv`, `-q` / `--quiet`, `--no-color` (also honours `NO_COLOR`). Root-level flags must precede the command unless the command explicitly declares a command-level option.
608
+ - **Global flags:** `--version`, `--config <path>`, `--global`, `--use <name>`, `--timeout <ms>`, `--statement-timeout <ms>`, `-v` / `--verbose` / `-vv`, `-q` / `--quiet`, `--no-color` (also honours `NO_COLOR`). Root-level flags must precede the command unless the command explicitly declares a command-level option.
@@ -38,6 +38,7 @@ never the right move.
38
38
  [check](#check) ·
39
39
  [diff](#diff) ·
40
40
  [design](#design) ·
41
+ [impact assess](#impact-assess) ·
41
42
  [snapshot](#snapshot) ·
42
43
  [assert](#assert) ·
43
44
  [proxy](#proxy) ·
@@ -51,12 +52,14 @@ never the right move.
51
52
  [verify](#verify) ·
52
53
  [verification](#verification) ·
53
54
  [backfill](#backfill) ·
55
+ [evidence](#evidence) ·
54
56
  [doctor](#doctor) ·
55
57
  [completion](#completion) ·
56
58
  [upgrade](#upgrade) ·
57
59
  [shell](#dbcli-shell) ·
58
60
  [migrate](#migrate) ·
59
61
  [semantic](#semantic) ·
62
+ [contract](#contract) ·
60
63
  [skill](#skill) ·
61
64
  [skill context](#skill-context) ·
62
65
  [skill tasks](#skill-tasks-agent-task-packs)
@@ -80,13 +83,16 @@ command-level option is only valid after the command that declares it.
80
83
  | `--global` | Select the user-global registry at `~/.config/dbcli/config.json` instead of the current project's `.dbcli` config. Place it before the command path. |
81
84
  | `--use <connection>` | Select a named connection for this invocation; place it before the command path unless that command explicitly lists a command-level `--use`. |
82
85
  | `--timeout <ms>` | Connection timeout in milliseconds (integer, 100–600000), overriding the connection config's `timeout` field for this invocation. Applies to every engine adapter. Without either the flag or the config field, adapters fall back to their built-in 5000ms default. |
86
+ | `--statement-timeout <ms>` | How long a single statement may run, in milliseconds (integer, 0–3600000; `0` removes the limit), overriding the connection config's `statementTimeout` field. Independent of the connection timeout — raising it does not slow down detection of an unreachable host. Falls back to `--timeout` when unset, and to the server's own setting when neither is given. |
83
87
 
84
88
  `--timeout` is applied only when the adapter is constructed for this invocation — it is
85
89
  never written back to `config.json`. Set the connection's `timeout` field instead for a
86
- value that persists across runs. On PostgreSQL, the same value is also used as the
87
- session's `statement_timeout` (not just the connection timeout), so a low value can cut
88
- off a long-running query with an error that looks like a connection timeout; the 100ms
89
- floor exists specifically to keep that failure mode from being too easy to trigger.
90
+ value that persists across runs. `--timeout` caps statement time as well as connection time, so a
91
+ low value cuts off a long-running query with an error that reads like a connection
92
+ problem; the 100ms floor exists specifically to keep that failure mode from being too
93
+ easy to trigger. Use `--statement-timeout` when only the statement limit should change.
94
+ With neither flag, dbcli sets no statement limit at all — the server's setting decides,
95
+ so a query that runs longer than the connection timeout is no longer cut off.
90
96
  Elasticsearch applies its timeout per request rather than once for the whole connection.
91
97
  The `timeout` field itself always takes a literal number — unlike other connection
92
98
  fields, it does not accept an `{"$env": "..."}` reference.
@@ -217,8 +223,8 @@ dbcli list --include-system # Elasticsearch: include `.system` indices
217
223
  **Permission:** query-only+
218
224
 
219
225
  > **MongoDB:** Lists collections with estimated document count.
220
- > **Redis:** Returns up to 100 000 keys via `SCAN MATCH * COUNT 1000`. The header reads `Keys in db <n> (redis):` where `<n>` is the logical DB index.
221
- > **Elasticsearch:** Returns indices with `documentCount` from `/_stats/docs`; aliases are tagged separately. System indices (names starting with `.`) are hidden unless `--include-system` is passed.
226
+ > **Redis:** Samples the first 1 000 keys scanned via `SCAN MATCH * COUNT 1000`, applying the blacklist during the scan. When the keyspace is larger, table output adds a `Sampled the first 1000 keys scanned` line and JSON output carries `sampled: true` with `sampleLimit`. The header reads `Keys in db <n> (redis):` where `<n>` is the logical DB index.
227
+ > **Elasticsearch:** Returns indices with `documentCount` from one `/_cat/indices?h=index,docs.count&expand_wildcards=all` request (open and closed indices alike). The count is primaries-only, so a replicated index no longer reports its replica copies as extra documents. Aliases are tagged separately. System indices (names starting with `.`) are hidden unless `--include-system` is passed.
222
228
 
223
229
  ### schema
224
230
 
@@ -240,6 +246,13 @@ dbcli schema --use prod # Scan prod DB; saves to .dbcli/schemas/prod
240
246
  **Options:** `--format <table|json>`, `--refresh`, `--reset`, `--force`, `--use <connection>`, `--sample-size <n>` (mongo only), `--sample-method <random|natural>` (mongo only)
241
247
  **Permission:** query-only+
242
248
 
249
+ > **Row counts on a full scan:** scanning every table records
250
+ > `rowCountIsEstimate: true` and reports the engine's row *estimate* (`information_schema.TABLES.TABLE_ROWS` on MySQL/MariaDB,
251
+ > `pg_class.reltuples` on PostgreSQL) rather than running `COUNT(*)` per table —
252
+ > a hundred full-table counts is what made scanning a large database unusable.
253
+ > `dbcli schema <table>` on a single table still reports the exact count. Tables
254
+ > are scanned with bounded parallelism (4 at a time).
255
+
243
256
  **Schema storage (v1.4+):** Schema is persisted as layered files under `.dbcli/schemas/`. With v2 multi-connection config each connection gets its own subdirectory (`.dbcli/schemas/<connection>/`). Run `dbcli schema --use <connection>` once per connection before querying it — otherwise `schema <table>` may return data from the wrong connection's cache.
244
257
 
245
258
  > **PostgreSQL:** Introspection uses the exact `public` catalog identity throughout. Full catalog/schema/table joins prevent a reused constraint name from contaminating another table; enum lookup includes its namespace; composite primary-key order comes from the exact table OID and index ordinality; and row estimates are scoped to the exact `public` relation. Row-count SQL qualifies and quotes both `"public"` and the exact table identifier, escaping embedded quotes so mixed-case or punctuation-bearing names remain distinct and safe.
@@ -283,6 +296,12 @@ dbcli query "SELECT * FROM orders" --format html > orders.html # pipe to stdou
283
296
  **Options:** `--format <table|json|csv|html>`, `--ui` (open the dashboard in the system browser; implies `--format html`), `--limit <number>`, `--no-limit`, `--collection <name>` (MongoDB / Elasticsearch), `--index <name>` (Elasticsearch alias for `--collection`), `--fields <list>`, `--truncate <number>` / `--no-truncate`, `-f, --query-file <path>`, `--use <name[,name]>`, `--slow-ms <number>`, `--recovery`
284
297
  **Permission:** query-only+ (Redis: per-command; Elasticsearch: per HTTP method/path)
285
298
 
299
+ > **Server-side scripts are rejected on every path.** MongoDB `$where`,
300
+ > `$function`, and `$accumulator`, and Elasticsearch `script` / `script_fields`,
301
+ > execute code on the database server. The adapters reject them anywhere in a
302
+ > filter, pipeline, or DSL body — before the request is sent — so `query`, `q`,
303
+ > saved snippets, and DML planning all behave the same way.
304
+
286
305
  #### Passive slow-query hint (`--slow-ms`)
287
306
 
288
307
  `query` and `q` read the execution time they already measured for a finished
@@ -1189,6 +1208,7 @@ dbcli design validate [--file <path>] [--format <format>]
1189
1208
  dbcli design render [--file <path>] [--format <format>]
1190
1209
  dbcli design diff (--against-cache | --against-orm <paths>) [options]
1191
1210
  dbcli design propose (--against-cache | --against-orm <paths>) [options]
1211
+ dbcli impact assess --design <path> (--against-cache | --against-orm <paths>) --output <path> [options]
1192
1212
  ```
1193
1213
 
1194
1214
  ```bash
@@ -1200,6 +1220,7 @@ dbcli design render --format mermaid
1200
1220
  dbcli design diff --against-cache --format markdown
1201
1221
  dbcli design diff --against-orm ./prisma/schema.prisma --format markdown
1202
1222
  dbcli design propose --against-orm ./prisma/schema.prisma --format markdown
1223
+ dbcli impact assess --design ./dbcli.design.json --against-cache --output ./impact.json --fail-on warn
1203
1224
  ```
1204
1225
 
1205
1226
  | Option | Applies to | Default | Meaning |
@@ -1216,6 +1237,10 @@ dbcli design propose --against-orm ./prisma/schema.prisma --format markdown
1216
1237
  `diff` and `propose` require **exactly one** comparison target; passing both or
1217
1238
  neither is an error.
1218
1239
 
1240
+ ### impact assess
1241
+
1242
+ Writes an offline JSON or Markdown report for the known declared impact of a design change. It requires `--design`, exactly one baseline (`--against-cache` or `--against-orm`), and an explicit workspace-contained `--output`. `--format` is `json` (default) or `markdown`; `--fail-on` is `error`, `warn`, or `never` (default). The threshold changes only the successful command exit code after the report is written. The report is limited to declared/partial coverage and never claims complete coverage. It may join the optional reviewed `dbcli.data-access.json` manifest only after validating its canonical semantic references and existing workspace-relative source paths; it never reads those sources. An optional explicit `--events <path>` is bounded and streamed through a redaction-first projection that retains recent safe table metadata only. It never starts a proxy, reads a rotated log, renders SQL/literals/errors/sessions/paths, or makes the command fail solely because workload evidence is absent or advisory. It reads no database, executes no SQL, and never reads saved-query bodies.
1243
+
1219
1244
  #### Artifact shape
1220
1245
 
1221
1246
  This example validates clean (0 errors, 0 warnings):
@@ -1939,7 +1964,7 @@ Output reports: writer enabled/disabled, last write result, file-lock state, rot
1939
1964
  ### verify
1940
1965
 
1941
1966
  Run a verification scenario. `verify` **runs** verification scenarios (safe-backfill,
1942
- migration, rollback) and never executes writes/DDL. `verification` **inspects and manages**
1967
+ migration, rollback, constraint) and never executes writes/DDL. `verification` **inspects and manages**
1943
1968
  the local result artifacts those scenarios produce under `.dbcli/verification/`.
1944
1969
 
1945
1970
  ```bash
@@ -1951,7 +1976,8 @@ dbcli verify safe-backfill \
1951
1976
  --expect "value == 0"
1952
1977
 
1953
1978
  # After-write: re-run guards, run the read-back assertion, write a v1 artifact.
1954
- dbcli verify safe-backfill ... --after-write
1979
+ # An optional receipt is provenance only, never approval to execute a write.
1980
+ dbcli verify safe-backfill ... --after-write --evidence-receipt .dbcli/evidence/verify-receipt.json
1955
1981
 
1956
1982
  # JSON for agents.
1957
1983
  dbcli verify safe-backfill ... --format json
@@ -1959,7 +1985,11 @@ dbcli verify safe-backfill ... --format json
1959
1985
 
1960
1986
  Options: `--table` (req), `--query` (req, analyzed not executed), `--verify-query`
1961
1987
  (req, **plain SELECT only**), `--expect` (req), `--after-write`, `--format <table|json>`,
1962
- `--subject-name <name>`, `--summary <text>`.
1988
+ `--subject-name <name>`, `--summary <text>`, `--evidence-receipt <workspace-relative-path>`
1989
+ (after-write only). A receipt is safe provenance for the already-executed verification,
1990
+ not approval to execute a write. Its `succeeded`/`failed` outcome remains distinct from
1991
+ the artifact status (`verified`, `not_verified`, `indeterminate`, or `blocked`); task-pack
1992
+ `planned` evidence stays plan-only.
1963
1993
 
1964
1994
  Guard constraints (fail closed): `--verify-query` must be a **plain `SELECT`** —
1965
1995
  `EXPLAIN`/`EXPLAIN ANALYZE`, `SHOW`, `DESCRIBE`, and data-modifying CTEs are rejected
@@ -2464,6 +2494,66 @@ dbcli migrate drop-enum status --execute --force
2464
2494
 
2465
2495
  **AI agent note:** Always use dry-run first (no `--execute`) to preview generated SQL. Only add `--execute` after confirming the SQL is correct. For DROP operations, both `--execute` and `--force` are required.
2466
2496
 
2497
+ ### evidence
2498
+
2499
+ Compose a canonical, offline **Evidence Pack** from existing verification artifacts
2500
+ and audit entries. This command never opens a database connection. A pack retains only
2501
+ safe pointers and outcome fields: it excludes SQL, targets, audit metadata, verification
2502
+ summaries, result data, and credentials. Claims are external statements, never dbcli
2503
+ verification verdicts.
2504
+
2505
+ #### `evidence compose`
2506
+
2507
+ ```bash
2508
+ dbcli evidence compose --claims ./claims.json --verification ver_abcd --audit 1a2b \
2509
+ --receipt .dbcli/evidence/verify-receipt.json \
2510
+ --output .dbcli/evidence/review.json --format json
2511
+ ```
2512
+
2513
+ | Flag | Purpose | Default |
2514
+ |---|---|---|
2515
+ | `--claims <file>` | Required JSON file with exactly `subject` and `claims`; every claim has an `id` and plain-language `text`. SQL-shaped text, credentials, error content, and blacklisted identifiers are rejected. | — |
2516
+ | `--verification <selector...>` | One or more verification artifact ids, unique prefixes, filenames, or in-bounds paths. | none |
2517
+ | `--audit <selector...>` | One or more audit ids or unique prefixes (minimum four characters) from the active connection. | none |
2518
+ | `--receipt <path...>` | Explicit workspace-relative receipt path(s). Receipts contribute safe provenance only; they are not execution approval. | none |
2519
+ | `--output <path>` | Required new JSON path under the current workspace. Existing files and paths outside the workspace are refused. | — |
2520
+ | `--format <json\|markdown>` | Compose receipt format printed to stdout. | `json` |
2521
+
2522
+ At least one `--verification`, `--audit`, or `--receipt` reference is required. The resulting pack
2523
+ contains a canonical SHA-256 integrity digest and `coverage.completeForDeclaredEvidence:
2524
+ true` for its explicitly selected references.
2525
+
2526
+ #### `evidence validate`
2527
+
2528
+ ```bash
2529
+ dbcli evidence validate --file .dbcli/evidence/review.json --format json
2530
+ ```
2531
+
2532
+ | Flag | Purpose | Default |
2533
+ |---|---|---|
2534
+ | `--file <path>` | Required evidence-pack JSON file. | — |
2535
+ | `--format <json\|markdown>` | Validation report format. | `json` |
2536
+
2537
+ Exit `0` when digest and all selected sources are valid. If a referenced audit or
2538
+ verification artifact later rotates, is cleared, disappears, or belongs to a different
2539
+ active connection, output stays parseable with `integrity: "valid"` and
2540
+ `references: "source-expired"`, then exits `1`.
2541
+
2542
+ #### `evidence render`
2543
+
2544
+ ```bash
2545
+ dbcli evidence render --file .dbcli/evidence/review.json --format markdown
2546
+ ```
2547
+
2548
+ | Flag | Purpose | Default |
2549
+ |---|---|---|
2550
+ | `--file <path>` | Required evidence-pack JSON file. | — |
2551
+ | `--format <json\|markdown>` | Render format. | `markdown` |
2552
+
2553
+ `render` validates the pack digest and active blacklist policy but does not resolve its
2554
+ original references. It is therefore available for historical review after `validate`
2555
+ reports `source-expired`, unless an exposed pack field is now blacklisted.
2556
+
2467
2557
  ### semantic
2468
2558
 
2469
2559
  Validate or print the optional, version-controlled `dbcli.semantic.json` in the
@@ -2590,6 +2680,39 @@ limits, audit, and recovery safeguards remain in force.
2590
2680
 
2591
2681
  **Permission:** n/a (local files only; no database connection).
2592
2682
 
2683
+ ### contract
2684
+
2685
+ Inspect the optional, version-controlled `dbcli.contracts.json` without opening a
2686
+ database connection. A contract adds a reviewed owner and descriptive evidence policy
2687
+ to canonical semantic references; it is not an executable data contract, assertion,
2688
+ query, or verification scenario.
2689
+
2690
+ ```bash
2691
+ dbcli contract validate --format json
2692
+ dbcli contract context --format json
2693
+ dbcli contract context --format markdown
2694
+ dbcli contract search customer --format json
2695
+ dbcli contract drift --format json
2696
+ ```
2697
+
2698
+ The strict v1 artifact contains `version` and `contracts`. Each contract has a unique
2699
+ canonical `name`, `status` (`draft`, `approved`, or `deprecated`), bounded plain-text
2700
+ `description` and `owner`, one or more canonical semantic `subjects`, optional aliases,
2701
+ and an `evidencePolicy` of `none`, `receipt-required`, or `verification-required`.
2702
+ Subjects must remain in the existing visible semantic registry; protected identifiers,
2703
+ unknown keys, duplicate names or subjects, SQL-like text, credentials, and stale
2704
+ references fail closed without exposing protected names.
2705
+
2706
+ `contract validate` requires an explicit valid artifact. `contract context` and
2707
+ `contract search` return only valid approved contracts; draft and deprecated contracts
2708
+ remain local review artifacts. `contract drift` reports `valid`, `stale`, `invalid`, or
2709
+ `unavailable` evidence offline and exits non-zero except for `valid`. A missing default
2710
+ file is allowed by `skill context` and leaves ordinary semantic context unchanged; a
2711
+ present invalid file fails closed. No contract command writes a file, opens a database
2712
+ connection, widens a `QueryDraft`, or changes permission/blacklist behavior.
2713
+
2714
+ **Permission:** n/a (local files only; no database connection).
2715
+
2593
2716
  ### skill
2594
2717
 
2595
2718
  Emit `SKILL.md` (and the companion `reference.md`) to stdout, a file, or an
@@ -110,8 +110,8 @@ still stop where those gates require human confirmation.
110
110
  term, or relationship/join intent instead of a physical table or field name, first run
111
111
  `dbcli skill context --format json`. If it includes `semantic`, treat that reviewed
112
112
  section as the governed vocabulary; use `dbcli semantic search <terms> --format json`
113
- to look up a specific term. If no semantic section exists or search returns no result,
114
- fall back to `blacklist` → `schema` mapping and tell the user that optional
113
+ to look up a specific term. If `contracts` is present, use only its approved terms and
114
+ their descriptive evidence policy; it never authorizes an assertion or query. If no semantic section exists or search returns no result, fall back to `blacklist` → `schema` mapping and tell the user that optional
115
115
  `dbcli.semantic.json` can make future requests consistent. Never create, update, or
116
116
  migrate that file without an explicit human request; semantic vocabulary never replaces
117
117
  schema confirmation or the normal query/write safety gates.
@@ -159,6 +159,7 @@ in **How to use dbcli** still applies.
159
159
  | ORM or migration work | `schema --format json` → `diff --against-orm <orm-schema>` → review error-level drift → proposals via `migrate` (dry-run) → `migration-review` task pack → `diff --against <snapshot>` after applying. |
160
160
  | Schema design, no database yet | `design init --output ./dbcli.design.json` → edit → `design validate` → `design render --format mermaid`. With existing ORM models, reconcile via `design diff --against-orm <path>` first. |
161
161
  | Design drift on a live database | `blacklist list` → `schema --format json` → `design diff --against-cache` → `design propose --against-cache`, then hand the plan to a human before any migration. |
162
+ | PR schema-change review | `blacklist list` → `impact assess --design ./dbcli.design.json --against-cache --output ./impact.json --fail-on warn`; optionally add explicit `--events ./.dbcli/proxy/events.jsonl` for advisory redacted workload table evidence (never SQL/log rendering or a blocker), then review declared findings, coverage gaps, and the optional reviewed `dbcli.data-access.json` (declared operations only; never source parsing). |
162
163
  | PR database review | Review changed persistence paths, then propose concrete `schema` / `plan` / `dry-run` / `report` / `guide` commands per material claim. |
163
164
  | Slow endpoint or query | `report --section perf` → task pack `analyze-table-perf` → `lint "<query>"` → `guide missing-index-for "<query>"`; use `proxy analyze` when logs exist. |
164
165
  | Safe data backfill | `blacklist list` → `schema <object>` → count/scope query → `update … --dry-run` → read-back or snippet `--verify`. |
@@ -201,7 +202,9 @@ Guardrails:
201
202
  - Durable evidence: `assert … --write-verification-artifact --verification-subject <kind:name>`;
202
203
  inspect with `verification summary` / `list` / `show <id>`. The `verify safe-backfill` /
203
204
  `migration` / `rollback --kind <ddl|dml>` / `constraint --check <fk|not-null|unique|custom>`
204
- family runs preflight + `--after-write` checks and **never executes the write**. Full flags
205
+ family runs preflight + `--after-write` checks and **never executes the write**. Add
206
+ `--evidence-receipt <workspace-relative-path>` only after after-write for a safe provenance
207
+ receipt; it is never approval to execute a write. Full flags
205
208
  and the per-command blocks are in [reference.md](reference.md#commands).
206
209
 
207
210
  ## Audit log
@@ -415,6 +418,7 @@ Full flags and edge cases: see [reference.md](reference.md#init).
415
418
  | `shell` | (same as query+) | Interactive REPL. SQL engines, MongoDB, and Redis (single-line; `.no-limit on/off`). Elasticsearch opens a Kibana Dev Tools-style REPL (`<METHOD> /<path>` + optional JSON body, blank line submits). |
416
419
  | `skill` | n/a | Generate / install AI skill docs (`--install <claude\|gemini\|antigravity\|copilot\|cursor\|codex\|windsurf>`); `skill tasks list/show/plan` for Agent Task Packs; `skill context` for an LLM prompt-context payload (for injecting into another LLM, not needed for normal operation). |
417
420
  | `semantic` | n/a | Validate, search, inspect drift, migrate to v2, or print the optional project-root `dbcli.semantic.json`. Give its reviewed context to an external agent, but keep provider credentials, prompts, and agent context outside dbcli. `semantic draft validate --input <file|-> [--format text\|json]` validates only the explicit untrusted `QueryDraft` offline against local semantic/schema/saved-query metadata; it returns safe hashes/references/violation codes, never executes or echoes candidate SQL. Review the original draft, then invoke `explain` or `query` separately if intended. |
421
+ | `contract` | n/a | Validate, inspect approved context, search, or inspect drift for optional project-root `dbcli.contracts.json`. Contracts add ownership and a descriptive evidence policy to canonical semantic references; they are offline, never execute SQL, and cannot create verification or query authority. `skill context` includes only valid approved contracts. |
418
422
  | `migrate` | admin | SQL only. **DDL; dry-run by default** — needs `--execute`. |
419
423
 
420
424
  Use root-level `dbcli --use <name> <command>` for any command; `query`, `schema`, `list`,
@@ -601,4 +605,4 @@ schema. Raw `query` / `export` invocations render a sortable table only.
601
605
  - Blacklisted tables and columns are redacted from query output.
602
606
  - `schema` reports `estimatedRowCount` and `sizeCategory` (small / medium / large / huge). For large/huge tables add `WHERE` or `LIMIT` — bands in [reference.md](reference.md#schema).
603
607
  - `doctor` on `mongodb+srv://` reports whether SRV resolves natively or through the DoH fallback — useful when the runtime restricts DNS.
604
- - **Global flags:** `--version`, `--config <path>`, `--global`, `--use <name>`, `--timeout <ms>`, `-v` / `--verbose` / `-vv`, `-q` / `--quiet`, `--no-color` (also honours `NO_COLOR`). Root-level flags must precede the command unless the command explicitly declares a command-level option.
608
+ - **Global flags:** `--version`, `--config <path>`, `--global`, `--use <name>`, `--timeout <ms>`, `--statement-timeout <ms>`, `-v` / `--verbose` / `-vv`, `-q` / `--quiet`, `--no-color` (also honours `NO_COLOR`). Root-level flags must precede the command unless the command explicitly declares a command-level option.
@@ -38,6 +38,7 @@ never the right move.
38
38
  [check](#check) ·
39
39
  [diff](#diff) ·
40
40
  [design](#design) ·
41
+ [impact assess](#impact-assess) ·
41
42
  [snapshot](#snapshot) ·
42
43
  [assert](#assert) ·
43
44
  [proxy](#proxy) ·
@@ -51,12 +52,14 @@ never the right move.
51
52
  [verify](#verify) ·
52
53
  [verification](#verification) ·
53
54
  [backfill](#backfill) ·
55
+ [evidence](#evidence) ·
54
56
  [doctor](#doctor) ·
55
57
  [completion](#completion) ·
56
58
  [upgrade](#upgrade) ·
57
59
  [shell](#dbcli-shell) ·
58
60
  [migrate](#migrate) ·
59
61
  [semantic](#semantic) ·
62
+ [contract](#contract) ·
60
63
  [skill](#skill) ·
61
64
  [skill context](#skill-context) ·
62
65
  [skill tasks](#skill-tasks-agent-task-packs)
@@ -80,13 +83,16 @@ command-level option is only valid after the command that declares it.
80
83
  | `--global` | Select the user-global registry at `~/.config/dbcli/config.json` instead of the current project's `.dbcli` config. Place it before the command path. |
81
84
  | `--use <connection>` | Select a named connection for this invocation; place it before the command path unless that command explicitly lists a command-level `--use`. |
82
85
  | `--timeout <ms>` | Connection timeout in milliseconds (integer, 100–600000), overriding the connection config's `timeout` field for this invocation. Applies to every engine adapter. Without either the flag or the config field, adapters fall back to their built-in 5000ms default. |
86
+ | `--statement-timeout <ms>` | How long a single statement may run, in milliseconds (integer, 0–3600000; `0` removes the limit), overriding the connection config's `statementTimeout` field. Independent of the connection timeout — raising it does not slow down detection of an unreachable host. Falls back to `--timeout` when unset, and to the server's own setting when neither is given. |
83
87
 
84
88
  `--timeout` is applied only when the adapter is constructed for this invocation — it is
85
89
  never written back to `config.json`. Set the connection's `timeout` field instead for a
86
- value that persists across runs. On PostgreSQL, the same value is also used as the
87
- session's `statement_timeout` (not just the connection timeout), so a low value can cut
88
- off a long-running query with an error that looks like a connection timeout; the 100ms
89
- floor exists specifically to keep that failure mode from being too easy to trigger.
90
+ value that persists across runs. `--timeout` caps statement time as well as connection time, so a
91
+ low value cuts off a long-running query with an error that reads like a connection
92
+ problem; the 100ms floor exists specifically to keep that failure mode from being too
93
+ easy to trigger. Use `--statement-timeout` when only the statement limit should change.
94
+ With neither flag, dbcli sets no statement limit at all — the server's setting decides,
95
+ so a query that runs longer than the connection timeout is no longer cut off.
90
96
  Elasticsearch applies its timeout per request rather than once for the whole connection.
91
97
  The `timeout` field itself always takes a literal number — unlike other connection
92
98
  fields, it does not accept an `{"$env": "..."}` reference.
@@ -217,8 +223,8 @@ dbcli list --include-system # Elasticsearch: include `.system` indices
217
223
  **Permission:** query-only+
218
224
 
219
225
  > **MongoDB:** Lists collections with estimated document count.
220
- > **Redis:** Returns up to 100 000 keys via `SCAN MATCH * COUNT 1000`. The header reads `Keys in db <n> (redis):` where `<n>` is the logical DB index.
221
- > **Elasticsearch:** Returns indices with `documentCount` from `/_stats/docs`; aliases are tagged separately. System indices (names starting with `.`) are hidden unless `--include-system` is passed.
226
+ > **Redis:** Samples the first 1 000 keys scanned via `SCAN MATCH * COUNT 1000`, applying the blacklist during the scan. When the keyspace is larger, table output adds a `Sampled the first 1000 keys scanned` line and JSON output carries `sampled: true` with `sampleLimit`. The header reads `Keys in db <n> (redis):` where `<n>` is the logical DB index.
227
+ > **Elasticsearch:** Returns indices with `documentCount` from one `/_cat/indices?h=index,docs.count&expand_wildcards=all` request (open and closed indices alike). The count is primaries-only, so a replicated index no longer reports its replica copies as extra documents. Aliases are tagged separately. System indices (names starting with `.`) are hidden unless `--include-system` is passed.
222
228
 
223
229
  ### schema
224
230
 
@@ -240,6 +246,13 @@ dbcli schema --use prod # Scan prod DB; saves to .dbcli/schemas/prod
240
246
  **Options:** `--format <table|json>`, `--refresh`, `--reset`, `--force`, `--use <connection>`, `--sample-size <n>` (mongo only), `--sample-method <random|natural>` (mongo only)
241
247
  **Permission:** query-only+
242
248
 
249
+ > **Row counts on a full scan:** scanning every table records
250
+ > `rowCountIsEstimate: true` and reports the engine's row *estimate* (`information_schema.TABLES.TABLE_ROWS` on MySQL/MariaDB,
251
+ > `pg_class.reltuples` on PostgreSQL) rather than running `COUNT(*)` per table —
252
+ > a hundred full-table counts is what made scanning a large database unusable.
253
+ > `dbcli schema <table>` on a single table still reports the exact count. Tables
254
+ > are scanned with bounded parallelism (4 at a time).
255
+
243
256
  **Schema storage (v1.4+):** Schema is persisted as layered files under `.dbcli/schemas/`. With v2 multi-connection config each connection gets its own subdirectory (`.dbcli/schemas/<connection>/`). Run `dbcli schema --use <connection>` once per connection before querying it — otherwise `schema <table>` may return data from the wrong connection's cache.
244
257
 
245
258
  > **PostgreSQL:** Introspection uses the exact `public` catalog identity throughout. Full catalog/schema/table joins prevent a reused constraint name from contaminating another table; enum lookup includes its namespace; composite primary-key order comes from the exact table OID and index ordinality; and row estimates are scoped to the exact `public` relation. Row-count SQL qualifies and quotes both `"public"` and the exact table identifier, escaping embedded quotes so mixed-case or punctuation-bearing names remain distinct and safe.
@@ -283,6 +296,12 @@ dbcli query "SELECT * FROM orders" --format html > orders.html # pipe to stdou
283
296
  **Options:** `--format <table|json|csv|html>`, `--ui` (open the dashboard in the system browser; implies `--format html`), `--limit <number>`, `--no-limit`, `--collection <name>` (MongoDB / Elasticsearch), `--index <name>` (Elasticsearch alias for `--collection`), `--fields <list>`, `--truncate <number>` / `--no-truncate`, `-f, --query-file <path>`, `--use <name[,name]>`, `--slow-ms <number>`, `--recovery`
284
297
  **Permission:** query-only+ (Redis: per-command; Elasticsearch: per HTTP method/path)
285
298
 
299
+ > **Server-side scripts are rejected on every path.** MongoDB `$where`,
300
+ > `$function`, and `$accumulator`, and Elasticsearch `script` / `script_fields`,
301
+ > execute code on the database server. The adapters reject them anywhere in a
302
+ > filter, pipeline, or DSL body — before the request is sent — so `query`, `q`,
303
+ > saved snippets, and DML planning all behave the same way.
304
+
286
305
  #### Passive slow-query hint (`--slow-ms`)
287
306
 
288
307
  `query` and `q` read the execution time they already measured for a finished
@@ -1189,6 +1208,7 @@ dbcli design validate [--file <path>] [--format <format>]
1189
1208
  dbcli design render [--file <path>] [--format <format>]
1190
1209
  dbcli design diff (--against-cache | --against-orm <paths>) [options]
1191
1210
  dbcli design propose (--against-cache | --against-orm <paths>) [options]
1211
+ dbcli impact assess --design <path> (--against-cache | --against-orm <paths>) --output <path> [options]
1192
1212
  ```
1193
1213
 
1194
1214
  ```bash
@@ -1200,6 +1220,7 @@ dbcli design render --format mermaid
1200
1220
  dbcli design diff --against-cache --format markdown
1201
1221
  dbcli design diff --against-orm ./prisma/schema.prisma --format markdown
1202
1222
  dbcli design propose --against-orm ./prisma/schema.prisma --format markdown
1223
+ dbcli impact assess --design ./dbcli.design.json --against-cache --output ./impact.json --fail-on warn
1203
1224
  ```
1204
1225
 
1205
1226
  | Option | Applies to | Default | Meaning |
@@ -1216,6 +1237,10 @@ dbcli design propose --against-orm ./prisma/schema.prisma --format markdown
1216
1237
  `diff` and `propose` require **exactly one** comparison target; passing both or
1217
1238
  neither is an error.
1218
1239
 
1240
+ ### impact assess
1241
+
1242
+ Writes an offline JSON or Markdown report for the known declared impact of a design change. It requires `--design`, exactly one baseline (`--against-cache` or `--against-orm`), and an explicit workspace-contained `--output`. `--format` is `json` (default) or `markdown`; `--fail-on` is `error`, `warn`, or `never` (default). The threshold changes only the successful command exit code after the report is written. The report is limited to declared/partial coverage and never claims complete coverage. It may join the optional reviewed `dbcli.data-access.json` manifest only after validating its canonical semantic references and existing workspace-relative source paths; it never reads those sources. An optional explicit `--events <path>` is bounded and streamed through a redaction-first projection that retains recent safe table metadata only. It never starts a proxy, reads a rotated log, renders SQL/literals/errors/sessions/paths, or makes the command fail solely because workload evidence is absent or advisory. It reads no database, executes no SQL, and never reads saved-query bodies.
1243
+
1219
1244
  #### Artifact shape
1220
1245
 
1221
1246
  This example validates clean (0 errors, 0 warnings):
@@ -1939,7 +1964,7 @@ Output reports: writer enabled/disabled, last write result, file-lock state, rot
1939
1964
  ### verify
1940
1965
 
1941
1966
  Run a verification scenario. `verify` **runs** verification scenarios (safe-backfill,
1942
- migration, rollback) and never executes writes/DDL. `verification` **inspects and manages**
1967
+ migration, rollback, constraint) and never executes writes/DDL. `verification` **inspects and manages**
1943
1968
  the local result artifacts those scenarios produce under `.dbcli/verification/`.
1944
1969
 
1945
1970
  ```bash
@@ -1951,7 +1976,8 @@ dbcli verify safe-backfill \
1951
1976
  --expect "value == 0"
1952
1977
 
1953
1978
  # After-write: re-run guards, run the read-back assertion, write a v1 artifact.
1954
- dbcli verify safe-backfill ... --after-write
1979
+ # An optional receipt is provenance only, never approval to execute a write.
1980
+ dbcli verify safe-backfill ... --after-write --evidence-receipt .dbcli/evidence/verify-receipt.json
1955
1981
 
1956
1982
  # JSON for agents.
1957
1983
  dbcli verify safe-backfill ... --format json
@@ -1959,7 +1985,11 @@ dbcli verify safe-backfill ... --format json
1959
1985
 
1960
1986
  Options: `--table` (req), `--query` (req, analyzed not executed), `--verify-query`
1961
1987
  (req, **plain SELECT only**), `--expect` (req), `--after-write`, `--format <table|json>`,
1962
- `--subject-name <name>`, `--summary <text>`.
1988
+ `--subject-name <name>`, `--summary <text>`, `--evidence-receipt <workspace-relative-path>`
1989
+ (after-write only). A receipt is safe provenance for the already-executed verification,
1990
+ not approval to execute a write. Its `succeeded`/`failed` outcome remains distinct from
1991
+ the artifact status (`verified`, `not_verified`, `indeterminate`, or `blocked`); task-pack
1992
+ `planned` evidence stays plan-only.
1963
1993
 
1964
1994
  Guard constraints (fail closed): `--verify-query` must be a **plain `SELECT`** —
1965
1995
  `EXPLAIN`/`EXPLAIN ANALYZE`, `SHOW`, `DESCRIBE`, and data-modifying CTEs are rejected
@@ -2464,6 +2494,66 @@ dbcli migrate drop-enum status --execute --force
2464
2494
 
2465
2495
  **AI agent note:** Always use dry-run first (no `--execute`) to preview generated SQL. Only add `--execute` after confirming the SQL is correct. For DROP operations, both `--execute` and `--force` are required.
2466
2496
 
2497
+ ### evidence
2498
+
2499
+ Compose a canonical, offline **Evidence Pack** from existing verification artifacts
2500
+ and audit entries. This command never opens a database connection. A pack retains only
2501
+ safe pointers and outcome fields: it excludes SQL, targets, audit metadata, verification
2502
+ summaries, result data, and credentials. Claims are external statements, never dbcli
2503
+ verification verdicts.
2504
+
2505
+ #### `evidence compose`
2506
+
2507
+ ```bash
2508
+ dbcli evidence compose --claims ./claims.json --verification ver_abcd --audit 1a2b \
2509
+ --receipt .dbcli/evidence/verify-receipt.json \
2510
+ --output .dbcli/evidence/review.json --format json
2511
+ ```
2512
+
2513
+ | Flag | Purpose | Default |
2514
+ |---|---|---|
2515
+ | `--claims <file>` | Required JSON file with exactly `subject` and `claims`; every claim has an `id` and plain-language `text`. SQL-shaped text, credentials, error content, and blacklisted identifiers are rejected. | — |
2516
+ | `--verification <selector...>` | One or more verification artifact ids, unique prefixes, filenames, or in-bounds paths. | none |
2517
+ | `--audit <selector...>` | One or more audit ids or unique prefixes (minimum four characters) from the active connection. | none |
2518
+ | `--receipt <path...>` | Explicit workspace-relative receipt path(s). Receipts contribute safe provenance only; they are not execution approval. | none |
2519
+ | `--output <path>` | Required new JSON path under the current workspace. Existing files and paths outside the workspace are refused. | — |
2520
+ | `--format <json\|markdown>` | Compose receipt format printed to stdout. | `json` |
2521
+
2522
+ At least one `--verification`, `--audit`, or `--receipt` reference is required. The resulting pack
2523
+ contains a canonical SHA-256 integrity digest and `coverage.completeForDeclaredEvidence:
2524
+ true` for its explicitly selected references.
2525
+
2526
+ #### `evidence validate`
2527
+
2528
+ ```bash
2529
+ dbcli evidence validate --file .dbcli/evidence/review.json --format json
2530
+ ```
2531
+
2532
+ | Flag | Purpose | Default |
2533
+ |---|---|---|
2534
+ | `--file <path>` | Required evidence-pack JSON file. | — |
2535
+ | `--format <json\|markdown>` | Validation report format. | `json` |
2536
+
2537
+ Exit `0` when digest and all selected sources are valid. If a referenced audit or
2538
+ verification artifact later rotates, is cleared, disappears, or belongs to a different
2539
+ active connection, output stays parseable with `integrity: "valid"` and
2540
+ `references: "source-expired"`, then exits `1`.
2541
+
2542
+ #### `evidence render`
2543
+
2544
+ ```bash
2545
+ dbcli evidence render --file .dbcli/evidence/review.json --format markdown
2546
+ ```
2547
+
2548
+ | Flag | Purpose | Default |
2549
+ |---|---|---|
2550
+ | `--file <path>` | Required evidence-pack JSON file. | — |
2551
+ | `--format <json\|markdown>` | Render format. | `markdown` |
2552
+
2553
+ `render` validates the pack digest and active blacklist policy but does not resolve its
2554
+ original references. It is therefore available for historical review after `validate`
2555
+ reports `source-expired`, unless an exposed pack field is now blacklisted.
2556
+
2467
2557
  ### semantic
2468
2558
 
2469
2559
  Validate or print the optional, version-controlled `dbcli.semantic.json` in the
@@ -2590,6 +2680,39 @@ limits, audit, and recovery safeguards remain in force.
2590
2680
 
2591
2681
  **Permission:** n/a (local files only; no database connection).
2592
2682
 
2683
+ ### contract
2684
+
2685
+ Inspect the optional, version-controlled `dbcli.contracts.json` without opening a
2686
+ database connection. A contract adds a reviewed owner and descriptive evidence policy
2687
+ to canonical semantic references; it is not an executable data contract, assertion,
2688
+ query, or verification scenario.
2689
+
2690
+ ```bash
2691
+ dbcli contract validate --format json
2692
+ dbcli contract context --format json
2693
+ dbcli contract context --format markdown
2694
+ dbcli contract search customer --format json
2695
+ dbcli contract drift --format json
2696
+ ```
2697
+
2698
+ The strict v1 artifact contains `version` and `contracts`. Each contract has a unique
2699
+ canonical `name`, `status` (`draft`, `approved`, or `deprecated`), bounded plain-text
2700
+ `description` and `owner`, one or more canonical semantic `subjects`, optional aliases,
2701
+ and an `evidencePolicy` of `none`, `receipt-required`, or `verification-required`.
2702
+ Subjects must remain in the existing visible semantic registry; protected identifiers,
2703
+ unknown keys, duplicate names or subjects, SQL-like text, credentials, and stale
2704
+ references fail closed without exposing protected names.
2705
+
2706
+ `contract validate` requires an explicit valid artifact. `contract context` and
2707
+ `contract search` return only valid approved contracts; draft and deprecated contracts
2708
+ remain local review artifacts. `contract drift` reports `valid`, `stale`, `invalid`, or
2709
+ `unavailable` evidence offline and exits non-zero except for `valid`. A missing default
2710
+ file is allowed by `skill context` and leaves ordinary semantic context unchanged; a
2711
+ present invalid file fails closed. No contract command writes a file, opens a database
2712
+ connection, widens a `QueryDraft`, or changes permission/blacklist behavior.
2713
+
2714
+ **Permission:** n/a (local files only; no database connection).
2715
+
2593
2716
  ### skill
2594
2717
 
2595
2718
  Emit `SKILL.md` (and the companion `reference.md`) to stdout, a file, or an