# weavatrix-refactor-plan
The protocol-independent, filesystem-independent contract for exact Weavatrix
refactor plans.
The dependency direction is deliberate:
```text
weavatrix-edit <- weavatrix-refactor-plan <- weavatrix-worktree
```
`weavatrix-edit` owns exact source edits. This crate owns the multi-operation
plan, evidence, validation, and fingerprint. `weavatrix-worktree` executes an
already validated plan transactionally. MCP, LSP clients, planners, sessions,
locks, confirmation tokens, journals, and rollback do not belong here.
## Contract
`RefactorPlan` uses schema `weavatrix.refactor-plan.v1` and supports:
- `Modify(FileEdit)`: exact text edits guarded by the whole-file SHA-256;
- `Create(CreateFile)`: exact UTF-8 contents at a path that must be absent;
- `Delete(DeleteFile)`: deletion guarded by the whole-file SHA-256;
- `Rename(RenameFile)`: an exact source hash, absent destination, and optional
exact edits against the original `from` source, applied before it is moved.
`TextEdit` coordinates are frozen as 1-based lines and 0-based UTF-16 code
units. This is part of v1 and is not negotiated from an LSP client.
The operations array is one simultaneous transition set, not a sequential
script. Rename chains and cycles snapshot each original input; an executor's
deterministic commit order must not expose intermediate array states. Array
order is still retained and fingerprinted for stable evidence and
`operationIndex` references.
Operations use Serde's adjacent `kind` / `value` wire shape. The value is not
an arbitrary payload: it is the typed contract for that operation.
```json
{
"schemaVersion": "weavatrix.refactor-plan.v1",
"operation": "move_and_generate",
"operations": [
{
"kind": "rename",
"value": {
"from": "src/old.rs",
"to": "src/new.rs",
"expectedSourceSha256": "0000000000000000000000000000000000000000000000000000000000000000"
}
},
{
"kind": "create",
"value": { "path": "src/generated.rs", "contents": "// generated\n" }
}
]
}
```
## Quick start
```rust
use weavatrix_refactor_plan::{
CreateFile, RefactorOperation, RefactorPlan, RefactorPlanLimits,
validate_executor_plan,
};
# fn main() -> Result<(), Box<dyn std::error::Error>> {
let plan = RefactorPlan::new(
"generate",
vec![RefactorOperation::Create(CreateFile::new(
"src/generated.rs",
"pub const GENERATED: bool = true;\n",
))],
);
let checked = validate_executor_plan(&plan, RefactorPlanLimits::default())?;
println!("{}", checked.fingerprint());
# Ok(())
# }
```
The minimal constructor is intentionally executable. Semantic completeness is
not a filesystem safety prerequisite: a reviewed `PARTIAL` plan can still
contain exact, safely applicable operations.
## Evidence and completeness
Evidence is typed in Rust and flattened at the top-level JSON object. Unknown
extension fields are preserved, bounded, validated for reserved-key collisions,
and included in the fingerprint.
`CompletenessProof` is machine-comparable rather than a free-form label:
- `EvidenceScope` has an open `kind`, a stable `value`, optional portable roots,
and languages;
- `PlannerIdentity` identifies planner name/version and backend, with an
optional backend version;
- `graphRevision` preserves missing, explicit `null`, and string states.
`UncertainReference` must identify a safe repository path (the legacy `file`
spelling is accepted) or a typed subject, and must include a kind or reason.
`NotModified` must identify a path, typed subject, or valid `operationIndex`,
and must include a reason. Portable aliases and duplicate evidence entries are
rejected.
There are three entry points:
- `validate_consumer_plan`: exact operations plus internal consistency of any
recognized evidence;
- `validate_executor_plan`: the same exact-operation safety contract, exposed
as an executor-specific validated wrapper;
- `validate_planner_plan`: a strict producer profile requiring completeness,
RFC 3339 `createdAt`, explicit `graphRevision`, typed proof, explicit evidence
arrays, and a follow-up.
Strict `PARTIAL` output needs at least one uncertainty or omission. Any explicit
`COMPLETE` claim needs a typed proof and cannot contain either.
## Safety and resource contract
Validation is pure; it does not open the repository. Before a plan can be
fingerprinted or handed to an executor it checks:
- schema, operation and operation-count bounds;
- repository-relative paths, `.git` and `.weavatrix` exclusion, Windows device
names, case/Windows suffix aliases, and Unicode NFC aliases;
- exact lowercase SHA-256 preconditions;
- duplicate input/output roles, unsafe cross-operation overlaps, rename aliases,
and per-file overlapping text ranges;
- edit counts/text, create bytes, distinct paths, evidence text/counts, and one
combined byte/node/depth budget for every extension map;
- reserved flattened keys at plan, operation, edit, proof, scope, planner,
uncertainty, omission, and subject levels.
Use `parse_refactor_plan` for untrusted JSON. It caps input before allocation,
limits recursion/value count, rejects duplicate object names recursively before
typed deserialization, and then runs normal validation. Generic JSON-to-map
parsing is not an equivalent security boundary because duplicate names have
already been collapsed.
## Fingerprint contract
`FINGERPRINT_ALGORITHM` is
`weavatrix.refactor-plan.jcs-sha256.v1`. The digest is:
```text
The implementation uses a crate-owned streaming RFC 8785 serializer (ECMAScript
number formatting via `ryu-js`), orders keys by UTF-16 code units, and streams
sorted top-level fields into SHA-256. The `operations` array is not
materialized as one canonical byte vector. It rejects negative zero and exact
integers outside `[-9007199254740991, 9007199254740991]` before JCS because
those inputs are not stable I-JSON values.
Only the top-level `createdAt` is excluded: it records when the same plan was
produced, not what it proves or executes. A nested field named `createdAt` is
ordinary extension evidence and remains fingerprinted. Every operation,
precondition, completeness claim, proof, warning, and unknown extension remains
inside the digest.
`canonical_plan_bytes` exists for diagnostics and golden tests. Production code
should retain the `PlanFingerprint` returned by a validated wrapper.
## Legacy text plans
The frozen `weavatrix.edit-plan.v1` types remain re-exported. Explicit,
lossless text-only helpers avoid confusing the two schemas:
- `RefactorPlan::from_text_edit_plan(EditPlan)` maps each file to `Modify` and
preserves completeness and every top-level extension;
- `try_into_text_edit_plan` succeeds only when every operation is `Modify`.
The lower-level crate is also available as `weavatrix_refactor_plan::weavatrix_edit`.
## Conformance evidence
- [`docs/schema/weavatrix.refactor-plan.profile.v1.schema.json`](docs/schema/weavatrix.refactor-plan.profile.v1.schema.json)
describes the strict producer profile and all four operation values.
- `tests/fixtures/refactor-plan-v1.jsonl` contains Node-generated canonical JCS
payloads and fingerprints checked by Rust.
- `tests/fixtures/generate-refactor-plan-v1.mjs` is the independent Node oracle.
- `tests/fixtures/refactor-plan-conformance.jsonl` binds raw JSON cases to the
runtime consumer/planner results.
- `tests/fixtures/js-v0.1.5-ownership.json` accounts for all 175 legacy
JavaScript tests without claiming that this crate owns planner, LSP, session,
MCP, or transaction behavior.
## Measured performance
Recorded on a frozen tree against the direct predecessor, npm
`weavatrix-refactor@0.1.5`, with `canonicalize@3.0.0` as the fingerprint oracle.
Correctness gates run before any timing: canonical JCS bytes and the
domain-separated digest must match the Node oracle exactly. Medians come from 30
samples per cell inside warmed persistent workers; the conservative column is
the JavaScript p25 divided by the Rust p75.
| Cached fingerprint lookup | 0.005 -> 0.000 µs | 11.19x | Equal semantics |
| End-to-end validate + fingerprint | 3570 -> 1092 µs | 2.44x | Rust validates strictly more |
| Legacy envelope validation | 370 -> 233 µs | 1.27x | Equal declared subset |
| Parse + legacy validation | 855 -> 1018 µs | 0.65x | Equal declared subset |
These numbers were recorded against `weavatrix-edit` 0.1.5. That dependency has
since replaced its derived envelope codecs with hand-written ones, which sits
inside the timed region of the two decode-bearing classes, so the table stands
until a publication rerun replaces it.
Parse plus validation is the one class where this crate is slower, and only at
the largest size. The cause is not the JSON decoder: measured fairly, under a
production profile, `blazingly-json` decodes faster than `serde_json` on every
realistic corpus
([evidence](https://github.com/sergii-ziborov/weavatrix-edit/blob/main/docs/decoder-comparison.md)).
The cost is that this class materializes an extension map per file and per edit
for members the workload never reads — skipping them decodes the same 500-file
plan roughly twice as fast — on top of path-alias canonicalization,
reserved-key scans, and size budgets that `JSON.parse` plus the npm validator
do not perform at all. So the row measures strictly more work.
Skipping those members is available upstream as `DeclaredEditPlan`, and this
crate deliberately does not use it. Plan annotations live in undeclared
members, and the crate's own evidence budget and reserved-key checks walk the
extension maps, so a declared-only decode here would be a validation bypass
rather than an optimization: an oversized annotation blob that is rejected
today would pass. `tests/declared_decode.rs` pins that, and
[`docs/benchmarks.md`](docs/benchmarks.md) records the decision.
The product route this crate exists for, validating a plan and binding it to a
canonical fingerprint, is 3.3x faster at that size and 2.4x on the conservative
gate.
A row states a "≥2.0x" claim only when its scope is declared equal and its
conservative ratio clears 2.0; stronger or mismatched scopes stay ineligible
regardless of ratio, and losing rows stay visible. This is not a universal
ranking. The harness, policy, and raw samples live in
[`tools/benchmarks`](tools/benchmarks) and [`docs/benchmarks.md`](docs/benchmarks.md).
## MSRV and license
Rust 1.88 or newer, edition 2024. MIT licensed.