M5b plan: task 14, the runbook entry sanitizer-rules
The last runbook entry, the rule-change procedure of spec 6.5; the entries memory-write-refused and memory-write-flagged now send the reader to it instead of to the spec. Tasks 06, 08 and 12 added the other five, because the gate needs an entry for every pointer. Checks: the edits, applied from the task's text to ref 13, give a runbook byte-identical to the reference; each before block found once; the gate passes on the reference with 1118 tests; /private/tmp unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
## sanitizer-rules
|
||||
|
||||
**What you see.** Not a failure: the procedure for changing a sanitizer rule, which the entries
|
||||
`memory-write-refused` and `memory-write-flagged` send you to when a rule catches ordinary text,
|
||||
or which you follow when an attack gets through. The rules are in `crates/bxcore/src/sanitize/`:
|
||||
`refuse.rs` (6.1 of the M5b spec), `tags.rs` (the chat-template tags that are neutralised, 6.2)
|
||||
and `flag.rs` with `normalise.rs` (6.3).
|
||||
|
||||
**Why.** The rules are compiled in rather than read from a file, so that every change passes the
|
||||
two corpora and review, and a typo cannot switch a rule off (M5b spec, section 6.5). A rule that
|
||||
refuses code is as much a bug as one that lets an attack through: the agent works on code
|
||||
projects, and a flagged note makes every session that recalls it untrusted.
|
||||
|
||||
**Confirm.** The evidence, before anything changes:
|
||||
|
||||
- a rule's name in `bxctl memory log` (`flagged <rule>`), in `memoryd`'s log, or in a refusal the
|
||||
agent passed on;
|
||||
- `bxctl sanitize check` with the text, which names each rule that fires and writes nothing;
|
||||
- a device check, a review or new research that shows an attack the rules miss.
|
||||
|
||||
**Fix.** In this order, one commit:
|
||||
|
||||
1. **The case first.** Add the text to a corpus, with a comment saying where it was seen: the
|
||||
attack corpus if it must be caught, the code-work corpus if it must pass. The corpora are the
|
||||
given tests `crates/bxcore/tests/sanitize_refuse_corpus.rs` (refuse),
|
||||
`sanitize_corpus.rs` (neutralise) and `sanitize_flag_corpus.rs` (flag). Build a tag or a key
|
||||
from pieces, as the files already do: never write one whole. Run `cargo test -p bxcore` and see
|
||||
the new case fail.
|
||||
2. **The rule.** Add or narrow the entry in the rule's table, with a comment naming its source.
|
||||
Keep it as narrow as the evidence: a flag rule ported from Hermes keeps its attribution.
|
||||
3. **The gate.** `make gate` runs both corpora for every action, so a rule that catches code
|
||||
fails before it lands.
|
||||
4. **The record.** A policy change (a new kind of refusal, or a rule moved from flag to refuse)
|
||||
gets a row in `docs/decisions.md`; an ordinary rule change is its commit.
|
||||
|
||||
A change reaches an agent when it is rebuilt and restarted. Stored memory is never rewritten: an
|
||||
identity entry that breaks a new refuse rule leaves the memory block at once (see
|
||||
`memory-entry-excluded`), and a note flagged under an old rule stays as it was written.
|
||||
|
||||
**Check.** `bxctl sanitize check` with the text gives the new answer (nothing, and exit 0, for a
|
||||
text that must pass). After the rebuild, the agent's next write of it is answered as expected.
|
||||
Reference in New Issue
Block a user