refactor: decouple rulespec from plan_write, read from analysis/rulespec.yaml

- Remove rulespec parameter from plan_write tool definition and execution
- Remove rulespec compilation from plan_approve (no longer pre-compiles)
- Remove write_rulespec, get_rulespec_path, format_rulespec_yaml/markdown
  from invariants.rs; read_rulespec() now takes &Path working dir
- Remove save/load_compiled_rulespec, get_compiled_rulespec_path from datalog.rs
- Update shadow_datalog_verify() to compile on-the-fly from
  analysis/rulespec.yaml, writing rulespec.compiled.dl and
  datalog_evaluation.txt to session dir
- Remove rulespec display from plan_read output
- Remove Invariants/Rulespec section from native.md system prompt
- Remove rulespec from prompts.rs plan_write format and examples
- Update existing tests to remove rulespec from plan_write calls
- Add 3 integration tests for on-the-fly rulespec verification
This commit is contained in:
Dhanji R. Prasanna
2026-02-06 15:31:23 +11:00
parent a93ce932a3
commit f7a240a99b
9 changed files with 290 additions and 397 deletions

View File

@@ -19,7 +19,7 @@ Plan Mode is a cognitive forcing system that prevents:
## Workflow
1. **Draft**: Call `plan_read` to check for existing plan, then `plan_write` with BOTH plan AND rulespec
1. **Draft**: Call `plan_read` to check for existing plan, then `plan_write` with the plan YAML
2. **Approval**: Ask user to approve before starting work ("'approve', or edit plan?"). In non-interactive mode (autonomous/one-shot), plans auto-approve on write.
3. **Execute**: Implement items, updating plan with `plan_write` to mark progress
4. **Complete**: When all items are done/blocked, verification runs automatically
@@ -44,47 +44,10 @@ When drafting a plan, you MUST:
- Keep items ~7 by default
- Commit to where the work will live (touches)
- Provide all three checks (happy, negative, boundary)
- **Include rulespec with invariants** (required for new plans)
When updating a plan:
- Cannot remove items from an approved plan (mark as blocked instead)
- Must provide evidence and notes when marking item as done
- Rulespec is optional for updates (already saved from initial creation)
## Invariants (Rulespec)
For all NEW plans, you MUST extract invariants and provide them as the `rulespec` argument to `plan_write`.
### What are Invariants?
Invariants are constraints that MUST or MUST NOT hold. Extract them from:
- **task_prompt**: What the user explicitly requires ("must support TSV", "must not break existing API")
- **memory**: Persistent rules from workspace memory ("must be Send + Sync", "must not block async runtime")
### Rulespec Structure
```yaml
claims:
- name: csv_capabilities
selector: "csv_importer.capabilities"
predicates:
- claim: csv_capabilities
rule: contains
value: "handle_tsv"
source: task_prompt
notes: "User explicitly requested TSV support"
```
### Predicate Rules
- `contains`: Array contains value, or string contains substring
- `equals`: Exact match
- `exists`: Value is present
- `not_exists`: Value is absent
- `min_length` / `max_length`: Array size constraints
- `greater_than` / `less_than`: Numeric comparisons
- `matches`: Regex pattern match
## Example Plan
@@ -108,17 +71,6 @@ plan_write(
- desc: Empty file yields empty import without error
target: import::csv
",
rulespec: "
claims:
- name: csv_capabilities
selector: csv_importer.capabilities
predicates:
- claim: csv_capabilities
rule: contains
value: handle_tsv
source: task_prompt
notes: User explicitly requested TSV support
"
)
```
@@ -126,7 +78,7 @@ When marking done, add `evidence` and `notes` to the item.
## Action Envelope
Before marking the last plan item done, write an `envelope.yaml` file with facts about completed work. The envelope captures what was actually built so it can be verified against the rulespec.
Before marking the last plan item done, write an `envelope.yaml` file with facts about completed work. The envelope captures what was actually built so it can be verified against invariants in `analysis/rulespec.yaml` if present.
```yaml
facts:
@@ -141,10 +93,10 @@ facts:
```
**Rules:**
- Selectors in rulespec (e.g., `csv_importer.capabilities`) are evaluated against envelope facts
- Selectors in `analysis/rulespec.yaml` (e.g., `csv_importer.capabilities`) are evaluated against envelope facts
- Use dot notation for nested access: `api_changes.breaking`
- Use `null` to explicitly assert absence (for `not_exists` predicates)
- The envelope is automatically verified against the rulespec when the plan completes
- The envelope is automatically verified against `analysis/rulespec.yaml` when the plan completes (if the file exists)
# Workspace Memory