schema_version = 3

[workspace]
root = "."
index_path = ".pituitary/pituitary.db"

# Fixture embedder for CI speed and determinism. Switch to a runtime
# profile (see Pituitary docs) if/when this repo wants real semantic
# checks; the CI template re-uses whatever profile is selected here.
[runtime.embedder]
provider = "fixture"
model = "fixture-8d"
timeout_ms = 1000
max_retries = 0
max_response_tokens = 0

# Terminology policies.
#
# Pituitary auto-tolerates "historical context" passages (e.g. lines
# explaining a rename: "X used to be Y, now Y") so the spec sections
# that document each rename do not false-positive against the rules
# below.
#
# Severity convention used throughout this file:
#   * specs_severity = "ignore"  — the spec body is the normative
#     record of the rename and is expected to mention the deprecated
#     term while documenting the transition.
#   * specs_severity = "error"   — the deprecated term should never
#     appear in spec text (lifecycle-moment renames where the spec
#     should already speak the v1 vocabulary).
#   * docs_severity  = "warning" — keeps drift visible in
#     docs/playbooks/AGENTS.md/harness READMEs without fail-closing
#     the gate during the rollout window.
#
# Schema gap (documented, not worked around):
#   The schema (configuration.md "Terminology Governance") models
#   policies as "preferred + historical_aliases + deprecated_terms +
#   forbidden_current". It does NOT model "preferred-only presence
#   enforcement" (i.e. "the corpus must mention this term somewhere").
#   Several #18 deliverables ask for exactly that — frame.opened,
#   receipt.gap_detected, idempotency_key, lifeloop_run_id, frame_id,
#   parent_frame_id, frame_class, and the failure-class names. We
#   leave them as named comments below instead of inventing a new
#   field; if/when Pituitary grows a presence assertion, lift those
#   comments into [[terminology.policies]] entries.

# Nanto-wide convention: CCD expands to "Continuous Context Deployment".
# Kept here as a guardrail in case the older long-form leaks into docs
# (memory: feedback_*_ccd_acronym.md in the operator's auto-memory).
[[terminology.policies]]
preferred = "Continuous Context Deployment"
forbidden_current = ["Claude Coding Daemon"]
docs_severity = "warning"
specs_severity = "warning"

# Spec rename (issue #6 cleanup): "simulated" -> "synthesized".
# Source: src/lib.rs ("simulated -> renamed to synthesized") and the
# spec's "Support states" section. The pre-issue-#6 vocabulary
# distinguished simulated from inferred; #6 renamed simulated to
# synthesized for clearer derivation semantics.
#
# specs_severity = "ignore" because the spec body itself is the
# normative record of the rename and is expected to mention both the
# preferred and the deprecated term to document the transition.
# docs_severity = "warning" so any *new* doc that adopts the old
# term gets flagged.
[[terminology.policies]]
preferred = "synthesized"
historical_aliases = ["simulated"]
docs_severity = "warning"
specs_severity = "ignore"

# Spec rename (issue #6 cleanup): "inferred" -> "partial".
# Same #6 cleanup folded "inferred" capability into "partial":
# telemetry-derived behavior is partial behavior. The English word
# "inferred" appears in unrelated contexts (e.g. type inference);
# warning severity in docs keeps it visible without false-positive
# pressure on the spec body.
[[terminology.policies]]
preferred = "partial"
historical_aliases = ["inferred"]
docs_severity = "warning"
specs_severity = "ignore"

# v0 -> v1 lifecycle rename: "turn.ended" -> "frame.ended".
# Source: docs/tombstones/lifeloop.v0.md section 2 (lifecycle moment
# rename). The lifecycle contract should already speak the frame.*
# vocabulary; the deprecated turn.* moment should never appear in
# spec text. specs_severity = "error" enforces that. The tombstone
# itself is auto-tolerated because Pituitary detects historical
# rename context.
[[terminology.policies]]
preferred = "frame.ended"
historical_aliases = ["turn.ended"]
docs_severity = "warning"
specs_severity = "error"

# v0 -> v1 lifecycle rename: "prompt.building" -> "frame.opening".
# Source: docs/tombstones/lifeloop.v0.md section 2. The deprecated
# term was a lifecycle moment; like turn.ended, it should not appear
# in current spec text. The English phrase "prompt building" without
# the dot is intentionally not flagged — only the lifecycle-moment
# token form.
[[terminology.policies]]
preferred = "frame.opening"
historical_aliases = ["prompt.building"]
docs_severity = "warning"
specs_severity = "error"

# Preferred lifecycle moment with no historical alias: "frame.opened".
# Schema gap: Pituitary cannot enforce "this term must appear
# somewhere in the corpus" — see the schema-gap note at the top of
# this file. Recorded here so that when presence assertions land
# upstream the policy can be filled in. Issue #18 acceptance.

# Preferred lifecycle event with no historical alias:
# "receipt.gap_detected". Same schema-gap note as frame.opened.

# Preferred identifier surface (schema-gap note as above):
#   idempotency_key, lifeloop_run_id, frame_id, parent_frame_id,
#   frame_class.
# These are wire-level identifier names that the spec body and src/
# already expose; they have no historical aliases worth governing.

# Receipt-status rename: "accepted" -> "applied".
# Source: docs/tombstones/lifeloop.v0.md section 5 (receipt-status
# vocabulary cleanup). The bare word "accepted" is also used as a
# spec-bundle status value (see docs/specs/lifecycle-contract/spec.toml,
# `status = "accepted"`), so specs_severity = "ignore" avoids
# false-positives on the spec descriptor; docs_severity = "warning"
# still surfaces drift in operator-facing prose.
[[terminology.policies]]
preferred = "applied"
historical_aliases = ["accepted"]
docs_severity = "warning"
specs_severity = "ignore"

# Receipt-status deprecation: "completed" as a lifecycle status.
# Source: docs/tombstones/lifeloop.v0.md section 5. Unlike the
# accepted -> applied rename, "completed" maps to "delivered" and is
# only a violation when used as a *receipt status*. The plain English
# word "completed" appears in unrelated contexts (test names,
# narrative prose); warning severity keeps the signal without forcing
# pre-emptive renames of unrelated identifiers.
[[terminology.policies]]
preferred = "delivered"
historical_aliases = ["completed"]
docs_severity = "warning"
specs_severity = "ignore"

# Failure classes (preferred vocabulary; no historical aliases —
# schema-gap note at top of file applies):
#   placement_rejected, hook_protocol_error, receipt_conflict,
#   state_conflict, telemetry_unavailable, internal_error.
# These are the v1 failure-class names from docs/tombstones/
# lifeloop.v0.md section 6. No deprecated names existed pre-v0 so
# there is nothing to forbid; this stays a presence concern only.

# Retry-class rename (v0 -> v1): the v0 set
# `{ retry_same_adapter, retry_after_backoff, retry_different_adapter,
#   ask_operator }` collapses to the v1 set `{ safe_retry,
# retry_after_reread, retry_after_operator_action }`.
# Source: docs/tombstones/lifeloop.v0.md section 7. Encoded as three
# separate policies (one preferred per old->new pairing) so each
# replacement carries its own canonical target. specs_severity =
# "ignore" because the tombstone documenting the migration is itself
# a spec-adjacent doc that legitimately names every old term.
[[terminology.policies]]
preferred = "safe_retry"
historical_aliases = ["retry_same_adapter"]
docs_severity = "warning"
specs_severity = "ignore"

[[terminology.policies]]
preferred = "retry_after_reread"
historical_aliases = ["retry_after_backoff"]
docs_severity = "warning"
specs_severity = "ignore"

# Two old retry classes (`retry_different_adapter` and `ask_operator`)
# collapse into the single v1 class `retry_after_operator_action`.
# Both old names are listed under `historical_aliases` so either
# legacy reference resolves to the same canonical replacement.
[[terminology.policies]]
preferred = "retry_after_operator_action"
historical_aliases = ["retry_different_adapter", "ask_operator"]
docs_severity = "warning"
specs_severity = "ignore"

# Specs: the lifecycle contract is the normative target the Rust
# implementation in src/lib.rs is pinned against. spec.toml
# descriptor is the sibling docs/specs/lifecycle-contract.toml; its
# body field references docs/specs/lifecycle-contract.md so the
# existing markdown stays at its current path (no link breakage in
# README, playbooks, or other docs that reference it).
[[sources]]
name = "specs"
adapter = "filesystem"
kind = "spec_bundle"
path = "docs/specs"
files = [
  "lifecycle-contract/spec.toml",
]

# Reference docs: product thesis, runbooks, supporting specs index.
# The lifecycle-contract.md body lives under the spec_bundle source
# above and is intentionally NOT re-listed here.
#
# docs/README.md is intentionally NOT listed: it would normalize to
# `doc://README` and collide with the repo-root README.md (also
# `doc://README`) indexed by the `project-docs` source below.
# Pituitary's filesystem adapter derives refs from path-minus-
# extension relative to the source `path`, so only one README per
# basename can be indexed across the workspace. The repo-root README
# is the higher-stakes operator entry point and wins.
[[sources]]
name = "docs"
adapter = "filesystem"
kind = "markdown_docs"
path = "docs"
files = [
  "product-thesis.md",
  "rlm-development-contract.md",
  "harness-concept-boundary.md",
  "specs/README.md",
  "playbooks/README.md",
  "playbooks/schema-bump.md",
  "playbooks/wire-contract-review.md",
]

# Project-level operator docs: AGENTS.md plus the repo-root README.
# These are the entry points operators read first; drift here is
# high-impact. Restricted to an explicit allow-list so unrelated
# repo-root files (LICENSE, CHANGELOG, etc.) stay out of scope.
[[sources]]
name = "project-docs"
adapter = "filesystem"
kind = "markdown_docs"
path = "."
files = [
  "AGENTS.md",
  "README.md",
]

# Harness wrapper directories. Each harness ships a thin README and,
# in some cases, agent/skill definitions; these are the surfaces
# where operator-facing prose tends to accumulate drift first because
# they are edited by every harness independently. Indexed as
# markdown_docs (drift + search), not markdown_contract (no inferred
# spec metadata expected here).
#
# Harness README ref-collision note: each `.<harness>/README.md`
# would otherwise normalize to `doc://README` (filesystem refs strip
# the source `path` prefix and the `.md` suffix), colliding with the
# repo-root README. Mounting them under the repo root with `files`
# entries like `.claude/README.md` keeps the leading directory in
# the rel path, so the resulting refs are `doc://.claude/README`,
# `doc://.codex/README`, etc. — distinct.
[[sources]]
name = "harness-claude"
adapter = "filesystem"
kind = "markdown_docs"
path = "."
files = [
  ".claude/README.md",
  ".claude/agents/mr-author.md",
  ".claude/agents/wire-contract-reviewer.md",
]

[[sources]]
name = "harness-codex"
adapter = "filesystem"
kind = "markdown_docs"
path = "."
include = [".codex/**/*.md"]

[[sources]]
name = "harness-hermes"
adapter = "filesystem"
kind = "markdown_docs"
path = "."
include = [".hermes/**/*.md"]

[[sources]]
name = "harness-openclaw"
adapter = "filesystem"
kind = "markdown_docs"
path = "."
include = [".openclaw/**/*.md"]

[[sources]]
name = "harness-pi"
adapter = "filesystem"
kind = "markdown_docs"
path = "."
include = [".pi/**/*.md"]

# Schema gap: src/ (Rust code identifier surface).
#
# Issue #18 acceptance asks for `src/` to be in the indexed scope so
# the gate can audit code-side identifier drift (frame_id,
# idempotency_key, the failure/retry-class names, etc.) alongside
# prose. Pituitary's schema_version = 3 source kinds are
# `spec_bundle`, `markdown_docs`, `markdown_contract`, `json_spec`,
# `json_doc`, and `issue` (configuration.md, "Source Kinds"). There
# is no Rust-code adapter today.
#
# Adding `src/` as `markdown_docs` would mis-index .rs files (or
# silently exclude them, since the markdown_docs `files` selector
# requires `.md` paths). Until Pituitary grows a code-aware adapter,
# the structural counterpart to this lexical gate is
# `tests/spec_alignment.rs`, which pins the Rust implementation's
# identifier surface against the lifecycle-contract spec body.
# Re-evaluate this gap when Pituitary adds a code-source kind.
