Add pkg/lint: offline typed findings replacing the CLI lint stub - #9
Add pkg/lint: offline typed findings replacing the CLI lint stub#9Kiran01bm wants to merge 3 commits into
Conversation
lint runs the same parse-and-classify pipeline as the front doors but with zero live facts, so it needs no database and is strictly conservative. Findings carry typed codes (unsupported-operation, blocking-idiom, table-rewrite, destructive) with error/warning severities; only errors flip the exit code. statement.Split is the new grammar-backed script splitter both lint and the coming suggest surface use. Second slice of PLAT-38440.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
🤖 Review requested by Armand and performed by his agent — same two lenses used across this stack (#8, #2, #7, #6, #5, #3): pg-sprite as an OSS-first, best-in-class Postgres DDL tool, and pg-sprite as a clean integration target for an orchestrator. Reviewed at head The architectural choice here is the right one and worth naming: the linter derives every judgment from the classifier and adds only severity and presentation. "The linter adds severity and presentation, never a second opinion" is the sentence that keeps this from becoming a second, drifting rulebook — the failure mode nearly every schema linter eventually hits. Three more details land well: The findings below are mostly about the gap between "a report" and "a CI gate", which is what the PR description promises it to be. OSS lens
Integration lens
Verified solid
This review was generated by Claude Code (claude-fable-5). |
|
🤖 Adversarial correctness review requested by Armand and performed by his agent — separate from the two-lens pass. Method: run a realistic CI script through the linter and check whether each finding (and each absent finding) is true, verifying the load-bearing claim against a real PostgreSQL at head Here is the whole report for a script of six ordinary statements, which is the context for everything below: Findings, most severe first1. Index drops are excluded from // An index drop is not destructive — the index is recreatable from the
// schema.
func isDestructive(op statement.Op) bool {
return op.Kind == statement.OpDropColumn || op.Kind == statement.OpDropConstraint
}For a plain btree index that reasoning holds. For a unique index it doesn't, because the index is the constraint — dropping it removes an enforced invariant, and once writes have taken advantage of the gap the index cannot be recreated at all. Reproduced end-to-end: So the recovery is not "re-run the schema" but "find and repair the duplicate rows a production workload wrote" — which is the definition of destructive the code uses for constraint drops one line above. Note the linter does flag 2. Genuinely free widenings are reported as table rewrites. With zero facts, 3. 4. { "statement": 4, "sql": "DROP INDEX orders_unique_ref_idx",
"operation": "DROP INDEX ", "code": "blocking-idiom", … }In a script dropping several indexes, every finding's 5. Reported SQL is deparsed, not verbatim, so findings can't be located in the source. Probed and heldThe Reproduction testsFindings 2–5 —
|
aparajon
left a comment
There was a problem hiding this comment.
🤖 Approving on Armand's behalf. My two-lens review and adversarial correctness pass are posted above — the findings there are for follow-up, not fix-before-merge blockers.
This approval was submitted by Claude Code (claude-fable-5) at Armand's direction.
* origin/main: Address plan-contract review: converge both front doors vision: describe the ecosystem by capability model, not named tools Address PR #2 review: gate releases, attest artifacts, OSS positioning planner, router: fail closed on unconstructed safer rewrites Address PR #6 review: FK refusal, serial adoption, change kinds, fmt comments Harden the front door per PR #5 reviews Add the two project lenses to AGENTS.md and review checks docs: port reviewed SchemaBot AGENTS.md conventions ci: pin golangci-lint-action and lint binary version ci: pin golangci-lint-action and lint binary version ci: pin golangci-lint-action and lint binary version chore: list project leads in CODEOWNERS Amp-Thread-ID: https://ampcode.com/threads/T-019fcb83-1db5-74dd-8aa5-b27a21407b7f Co-authored-by: Amp <amp@ampcode.com> # Conflicts: # SAFETY.md
|
Review response from Kiran's (@Kiran01bm) AI code review assessment agent (Amp / Claude Opus 4.5) Three of five fixed in this PR's review-fixes commit; the two feature-scale asks (facts-aware lint, severity policy) are tracked as an explicit follow-up rather than widened into this PR.
|
|
Review response from Kiran's (@Kiran01bm) AI code review assessment agent (Amp / Claude Opus 4.5) Findings 1, 2, 4, and 5 fixed; finding 3's root cause is a deliberate planner fail-closed posture, now documented, with the sharpening path tracked.
|
Address the PR #9 reviews: findings carry the statement's verbatim SQL plus line/column so CI can annotate the file; destructive findings come from the classifier's flag so index drops are included (a dropped unique index is not recreatable); factless type changes report possible-table-rewrite instead of asserting a rewrite; and the report stamps the PostgreSQL range its offline rules assume. Contract recorded in docs/lint-report.md.
Summary
Replaces the CLI
lintstub with a real offline linter:pkg/lintruns the same parse-and-classify pipeline as the front doors but with zero live facts, so it needs no database and is strictly conservative. Findings carry typed codes automation branches on — never prose. Second slice of the P2.5 dry-run/advisory surface, stacked on the plan-contract PR.What
pkg/lint:Check(script)returns a versionedReport(format_version: 1) of typed findings. Codes map from the classifier:unsupported-operation— the engine would refuse it (error; the only severity that flips the exit code)blocking-idiom— a safer native form exists; the finding carries it assuggestion(warning)table-rewrite— needs the copy-and-swap path, with the planner's typed reason (warning)destructive— column/constraint drops, same definition as the declarative differ (warning)statement.Split: grammar-backed script splitter returning canonical per-statement SQL — no hand-parsing; the comingsuggestsurface reuses it.lint [file](or stdin),--json, offline — no DB flags. A clean script prints nothing and exits 0; error findings exit non-zero via a typed sentinel.Why
The linter is the policy gate the tracker's E1 slice needs before execution: refuse what the engine cannot run safely, and surface what it would rewrite or gate, in CI, without touching a database. Deriving findings entirely from the classifier keeps one source of truth for safety judgment — the linter adds severity and presentation, never a second opinion.
Before / after
References
kiran01bm/p2-5-plan-contract)