The rule store
rules.jsonl is append-only; the latest record per rule id wins (so retiring or promoting a rule appends an updated record rather than rewriting history). Each rule carries:
| Field | Purpose |
|---|---|
id, created_at | Identity (r- + 10 hex chars) and provenance timestamp. |
rule, rationale | The constraint and why it exists — both sanitized on write. |
source_notice_id, metric | Provenance: which notice motivated it, which metric it targets. |
status | candidate → active | retired. See Rule validation. |
tags | Retrieval hooks — auto-derived from the source notice (signatures, metric names, signal names, severity) plus any explicit tags. An untagged rule is global: always injected. |
trial | Validation bookkeeping: baseline vs. observed breach rates, sessions watched, replay attempts, and the final verdict. |
add:
- Dedup — a rule whose normalized text matches a live rule returns the existing rule instead of creating a duplicate.
- Cap — at
max_active_rules(default 50, counted over active + candidate) the add fails with a message telling the agent to retire something first. Compaction is agent-driven; nothing is silently evicted. - Sanitization — rule text and rationale pass the trust boundary (
sanitize_text) before they can ever reach a prompt.
The rendered context
harness_rules.md is a projection, regenerated from the store on every change: the packaged template preamble (the self-healing contract and tool table), then the rules:
Task-conditioned retrieval
With more than a handful of rules, injecting all of them dilutes attention and lets a rule learned from one failure mode overfit onto unrelated tasks. Withrule_retrieval=true (the default), the context renders:
- Every global (untagged) rule — always, exempt from the budget.
- The top-
rules_context_topk(default 8) tagged rules ranked by lexical relevance to the current query: the pending notices’ signatures and metric names, plus an optional caller-supplied task hint:
- A one-line note when rules were trimmed, pointing at
harness_rules_search/harness_rules_list— the context stays small while every rule stays reachable.
breach:agent_reliability tokenizes to breach + agent_reliability, so signatures, metric names, and task words all match naturally.
Behavior at the edges:
- No signal (no pending notices, no hint) → everything renders; retrieval never hides rules without a reason.
- No overlap → ranking degrades to recency under the same top-k.
- Candidates never consume top-k slots — retrieval can’t starve a trial.
rule_retrieval=falserestores render-everything (the pre-v0.6 behavior).- The on-disk
harness_rules.mdis always the full render; retrieval only shapes the composed prompt.
Working with rules programmatically
harness_rules_list, harness_rules_search, harness_rule_retire, harness_rule_status, and harness_reflect — see the toolset.
