Skip to content

feat(metaschema-schema): port system-controlled database standing columns - #128

Merged
pyramation merged 1 commit into
mainfrom
feat/database-standing-columns
Sep 8, 2026
Merged

feat(metaschema-schema): port system-controlled database standing columns#128
pyramation merged 1 commit into
mainfrom
feat/database-standing-columns

Conversation

@pyramation

Copy link
Copy Markdown
Contributor

Summary

Ports the metaschema_public.database standing columns that shipped in constructive-db (PR 3701, commits fac0698a8ce / 7218535ebd1) to the upstream mirror so @pgpm/metaschema-schema can be published with them:

suspended_at     timestamptz,   -- NULL = in good standing
suspended_reason text,          -- 'billing' | 'admin'
CONSTRAINT database_suspension_chk CHECK ((suspended_at IS NULL) = (suspended_reason IS NULL) AND ...)
CREATE INDEX database_suspended_at_idx ON metaschema_public.database (suspended_at);
COMMENT ... '@behavior -insert -update'   -- hidden from generated write inputs

Needed because constructive-io/constructive's integration fixtures deploy the published @pgpm/metaschema-schema (pinned in its pgpm.json), and the new GraphQL standing loader in constructive#1815 reads these columns — CI there currently fails with column "suspended_at" does not exist. After this lands: publish (0.44.2), then bump the pin in constructive.

Bundle artifacts regenerated with pgpm package. Only the database/table.sql change is ported here; the mirror still trails constructive-db on unrelated is_valid_step_up / index.nulls_not_distinct edits.

Link to Devin session: https://app.devin.ai/sessions/86a73d903b3546c1afbf5361bfa384b6
Open in Devin Desktop: https://app.devin.ai/desktop/session/86a73d903b3546c1afbf5361bfa384b6?variant=devin
Requested by: @pyramation

…umns

Mirrors constructive-db fac0698a8ce / 7218535ebd1: suspended_at +
suspended_reason on metaschema_public.database, the paired check
constraint, the suspended_at index, and the @behavior -insert -update
column comments. Bundle repackaged.
@devin-ai-integration

Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@tenki-reviewer

tenki-reviewer Bot commented Sep 8, 2026

Copy link
Copy Markdown

Review complete. 🟡 2 medium

💬 Inline comments (2)

  • 🟡 Suspended columns lack promised guard triggertable.sql:53
  • 🟡 No upgrade path for existing databasestable.sql:28
🧹 Nitpicks (1) — 🟢 1 low
  • 🟢 Verify does not prove new suspension state (table.sql:4) — The deploy adds suspended_at/suspended_reason, database_suspension_chk, and database_suspended_at_idx (table.sql:28-50), but the paired verify script only runs assert_table and never proves these elements (verify/.../database/table.sql:4).

The change introduces a database-suspension feature by editing the write-once CREATE TABLE in the deploy script and regenerating the base install artifact. Three concerns were raised: existing installs get no ALTER TABLE/upgrade path so the feature silently no-ops there; the comment promises a guard trigger that does not exist (only PostGraphile @behavior hints constrain writes); and the paired verify script still only asserts the table exists, not the new columns/constraint/index.

Files Change
deploy/.../database/table.sql Adds suspended_at/suspended_reason columns, database_suspension_chk, and database_suspended_at_idx to the CREATE TABLE.
sql/metaschema-schema--0.44.0.sql Regenerated base install script mirroring the new columns/constraint/index.

Reviewed commit: ac02139

@tenki-reviewer tenki-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR adds database suspension columns (suspended_at, suspended_reason), a CHECK constraint, and an index to the write-once metaschema_public.database table, plus the regenerated sql/metaschema-schema--0.44.0.sql artifact.

Key findings

  • 🟡 Suspended columns lack promised guard triggertable.sql:53
  • 🟡 No upgrade path for existing databasestable.sql:28

Comment on lines +53 to +54
COMMENT ON COLUMN metaschema_public.database.suspended_at IS '@behavior -insert -update';
COMMENT ON COLUMN metaschema_public.database.suspended_reason IS '@behavior -insert -update';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 security · medium

Suspended columns lack promised guard trigger

The comment at table.sql:24 promises a guard trigger restricting writes to the system role/platform admin, but no trigger or RLS policy on metaschema_public.database exists anywhere in metaschema-schema or metaschema-modules. Only the PostGraphile @behavior -insert -update comments (table.sql:53-54) restrict writes, and those are API-layer hints that do not constrain direct SQL, so any role with UPDATE on the table can set or clear suspension.

📋 Prompt for AI Agents

In packages/metaschema-schema/deploy/schemas/metaschema_public/tables/database/table.sql, the new suspended_at and suspended_reason columns (lines 28-29) are documented as system-controlled with a guard trigger, but no such trigger exists. Add a BEFORE INSERT OR UPDATE trigger function in metaschema_private that raises an exception unless the current role is the system role or a designated platform-admin role, and attach it to metaschema_public.database guarding the suspended_at/suspended_reason columns, so the invariant is enforced at the database level rather than only by the PostGraphile @behavior -insert -update comment.

Comment on lines +28 to +29
suspended_at timestamptz,
suspended_reason text,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 bug · medium

No upgrade path for existing databases

The new suspended_at/suspended_reason columns, database_suspension_chk, and database_suspended_at_idx are added only inside the write-once CREATE TABLE (table.sql:28-50) and the regenerated base install script, with no ALTER TABLE migration, no version bump, and no extension upgrade script in sql/. Installations where metaschema_public.database already exists never receive the new columns, so the suspension feature silently does nothing there while fresh installs get it.

📋 Prompt for AI Agents

In packages/metaschema-schema, add a migration path for existing installs: bump the extension version (package.json, metaschema-schema.control, and the sql/ artifact name) and add an upgrade script (e.g. metaschema-schema--0.44.0--0.45.0.sql) that runs ALTER TABLE metaschema_public.database ADD COLUMN suspended_at timestamptz, ADD COLUMN suspended_reason text;, adds the database_suspension_chk CHECK constraint, and creates database_suspended_at_idx, so databases where the table already exists receive the same columns/constraint/index as fresh installs.

@pyramation
pyramation merged commit 8e775e6 into main Sep 8, 2026
30 checks passed
@pyramation
pyramation deleted the feat/database-standing-columns branch September 8, 2026 18:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant