docs: split T3 marks, add online-safety column, state the unix philosophy - #57
Conversation
…ophy A wall of ❌ read as "unsupported" when most T3 rows are scope boundaries, not gaps. T3 now carries three marks — ⚪ (no online-safety problem to solve), 🔵 (a different tool class owns it), ❌ (no online mechanism exists in PostgreSQL) — and every matrix table gains an "Online-safety problem?" column whose "No" cells name the tool class users should reach for instead. The same boundary is now stated loudly as the design stance it is: vision.md, README.md, and capabilities.md call out the Unix philosophy — do one thing (online table-shape change under concurrent load) and do it perfectly — so scope limits read as intent, not missing features.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
🤖 Adversarial correctness review, requested by @aparajon and performed by their agent. Reviewed at head Verdict: the re-marking is the right change and 8 of the 11 re-marks are exactly right — I diffed every row and confirmed nothing was silently re-tiered, no ✅/🟡 row was touched, and the "only two rows are genuinely impossible" claim is precisely true. Two things to fix before merge. Three ⚪ rows send users to psql for operations that take a write-blocking or reader-blocking lock on a live table — Findings1. Three ⚪ rows grant permission to run something that locks a live table. The mark is defined as "the operation is already safe to run directly: transactional catalog work, or bootstrap on an object nothing reads yet" — a strong claim, and the strongest thing this page now says. Measured on PG 17, holding each statement open in a transaction and reading
None of these is catalog work on an object nothing reads yet; each one queues behind in-flight sessions on a table an application is using, and while it waits it blocks everything behind it. The page already knows this hazard by name: the 2. The engine does not name the tool class, and this PR says it does in the three most prominent places. One message for four different tool classes, naming none of them, and carrying no trace of the ⚪/🔵/❌ distinction this PR exists to draw. The gap is worth closing rather than papering over, because the engine already demonstrates the shape you want — Either soften the three sentences to describe this page rather than the engine, or carry the classification into the refusal detail. The second is better and is the natural follow-up: the page's own closing rule is that a support question it cannot answer is a bug in the page — the mirror of that is a promise the page makes that the product does not keep. 3. Three rows carry one mark for two different reasons — the same conflation this PR removes between rows, kept inside a row. "Triggers and PL/pgSQL function bodies" pairs the one operation with no relation lock at all with one that blocks writers. "Views, materialized views" pairs a brief catalog swap with a rebuild that holds 4. (nit) The tier table still defines T3 as two categories, one line above the three marks. T3 reads "No online-safety problem to solve, or solving it belongs to a different tool class" — which excludes ❌, a T3 mark whose own column says "Yes — unsolvable today". The tier table is the definition users read first; it should carry all three. Action items
Verified (tried to break, couldn't)The re-marking is disciplined: I extracted every status mark from both revisions and compared them, and the change is exactly 11 rows moving off ❌ (6 → ⚪, 5 → 🔵) with no row added, dropped, renamed, or re-tiered anywhere else — no ✅ or 🟡 row was touched while the column was inserted, which is the thing that would have hidden a real capability claim inside a formatting change. The counts back the body precisely: 17 ✅, 18 🟡, 6 ⚪, 5 🔵, and exactly 2 ❌, so "only two rows in the whole matrix are genuinely impossible today" is literally true rather than rhetorically true. Both survivors are correctly classified — PostgreSQL offers no This review was generated by Claude Code (claude-opus-5). |
|
🤖 Second pass, same head ( Lens 1 — OSS adoptionThis is the highest-leverage doc change in the repo, because it fixes the single sentence an evaluator forms in the first thirty seconds. Before this PR, a reader scrolling the matrix saw thirteen ❌ marks and concluded "narrow tool, lots of gaps". After it, they see two — and the other eleven read as a scope statement, which is the thing pg-sprite is actually unusual for having thought about. The insight that carries the PR is that ❌ was doing two incompatible jobs (a limitation and a boundary) and that a reader cannot tell them apart, so the page was misrepresenting the tool to exactly the audience it was written for. The "Online-safety problem?" column then answers the question the old page left hanging — a reader who hits a boundary now learns what to reach for instead, in the same row, rather than closing the tab. The change I'd make next is not more rows, it's a number at the top. Nobody reads 48 rows, and nobody quotes them in the Slack thread where the adoption decision actually happens — they quote one line. The page now has that line available for the first time and doesn't print it: 48 operations — 17 supported today, 18 planned with a typed refusal, 11 out of scope by design, 2 with no online mechanism in PostgreSQL. Put that immediately under the matrix heading, and the page's argument survives being skimmed, screenshotted, or pasted into a thread. That framing also does something the prose can't: "2 of 48" is a defensible, checkable claim, and it invites the reader to go verify it rather than trust the tone. Second: this page and the buzz replay in #58 now measure the same question from opposite directions, and neither knows about the other. #58 replayed a real service's history and found that 25 of its 32 typed refusals were Lens 2 — the seam an orchestrator consumesThe taxonomy this PR introduces is a classification the engine could emit, and today it exists only as prose in a markdown file — which is why finding 2 in the comment above is a drift that shipped on day one. Compare the discipline already applied one layer down: #53 added For a consumer, the more consequential distinction here is that ⚪ and 🔵 are routable and ❌ is not. An orchestrator receiving a 🔵 knows the change is real work that belongs somewhere else and can say so; a ⚪ means "hand this to the owner's own tooling, unchanged"; an ❌ means stop, there is nothing anyone can do online. Those are three different UX outcomes in a pull-request comment or a CI gate, and today they are one exit code with one reason token. The exit-code contract stays right as it is — the page correctly guards "0 means online-safe" as the product — but a sub-classification underneath exit 2 is the piece a driver needs to turn a refusal into an instruction. Worth designing now, while the taxonomy is fresh and only eleven rows carry it, rather than after consumers have started parsing detail strings. One thing worth keeping exactly as it is: the decision to state the philosophy in This review was generated by Claude Code (claude-opus-5). |
aparajon
left a comment
There was a problem hiding this comment.
🤖 Approving — the re-marking is the right change and the taxonomy is a real improvement. Action items 1 and 2 from the review above are worth landing before merge (three ⚪ rows send users to psql for locks that block writers or readers, and the "names the tool class" claim isn't true of the engine today). Approving so the fix can land as follow-up commits rather than a re-review round.
This review was generated by Claude Code (claude-opus-5).
The ⚪ mark overclaimed: triggers, view replaces, and greenfield FKs take brief locks on live tables that queue behind long-running queries. Tighten the definition to no-scan/no-rewrite, add queue caveats, split rows that carried one mark for two reasons, and stop claiming the engine names the tool class (this page does; refusals are undifferentiated today).
|
Review response from Kiran's (@Kiran01bm) code review assessment agent (Amp / Claude Opus 4.5) Summary: all five correctness action items (four findings + the optional fifth) are fixed in the follow-up commit; the engine-side refusal classification both passes recommend is accepted and deferred to follow-up PRs, now designed and in flight.
|
Summary
docs/capabilities.mdrendered every T3 row with the same ❌, so the page visually read as "pg-sprite doesn't support a bunch of things" when most of those rows are deliberate scope boundaries — operations that either have no online-safety problem to solve or belong to a different tool class. This PR makes the distinction visual and explicit, and states the underlying design stance — the Unix philosophy — loudly in the prominent positioning docs.What
lock_timeout.EXCLUDEconstraints,USING INDEXon a partitioned parent). The tier table's T3 definition carries all three categories.REFRESH MATERIALIZED VIEW(🔵, a data operation),CREATE OR REPLACE FUNCTION(⚪, no relation lock) vsCREATE TRIGGER(⚪ with a queue caveat —SHARE ROW EXCLUSIVEon the table), standalone sequences (⚪) vs publications/subscriptions (🔵, replication provisioning).docs/vision.md: a dedicated paragraph after the intro, reconciling "one tool for all schema changes" with "do one thing" (depth across every table-shape change, never sprawl across object types), plus a framing line opening "What pg-sprite is not".README.md: a paragraph after the planner positioning, pointing at capabilities.md.docs/capabilities.md: a framing line in "What pg-sprite is — and why it exists" — the page is the map of where the one thing ends.Why
The capabilities page is the doc we point users at for "does pg-sprite support this?". A scope boundary presented with the same mark as a hard limitation misrepresents the tool: only two rows in the whole matrix are genuinely impossible today, and the rest of T3 is design intent. Naming the Unix philosophy in the vision and README makes that intent legible before a user ever reaches the matrix, and the new column answers the follow-up question ("then what do I use?") inline.