MyronCMS Developers Hub Docs sandbox review

Reference

Migration Constraints

Extension migrations are intentionally narrow. They exist so an extension can own its own storage without weakening core schema boundaries.

Boundary Rule

Every extension-owned table must start with:

{vendor}_

For vendor my_vendor, valid table names include:

my_vendor_notes
my_vendor_settings
my_vendor_schema_migrations

Invalid table names include:

pages
users
settings
other_vendor_notes
core_table_violation

The boundary is a safety rule, not a naming preference.

Runner Contract

MyronExtensionMigrationRunner::run() accepts:

run(string $vendor, PDO $pdo, array $migrations): void

The vendor must be snake_case:

^[a-z][a-z0-9_]*$

The runner creates this tracking table automatically:

{vendor}_schema_migrations

It then skips already-applied versions and runs each new version in a transaction.

Checked SQL Statements

Array SQL migrations are checked when they begin with one of these statement shapes:

StatementBoundary checked
CREATE TABLE ...Created table must start with {vendor}_.
ALTER TABLE ...Altered table must start with {vendor}_.
DROP TABLE ...Dropped table must start with {vendor}_.
CREATE INDEX ... ON ...Indexed table must start with {vendor}_.
CREATE UNIQUE INDEX ... ON ...Indexed table must start with {vendor}_.

If the table does not start with the vendor prefix, the runner throws:

Extension migrations may only modify tables prefixed with {vendor}_.

Callable Migrations

Migration files may return callables. Callable migrations are useful for small data transforms or database-specific operations, but the static SQL prefix check cannot inspect arbitrary PHP.

The contract still applies:

  • callable migrations must only touch {vendor}_* tables,
  • callable migrations must not mutate core or cross-vendor tables,
  • callable migrations must not store secrets,
  • callable migrations must not bypass tracking.

Prefer array SQL for schema creation when possible because the runner can inspect it.

Versioning

Use stable, descriptive version keys:

return [
    'v001_create_notes_table' => [
        'CREATE TABLE IF NOT EXISTS my_vendor_notes (...)',
    ],
    'v002_add_note_status' => [
        "ALTER TABLE my_vendor_notes ADD COLUMN status VARCHAR(32) NOT NULL DEFAULT 'draft'",
    ],
];

Once a version has shipped, do not change its meaning. Add a new version for subsequent changes.

Human Path

The developer authors migration files under:

app/extensions/{vendor}/migrations/

The operator registers and enables the extension. On boot, the loader runs unapplied migrations before registering runtime contributions.

AI Path

An AI coding agent can author local migration files, check table prefixes, and run verification. An installed MCP client cannot run migrations directly and must not be documented as having migration-control parity.

Scopes

Migrations are not called through API or MCP scopes. They run as part of extension loading. The extension grant still determines whether the extension is loadable.

Artifacts

  • app/extensions/{vendor}/migrations/*.php
  • {vendor}_schema_migrations
  • extension-owned {vendor}_* tables

Safety Boundary

Do not document these operations as allowed:

  • creating or altering core tables,
  • creating or altering another extension's tables,
  • storing API keys or secrets in migration files,
  • editing {vendor}_schema_migrations by hand,
  • running migration PHP files outside the loader to get around a load error.

Verification

Run:

php app/tests/verify-extension-system-foundation.php

The test confirms both the positive and negative paths:

CheckExpected result
Reference migration creates myron_sample_pingsPass.
Runner creates myron_sample_schema_migrationsPass.
Non-prefixed table migration is attemptedRejected.

Failure Modes

FailureSourceSafe response
Extension migration vendor must be snake_case.Vendor validation.Use a valid manifest vendor.
Extension migrations may only modify tables prefixed with ...SQL table isolation check.Rename the table under {vendor}_*.
Migration version never recordsMigration threw before tracking insert.Fix the migration and rerun through normal loader boot.
Migration partially appliesDatabase-specific transaction behavior or DDL semantics.Keep migrations idempotent and review database behavior before shipping.
Callable migration mutates core stateContract violation.Move state into extension-owned tables or return to Evaluate for a new primitive.