Agent feedback: schema introspection, static check, error codes, docs - #3
Merged
Conversation
The database worker reports the driver-native code (inner_code — the Postgres SQLSTATE, or the SQLite extended result code) but it was buried inside the raw error body, invisible unless the caller dug into database_error. Extract it once at error construction and suffix the message — 'db error (SQLSTATE 42703)' — so every path (MIGRATION_FAILED, config errors, logs) names the actual cause. The full structured body is still attached unchanged.
migrate::status flagged future-dated files but left the caller to work out
what to do, and the answer depends on the state: an applied file is
harmless (it expires once the clock catches up), a pending one breaks
ordering and should be re-scaffolded. Each entry now carries { name,
applied, hint } with the remediation spelled out. Breaking (0.x): the
field was a list of bare names.
Forward-only migrations cannot be rolled back, yet the first feedback on a hand-written file used to arrive while it was being applied. migrate::check answers 'would migrate::up succeed?' without executing any SQL: same statement splitter, empty-file detection, naming scheme, checksum drift. It reports every problem at once (new migrations::scan_migrations keeps collecting past invalid names; list_migrations keeps its fail-fast contract), and stays useful while the database worker is down — db_checked: false marks the drift lists as unknown.
Verifying a migration's effect (column order, foreign keys, triggers) used
to mean hand-writing information_schema/pg_catalog queries through the CLI
— exactly where quoting mistakes happen. The worker already introspects for
codegen; this exposes a full structured report instead: ordered columns
with defaults, primary keys, foreign keys (paired column-by-column via
pg_constraint + unnest WITH ORDINALITY — information_schema cannot express
multi-column pairings), indexes, triggers, and Postgres enums. SQLite goes
through the pragma functions. Pure rows-to-report pipeline, fixture-tested
without a database; optional { table } filter; tracking table excluded.
Reordering columns or making an incompatible type change on Postgres means recreating the table, and the dangerous part is not the DDL — it is the objects attached to the old table that die silently with DROP TABLE: incoming foreign keys, the serial sequence (OWNED BY), indexes, triggers, defaults. Canonical single-migration example plus the checklist, mirroring the existing SQLite recreate recipe; verify with migrate::schema.
Discovered by agents through a live SQLSTATE 25006 — one Boundaries line saves that round-trip every session: reads via database::query, ad-hoc writes via database::execute or database::transaction.
The rule said 'resolve future_dated entries' without saying how, and a careful agent can stall on an anomaly that is already handled: create's timestamps are monotonic, so scaffolding as usual lands after any future-dated file. Spell out both cases (applied: harmless; pending: just use migrate::create), consistent with the status hints.
The only real failures of the feedback session were shell-quoting accidents: SQL with single quotes inlined into --json '…'. The iii CLI has no @file/stdin form, so document the two escape hatches — read the JSON from a file with --json "$(cat …)", and key=value pairs for scalar fields.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements the 8 friction points reported by an agent session that exercised miiigrate on a real workload (table creation + column reordering). One commit per point, most-severe first. Core behaviors (monotonic scaffolding, atomicity, checksums, codegen_on_up) needed no change — everything here is observability and ergonomics at the edges.
Features
migrate::schema— read-only structured report of the live schema: ordered columns with defaults, primary keys, foreign keys (multi-column pairs viapg_constraint+unnest … WITH ORDINALITY), indexes, triggers, Postgres enums. Optional{ table }filter. Ends the era of hand-writteninformation_schemaqueries through the CLI.migrate::check— static validation of pending migrations (same splitter asmigrate::up, empty files, naming scheme, checksum drift) without executing any SQL. Lists every problem at once; degrades to static-only when the database worker is down (db_checked: false).db error (SQLSTATE 42703)) instead of burying it in the raw body.future_dated— status entries carry{ name, applied, hint }with the remediation spelled out (breaking, 0.x).Docs & skill
OWNED BY, indexes, triggers checklist).database::queryis read-only (SQLSTATE 25006);future_datednever blocks (create is monotonic); check-before-apply and schema-verification flows.@file/stdin).Validation
cargo fmt --check,clippy --all-targets -- -D warnings, 67 tests (new fixture suites for the pg/sqlite schema pipelines) — green on every commit.migrate::schemamatches the real events/reservations/users schema (FK CASCADE, aggregated trigger events, tracking table excluded);migrate::checkcorrectly reports stray names, unsplittable files, and future-dated hints; a deliberate duplicate-column migration fails with… (SQLSTATE 42701); full smoke test green.