executor: closed CreateShapeCause vocabulary for create-path refusals - #82
Conversation
The create path refused a statement's shape with prose that the text diff, the CLI and migrate each recomputed by hand. A typed *CreateShapeError carrying one of nine stable causes gives consumers an identity to branch on and a single owner for each sentence; the sentinels and OutcomeCode mapping are unchanged so errors.Is callers keep working. The plan report field and consumer adoption follow.
…e-cause-vocabulary * origin/main: feat(executor): prove and recover abandoned invalid indexes (#79) # Conflicts: # pkg/executor/docs_test.go # pkg/executor/native.go
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
…less refusal Addresses the agent review: nothing closed the cause vocabulary against Description() and Unwrap(), so a cause added without both arms rendered "unknown create-shape refusal" with the execution-failed code. The mappings test now walks CreateShapeCauses() and pins each cause to its own sentence and sentinel; the assignment sites below the ParseDesired boundary are covered white-box; the one refusal that was not a CreateShapeError becomes the parse error it is; and the dead SequenceStepError branch in CreateShapeCauseOf goes.
|
🤖 Adversarial correctness review (1/2 — correctness) — The shape of this is right, and the part I'd have asked for is already here. My standing worry with a new closed vocabulary is that the completeness test pins the vocabulary while nothing pins the routing — that every cause has a description, a sentinel and a code, but not that the right site emits the right cause. Both halves are covered here: And Mutations — 11 run, 11 killed. No survivors on the vocabulary, the routing, or the closure. Both findings below are about what the docs and one test claim, not about code they fail to cover.
1 — two causes drop the detail that would explain them (low)Six causes lose the Under the typed design that's structural rather than careless — one cause, one sentence, and a count or a kind isn't a sentence. It matters here specifically because of when these fire. Both are the arms — and
2 — the unwrap path the doc advertises can't happen; the one that can isn't pinned (low)
Admission refuses the whole set on the first refusal, so no refused step is ever executed, and both This is worth a line now rather than later because Verified — the byte-identical claims, the sentinel compatibility contract, and two attacks that dissolvedThe three "byte-identical" claims hold exactly. The Attack that dissolved — a Attack that dissolved — the The docs table is consistent with The Local checks. This review was generated by Claude Code (claude-opus-5). |
|
🤖 Adversarial correctness review (2/2 — invariants, docs, and the stack) — InvariantsUpholds RF, and tightens what "a stated reason" means. The RF preamble says each refusal is "a preflight error with a stated reason — never a warning, never attempted." Every create-shape refusal here is still decided before anything runs, still an error, and the reason is now a typed identity instead of a sentence a consumer would have to pattern-match. Nothing in the RF entries names the create path's shape checks specifically, so no Enforced: line moves — but the registry's framing is exactly what this change is serving, and the PR summary is a good place to say so. Enforces CO-7 more exactly, which is the argument for the one hunk that isn't vocabulary. CO-7 is "every statement parses, or it is an error" — no silently skipping unparseable statements, a parse failure surfaced to the caller as an error. Before this PR, The left column reports a parse failure as a shape verdict — the statement gets described as an unsupported shape when what actually happened is that two parse boundaries disagreed about it. That's the "classified or refused" capability CO-7 pins being satisfied in name only. The right column is a parse failure surfaced as an error, which also makes it consistent with the Worth citing CO-7 explicitly in the summary, because that hunk is the one thing here that isn't "adds the vocabulary only" — it changes what a caller sees — and it reads as incidental refactoring next to the typed-error work. A reviewer who spots the disposition change without the invariant behind it has to decide on instinct whether it was deliberate. No new invariant. The closed-vocabulary property is a code and docs contract pinned by tests, not a safety MUST about the target database, so it belongs where it is rather than in the registry. Docs
That's the sentence an integrator needs and would never derive. It tells them the vocabulary is closed for completeness rather than for coverage, and it turns three causes from "handle these" into "if you see one, your input didn't come from admission" — which is a security-relevant reading, not just a convenience. I verified all three are actually unreachable rather than taking the paragraph's word for it (details in my first comment), and One small thing: the section explains what a cause is and what The stackTwo things about how this lands, given the plan-report The recomputation this PR leaves in place is worth flagging in the stack's ordering.
This review was generated by Claude Code (claude-opus-5). |
aparajon
left a comment
There was a problem hiding this comment.
🤖 Approving — 11 mutations run, 11 killed; the routing, the mapping and the closed-set guard are all genuinely pinned. Findings are in my two review comments (correctness, invariants & stack) — both low, neither blocking.
This stamp was left by Claude Code (claude-opus-5).
|
🤖 Review response — created by Kiran's code review agent (Amp, Claude Opus 4.5) — pull/82, follow-up commit All six findings and the three suggestions are addressed in the follow-up commit; nothing deferred, nothing rejected. The four mutants the review reported as surviving were reintroduced and each now fails its test.
Verification on the follow-up: Agent review at head |
The create path's shape refusals now carry a closed, typed
CreateShapeCauseinstead of only prose, so consumers can branch on the cause the same way they branch on outcome codes.Why
When the create path refuses a desired statement by its shape (
PARTITION OF,INHERITS,LIKE,OF type,IF NOT EXISTS,CONCURRENTLY, a duplicate relation name, a multi-operation statement, an unsupported kind), the only stable signal was one of four sentinel errors and the rest was sentence text. The text diff, the CLI's greenfield refusal rendering andmigrate's desired-state detail each re-derived the cause from the statement on their own, so the same shape could be described three ways and a new refusal needed three edits. The plan report cannot carry a per-statementcausefield until the executor owns that vocabulary.What
pkg/executor/create_shape.godeclaresCreateShapeCause(nine flat kebab-case values,CreateShapeCauses()enumerates them),Description()as the single owner of each human sentence,*CreateShapeError{Cause, Name}whoseUnwrap()returns the sentinel the cause belongs to, andCreateShapeCauseOf(err), which reads through wrappers including aSequenceStepError. Every refusal site increate.goreturns the typed error; the sentinels andnative.gonow derive their text fromDescription(), soerrors.Iscallers and theOutcomeCodemapping are untouched. Six causes drop thestatement is not a shape the create path can run:prefix their sentinel text used to carry — every renderer already says the create path refuses the statement, so the prefix was duplication;PARTITION OF,IF NOT EXISTSand duplicate-name text is byte-identical.docs/execution-model.mdgains a "Create-shape causes" table, pinned by a docs test the same way outcome codes are, and notes thatconcurrently,multiple-operationsandunsupported-kindre-verify preconditionsParseDesiredalready enforces. The mappings test walksCreateShapeCauses()and pins each cause to its own sentence, sentinel and code, so a cause added without aDescription()orUnwrap()arm fails the suite instead of rendering "unknown create-shape refusal" at runtime. This PR adds the vocabulary only; the plan-reportcausefield (with itsformat_versionbump) and the deletion of the three recomputations stack on it.Before / after