Imported Trace Contract

July 7, 2026 ยท View on GitHub

PolicyStrata scans newline-delimited JSON (.jsonl) records. Each line is one observed tool call, ORM query, semantic-layer query, or SQL span.

Minimal Record

{
  "id": "ticket_count_001",
  "principal": "acme_analyst",
  "tenant_ids": ["acme"],
  "release_allowed": true,
  "semantic_ir": {
    "metric": "ticket_count",
    "dimensions": ["region"],
    "time_range": "last_month",
    "grain": "month",
    "limit": 100
  },
  "sql": "select count(distinct support_tickets.id) as value from accounts left join support_tickets on support_tickets.account_id = accounts.id where accounts.tenant_id in ('acme') limit 100"
}

TypeScript SDK records may put SQL under query.sql; the scanner normalizes that to the top-level sql field during import. The SDK can also emit record_type: "agent_session", "tool_execution", or "mutation" records in the same JSONL stream. Those records are ignored by the SQL scanner unless they include top-level read-only sql.

Fields

FieldRequiredMeaning
idyesStable trace identifier. Use letters, numbers, _, ., or -.
principalyesPolicy principal id from domain/policy.yaml.
sqlyesRead-only SQL emitted by the application, ORM, semantic layer, or traced span.
tenant_idsrecommendedTenant ids bound for the principal/request. These are required for static validation when tenant predicates are parameterized.
semantic_irrecommendedPolicyStrata semantic query to authorize independently of SQL generation.
release_allowedrecommendedWhether the application released the result to the user.
expected_policyoptionalFree-form expected-policy notes for review and reporting. These notes are advisory and do not suppress scanner findings.
sourceoptionalAdapter or service that emitted the trace, such as prisma, sqlalchemy, or otel.
timestampoptionalISO-8601 event timestamp.
regression_caseoptionalOne of fail_to_pass, pass_to_pass, contain_to_contain, deny_to_deny, allow_to_allow, unclassified.

semantic_ir supports:

FieldMeaning
metricCanonical policy metric or allowed alias.
dimensionsRequested dimensions.
filtersStructured filters captured before SQL lowering.
time_rangeCanonical time range label.
grainAggregation grain.
limitRow budget requested or applied.

Tenancy Configuration

Configure real application tenancy vocabulary in policystrata.yaml:

tenancy:
  canonical_predicates:
    - "transactions.household_id = :principal.tenant_id"
    - "accounts.household_id = :principal.tenant_id"
    - "orders.organization_id = current_setting('app.organization_id')"
  tenant_columns:
    - transactions.household_id
    - accounts.household_id
    - organization_id

Trace-supplied expected_policy fields are not trusted as scanner controls. If SQL intentionally relies on database RLS rather than literal tenant predicates, add trusted database.rls_checks or database.state_assertions in policystrata.yaml so the containment layer is exercised directly.

Validation

Render the imported trace schema when building or testing an exporter:

uv run policystrata schema --kind imported-trace --out schemas/imported-trace.schema.json

Run a local scan against imported traces:

uv run policystrata scan --config policystrata.yaml --out runs/scan

Findings include what_changed, owner, probable_fix, minimal_repro_trace, and ci_gate_command so the scan artifact can be used directly in review or CI.