This is the prose the AGENT reads before writing any schema/*.sql file. It pairs with the deterministic façade dispatch/write_sql.sh — the machine half that runs the mechanically-checkable subset and emits one verdict block. Read docs/SCHEMA_CONVENTIONS.md first — it is the source-of-truth for table/column naming, type choices, and schema-qualification (the analogue of docs/REST_API_DESIGN_GUIDELINES.md for write_http). The dissolving Schema Table Removal Guard card is merged verbatim below, while the durable SQL rules (NSQ, STS, SGR, ITF) stay in docs/greptile-learnings/RULES.md (retained) — referenced here, enforced by the GREPTILE GATE. Mechanical thresholds live once in the .sh; this file references rule codes, never restates the numbers.
Signal legend (printed by write_sql.sh):
- 🟢 pass — deterministic check passed.
- 🔴 fail — deterministic check failed (or helper absent); STOP, fix, rerun.
- 🔵 DECIDE — judgment-only; no script can decide, the agent reads the section and makes the call (blocks the TURN, not the script).
- ⚪ delegated — the checker runs only in the product repo, not in dotfiles.
Tag legend — each section heading below carries one of:
> [DETERMINISTIC → <CODE>]— a machine can pass/fail it; the.shrow for<CODE>(e.g.FLL) enforces it.TODO-CHECKmarks a mechanizable rule with no helper wired yet (build-the-check).NEW:<name>marks a proposed-but-not-yet-existing code.> [JUDGMENT → <CODE>]— no script can decide; the agent decides at write time against the prose.> [container]— a non-enforcement wrapper heading (e.g. "Merged from dissolved gate cards"); its tagged subsections carry the real codes, and the coherence audit (§6.3) skips it.
See docs/DISPATCH_ARCHITECTURE.md §3 for the tag grammar and semantic-anchor model.
[JUDGMENT → SCH]
Triggers on every Edit/Write to schema/*.sql, schema/embed.zig (@embedFile constants), and the canonical migration array in src/cmd/common.zig. Before authoring DDL, read docs/SCHEMA_CONVENTIONS.md (naming, types, schema-qualification). SQL embedded in handlers (*.zig) and integration-test fixtures is also governed by the companion rules below — those surfaces additionally fire write_zig.md and the GREPTILE GATE.
[container]
The Schema Table Removal Guard card dissolves into this façade; its prose is preserved verbatim below (title demoted to a tagged ###, its subsections demoted to #### and tagged SCH).
[JUDGMENT → SCH]
Family: Schema discipline. Source: AGENTS.md (project-side guard). Related: RULE STS (no static strings in SQL schema), RULE NSQ (named constants, schema-qualified SQL) — both in docs/greptile-learnings/RULES.md.
Triggers — before any of these, run cat VERSION and print the guard output:
- Creating, editing, or deleting any file under
schema/*.sql. - Editing
schema/embed.zig(any@embedFileconstant). - Editing the canonical migration array in
src/cmd/common.zig. - Writing
DROP TABLE,ALTER TABLE, orSELECT 1;into any SQL file. - Accepting a spec dimension prescribing a "DROP migration", "ALTER migration", or "version marker".
Override: SCHEMA GUARD: SKIPPED per user override (reason: ...). User-invokable only. Spec violates the guard → amend the spec first.
[JUDGMENT → SCH]
To remove a table:
rm schema/NNN_foo.sql- Remove
@embedFilefromschema/embed.zig - Remove the entry from the migration array in
src/cmd/common.zigand update length + index-based tests.
Forbidden: ALTER TABLE, DROP TABLE, SELECT 1; markers, comment-only files, "keep file for slot numbering". Slot gaps are fine — the DB is wiped on rebuild.
[JUDGMENT → SCH]
Proper ALTER/DROP migrations in new numbered files. No teardown.
[JUDGMENT → SCH]
SCHEMA GUARD: VERSION=<v> (<2.0.0 ? teardown : alter)
rm:schema/<file>.sql
rm-embed:<const>
rm-migration:v<N>
For pre-v2.0.0 path, all three rm- lines appear. For v2.0.0+, replace with migration:schema/<NNN>_<change>.sql.
[container]
These rules are not dissolved — they remain in docs/greptile-learnings/RULES.md. STS/NSQ/SGR are enforced by the GREPTILE GATE until a leaf check is wired (TODO-CHECK); ITF additionally surfaces as a 🔵 DECIDE judgment row in write_sql.sh. Summarised here so the SQL author sees the full surface in one place; RULES.md stays canonical (read it for the full text + Ref: provenance).
[DETERMINISTIC → TODO-CHECK]
Never DEFAULT or CHECK (… IN (…)) with hardcoded strings in schema — SQL cannot reference Zig/JS constants, so schema strings drift from code. Enforce value constraints via application constants. (RULES.md RULE STS.)
[DETERMINISTIC → TODO-CHECK]
No magic numbers; all SQL in handlers is schema-qualified (core.table, not table) — unqualified names fail when search_path differs across environments. (RULES.md RULE NSQ.)
[DETERMINISTIC → TODO-CHECK]
Every CREATE TABLE migration ends with GRANTs for every role that queries the table (api_runtime / worker_runtime), mirroring the table's callers. PostgreSQL denies by default — a missing grant fails only at first runtime use. (RULES.md RULE SGR.)
[JUDGMENT → ITF]
An integration test touching a production table seeds rows through a shared src/db/test_fixtures_<scope>.zig module against the real schema — never a session-local CREATE TEMP TABLE mocking the production shape (the mock drifts and hides schema changes). Fixtures use semantic scope names, never milestone-numbered ones. (RULES.md RULE ITF.)