Tarski/ docsJoin the waitlist

Write policies

Admit observations before append with explicit actor, payload, target, metadata, and idempotency bindings.

Write policies are Tarski’s pre-append security boundary. A policy decides whether one named writer may append one exact observation kind to one target. A denial leaves no observation or relay evidence behind, so unauthorized data never becomes canonical truth.

This reference describes the contract introduced with tarski 0.5.9-preview.8.

Bindings, selection, and extension

[write_policies.customer_message]
description = "A customer may write only to a session they can access."
writer_kind = "client"
append_target = "chat:{session_id}"
required_metadata = ["actor_id", "actor_kind", "session_id"]
on_denied = "reject_append"

[[write_policies.customer_message.direct_observations]]
kind = "chat.user_message"
allow = "access.chat_message_append_allowed"
args = ["actor.actor_id", "payload.session_id"]

[write_policies.customer_message.idempotency]
mode = "required"
key_field = "payload.message_id"

At append time the caller explicitly selects customer_message. Tarski evaluates only that policy:

  • direct_observations[].kind is an exact string. contact.* globs are rejected.
  • A direct observation entry without allow is a static, unconditional grant, but only after that named policy is selected. Required metadata, target, and idempotency still apply.
  • An allow relation succeeds when the current worldview contains the requested tuple. The tuple may come from a rule or a static assert; its origin does not change policy semantics.
  • actor.* values come from trusted ingress context. Nested payload.* values may be lookup arguments, but never become authority by themselves. Missing fields and wrong scalar types deny the append.
  • Delegated platform-builder contexts can bind actor.tier, actor.issuing_authority.authority_id, and actor.delegation_chain.tenant_organization.

Two policies may name the same exact kind. This is useful for separate writer roles, but it never means “any policy may allow”: only the explicitly selected policy is evaluated.

Imported or package-owned policies are immutable. To extend one, declare a new complete policy containing the original and additional kinds, then rebind the interface or ingress to the new policy. Tarski does not merge policy fragments across packages.

Relay writers use writes for reserved candidate.* and proposal.* evidence; this is the one write-policy surface where namespace globs are supported. contributes_to documents what the ontology may eventually derive. Neither field lets a writer append a trusted fact or executable intent directly.

Inspect the effective policy

Do not reverse-engineer package overlays. Tarski generates the selected policy contract:

tarski agent inspect support_agent --json
tarski agent interface inspect support_agent customer_chat --json

Read write_policy_contract for the effective policy id and digest, exact kinds, conditional versus static entries, target, arguments, required metadata, idempotency, relay writes, overlap semantics, and package-extension rules.

Actor context and expected denials in fixtures

JSONL fixtures can exercise the real pre-append boundary with a fixture.write_policy_attempt control record:

{"kind":"fixture.write_policy_attempt","payload":{"lineage_id":"chat:s1","policy_id":"customer_message","observation":{"kind":"chat.user_message","payload":{"session_id":"s1","message_id":"m-denied","text":"must not enter truth"}},"actor":{"actor_id":"user:other","actor_kind":"human","session_id":"s1"},"expected_denial":{"code":"write_policy_denied","message_contains":"denied observation kind"}}}

The outer record is a test instruction, not an observation. During tarski verify, the runner evaluates the named policy against the preceding fixture world and actor context. The test passes only when the denial code and optional message fragment match. Neither the control record nor the denied observation enters the replay timeline.

Put allowed and denied attempts in the same scenario when the boundary depends on ontology-derived access facts. This proves both the positive permission and the absence of leaked evidence under one deterministic world.