P09 · Host · Rendered from source

P09 first principles — data and state plane

Data and state plane

91 lines5,848 bytessha256 90073cef0865

P09 first principles — data and state plane

Lane S1-L4 · run 2026-08-27-sprint-1-fable · status: drafted from local evidence, finalized after external surveys (see research-report.md for the joined view).

Objective

Let one assembled Actionist product read and write state across capabilities that were never designed together — newly-written owned code, absorbed donor code, intact donor services, and external systems — without hidden dual writes, contested migrations, or a universal-database fiction.

Constraints (evidence-backed)

  1. Donor data layers are expensive to move: Django/Prisma emit store-specific SQL; the

cost of forcing a store is the fork, not the database (SISOCRM, observed).

  1. A shared mutable schema couples independently-versioned donors at their most brittle

layer — migrations (SISOCRM, observed rejection).

  1. Clients ultimately receive a product Cena's team must operate; per-donor database

servers multiply backup/restore/monitoring burden (SISOCRM, observed).

  1. LLM-authored access policy on a directly reachable database is a known data-leak

class (Lovable teardown, observed externally). Data authority must be host-owned and deterministic.

  1. Research boundary: no benchmark or execution was authorized this sprint; workload

claims here come from precedent reads and first principles, not measurement.

Invariants (proposed, with falsifiers)

  • INV-P09-1 One authoritative owner per stateful resource — per table, per

migration lineage, per file namespace, per event stream. Falsifier: any workflow in the Loop-2 bake-off that cannot be expressed without two writers on one table.

  • INV-P09-2 Workload shape precedes store choice. The unit of decision is the

state class (owned-transactional, donor-owned, document/collab, analytics, search/vector, files, events, cache/ephemeral), not the product. Falsifier: if ≥80% of pilot state classes land on Postgres anyway AND the port abstraction costs more than it saves, the taxonomy over-engineers and Postgres-first should be the rule.

  • INV-P09-3 Postgres is the default for NEW owned transactional state only (A08),

never an invariant imposed on donors (A09 rejected). Falsifier: a donor whose native store creates operational burden exceeding its fork-avoidance savings.

  • INV-P09-4 Cross-owner product views are read models fed by events, never

cross-owner table mutation. Synchronous cross-owner consistency is an explicit, justified exception, not a default. Falsifier: a pilot workflow where eventual consistency measurably breaks the client outcome (e.g. approval gates reading stale state) — that discovers the sync-boundary list, it doesn't kill the invariant.

  • INV-P09-5 Capabilities consume typed data ports; stores hide behind adapters.

ORM choice is adapter-local (A10 rejected as contract content). Falsifier: Loop-0 — if the port needed to cover three genuinely different reuse shapes becomes so wide it leaks store semantics anyway, thin ports fail and per-shape contracts win.

  • INV-P09-6 Migration authority is release-scoped. An assembled release pins the

schema versions of every owned resource and the expected donor schema versions; a release without a rollback path for its migrations is not releasable (aligns ReleaseManifest, D18).

  • INV-P09-7 Tenant identity is a first-class column/key on every owned resource

from day one; per-tenant encryption keys for credential-class data. (OpenConnector's missing tenant column is the local proof of retrofit cost.)

Workload taxonomy (the P09 deliverable shape)

Eight state classes, each with distinct ownership defaults:

ClassDefault ownerDefault bindingNotes
Owned transactionalActionist hostPostgres via typed portINV-P09-3
Donor-owned stateDonor (service) or absorbed schemaDonor API / separate schema, one serverreuse-shape-dependent (SISOCRM)
Document/collaborationDonor engine usually (AFFiNE-class)Engine API + FK linkage to owned recordsabsorption adds real FKs
Analytics/read modelsActionist hostEvent-fed owned tables/viewsthe cross-owner join answer
Search/vectorDedicated engine only when workload demandsPort over engineintroduce late, not by default
Files/objectsHost file capabilityObject-store port (impl per deployment scale)undecided even in SISOCRM
EventsHost event envelopeOutbox → bus/logalso P11 receipts substrate
Cache/ephemeral/localCapability-localSQLite/libSQL/memorynever source of truth

Contradictions and tensions

  • Absorption (one schema, real FKs) vs federation (schemas + read models) pull the

data plane in opposite directions; both are locally proven choices. Resolution: the choice is made per capability by PackagingProfile, and the data plane must price both.

  • Thin ports vs expressiveness: Refine-style CRUD providers prove UI decoupling, but

transactions/bulk/subscription/search stretch a single port. Likely resolution: port FAMILY (crud, query, tx, files, search, events) with capability-declared needs.

  • Read models demand event discipline donors don't natively have; retrofitting CDC on

a donor may exceed the cost of just calling its API synchronously for low-volume views. The bake-off must price CDC-per-donor honestly.

Unknowns carried to experiments

Q11-Q16 from knowledge/04 remain open; Loop 0 (contract surgery) and Loop 2 (bake-off) in knowledge/05 are the designated falsifier vehicles. This lane adds: the dual-write detection question (what mechanically prevents a capability from writing a table it does not own — schema privileges? separate roles per capability? review-time static analysis of adapters?) — proposed as a Loop-2 measured dimension.