Pharos Framework Data Contracts
Pharos needs a data contract that is broader than a single SQLite proving path, but still concrete enough to force PostgreSQL-ready semantics before competitiveness claims.
Entity Contract
Every entity must specify:
entity_idstorage_kindidentity_fieldfieldsrelationsuniqueness_rulestenancy_scopegenerated_surfacesbackend_targets
Example shape:
{
"entity_id": "tenant_invoice",
"storage_kind": "relational",
"identity_field": "id",
"fields": [
{"field_id": "id", "type": "uuid", "nullable": false},
{"field_id": "tenant_id", "type": "uuid", "nullable": false},
{"field_id": "status", "type": "enum", "nullable": false}
],
"relations": ["tenant", "invoice_line_item"],
"uniqueness_rules": ["tenant_id + external_reference"],
"tenancy_scope": "tenant_required",
"generated_surfaces": ["admin", "form", "api", "manifest"],
"backend_targets": ["sqlite", "postgresql"]
}
Required tenancy scopes:
globaltenant_requiredtenant_optional
Query Contract
Every reusable query must specify:
query_identity_idvisibility_scopefilter_setsort_setpagination_modepreload_relationsbackend_requirements
Example shape:
{
"query_id": "tenant_invoice_list",
"entity_id": "tenant_invoice",
"visibility_scope": "tenant_bound",
"filter_set": ["status", "created_after", "search"],
"sort_set": ["created_desc", "amount_desc"],
"pagination_mode": "cursor_or_offset",
"preload_relations": ["tenant"],
"backend_requirements": ["sqlite", "postgresql"]
}
Required visibility scopes:
globaltenant_boundteam_boundpolicy_bound
Transaction Contract
Every multi-entity mutation must specify:
transaction_idread_setwrite_setisolation_expectationside_effect_policyidempotency_scopefailure_contract
Example shape:
{
"transaction_id": "approve_invoice",
"read_set": ["tenant_invoice", "approval_policy"],
"write_set": ["tenant_invoice", "approval_decision", "audit_event"],
"isolation_expectation": "read_committed_or_stronger",
"side_effect_policy": "defer_external_effects_until_commit",
"idempotency_scope": "invoice_id + action_id",
"failure_contract": "no_partial_external_effects"
}
Migration Contract
Every migration must specify:
migration_idschema_versionadapter_targetsforward_stepsverification_checksdrift_inputssafety_class
Example shape:
{
"migration_id": "tenant_invoice_v3_add_due_at",
"schema_version": 3,
"adapter_targets": ["sqlite", "postgresql"],
"forward_steps": ["add_column due_at timestamp nullable"],
"verification_checks": ["column_exists", "default_query_shape_ok"],
"drift_inputs": ["entity_contract_hash", "query_contract_hash"],
"safety_class": "expand_only"
}
Required safety classes:
expand_onlybackfill_requireddestructive_requires_gate
App Database Manifest Contract
Apps may declare their database policy directly in pharos.app.json:
{
"database": {
"preferred_backend": "postgresql",
"development_backend": "sqlite",
"testing_backend": "sqlite",
"entity_fixture": "data/framework/framework-app-entity-fixture-v1.json",
"query_fixture": "data/framework/framework-app-query-fixture-v1.json",
"migration_fixture": "data/framework/framework-app-migration-fixture-v1.json",
"seed_sources": [
"data/live/public-state.json",
"data/live/private-state.json"
]
}
}
Pharos provides the following database command surface:
pharos migrate plan app <target-id> --backend sqlite|postgresqlpharos migrate status app <target-id> --backend sqlite|postgresqlpharos migrate seed app <target-id> --backend sqlite|postgresqlpharos migrate verify app <target-id> --backend sqlite|postgresqlpharos migrate apply app <target-id> --backend sqlite|postgresqlpharos migrate rollback app <target-id> --backend sqlite|postgresqlpharos db seed app <target-id> --backend sqlite|postgresql
SQLite is the default development and proving backend. PostgreSQL remains available for production-oriented deployments when the app contract allows it.
Backend bundle entries in the migration fixture may also declare a structured verification_contract:
{
"backend": "sqlite",
"verification_contract": {
"required_tables": ["auth_user", "audit_event"],
"required_migration_ids": ["tenant_invoice_v3_add_due_at"],
"seed_expectations": [
{"table": "auth_user", "minimum_rows": 1}
]
}
}
pharos migrate verify consumes this contract so verification rules stay app-owned while the verification engine stays framework-owned. The migration contract also drives non-destructive apply planning, checksum drift detection, rollback policy reporting, and runtime bridge selection when an app declares relational cutover.
Backend Matrix Rule
Pharos treats:
- SQLite as the proving and local-development backend
- PostgreSQL as the production-completeness backend
A data feature is not complete unless it works on the contractually supported backends.
Contract Discipline
The data layer rejects:
- ORM-only truth not mirrored in entity or query contracts
- tenant boundaries enforced only in application code and not query contracts
- migrations without explicit adapter targets
- transactions with implicit external side effects