Opus-backed reasoning tool that checks a proposed decision, a recent
record, or an observed pattern against the active constitution tree.
Produces a structured verdict and leaves a durable citation on the
principles it leaned on.
After acting on a verdict, the caller MAY invoke the skill in followup mode
to record post-action signal. Missing followups are themselves data — the
lens treats absence as observable, not as a contract violation.
-
Regenerate derived views. Invoke /ztn:regen-constitution (or run
python3 _system/scripts/regen_all.py) first. Single consistency
rule: every pipeline regenerates before reading.
-
Load the filtered visible tree. Call the helper:
ZTN_BASE="$ZTN_BASE" python3 "$ZTN_BASE/_system/scripts/query_constitution.py" \
${DOMAINS:+--domains "$DOMAINS"} \
--compact
JSON array of visible active principles with full body, statement,
metadata. Fields: id, title, type, domain, priority_tier,
core, scope, applies_to, binding, framing, confidence,
status, last_reviewed, last_applied, derived_from,
contradicts, statement, body, path.
-
Reason. For the given situation, work the candidate list in
priority-tier order (1 → 2 → 3). For each candidate match, classify
the relation:
| Relation | Meaning |
|---|
aligned | The situation follows the principle — chose the path the principle recommends. |
violated | The situation breaks the principle — would degrade or ignore it. |
tradeoff | The situation trades one principle for another — surface both sides. |
Conflict resolution inside a tier:
- Explicit
contradicts: [other-id] in either frontmatter → higher
confidence wins (proven > working > experimental).
- Otherwise → verdict is
tradeoff; surface both principles.
Cross-tier: tier 1 beats tier 2 beats tier 3 (see
0_constitution/CONSTITUTION.md §6).
-
Emit JSON verdict on stdout:
{
"verdict": "aligned | violated | tradeoff | no-match",
"citations": [
{ "id": "axiom-identity-001", "relation": "aligned" }
],
"tradeoffs": [
{ "between": ["axiom-id-001", "axiom-id-002"], "chosen": "axiom-id-001", "reason": "..." }
],
"rationale": "prose explanation — 2–4 sentences max",
"record_ref": "[[_records/...]] or session id",
"run_id": "2026-05-03T15:22:11Z-7c4a9f02",
"followup_hint": "optional — after acting on this verdict, you MAY call /ztn:check-decision --record-followup 2026-05-03T15:22:11Z-7c4a9f02 with --post-confidence / --decision-taken / --human-needed-after / --verdict-resolved to enrich audit substrate. Skipping is fine."
}
verdict is the overall call; citations list every principle the
verdict leans on.
tradeoffs is empty unless verdict == "tradeoff".
no-match = no candidate applies; still emit with citations: [].
run_id is the substrate join-key; deterministic for the
invocation, present even on failed-status runs.
followup_hint is informational, not a contract — the caller
decides whether to follow up.
-
Update Evidence Trail (L1 autonomous write). For every principle
in citations, use the Edit tool on its .md file to:
a. Insert at the top of the ## Evidence Trail section (newest-first,
per CONSTITUTION.md §9) a line of the form:
- **YYYY-MM-DD** | citation-{relation} | {record_ref or session id} — verdict: {verdict}; {short one-line reason}
{relation} is one of aligned, violated, tradeoff.
b. Bump the frontmatter last_applied: field to today's ISO date.
Use a precise Edit: read the current value, then replace only that
specific line. Patterns to handle:
last_applied: null → last_applied: {today}
last_applied: {older-date} → last_applied: {today}
last_applied: {today} → no-op (already today's date; skip the
Edit to avoid spurious diffs and to keep the step idempotent)
Never use a non-unique match like last_applied: alone — the word
appears in other places. Always include the current value in the
old_string so the match is unambiguous, and if multiple citations
on the same principle fire in the same run, the second one is the
no-op case above.
Skip step 5 entirely when dry_run == true.
Never edit the body of the principle outside ## Evidence Trail
and outside the last_applied: frontmatter field. This is the L1
limit defined in 0_constitution/CONSTITUTION.md §8.
-
Emit telemetry (always — fires on every exit path, success or
failure). Append one JSON line to _system/state/check-decision-runs.jsonl
via the helper. Required arguments are --kind run, --run-id,
--status, --situation; everything else is optional and only
passed when available on the current code path.
python3 "$ZTN_BASE/_system/scripts/emit_telemetry.py" \
--kind run \
--run-id "$RUN_ID" \
--status "$STATUS" \
--working-dir "$PWD" \
--situation "$SITUATION" \
${TREE_SIZE:+--tree-size "$TREE_SIZE"} \
${IS_SENSITIVE:+--is-sensitive} \
${DRY_RUN:+--dry-run-flag} \
${DOMAINS:+--domains "$DOMAINS"} \
${RECORD_REF:+--record-ref "$RECORD_REF"} \
${VERDICT:+--verdict "$VERDICT"} \
${CITATIONS_JSON:+--citations "$CITATIONS_JSON"} \
${TRADEOFFS_JSON:+--tradeoffs "$TRADEOFFS_JSON"} \
${RATIONALE:+--rationale "$RATIONALE"} \
${INTENT:+--intent "$INTENT"} \
${PRE_CONFIDENCE:+--pre-confidence "$PRE_CONFIDENCE"} \
${EXPECTED_VERDICT:+--expected-verdict "$EXPECTED_VERDICT"} \
${PIPELINE:+--from-pipeline "$PIPELINE"}
The helper derives caller_class from presence/absence of
--from-pipeline (whitelist of mechanical pipelines: /ztn:process,
/ztn:lint, /ztn:maintain, /ztn:agent-lens, /ztn:bootstrap).
Caller never passes caller_class directly.
RUN_ID format: <run_at_ISO>-<uuid4[:8]> — generate at the very
start of the invocation (before Step 1), so failed-run telemetry
shares the same identifier shape as successful runs and the followup
contract works regardless of which step failed.
Failure-path ordering (load-bearing): if Step 1 / 2 / 5 fails,
the failure handler (a) still runs this Step 6 with --status set
to failed_regen / failed_query / failed_edit and whatever
contextual fields are available (always: run_id, status, situation,
working_dir; never: verdict, citations, rationale on early failures),
then (b) exits non-zero with the original stderr surfaced to the
user. Telemetry is the LAST action before exit on every code path.
The helper handles atomic append under flock, sensitive-redaction
(omits situation_text + rationale when --is-sensitive is passed,
keeps situation_hash + verdict labels), and per-class auto-commit
(judgmental only). Failures of the commit step degrade gracefully —
helper writes the JSONL line, prints a warning, exits 0.
Telemetry is opportunistic substrate: the lens consumes whatever
fields are present, treats missing optional fields as no-signal
rather than as errors. Schema is append-only; never mutate prior
lines, never aggregate or compact JSONL prematurely.
The skill must produce exactly this JSON (pretty-printed for the user
is OK so long as the structure is unambiguous). Extra fields should not
appear. Missing fields should not appear — use empty arrays / null.