The Shelf / The Laravel Edition canon v3.5.9 · gate PASS

Management as Ontology via Laravel (the stack edition)

What this is: the binding artifact between the canon (the spec) and a Laravel codebase (one implementation): every canon concept landed on a named Laravel primitive (Model, migration, relation, Form Request, Action, scheduler entry, storage disk), then one real concern walked from its spine to its tables with every claim cited. The canon stays portable and stack-silent by design; THIS document is where the methodology gets a codebase body in the stack both living deployments run. Relationship per the canon's own spec-and-implementation law: the canon owns intent, the code owns mechanism, this edition declares the conformance mapping between them. Built against: canon v3.5.9 (2026-09-04). Status: a BINDING, and public: it cites the canon and the canon never cites it; an estate on Rails or Django reads the same canon and writes a sibling edition, and the day two such editions sit side by side, whatever structure they share is the only thing that could ever be proposed as a canon instrument, through the usual door and under the register's cap. Nothing here is law. Source: the estate map's first teaching read (2026-09-05), when the question "in Laravel we have Models represented in a MySQL database, how does that relate?" arrived from the canon's own author, minutes after the map first rendered. Sibling: the Relay edition (a product body for the same canon; unpublished pending its owner's call).

Why this edition is not a canon Part

Two laws forbid it. The canon owns TYPES and a deployment owns only BINDINGS (the types-and-bindings law): "register" is a type, "an Eloquent model backed by a MySQL table" is one deployment's binding of it, and a Notion database is another. And the spec never restates mechanism (the spec-and-implementation law): a Laravel section inside the canon would be the first mechanism in the spec, and it would date the whole document to one stack. So the mapping lives here, in the teaching layer, stamped with the canon version it binds against so the release gate flags drift.

The mapping

Read each row as "the MO concept, the Laravel mechanism it is usually implemented with, and the distinction that keeps the two from collapsing into each other".

MO concept Laravel mechanism The distinction that matters
Noun (layer 1 entity) An Eloquent Model class The noun is the concept; the model is its code shape. A noun may live in Notion, or only inside an index, and stay the same noun.
Identity scheme The primary key underneath, the declared natural key as a UNIQUE index The identity law: machines keep ids, humans speak the natural key.
Legal states A status column whose values are the spine's state words Transitions belong in an Action, never scattered through controllers.
Decision fields Columns A column that changes no decision is a fitness failure. Timestamps and sync bookkeeping are mechanism, which the spine never lists.
Typed link An Eloquent relation over a foreign key The relation names the edge's shape (belongsTo, hasMany); the sidecar's verb names its meaning. The relation implements the declared link.
Cross-concern link A relation to a model homed in another concern, by id Reference, never copy (the jurisdiction law). The spine names the home; the foreign key names the mechanism.
Register The table or tables behind the noun, plus the named scopes that walk exceptions One register can span several tables. The exception walk is a scope in the domain's words, not a raw query.
Ledger Append-only tables: activity logs, run receipts, event streams Insert only. A base model with activity logging gives every register a ledger for free.
Court Usually a query over registers: rows with an owner and a since It becomes its own table when balls are first-class.
Board A work-item table with a definition of done and a closed state A state machine on a table.
Door Form Requests, controllers, Actions, MCP tools Validation and database constraints are the gate. A write that bypasses them (a tinker session in production) is not a door.
Surface A Vue route or Blade view Read-only where the deployment rules chat as the write surface.
Index A computed endpoint, or a table rebuilt on events Never hand-editable. Empty means nothing needs a human.
Corpus Storage disks: PDFs, JSONL manifests, object storage What backfill commands recompute from.
Verb, on its clock An Artisan command or Action, scheduled in routes/console.php The scheduler file is layer 2. A verb with no scheduler line and no ceremony seat has "sometime" for a clock.
Layer-1 amendment A migration Additive and versioned. Retirement is a new drop-migration; the create-migration is history and is never deleted.
The spine, the jobs Not code The dossier and its machine-form sidecar own the why and the legal states. A feature test per job is the closest code cousin.

One concern walked end to end: payment cards

The spine is the estate's payment-cards-management dossier with its sidecar; the code is the nwos-finance application. Left column the spine's claim, right column what the code shows. Every claim below cites its file.

Nouns become models. Payment Card is App\Models\PaymentCard on the payment_cards table. Its identity scheme, "the last-four plus nickname", appears in the schema as UNIQUE (user_id, card_nickname): the declared natural key made into a constraint. Its states, active and retired, are the is_active boolean. Its decision fields (expires_on, is_active, replaced_by_card_id) are columns. Service Registration is App\Models\CardServiceRegistration on card_service_registrations; its states healthy, unknown, and unhealthy are the health_status column, and the spine's rule that healthy is EARNED by the next landed charge, never asserted, is visible in the schema as default('unknown'). The third noun, Attention Item, has no model and no table: the spine declares it "computed per request by the index, never stored", and the code agrees. Not every noun has a table. A noun may live only in an index, and that is legal.

Links become relations. "Service Registration CHARGES Payment Card" is CardServiceRegistration::paymentCard() (belongsTo) with its inverse PaymentCard::cardServiceRegistrations() (hasMany) over payment_card_id. "Payment Card REPLACES Payment Card", the retirement chain, is the self-referencing pair replacedByCard() and replacesCard() over replaced_by_card_id, a foreign key onto the same table. The cross-concern link, "Statement Charge VERIFIES Service Registration" with its home in the finance close, is matchedTransactions() (hasMany SpendingTransaction): a relation onto a noun another concern owns, by id, inside the same app. The spine names the home; the foreign key names the mechanism; the docblock should name the verb, and today it does not, which is the first conformance note.

The register. The spine binds two tables as one organ, "the card register", and the code agrees: the two tables, both on the base model. The exception walk (which cards expire within sixty days, which registrations are unhealthy) lives as queries inside a controller rather than as named scopes. The readability law's ORM clause would prefer PaymentCard::expiringWithin($days) so the query speaks layer 1. Second conformance note.

The ledger, for free. Both models extend a base model carrying SoftDeletes and activity logging (logAll, logOnlyDirty). Every create, update, and soft delete lands in activity_log with old and new values. The concern declares no ledger organ of its own and needs none: the base model gave every register one.

The door. Three MCP tools (record_card_service_registration, transfer_card_service_registration, mark_registration_reregistered) front POST routes whose controllers begin with $request->validate([...]). The validation rules are the gate: a registration without a card that exists, or without a service name, cannot enter. A web form for the same rows exists on the surface and is a lens by the estate's ruling; the door is the typed path.

The index. GET /api/mcp/cards/attention is computed on every request from the two tables and returns five exception lists (expired, expiring soon, expiry unknown, needs re-registration, unhealthy). It is stored nowhere, and an empty response means nothing needs a human. This is also where the specimen teaches something the canon has not yet ruled: by mechanism it is an index (derived, recomputed), by job it is a court (where the card balls sit). The estate typed it index; the same shape in the claims concern was typed board. The candidate ruling, type by job with derivation as a qualifier, is filed for the canon's door, not decided here.

The surface. The /card-registry route in the Vue app. Read-only by ruling.

The verbs, on their clocks. The weekly expiry watch is Schedule::command('alfred:weekly-walk')->weeklyOn(0, '09:25') in the Alfred application's routes/console.php; its cards segment calls the attention feed. That is layer 2 in one line: a verb, a clock, an owner. The monthly health sweep rides the card-statement-close workflow, which a human invokes. That verb has an owner and a stated cadence but no scheduler line and no ceremony seat, so the absence test would catch it: third conformance note, and an honest one.

The corpus. None declared, and correctly so: the statement PDFs that would verify a charge belong to the finance close. A register-only concern has no corpus.

Layer-1 amendments. Four migrations: the two create-migrations (2026-02-25), the identifier fields (2026-03-26), and health tracking (2026-04-06). The last one is a ruling in schema form: the day the concern decided that health is earned, the column arrived with unknown as its default.

The conformance checklist

What a reviewer checks a Laravel codebase against, given the concern's spine. Each line is one law made mechanical.

  1. One model per declared noun, named as the noun. A noun declared as computed may have none.
  2. A primary key underneath and the declared natural key as a UNIQUE index.
  3. A states column whose legal values are the spine's state words; transitions in one Action, never in controllers.
  4. Every column changes a decision, or is mechanism the spine never lists.
  5. One relation per typed link, the verb named in its docblock; a cross-concern link points at a model homed elsewhere, by id.
  6. Registers extend the base model with soft deletes and activity logging; nothing hard-deletes.
  7. Every door validates; no production write outside a door.
  8. Every clocked verb has a scheduler line or a ceremony seat.
  9. Indexes are computed or rebuilt on events; no hand-editable derived table.
  10. Exception walks are named scopes in the domain's words.
  11. Migrations are additive; retirement is a new drop-migration.
  12. One feature test per job, named as the hirer's question.

Three things to say out loud when teaching this

A noun is not a table. The model is the concept and the table is one place it can live. Keeping them apart is what lets the same noun sit in Notion today and in MySQL after graduation with no change to the spine, and what lets Attention Item be a noun with no table at all.

Relations are links with the verb left off. belongsTo names the shape; CHARGES names the meaning. Cardinality is the one thing relations carry that the spine's links do not yet; it becomes worth declaring the day a conformance lint wants to check relation shapes against the spine.

The scheduler is layer 2. Every line in routes/console.php is a verb with a clock and an owner. Read a concern's SOP suite beside its scheduler file and the verbs with "sometime" for a clock show themselves.

The guards that keep this edition a binding

It cites the canon and the canon never cites it. It is stamped with the canon version it binds against and re-bound when the canon's major or minor version moves. It carries a flip line: a second stack binding the same spine earns a sibling edition, and only structure common to both could ever be proposed as a canon instrument, through the usual door and under the register's cap.

Why this edition exists

The worked examples show the doors (a pain door, a JTBD door, a regulated import). This edition shows the other half of the discipline, the implementation conforming to the spec, in the stack the readers already write. It also shows the review working: a real concern, read against its own spine, produced three conformance notes and one candidate canon ruling in a single pass. That is the double loop at codebase scale, and the reason the mapping is worth an edition.