Pharos Framework

← Back

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_id
  • storage_kind
  • identity_field
  • fields
  • relations
  • uniqueness_rules
  • tenancy_scope
  • generated_surfaces
  • backend_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:

  • global
  • tenant_required
  • tenant_optional

Query Contract

Every reusable query must specify:

  • query_id
  • entity_id
  • visibility_scope
  • filter_set
  • sort_set
  • pagination_mode
  • preload_relations
  • backend_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:

  • global
  • tenant_bound
  • team_bound
  • policy_bound

Transaction Contract

Every multi-entity mutation must specify:

  • transaction_id
  • read_set
  • write_set
  • isolation_expectation
  • side_effect_policy
  • idempotency_scope
  • failure_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_id
  • schema_version
  • adapter_targets
  • forward_steps
  • verification_checks
  • drift_inputs
  • safety_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_only
  • backfill_required
  • destructive_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|postgresql
  • pharos migrate status app <target-id> --backend sqlite|postgresql
  • pharos migrate seed app <target-id> --backend sqlite|postgresql
  • pharos migrate verify app <target-id> --backend sqlite|postgresql
  • pharos migrate apply app <target-id> --backend sqlite|postgresql
  • pharos migrate rollback app <target-id> --backend sqlite|postgresql
  • pharos 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