# PROP-056 — Scraped project export and in-place VibeVM removal {#root}

@status:impl/done

[p01] @fact:STATUS-LINE This PROP defines and implements the deterministic
  operation that turns a VibeVM-managed consumer into a self-contained native
  project with no selected VibeVM repository residue. It freezes the contract,
  plan, typed rewrite, verification, export, in-place transaction, recovery and
  evidence semantics for epoch-1 Windows execution; portable planning remains
  available and other mutating hosts fail closed. @status:impl/done

## 1. Owner mandate and outcome {#mandate}

[p02] @fact:OWNER-MANDATE The owner requires a project that may
    be authored and maintained with VibeVM and then delivered without VibeVM
    repository artifacts: the `vibevm/` tree, project `.vibe/` state,
    `vibe.toml`, `vibe.lock`, discipline policy/index artifacts, managed
    harness blocks and source-level traceability metadata as selected by policy.
    The operation must preserve the native build. Ambiguity is expressed once in
    a project contract, after which inventory, rewriting, deletion, health
    checks, rollback and proof are algorithmic. @status:spec/done

[p03] @fact:OWNER-CONTRACT-RULING The default contract lives at
    `vibevm/scrape/contract.toml`, may be replaced by an explicit
    `--contract` path, and—when contained in the project and selected for
    removal—is the last project payload file removed. Standard Cargo, npm,
    Maven and Python/pip health checks are declarative; a snapshotted
    user-defined verifier is the escape hatch for domain checks. @status:spec/done

## 2. Relationship to existing laws {#related}

- [p04] @fact:RELATED-ALGORITHMIC-REFACTORING PROP-031 supplies
      the write-side law: typed operation, deterministic plan, no free-form LLM
      rewriting, and post-operation gating. Scrape is one composed refactoring
      over source, manifests, generated state and project topology. @status:spec/done
- @fact:RELATED-LAYOUT PROP-052 defines the
      `vibevm/` root. Scrape is the explicit terminal exception that removes
      that root from an exported consumer; it does not reintroduce the retired
      pre-PROP-052 Vibe layout. @status:spec/done
- @fact:RELATED-CLEAN PROP-053 `vibe clean` removes
      regenerable dependency and boot products while retaining authored project
      state and `vibe.lock`. Scrape is not clean: it removes the Vibe
      relationship itself and therefore requires a contract, native health
      proof and recoverable commit. @status:spec/done
- @fact:RELATED-LIFECYCLE PROP-054 supplies typed lifecycle
      planning, injected environment authority, artifact identity and durable
      transaction precedents. Scrape reuses those principles but has a distinct
      external journal because project `.vibe/` is removable. @status:spec/done
- @fact:RELATED-DISCIPLINES The Rust, TypeScript and Go
      AI-Native stacks remain authoring disciplines. Scrape removes their
      registered metadata and tool wiring; it never erases useful product code
      merely because a discipline helped create it. @status:spec/done

## 3. Problem, boundary and vocabulary {#problem}

[p05] @fact:SCRAPE-TERM-BOUNDARY Scrape
    is the terminal cleaning operation defined here: it removes the selected
    VibeVM repository layer while preserving the native product. The command
    vocabulary deliberately reserves attach and
    detach for a future live-tool relationship such as connecting
    and disconnecting a debugger. Scrape is never an alias for that future
    runtime operation, and no detach spelling is accepted by this command. @status:spec/done

[p06] @fact:SCRAPE-PROBLEM Blindly deleting Vibe paths is not
    safe. A Rust consumer may path-depend on the `specmark` proc macro inside
    `vibevm/vibedeps`; build scripts or CI may call `vibe bin`; generated
    product source may live beside disposable generated state; authored
    specifications may share a tree with generated boot output. A path name
    alone cannot decide disposition. @status:spec/done

- [p07] @fact:SCRAPED-TREE A scraped tree is a project
      tree for which every contract-selected Vibe path, dependency, managed
      marker, source annotation, tool script and environment reference is absent
      or explicitly retained under a neutral identity, and whose required
      native health panel is accepted after scraping under the declared strict
      or no-regression baseline policy. A retained non-pass verdict is never
      described as an unconditional pass. @status:spec/done
- @fact:PRODUCT-PRESERVATION Product preservation means:
      all untouched files are byte-identical; every authored source rewrite is
      metadata erasure-equivalent; every declared relocation preserves exact
      bytes and mode; native manifests and lockfiles describe the scraped
      dependency graph; the health oracle accepts the result. @status:spec/done
- @fact:ZERO-RESIDUAL-SCOPE Zero residue means zero
      registered Vibe identities, paths and markers selected by this contract.
      It does not mean deleting an ordinary word such as “vibe” from prose, nor
      undoing architectural choices learned while using a discipline. @status:spec/done
- @fact:ALGORITHMIC-BOUNDARY The owner supplies policy:
      delete, keep, relocate, strip, retain, required checks and acceptable
      baseline mode. The engine supplies all mechanics and verdicts. Any state
      not decidable from the sealed contract and observed tree is a blocker,
      never a guess or best-effort success. @status:spec/done

[p08] @fact:NON-GOALS Schema 1 does not reverse the historical
    influence of VibeVM on product architecture, infer replacements for arbitrary
    runtime libraries, mutate Git history, publish artifacts, or silently remove
    user-global deployments. Schema 1 does not discover, report or remove
    receipt-owned user-global deployments; the operator runs the existing
    explicit undeploy operation separately when external removal is
    desired. @status:spec/done

[p09] @fact:SCRAPE-EXECUTION-PLATFORM-E1 Epoch-1 contract
    parsing, planning and contract checking are portable. Mutating
    `--output`, `--in-place` and `--recover` execution is enabled only
    on Windows, where the implementation proves handle-relative exclusive
    directory creation, no-replace publication, write/delete-denying namespace
    seals and restartable cleanup. Linux, macOS and other hosts return the typed
      blocker `scrape-platform-unsupported` before journal creation or project
      mutation. Their wire/state-machine shape remains portable, but the product
      does not claim a weaker check-then-rename implementation as support. @status:spec/done

[p10] @fact:WINDOWS-NAMESPACE-DURABILITY-E1 Windows epoch 1
      does not claim POSIX directory fsync or a persistent-media namespace-flush
      guarantee that the public handle-relative rename/delete APIs do not provide.
      Every namespace change instead runs under an already-durable external WAL
      intent, uses the native held-source/expected-identity atomic primitive, is
      re-observed as exactly its sealed before or after state, and is replayed on
      recovery. This is reported as journal-recoverable namespace evidence, never
      as synced or write-through evidence. A verified Windows scrape therefore
      carries reduced assurance; a future strict media-durable profile remains
      unsupported until the platform supplies a compatible capability-relative
      primitive. Path-based `MoveFileEx` is not substituted because it would
      discard the no-follow/root-capability authority. @status:spec/done

## 4. Command surface {#surface}

- [p11] @fact:SCRAPE-PLAN-COMMAND `vibe scrape --plan
      [--contract <path>] [--output <dir> | --in-place]` is read-only.
      With neither execution mode, it plans the in-place form because that is the
      larger risk surface; it writes no project, journal, quarantine or report
      file. @status:impl/done
- @fact:SCRAPE-EXPORT-COMMAND `vibe scrape --output
      <absent-dir> [--contract <path>]` creates a scraped export and
      never changes the source tree. The destination must be absent; adoption of
      an existing directory is forbidden. @status:impl/done
- @fact:SCRAPE-INPLACE-COMMAND `vibe scrape --in-place
      [--contract <path>]` executes the journaled in-place transaction.
      Interactive use shows the exact modified-file and deletion census;
      unattended use requires `--assume-yes` after a green plan. @status:impl/done
- @fact:SCRAPE-RECOVER-COMMAND `vibe scrape --recover
      --path <project>` settles the one pending user-local transaction.
      Recovery reads the journaled contract and plan, never the possibly removed
      project contract. A new scrape refuses while recovery is pending. @status:impl/done
- @fact:SCRAPE-CONTRACT-COMMANDS `vibe scrape contract
      init` writes a conservative default contract only when absent;
      `vibe scrape contract check` parses and plans it read-only. Existing
      contracts are never silently refreshed by install or a language
      discipline. @status:impl/done
- @fact:SCRAPE-MODE-EXCLUSIVITY `--output` and
      `--in-place` are mutually exclusive. `--recover` accepts neither
      mode nor contract because the durable journal already fixes both. @status:spec/done

## 5. Contract discovery, schema and snapshot {#contract}

[p12] @fact:DEFAULT-CONTRACT The default is the project-root
    literal `vibevm/scrape/contract.toml`. Every operand inside it is
    project-root-relative regardless of where an alternate contract lives.
    Contract location never changes mutation authority. @status:spec/done

- [p13] @fact:ALTERNATE-CONTRACT An explicit
      `--contract` may name a portable project-relative literal or an
      explicit absolute regular file. A contained contract may be removed under
      the contract-last law. An external contract is read-only and can never be
      deleted or make any external path writable. Absolute selection walks and
      pins every parent no-follow; contained/external identity is decided by
      capability ancestry, never lexical prefix. @status:spec/done
- @fact:CONTRACT-STRICTNESS The TOML schema rejects unknown
      tables, fields, tagged kinds and enum values. `schema` must equal 1;
      every id is a unique portable token across classification, rewrite,
      relocation, assertion and health rows. @status:spec/done
- @fact:CONTRACT-READ-SAFETY The contract is opened
      no-follow as a regular single-link file, size-bounded to 1 MiB and read
      stably through one held handle. A symlink, reparse point, hard link,
      special file, identity change or second-pass mismatch refuses. @status:spec/done
- @fact:CONTRACT-SNAPSHOT Before the first mutation the
      engine durably stores exact contract bytes, digest, canonical parsed value,
      expanded inventory, prepared rewrite outputs, verifier snapshots and plan
      hash in the user-local transaction. Recovery never rereads or reparses the
      source contract. @status:spec/done
- @fact:CONTRACT-LAST For a contained contract,
      `commit.contract = "delete-last"` reserves it from every earlier
      wildcard batch. It is the last project payload file moved to quarantine;
      only deterministic pruning of now-empty ancestor directories follows.
      An external contract requires `commit.contract = "preserve"`. @status:spec/done
- @fact:CONTRACT-LAST-VALIDATION A contained
      delete-last contract must resolve to exactly one regular effective-delete
      file. It cannot be effectively kept/generated, a rewrite target, relocation
      source/destination, baseline target or ordinary deletion entry. Broad
      patterns may select it only because the engine reserves its exact identity
      into the last slot before classification ordering. Any overlap that would
      produce another disposition refuses. @status:spec/done

[p14] @fact:CONTRACT-EXAMPLE-LEAD Schema-1 example for a mixed
    Rust/TypeScript/Go consumer: @status:spec/done

[p15]
```toml
schema = 1
id = "org.example.scraped-release"

[policy]
unclassified = "refuse"
links = "refuse"
concurrent_change = "refuse"

[scope]
closed_roots = ["vibevm", ".vibe"]
outside = "implicit-keep"

[commit]
contract = "delete-last"

[[classify]]
id = "remove-vibevm-tree"
kind = "delete"
patterns = ["vibevm", "vibevm/**"]
owner = "vibe"
proof = "contract-assertion-v1"
modified = "delete"
require_match = true

[[classify]]
id = "remove-project-vibe-state"
kind = "delete"
patterns = [".vibe", ".vibe/**", "vibe.toml", "vibe.lock"]
owner = "vibe"
proof = "contract-assertion-v1"
modified = "delete"
require_match = false

[[classify]]
id = "remove-discipline-state"
kind = "delete"
patterns = [
  "conform.toml",
  "specmap.toml",
  "specmap.json",
  "*-ai-native-conform-baseline.json",
  "discipline/**",
]
owner = "vibe"
proof = "contract-assertion-v1"
modified = "delete"
require_match = false

[[classify]]
id = "keep-harness-docs"
kind = "keep"
patterns = ["AGENTS.md", "CLAUDE.md", "GEMINI.md"]
owner = "project"
require_match = false

[[rewrite]]
id = "remove-harness-blocks"
kind = "managed-block-remove-v1"
paths = ["AGENTS.md", "CLAUDE.md", "GEMINI.md"]
marker = "vibevm"
matches = "zero-or-one-per-file"

[[rewrite]]
id = "strip-rust-specmark"
kind = "rust-specmark-strip-v1"
patterns = ["**/*.rs"]
exclude = [".git/**", "vibevm/**", ".vibe/**", "target/**"]
forms = ["scope", "spec", "verifies", "cell"]
matches = "zero-or-more"

[[rewrite]]
id = "remove-rust-specmark-dependency"
kind = "cargo-package-remove-v1"
manifests = ["Cargo.toml", "crates/*/Cargo.toml"]
package = "core-ai-native-specmark"
aliases = ["specmark"]
matches = "zero-or-more"

[[rewrite]]
id = "remove-vibe-workspace-excludes"
kind = "toml-array-values-remove-v1"
path = "Cargo.toml"
table = ["workspace"]
key = "exclude"
values = ["vibevm", "vibevm/vibedeps"]
matches = "zero-or-more"

[[rewrite]]
id = "strip-typescript-spec-tags"
kind = "typescript-spec-comments-strip-v1"
patterns = ["src/**/*.ts", "src/**/*.tsx"]
matches = "zero-or-more"

[[rewrite]]
id = "strip-go-spec-directives"
kind = "go-spec-directives-strip-v1"
patterns = ["**/*.go"]
exclude = [".git/**", "vibevm/**", ".vibe/**"]
matches = "zero-or-more"

[[assert]]
id = "vibe-paths-absent"
kind = "paths-absent-v1"
patterns = ["vibevm", "vibevm/**", ".vibe", ".vibe/**", "vibe.toml", "vibe.lock"]

[[assert]]
id = "vibe-cargo-paths-absent"
kind = "cargo-path-prefix-absent-v1"
manifests = ["Cargo.toml", "crates/*/Cargo.toml"]
prefixes = ["vibevm/", ".vibe/"]

[health]
baseline = "strict"
before_failure = "refuse"
after_failure = "rollback"
parallel = false
network = "tool-offline"
max_stdout_bytes = 1048576
max_stderr_bytes = 1048576
max_result_bytes = 1048576
termination_grace_seconds = 5

[[healthcheck]]
id = "rust"
kind = "cargo"
root = "."
build = "build"
workspace = true
locked = true
all_targets = true
tests = "required"
profile = "dev"
features = []
timeout_seconds = 900

[[healthcheck]]
id = "web"
kind = "npm"
root = "web"
manager = "npm"
lockfile = "package-lock.json"
install = "none"
build_script = "build"
tests = "required"
test_script = "test"
timeout_seconds = 900
when = { path_exists = "package.json" }

[[healthcheck]]
id = "domain-health"
kind = "custom"
root = "."
source = "vibevm/scrape/health/domain_health.py"
snapshot = [
  "vibevm/scrape/health/domain_health.py",
  "vibevm/scrape/health/lib/**",
]
interpreter = "python"
argv = ["--phase", "{phase}", "--result", "{result}"]
protocol = "vibe-health-json-v1"
network = "deny"
reads = ["**"]
writes = []
spawn = true
timeout_seconds = 120
```

### 5.1 Closed schema-1 shape {#schema-shape}

[p16] @fact:SCHEMA-TOP-LEVEL Required singleton tables are
      `policy`, `scope`, `commit` and `health`.
      Required scalars are `schema = 1` and one nonempty portable
      `id`. The repeated tables are `classify`,
      `baseline`, `rewrite`, `relocate`,
      `assert` and `healthcheck`. At least one classify, one
      assertion and one required after healthcheck must exist. Every omitted
      optional collection is empty; there are no open extension tables. @status:spec/done

- [p17] @fact:SCHEMA-POLICY `policy` requires
        `unclassified = "refuse"`, `links = "refuse"` and
        `concurrent_change = "refuse"`; schema 1 admits no other values.
        `scope` requires a nonempty set of portable literal
        `closed_roots` and `outside = "implicit-keep"`.
        Missing closed roots are observations, and are errors only when a
        covering classify row requires a match. @status:spec/done
- @fact:SCHEMA-COMMIT `commit.contract` is
        `delete-last` for a contained contract and `preserve` for
        an external contract. The contained/external observation selects which
        value is legal; the contract cannot weaken it. @status:spec/done
- @fact:SCHEMA-WHEN Schema-1
        `when` is an optional deny-unknown table containing exactly one
        required portable literal `path_exists`, resolved below that
        check's root. No environment, command or OS predicate is inferred here;
        the future common applicability feature may replace this shape only by
        an explicit schema epoch. @status:spec/done

[p18] @fact:SCHEMA-CLASSIFY Every
      `[[classify]]` requires `id`, a nonempty canonical set of
      `patterns`, `kind`, `owner` and
      `require_match`. Keep requires
      `owner = "project"` and forbids `proof`/
      `modified`. Delete/generated require
      `owner = "vibe"`, proof and modified policy. Proof is exactly
      `contract-assertion-v1 | sha256-v1 | vibe-generated-v1`;
      modified is exactly `refuse | keep | delete`. Variant-inapplicable
      fields are rejected. @status:spec/done

[p19] @fact:SCHEMA-BASELINE Each
      `[[baseline]]` has one portable literal `path` and one
      lowercase `sha256:<64-hex>`. Paths are globally unique.
      Exactly one baseline is required for each regular file selected by a
      `sha256-v1` rule; a baseline selected by no such rule is an error. @status:spec/done

[p20] @fact:SCHEMA-MATCH-CARDINALITY Every rewrite requires
      one `matches` enum. Set-level adapters admit exactly
      `zero-or-more | one-or-more | exactly-one`. Per-file adapters admit
      exactly `zero-or-one-per-file | exactly-one-per-file`. A kind's row
      below fixes which family it uses; integer/free-text cardinalities are
      rejected. @status:spec/done

[p21]
| Rewrite kind | Required variant fields |
| --- | --- |
| @fact:SCHEMA-RW-MANAGED `managed-block-remove-v1` @status:spec/done | @fact:SCHEMA-RW-MANAGED-FIELDS Literal `paths`, registered `marker`, and `matches = zero-or-one-per-file or exactly-one-per-file`. @status:spec/done |
| @fact:SCHEMA-RW-RUST `rust-specmark-strip-v1` @status:spec/done | @fact:SCHEMA-RW-RUST-FIELDS Nonempty `patterns`, optional `exclude`, nonempty unique `forms` drawn from scope/spec/verifies/cell, and `matches = zero-or-more or one-or-more`. @status:spec/done |
| @fact:SCHEMA-RW-CARGO `cargo-package-remove-v1` @status:spec/done | @fact:SCHEMA-RW-CARGO-FIELDS Manifest patterns, exact Cargo `package`, optional alias allowlist and set-level `matches`. Observed aliases outside a nonempty allowlist refuse rather than disappear. @status:spec/done |
| @fact:SCHEMA-RW-NODE `node-package-remove-v1` @status:spec/done | @fact:SCHEMA-RW-NODE-FIELDS Required literal `package_json` and `lockfile`, selected `manager = npm or pnpm or yarn`, nonempty `packages` array, optional arrays of component-array `script_paths` and `config_paths`, plus set-level `matches`. @status:spec/done |
| @fact:SCHEMA-RW-GOMOD `go-module-remove-v1` @status:spec/done | @fact:SCHEMA-RW-GOMOD-FIELDS Required literal `go_mod`, optional literal `go_sum`, nonempty exact `modules` array and set-level `matches`. Replace/exclude/tool directives are part of the same parsed graph. @status:spec/done |
| @fact:SCHEMA-RW-TOML `toml-array-values-remove-v1` @status:spec/done | @fact:SCHEMA-RW-TOML-FIELDS One literal `path`, component-array `table`, scalar `key`, nonempty exact `values` and match cardinality. @status:spec/done |
| @fact:SCHEMA-RW-LANGUAGE `typescript-spec-comments-strip-v1` / `go-spec-directives-strip-v1` @status:spec/done | @fact:SCHEMA-RW-LANGUAGE-FIELDS Nonempty `patterns`, optional `exclude` and match cardinality; the registered grammar is adapter-owned, not contract-provided. @status:spec/done |
| @fact:SCHEMA-RW-JSON `json-member-remove-v1` @status:spec/done | @fact:SCHEMA-RW-JSON-FIELDS One literal `path`, component-array `object`, exact member names and match cardinality. @status:spec/done |
| @fact:SCHEMA-RW-TEXT `text-exact-replace-v1` @status:spec/done | @fact:SCHEMA-RW-TEXT-FIELDS One literal `path`, required complete-file `sha256`, UTF-8 `before`/`after` literals and positive exact `occurrences`. @status:spec/done |

[p22] @fact:SCHEMA-LOCK-CONSEQUENCE Cargo, Node and Go native
      lock changes are derived consequences of explicit package/module removal
      rows, never independent inferred authority. Each adapter records the
      selected manager and exact graph delta. A graph change with no authorizing
      rewrite row refuses. @status:spec/done

[p23] @fact:SCHEMA-RELOCATE-ASSERT Every relocation requires
      `id`, literal `from`/`to`,
      `conflict = "refuse"` and boolean `required`. Assertion kinds
      are closed: `paths-absent-v1` requires patterns;
      `text-literal-absent-v1` requires path patterns plus literal
      needles; `cargo-path-prefix-absent-v1` requires manifest patterns
      plus prefixes; `language-metadata-absent-v1` requires language plus
      source patterns; `dependency-identities-absent-v1` requires manager,
      manifest and identities. @status:spec/done

[p24] @fact:SCHEMA-HEALTH-COMMON `health` requires
      baseline, before/after failure policy, parallel flag, network policy,
      positive stdout/stderr/result caps and a positive
      `termination_grace_seconds`. These limits are authored explicitly in
      schema 1—there are no hidden process or protocol defaults. Schema 1 admits only
      `before_failure = "refuse"`,
      `after_failure = "rollback"` and `parallel = false`; these
      fields are explicit evidence, not open strategy extension points. Every
      `[[healthcheck]]` requires
      unique id, kind, literal root, positive timeout, optional strict
      `when` and optional per-check network override; health root alone may
      use the special literal `.`. Cargo requires
      `build = check | build`, booleans workspace/locked/all_targets,
      `profile = dev | release`, a possibly empty feature array and tests
      mode. npm requires manager, literal lockfile,
      `install = none | ci`, tests mode, and exactly one nonempty
      build_script or typecheck_script; test_script is required unless tests is
      skip. Maven requires `runner = wrapper-first | explicit`, goal,
      offline boolean and tests mode. Python requires interpreter, nonempty
      source_roots, dependency_check/build booleans and tests mode; test_runner
      is required unless tests is skip. Fields not named for a variant are
      forbidden. @status:spec/done

[p25] @fact:SCHEMA-HEALTH-CUSTOM Custom health requires
      source, nonempty snapshot patterns containing that source, explicit
      interpreter, argv, protocol, read/write patterns, spawn boolean and network
      policy. JSON protocol requires the complete `{result}` placeholder
      exactly once. Result and scratch paths are implicit transaction-owned
      writes and MUST NOT be repeated in `writes`. Exit-code protocol
      forbids `{result}`; optional diagnostics must live below
      `{scratch}`. @status:spec/done

[p26] @fact:SCHEMA-JTD-WIRES The normative machine shape is
      encoded as strict JTD wire schemas for
      `scrape_plan/e1`, `scrape_report/e1` and
      `scrape_health_result/e1` in the first implementation atom. Those
      schemas must reproduce this section's required/optional/forbidden sets and
      closed enums exactly; generated types are the sole JSON reader/writer and
      handwritten shadow DTOs are forbidden. @status:spec/done

## 6. Path, glob, inventory and classification law {#paths}

[p27] @fact:PATH-ROOTING Every mutation operand is resolved
    from the pinned project root. No contract field can name an absolute
    mutation path, parent traversal, drive, UNC path, URL or device. The explicit
    alternate contract source is the sole read-only external-path exception. @status:spec/done

- [p28] @fact:GLOB-GRAMMAR Schema 1 owns one glob grammar:
      `*` means zero or more non-separator characters within one component;
      `**` means zero or more complete components and is legal only as a
      whole component. `?`, character classes, braces, negation, escapes,
      `***`, embedded `**`, backslashes, colons, empty components and
      dot components are rejected. @status:spec/done
- @fact:NO-AMBIENT-GLOB The filesystem and shell never
      expand a pattern. The engine enumerates no-follow logical paths, renders
      forward slashes, matches case-sensitively, byte-sorts and deduplicates.
      Authored pattern order has no semantic effect. @status:spec/done
- @fact:INVENTORY-CLOSED Every entry beneath a selected
      deletion/classification root is inventoried. Any walk error, non-UTF-8
      name, unsafe component, link/reparse point, special file or changed
      identity is a failure rather than absence. Schema 1 requires
      `policy.unclassified = "refuse"`. @status:spec/done
- @fact:CLASSIFICATION-UNIVERSE The engine enumerates the
      whole pinned project for pattern matching and residual proof, excluding
      only `.git/` internals and externally owned transaction state.
      Every existing entry at or below a literal `scope.closed_roots`
      member must be explicitly classified; an unmatched entry there refuses.
      Outside closed roots, unmatched paths are implicit project-owned keep.
      Explicit classify/rewrite/assert patterns may still select them. Rewrite
      targets are effectively kept unless an explicit classification conflict
      says otherwise. @status:spec/done
- @fact:NO-RECURSIVE-BLIND-DELETE Project-selected trees
      are never passed to an ambient recursive delete. Files are classified and
      quarantined individually; directories are removed only when independently
      observed empty, deepest first. A kept descendant prevents ancestor
      deletion. @status:spec/done
- @fact:GIT-METADATA-PROTECTED `.git` and every
      descendant are non-addressable mutation paths in schema 1. A classify,
      rewrite, relocation, baseline, health-write or assertion operand that can
      effectively match them after include-minus-exclude evaluation refuses.
      Every broad source selector must therefore exclude `.git/**`;
      exclusion from inventory alone is never permission or a silent no-op. @status:spec/done
- @fact:CLASSIFICATION-LATTICE Classification uses a fixed
      lattice, not first-match order: keep plus generated is invalid; keep
      explicitly shields delete; generated proof dominates an overlapping delete;
      same-kind overlap is allowed only when owner, proof and modified policy are
      identical. Every path receives one effective disposition. @status:spec/done

### 6.1 Ownership and modification {#ownership}

[p29] @fact:FILE-CLASSES The plan classifies observations as
      `generated-owned`, `managed-region`,
      `authored-metadata`, `authored-product` or
      `unknown`. Path spelling alone never proves a class. @status:spec/done

- [p30] @fact:OWNERSHIP-PROOFS Vibe ownership is proven by a
        matching receipt/artifact record, an exact registered generated marker
        plus recorded digest, a contract SHA-256 baseline, or explicit
        `contract-assertion-v1`. A failed ownership proof always refuses;
        `modified = "delete"` cannot waive absent ownership. @status:spec/done
- @fact:MODIFIED-POLICY Modification policies are
        `refuse`, `keep` and `delete`. Refuse is the default.
        Keep reclassifies the path and updates ancestor disposition. Delete
        quarantines the modified bytes but must appear separately in human
        confirmation and JSON evidence. @status:spec/done
- @fact:MODIFICATION-STATE Observed modification is
        exactly `unmodified | modified | unknown | not-applicable`.
        SHA-256 proof compares the contract baseline; generated proof obtains
        its expected digest from the exact receipt/artifact record or registered
        generated transaction that names the path. Contract assertion has no
        baseline and therefore yields unknown. Refuse rejects modified and
        unknown; keep preserves either; delete accepts either only as the
        owner's explicit lossy disposition. Not-applicable belongs only to keep. @status:spec/done
- @fact:AUTHORED-SPECS Authored files under
        `vibevm/vibespecs` are not generated merely because of their
        directory. A full zero-residue contract must explicitly delete them or
        relocate them to a neutral home. No built-in policy silently decides
        their value. @status:spec/done
- @fact:PRODUCT-CODE-SURVIVES Generated cells, seams,
        tests, models and other useful application source are authored product
        once accepted into the project. They remain unless an exact contract
        relocation or deletion row names them. Origin in a discipline is not
        deletion authority. @status:spec/done

### 6.2 Relocation {#relocation}

[p31] @fact:RELOCATION-CONTRACT A
      `[[relocate]]` row names one exact source and one exact destination;
      schema 1 admits no relocation glob. Source descendants must be effectively
      kept, destination must be outside every deletion root, all relocations are
      nonoverlapping and acyclic, and `conflict = "refuse"` is the only
      collision policy. @status:spec/done

[p32] @fact:RELOCATION-PHYSICS In-place relocation is a
      capability-relative same-filesystem rename with journaled parent creation.
      Cross-filesystem copy-and-delete is not an implicit fallback. Export mode
      stages the corresponding byte/mode-identical copy inside its new
      destination tree. @status:spec/done

## 7. Typed rewrite algebra {#rewrites}

[p33] @fact:TYPED-ONLY Globs select candidates; they never
    rewrite bytes. Authored source and structural manifests are changed only by a
    closed typed adapter. Generic regex replacement, shell rewrite hooks,
    implicit format conversion and whole-document reserialization are
    forbidden. @status:spec/done

[p34] @fact:REWRITE-PRECONDITION Every planned rewrite records
    adapter epoch, parsed node identity, original byte span, complete before
    digest, prepared after bytes/digest, expected match cardinality and reason.
    Apply accepts only the journaled before state; recovery accepts only exact
    before or exact after. A third state is concurrent mutation and refuses. @status:spec/done

[p35]
| Schema-1 kind | Exact responsibility |
| --- | --- |
| @fact:REWRITE-MANAGED-KIND `managed-block-remove-v1` @status:spec/done | @fact:REWRITE-MANAGED-RESP Remove one registered, whole-line, correctly paired managed block while preserving every surrounding byte except deterministic adjacent-newline repair. @status:spec/done |
| @fact:REWRITE-RUST-KIND `rust-specmark-strip-v1` @status:spec/done | @fact:REWRITE-RUST-RESP Remove proven Specmark scope macros, attributes and now-unused import leaves through the Rust syntax tree; preserve attributed product items. @status:spec/done |
| @fact:REWRITE-CARGO-KIND `cargo-package-remove-v1` @status:spec/done | @fact:REWRITE-CARGO-RESP Remove resolved package identities/aliases from every dependency table, workspace inheritance, target table, feature edge, patch and replace entry after proving no remaining use. @status:spec/done |
| @fact:REWRITE-TOML-KIND `toml-array-values-remove-v1` @status:spec/done | @fact:REWRITE-TOML-RESP Use a formatting-preserving TOML editor to remove exact scalar array members at a typed table/key path and exact cardinality. @status:spec/done |
| @fact:REWRITE-TS-KIND `typescript-spec-comments-strip-v1` @status:spec/done | @fact:REWRITE-TS-RESP Remove only registered, grammar-valid discipline JSDoc tag nodes; retain descriptions and unrelated tags. @status:spec/done |
| @fact:REWRITE-GO-KIND `go-spec-directives-strip-v1` @status:spec/done | @fact:REWRITE-GO-RESP Remove grammar-valid `//spec:` directive lines from parsed Go comment groups without touching strings, block prose, `//go:` or build/lint directives. @status:spec/done |
| @fact:REWRITE-JSON-KIND `json-member-remove-v1` @status:spec/done | @fact:REWRITE-JSON-RESP Remove exact registered dependency/script/config members through a strict JSON object path and formatting-preserving emitter. @status:spec/done |
| @fact:REWRITE-NODE-PACKAGE-KIND `node-package-remove-v1` @status:spec/done | @fact:REWRITE-NODE-PACKAGE-RESP Remove explicit Node package/script/config identities and reconcile exactly one selected native lock manager as a derived graph operation. @status:spec/done |
| @fact:REWRITE-GO-MODULE-KIND `go-module-remove-v1` @status:spec/done | @fact:REWRITE-GO-MODULE-RESP Remove explicit Go module/tool identities and reconcile go.mod/go.sum without changing an unrelated module edge. @status:spec/done |
| @fact:REWRITE-EXACT-TEXT-KIND `text-exact-replace-v1` @status:spec/done | @fact:REWRITE-EXACT-TEXT-RESP Escape hatch for an unsupported textual format: one literal file, required complete-file SHA-256, literal before/after text and exact occurrence count. No regex, capture, encoding guess or glob target. @status:spec/done |

### 7.1 Rust and Specmark {#rust}

- [p36] @fact:RUST-ALIAS-RESOLUTION The adapter derives every
        local dependency name whose Cargo package identity is
        `core-ai-native-specmark`; it never assumes the alias is
        `specmark`. Qualified paths and explicit imports are resolved.
        Glob imports, macro re-exports, shadowed aliases or ambiguous identity
        refuse before mutation. @status:spec/done
- @fact:RUST-ERASURE A valid
        `scope!` expands to no product tokens; `spec`,
        `verifies` and `cell` preserve the item and add metadata/
        rustdoc only. The after AST with registered metadata erased must equal
        the before AST under the same erasure. Invalid pre-scrape macro grammar
        refuses rather than becoming a newly compiling program. @status:spec/done
- @fact:RUST-CARGO-COVERAGE Cargo removal covers normal,
        dev, build, target-specific and workspace dependency tables; member
        `workspace = true`; `dep:<alias>` and
        alias-feature references; patch and replace tables; examples, benches
        and build scripts. A dependency is removed only after the residual
        resolver proves no use. @status:spec/done
- @fact:RUST-LOCK `vibe.lock` is removable Vibe
        state; `Cargo.lock` is native project state. If Cargo.lock existed,
        a typed lock-reconciliation step runs after manifest rewriting and a
        final `--locked` check must pass. A previously lockless library
        stays lockless unless the contract explicitly requests creation. @status:spec/done
- @fact:RUST-RETAIN-MODE Schema 1 has no verified
        retain-annotations mode: a remaining registered Specmark macro, package
        identity or source reference is residue and refuses scrape. A future
        neutralization adapter would have to relocate a complete self-contained
        macro toolchain, change its registered identity/content and repoint every
        Cargo edge. Merely moving the shipped proc-macro—or copying it without
        its grammar/workspace dependencies—is not neutral scraping. @status:spec/done

### 7.2 TypeScript and Go {#typescript-go}

[p37] @fact:TYPESCRIPT-SCRAPE TypeScript metadata is parsed
      as JSDoc attached to AST nodes. In a mixed comment only registered tags
      whose payload parses under the discipline grammar leave; description,
      unrelated tags, indentation, order and line-ending style remain. Matching
      text in strings, templates, regexes, Markdown or ordinary comments is not
      a candidate. npm/pnpm/Yarn manifest and lock changes occur only under an
      explicit `node-package-remove-v1` row and are its derived graph
      consequence; ambiguous simultaneous managers or unrequested graph changes
      refuse. @status:spec/done

[p38] @fact:GO-SCRAPE Go metadata is parsed with
      `go/parser` and `go/token`. Only complete registered
      `//spec:` directive lines leave their comment group. Product prose,
      strings/raw strings, block comments, generated headers,
      `//go:`, build constraints and lint directives remain. Native
      `go.mod`/`go.sum` reconciliation removes only dependencies
      made unreachable by an explicit `go-module-remove-v1` row. A module
      graph delta without that authority refuses. @status:spec/done

### 7.3 Managed blocks {#managed}

[p39] @fact:MANAGED-BLOCK-SAFETY A managed block is removed
      only when exact registered begin/end markers form the expected number of
      nonoverlapping, correctly ordered pairs owned by the scraping provider.
      Missing ends, orphan ends, duplicate ids, illegal nesting, string-embedded
      pseudo-markers or digest drift refuse. Structural formats use their parser,
      never comment-like marker removal. @status:spec/done

## 8. Verification and user-defined health {#health}

[p40] @fact:HEALTH-IS-ORACLE Verification is part of the
    contract, not an informal script run after deletion. The engine
    deterministically resolves, snapshots, invokes and judges the declared
    oracle. It proves exactly that the declared oracle accepted; it cannot infer
    that an incomplete user oracle covers every product requirement. @status:spec/done

- [p41] @fact:HEALTH-BEFORE-AFTER The same canonical ordered
      health plan runs before and after. Strict baseline requires every check to
      pass; no-regression requires an admissible structured before verdict and
      its subset/severity relation after. A non-admissible before state causes no
      project mutation; an unacceptable after state rolls in-place work back.
      Executable, arguments, verifier snapshot, environment identity and policies
      are phase-identical except journaled phase/root/scratch values. @status:spec/done
- @fact:HEALTH-TESTS-MODE Each preset declares
      `tests = "skip" | "if-present" | "required"`. Required with no
      discoverable test target is a preflight failure. If-present records a
      typed skip, never pass. Skip is allowed but the final report labels
      verification reduced. @status:spec/done
- @fact:HEALTH-NO-RETRY No check retries by default.
      Timeout, cancellation, process-tree loss, unavailable executable,
      malformed protocol, undeclared effect or nonzero exit is an execution
      failure and never baselineable. A valid structured result written by an
      exit-0 custom verifier may carry a health-fail verdict; that is evidence
      eligible for explicit no-regression comparison, not an execution
      failure. @status:spec/done

### 8.1 Built-in presets {#presets}

[p42]
| Kind | Build/dependency checks | Tests |
| --- | --- | --- |
| @fact:HEALTH-CARGO-KIND `cargo` @status:spec/done | @fact:HEALTH-CARGO-BUILD Resolve one Cargo executable and run `check` or `build` with declared workspace, all-targets, features, profile, locked and offline flags. `CARGO_TARGET_DIR` is phase scratch. @status:spec/done | @fact:HEALTH-CARGO-TEST Run `cargo test` with the same graph selectors when not skipped. @status:spec/done |
| @fact:HEALTH-NPM-KIND `npm` @status:spec/done | @fact:HEALTH-NPM-BUILD Validate `package.json`/selected lock, optionally run explicit `ci`, then require the declared build or typecheck script. Missing build is not pass. Windows invokes the resolved Node plus npm-cli asset rather than reparsing through npm.cmd. @status:spec/done | @fact:HEALTH-NPM-TEST Run the exact declared test script; never use a silent `--if-present` shortcut for required tests. @status:spec/done |
| @fact:HEALTH-MAVEN-KIND `maven` @status:spec/done | @fact:HEALTH-MAVEN-BUILD Resolve Maven wrapper metadata or an explicit Maven installation, record Java/launcher identity, and run batch/no-transfer-progress offline `verify`. Module target writes are phase-owned. @status:spec/done | @fact:HEALTH-MAVEN-TEST Required/if-present runs normal verify tests; skip adds the adapter's exact `-DskipTests` policy and reports reduction. @status:spec/done |
| @fact:HEALTH-PYTHON-KIND `python-pip` @status:spec/done | @fact:HEALTH-PYTHON-BUILD Use an explicit interpreter/environment; run `python -m pip check` and compile selected files without importing project modules. A package-shaped project carrying `pyproject.toml`, `setup.cfg` or legacy `setup.py` must also run offline `python -m build --no-isolation` for full assurance; explicitly omitting it forces `assurance = "reduced"`. Bytecode/build output is phase scratch. @status:spec/done | @fact:HEALTH-PYTHON-TEST Run the declared test runner, initially pytest. Required with no runner is failure. @status:spec/done |

[p43] @fact:PRESET-NO-INSTALL-BY-DEFAULT Presets use already
      available dependencies by default. Network access and dependency
      installation require explicit contract choices. Missing offline inputs are
      failures with a recipe, never permission to fetch silently. @status:spec/done

### 8.2 Custom verifier {#custom}

[p44] @fact:CUSTOM-VERIFIER-SOURCE A custom verifier names a
      root-contained regular source/native executable, explicit interpreter and
      structured outer argv. The engine never adds an implicit shell or accepts
      an inline shell command string, implicit shebang choice or interpolated
      argv. Explicit Python, Node, Bash, PowerShell or direct-native interpreters
      are allowed because the snapshotted script is the owner's code-execution
      authority; shell-language behavior inside an explicitly selected Bash or
      PowerShell script is visible custom code, not engine reparsing. @status:spec/done

[p45] @fact:CUSTOM-VERIFIER-SNAPSHOT Before the before phase,
      the engine snapshots the exact declared source bundle—bytes, modes, paths,
      sizes and digests—into the external transaction. Both phases execute that
      snapshot. A verifier stored under `vibevm/` therefore remains
      available after contract-last; undeclared dynamic imports from its former
      source directory fail. @status:spec/done

- [p46] @fact:CUSTOM-ARGV Arguments are arrays. Placeholders
        `{root}`, `{phase}`, `{scratch}` and
        `{result}` are allowed only as an entire argument and expand to
        exactly one argument. JSON protocol requires `{result}` exactly
        once. The engine precreates private result/scratch parents outside the
        product view; writes there are implicit transaction effects. @status:spec/done
- @fact:CUSTOM-EXIT-PROTOCOL Under
        `protocol = "exit-code"`, exit 0 is pass and every other terminal
        state is fail. Output is diagnostic only. @status:spec/done
- @fact:CUSTOM-JSON-PROTOCOL Under
        `protocol = "vibe-health-json-v1"`, exit 0 plus one atomically
        written, size-bounded UTF-8 result object with protocol 1 is required.
        Its `pass | warn | fail` status is a valid health verdict: strict
        baseline admits only pass, while no-regression may compare warn/fail by
        stable findings. Missing, malformed, duplicate, oversized, wrong-version
        or nonzero-exit output is protocol/execution failure. Stdout can never
        spoof the result. @status:spec/done

[p47]
```json
{
  "protocol": 1,
  "status": "pass",
  "summary": "domain health passed",
  "findings": [
    {
      "id": "stable/check-id",
      "severity": "info",
      "message": "bounded diagnostic",
      "evidence": "root-relative/path:line"
    }
  ],
  "metrics": { "tests": 42 }
}
```

[p48] @fact:CUSTOM-FINDING-LAW Finding ids are nonempty,
      unique within one report and stable across phases. Severity is exactly
      `info < warning < error`. Pass carries no warning/error
      finding; warn carries at least one warning and no error; fail carries at
      least one error. A contradictory status/finding set is protocol-error. @status:spec/done

### 8.3 Executable identity, environment and effects {#execution}

- [p49] @fact:EXECUTABLE-IDENTITY Every executable,
        interpreter and adapter asset is resolved before mutation to canonical
        absolute path, stable file identity, digest, size and mode. Version
        evidence is tagged by the closed vocabulary `probe | content`;
        epoch-1 Windows uses the exact content digest as
        the version identity rather than executing an unjournaled probe during
        read-only planning. After uses the same held identity. PATH shadowing,
        replacement, disappearance or retargeting fails closed. @status:spec/done
- @fact:SCRAPED-ENVIRONMENT The child environment is
        allowlisted and removes Vibe-specific variables and Vibe-managed bin
        directories. Reports contain variable names and value digests, never
        secret values. A check inherits the global network policy unless it
        overrides it. Policy is exactly `deny`,
        `tool-offline` or `inherit`; deny must be OS-enforced or
        refuse. Tool-offline is legal only for built-in package-manager
        adapters, adds their native offline flags and reports network unverified
        beyond those flags. Custom checks default to deny, cannot select
        tool-offline, and must explicitly select inherit for unconfined network. @status:spec/done
- @fact:HEALTH-EFFECTS Checks declare read, write,
        process-spawn and network effects. In both phases every allowed write and
        known build output is redirected to phase scratch or an enforced
        copy-on-write view and discarded afterward; no healthcheck can mutate
        the source or delivered tree. The writes list authorizes paths inside
        that isolated view, never direct product writes. A custom verifier
        defaults to `writes = []`. Any
        undeclared project create, modify, delete, hardlink write or symlink
        escape is failure. Network is failure under deny; tool-offline/inherit
        instead report their explicitly narrower assurance. @status:spec/done
- @fact:WINDOWS-E1-HEALTH-ENFORCEMENT The Windows
        epoch-1 mutating backend runs both before and after health in freshly
        materialized disjoint exact copies under the identity-bound external
        transaction workspace. The actual source/delivered root is protected
        and completely re-proven immediately before and after each child, but is
        never the child cwd or `{root}`. The phase copy is also completely
        re-proven after execution, so a write to cwd/`{root}` fails health while
        leaving the product root unchanged. This different-path proof yields
        `assurance = reduced`, never masquerades as COW, and is allowed for
        custom code only for the narrow declared profile
        `protocol=exit-code, network=inherit, reads=["**"], writes=[],
        spawn=true` executed from the sealed bundle. Any stricter custom
        effects, denied network or structured result require a stronger backend
        and remain a plan blocker. @status:spec/done
- @fact:HEALTH-OUTPUT-BOUND Stdout and stderr are drained
        concurrently. The report retains total byte count, full-stream digest,
        truncation/UTF-8 state and an explicit `redacted` flag. Epoch 1 always
        emits `redacted = true` with empty head/tail fields, so
        `truncated = false` never implies that excerpts were retained; storage
        never grows beyond declared caps and no secret is printed. A structured custom
        result is independently limited by `max_result_bytes`; stdout cannot
        consume or enlarge that budget. @status:spec/done
- @fact:HEALTH-TIMEOUT-CANCEL Timeout or cancellation
        terminates the exact process tree. The prepared plan records
        `termination_mode = graceful-then-forced | forced-tree`. Unix sends a
        graceful group signal and forces after the explicitly declared
        `termination_grace_seconds`; Windows epoch 1 uses the non-escapable Job
        Object's `forced-tree` termination because it has no honest portable
        graceful broadcast. Either terminal is a health execution failure—never
        an accepted reduced result—and every pipe/process is reaped. Before-phase
        cancellation leaves the project untouched;
        after-phase cancellation enters rollback. @status:spec/done

### 8.4 Baseline comparison {#baseline}

[p50] @fact:STRICT-BASELINE `baseline = "strict"` is
      the default: all required before checks and all required after checks pass.
      An execution, environment or protocol failure is never baselineable. @status:spec/done

[p51] @fact:NO-REGRESSION-BASELINE `baseline =
      "no-regression"` is admitted only for structured verifiers with stable
      unique finding ids: every before pass remains pass, after findings are a
      subset of before findings, and no severity increases under
      `info < warning < error`. A well-formed exit-0 warn/fail
      report is a comparable health verdict; an opaque nonzero exit can never
      become an accepted baseline. @status:spec/done

[p52] @fact:NO-REGRESSION-ASSURANCE Any accepted after
      verdict other than pass forces `assurance = reduced`. Its complete
      retained finding ids and severities appear in JSON and the human headline;
      a no-regression comparison may authorize delivery but cannot relabel
      existing product illness as full health. @status:spec/done

## 9. Residual and preservation proof {#residual}

[p53] @fact:RESIDUAL-CLASSES The final verifier reports zero
    unresolved members of: source metadata, dependency identity, manifest path,
    managed marker, generated artifact, tool config, tool script, selected spec
    URI, environment reference, lock entry and link escape. @status:spec/done

- [p54] @fact:RESIDUAL-LAYERS Proof combines language-aware scans,
      parsed manifest/dependency graphs, exact registered path/identity scans and
      a supplemental bounded lexical scan. A lexical prose hit is a disposition
      blocker, never auto-deletion. @status:spec/done
- @fact:ERASURE-EQUIVALENCE For each authored Rust,
      TypeScript and Go source,
      `erase_registered_metadata(parse(before)) == parse(after)`.
      Untouched files have identical bytes; relocations have identical
      bytes/mode under the new path. @status:spec/done
- @fact:LOCK-GRAPH-PROOF Native manifest and lock adapters
      record before and after dependency graphs. Only dependencies made
      unreachable by planned removals disappear; shared transitive dependencies
      remain. @status:spec/done
- @fact:LOCK-GRAPH-E1 Epoch-1 implements Cargo.lock
      v3/v4 reconciliation when the removed package has one unambiguous root
      identity and records exact before/after/removed graph evidence. npm,
      pnpm, yarn and Go native lock reconciliation remains a typed plan blocker
      until each manager has an equally exact graph proof. @status:impl/done
- @fact:PROOF-OUTSIDE-TREE Canonical proof is emitted to
      stdout and the user-local transaction/report home, never into the scraped
      project whose zero-residue assertion it would contradict. @status:spec/done

## 10. Scraped export mode {#export}

- [p55] @fact:EXPORT-SOURCE-READONLY Export holds the source
      project in an enforced read-only/COW view. The requested output must be
      disjoint from the source—neither equal, descendant nor ancestor. The engine
      pins its parent no-follow and creates an exclusive sibling candidate on the
      output filesystem; inability to enforce source immutability refuses. @status:spec/done
- @fact:EXPORT-COPY-SET All project files outside selected
      deletion roots are copied byte/mode-identically except typed rewrites.
      The exact engine-reserved exclusion is `.git` and its descendants;
      authoritative transaction state is external and therefore not in the
      inventory. Ambient Git ignore or cache heuristics are never consulted:
      every other observed regular project file is copied unless the contract
      explicitly deletes it, so untracked/ignored product inputs cannot
      disappear by accident. @status:spec/done
- @fact:EXPORT-PUBLISH After candidate structural proof,
      publish uses an atomic no-replace rename onto the still-absent requested
      output; a raced occupant or platform without no-replace guarantee refuses.
      The output is still transaction-owned and rollback-capable. Full residual
      and after health run in the external exact-copy view while the requested
      final path is protected by complete pre/post reproof. Failure removes only
      the exact owned output back
      into stage; before that rename the engine re-enumerates the complete
      no-follow descendant set and requires exact equality with the journaled
      candidate paths, identities, digests and modes. An extra, missing or
      changed descendant is a third state and refuses, preserving the concurrent
      data in place. The source remains unchanged. @status:spec/done
- @fact:EXPORT-RECOVERY Export uses the same external
      journal with states `prepared → candidate → published-pending-verify →
      verified → cleanup-pending → complete`. Before verified, recovery
      discards or quarantines only the transaction-owned candidate/output and
      never publishes it as success; verified states roll forward through
      cleanup/report. Recovery validates the same complete descendant state,
      never only the root-directory identity; any third state refuses. @status:spec/done

## 11. In-place transaction and recovery {#inplace}

[p56] @fact:EXTERNAL-JOURNAL The authoritative journal and lock
    are user-local and outside the project, for example
    `~/.vibe/scrape/transactions/<project-key>/<transaction-id>/`.
    Project `.vibe/` is removable and can never contain the only journal,
    recovery intent, verifier snapshot or rollback bytes. The journal location
    is implementation-owned, not contract-configurable, and must itself be
    proven outside the pinned project root. @status:spec/done

[p57] @fact:SAME-VOLUME-QUARANTINE Removed and replaced bytes
    live in an exclusively created, identity-pinned sibling quarantine under the
    project parent on the same filesystem. A pre-existing, linked, replaced or
    unverifiable quarantine refuses and is never adopted or deleted. The chosen
    name is durable before creation. @status:spec/done

1. [p58] @fact:TX-STEP-RECOVER Acquire the user-local project
      transaction lock and settle any prior journal before loading a new
      contract. @status:spec/done
2. @fact:TX-STEP-PLAN Pin root and parent; read/validate the
      contract; inventory; prepare rewrites, relocations, native lock updates,
      assertions and health identities; calculate one canonical plan hash. @status:spec/done
3. @fact:TX-STEP-PREPARE Persist contract/verifier snapshots,
      canonical plan, full before identities, complete rollback map and prepared
      after bytes in the external journal; fsync it before executing any child.
      No project byte or quarantine exists yet. @status:spec/done
4. @fact:TX-STEP-BEFORE Run before health from the sealed
      verifier bundle in an enforced read-only/COW view whose writes are all
      redirected to phase scratch. Strict requires pass; no-regression admits
      only its specified structured baseline. If isolation cannot be enforced,
      refuse. A before refusal mutates no source-project byte. @status:spec/done
5. @fact:TX-STEP-QUARANTINE After an admissible baseline,
      durably select the name and creation intent, exclusively create and
      identity-check the same-volume quarantine, then persist its root identity
      and complete manifest before entering mutating state. A crash after create
      but before that first identity seal is fail-closed manual recovery: the
      existing name is never adopted from spelling alone. @status:spec/done
6. @fact:TX-STEP-REWRITE Copy and fsync every rewrite
      before-image into quarantine while its visible name remains present, then
      atomically replace that name with the prepared after-image. Reconcile
      native locks and apply exact relocations. Platforms lacking an atomic
      replace primitive for the target refuse; no move-then-create missing-name
      window is claimed atomic. @status:spec/done
7. @fact:TX-STEP-REMOVE Move every non-contract removal into
      quarantine in canonical file order, then prune only observed-empty
      non-contract directories. @status:spec/done
8. @fact:TX-STEP-PRECOMMIT Run residual/preservation proof
      with a contained delete-last contract as the sole permitted residue; an
      external preserved contract receives zero project-tree exemption. Any
      failure rolls back. @status:spec/done
9. @fact:TX-STEP-CONTRACT Durably enter the
      rollback-capable `contract-boundary` state. Its tagged action is:
      contained/delete-last moves the contract as the last payload and prunes
      empty ancestors; external/preserve performs no project mutation. Both then
      run zero-exemption residual proof and after health in the isolated view.
      After it exits, re-observe the complete scraped tree digest and residual
      proof before verified commit. Crossing the contract boundary is not commit. @status:spec/done
10. @fact:TX-STEP-COMMIT After all gates pass, durably mark
      verified, release project mutation ownership, copy the canonical report to
      the stable user-local report home, then clean the exact verified quarantine
      and transaction journal. Cleanup failure leaves a verified transaction in
      cleanup-pending state for roll-forward cleanup; it never reopens product
      mutation. @status:spec/done

[p59] @fact:ROLLBACK-DIRECTION The durable states are
    `prepared → before-passed → mutating → contract-boundary → verified →
    cleanup-pending → complete`, with
    `rolling-back → rolled-back | rollback-failed` as the inverse branch.
    The contract-boundary record carries exactly
    `delete-last-moved | external-preserved`. Failure or recovery from any
    state before verified restores in reverse journal order, including
    restoration of a moved contained contract, and proves the
    original bytes/modes. Verified and cleanup-pending only roll forward through
    report/quarantine/journal cleanup. Any path matching neither journaled before
    nor after is a third state and refuses rather than overwriting
    concurrent/user work. @status:spec/done

[p60] @fact:GIT-INDEPENDENCE Git is not the rollback engine.
    Scrape works in non-Git projects and preserves untracked/ignored files
    according to the contract. A dirty repository is allowed only when every
    affected path's observed digest is sealed in the plan; unrelated concurrent
    changes remain detectable and refuse at the affected boundary. @status:spec/done

## 12. Plan, report and observable outcomes {#plan-evidence}

[p61] @fact:PLAN-CONTENT Human and JSON plans are projections of
    one typed value. They include project/contract identities, mode, every
    matched path and effective class, ownership proof, modification state,
    rewrite before/after digests, relocation graph, native lock changes,
    residual assertions, exact health argv/executable identities, test modes,
    contract-last order, quarantine requirement, blockers and summary counts. @status:spec/done

[p62] @fact:PLAN-JSON-SHAPE The plan wire is
    `scrape_plan/e1`. Its required top-level members and enums are fixed
    below; item/rewrite/health variant members are the generated tagged unions
    from §5.1. Digests are lowercase `sha256:<64-hex>`, sizes/counts
    are nonnegative integers, and every array is already in canonical execution
    order. @status:spec/done

[p63]
```json
{
  "schema": 1,
  "command": "scrape",
  "mode": "in-place",
  "plan_id": "sha256:...",
  "project": {
    "display_root": "C:/work/project",
    "tree_digest": "sha256:..."
  },
  "contract": {
    "display_path": "vibevm/scrape/contract.toml",
    "contained": true,
    "sha256": "sha256:...",
    "action": "delete-last"
  },
  "items": [],
  "rewrites": [],
  "relocations": [],
  "native_lock_changes": [],
  "assertions": [],
  "healthchecks": [],
  "contract_boundary": {
    "kind": "delete-last",
    "path": "vibevm/scrape/contract.toml",
    "empty_ancestors": ["vibevm/scrape", "vibevm"]
  },
  "blockers": [],
  "summary": {
    "keep": 0,
    "rewrite": 0,
    "relocate": 0,
    "delete_unmodified": 0,
    "delete_modified": 0,
    "delete_unknown": 0,
    "delete_last": 1
  }
}
```

[p64] @fact:PLAN-CONTRACT-BOUNDARY The required
    `contract_boundary` tagged union is either
    `{"kind":"delete-last","path":<project-relative>,
    "empty_ancestors":[...]}` or exactly
    `{"kind":"preserve"}`. Preserve has no path/ancestor members; delete-last
    requires both. Variant leakage is rejected by JTD. @status:spec/done

[p65] @fact:PLAN-DETERMINISM Plan display may carry absolute
    root, contract and executable paths; the separately generated hash projection
    excludes timestamps, transaction nonce, project-root display path, external
    contract source path, user-local journal location and quarantine name. It
    includes contract/verifier bytes, project-relative operands, executable
    content/version identity, platform, mode and—for export—the canonical
    requested output identity because that is a mutation target. The strict JTD
    identity object contains no maps/floats and is encoded in schema field order
    with canonical array order before SHA-256. @status:spec/done

[p66] @fact:REPORT-CONTENT The canonical external JSON report
    records before/after root digests, unchanged-file hashes, deleted artifacts
    with provenance, typed rewrites, relocations, dependency graphs, every health
    command step/argv/terminal/output digest/finding, skipped tests, residual
    counts, actual apply/rollback/recovery work, bounded diagnostic events and
    final outcome. Human output is rendered from the
    same data. Outcome is exactly `verified | refused | rolled-back |
    rollback-failed`; orthogonal `assurance = full | reduced` and
    `cleanup = complete | pending` fields prevent an outcome-enum
    explosion. The headline renders all three. @status:spec/done

[p67] @fact:NO-FALSE-SUCCESS Unavailable verification,
    truncated/missing structured evidence and rollback failure cannot yield a
    verified outcome. Explicitly skipped/if-present checks may yield
    `outcome = verified, assurance = reduced`; committed quarantine/report
    cleanup residue yields `outcome = verified, cleanup = pending` and a
    recovery command. Neither is rendered as unqualified verified/full/complete. @status:spec/done

[p68] @fact:STABLE-REPORT-HOME Before transaction-journal
    cleanup, the canonical report is atomically copied to
    `~/.vibe/scrape/reports/<transaction-id>.json` (or emitted only to
    stdout when the operator explicitly disables retention). The report home is
    outside the project and distinct from the ephemeral transaction directory. @status:spec/done

## 13. Security and authority invariants {#security}

- [p69] @fact:SEC-CONTAINMENT All project reads/writes are
      capability-relative under pinned root/parent identities. No path
      normalization, glob, relocation, managed marker or verifier write may
      escape. @status:spec/done
- @fact:SEC-NO-FOLLOW Links, reparse points, special files,
      unexpected hard links and name/handle identity changes fail closed at
      inventory and again before mutation. @status:spec/done
- @fact:SEC-NATIVE-NOFOLLOW-BOUNDARY Epoch-1 Windows
      crosses a hand-written native ABI in exactly five narrowly reviewed functions:
      lease-entry, remove-expected, create-directory, rename-no-replace and NTSTATUS
      conversion. No safe standard-library or cap-std primitive preserves the required
      retained-handle, no-follow, no-replace and race semantics for those operations.
      Each function owns its inline SAFETY proof and exact tests. This is not a broad
      crate or file exemption. A second consumer or an expanded native ABI is the
      trigger to revisit a dedicated audit crate. @status:spec/done
- @fact:SEC-CUSTOM-CODE A custom health verifier is
      user-authorized code with the same trust consequence as a project build
      script. The plan names its exact snapshot/interpreter/effects before
      confirmation; packages cannot inject an executable scrape hook. Epoch 1
      exposes only the disjoint copy through cwd and `{root}`; arbitrary
      malicious host-absolute writes are outside its sandbox guarantee and
      therefore require the same operator trust as any other authorized build
      script. @status:spec/done
- @fact:SEC-SECRETS Contract, plan, argv, output and reports
      may contain variable names and paths but never credential values. Custom
      children receive only allowlisted environment. Output redaction and bounds
      precede persistence. @status:spec/done
- @fact:SEC-NO-SELF-DELETION The running Vibe executable,
      user-local journal and machine cache are outside project mutation
      authority. Scrape removes repository integration, not the operator's
      installed tool. @status:spec/done

## 14. Required verification matrix {#acceptance}

- [p70] @fact:ACCEPT-SCHEMA Strict parse/write tests cover every
      tagged variant, unknown field/kind/enum, duplicate id, missing required
      member, wrong schema and canonical plan identity. @status:spec/done
- @fact:ACCEPT-GLOBS Glob tests cover literal, component
      star and whole-component double-star; reject question/class/brace/negation/
      escape/triple-star/embedded-double-star, absolute/dot/backslash/colon
      spellings; prove no shell/host expansion and deterministic order. @status:spec/done
- @fact:ACCEPT-CLASSIFICATION Fixtures cover clean generated,
      modified generated, explicit authored deletion, keep shielding, invalid
      keep/generated overlap, unclassified members, authored specifications and
      kept descendants preventing ancestor deletion. @status:spec/done
- @fact:ACCEPT-RUST Rust goldens cover qualified/renamed
      aliases, explicit/grouped imports, scope/spec/verifies/cell, every Cargo
      dependency table, workspace inheritance, features and lock pruning across
      src, tests, examples, benches, build.rs and arbitrarily nested workspace
      members. Negatives preserve same-named local macros, strings/comments,
      re-exports, glob imports and invalid macro grammar. End-to-end REDs prove
      that a still-present path dependency blocks tree deletion before mutation,
      and a still-present macro/attribute blocks dependency removal rather than
      becoming rustc E0433 after publication. @status:spec/done
- @fact:ACCEPT-TS-GO TypeScript/Go goldens cover mixed
      comments, empty metadata comments, CRLF/indentation preservation and
      non-target strings/prose/compiler/build/lint directives; product
      source/tests remain native-buildable. @status:spec/done
- @fact:ACCEPT-MANAGED-RELOCATE Managed-block fixtures cover
      valid, absent, orphaned, reversed, duplicate, nested and embedded markers.
      Relocation covers destination collision, overlap, cycle, cross-filesystem
      refusal, byte/mode equality and ancestor retention. @status:spec/done
- @fact:ACCEPT-PRESETS Epoch-1 has a real hermetic Cargo
      before/after smoke plus exact argv and discovery unit coverage. Equivalent
      real npm, Maven and Python preset smokes remain planned and unsupported
      profiles remain typed blockers. @status:impl/plan
- @fact:ACCEPT-CUSTOM-HEALTH Epoch-1 ships the sealed
      Windows exit-code/inherit/reads-all/writes-none/spawn-allowed custom
      profile with bundle, argv, output, timeout, cancel and drift tests. Stronger
      structured, denied-network and restricted-effect profiles remain planned
      behind explicit capability blockers. @status:impl/plan
- @fact:ACCEPT-BASELINE Strict before-red refuses with zero
      writes; before-green/after-red restores exact tree; admissible structured
      no-regression before-fail/after-subset yields reduced assurance; a new or
      worsened after finding rolls back; opaque nonzero never baselines. @status:spec/done
- @fact:ACCEPT-TRANSACTION Fault injection at every journal,
      stage, rewrite, relocation, quarantine, contract-last, assertion, health,
      rollback and cleanup boundary proves restart idempotence, correct
      direction, third-state refusal and exact restoration. Before and after
      verifier cwd/`{root}` writes are trapped in the external exact
      copy/scratch, both the copy and delivered tree digest are re-proven after
      health, and ambient TMP/TEMP inside the project cannot redirect workspace
      creation into the product tree. @status:spec/done
- @fact:ACCEPT-EXPORT-RACES Export REDs cover output equal
      to/inside/above source, destination race, unavailable no-replace rename,
      crash before/after publication, after health in an exact disjoint copy
      while the final location remains sealed,
      and extra/missing/changed descendants before rollback. Concurrent output
      data is never captured into transaction stage. @status:spec/done
- @fact:ACCEPT-E2E Epoch-1 end-to-end fixtures cover real
      Rust export/in-place, Specmark erasure, Cargo.lock reconciliation, green
      before/after, zero selected residue, external report and safe second-scrape
      refusal. The mixed TypeScript/Go expansion remains planned. @status:impl/plan
- @fact:ACCEPT-HOST-DOGFOOD A future host fixture covers
      this repository's direct `vibevm/vibepacks` Cargo path wiring and
      proves the scraper reports non-Specmark product tool dependencies as
      blockers rather than deleting them into a broken build. @status:impl/plan

## 15. Implementation decomposition {#implementation}

1. [p71] @fact:IMPL-A A — strict contract model, default generator,
      path/glob parser, inventory/classification, canonical plan and human/JSON
      rendering. @status:impl/done
2. @fact:IMPL-B B — typed rewrite/relocation algebra,
      managed blocks, Rust/Cargo, TypeScript/npm and Go/module adapters, Cargo
      v3/v4 native-lock reconciliation and residual proof. npm/pnpm/yarn/Go
      manager-native lock rows remain explicit blockers. @status:impl/done
3. @fact:IMPL-C C — prepared Cargo/npm/Maven/Python
      presets, the exact-copy Windows Cargo backend, the narrow sealed custom
      profile, effect/output/process control and baseline comparison. Chains
      without complete runtime capabilities fail closed. @status:impl/done
4. @fact:IMPL-D D — read-only source export transaction,
      candidate publication and export evidence. @status:impl/done
5. @fact:IMPL-E E — external journal/lock, same-volume
      quarantine, in-place contract-last commit, rollback and recovery. @status:impl/done
6. @fact:JOURNAL-E2-TRANSITION The pre-public internal
      transaction journal moved from handwritten epoch 1 JSON to the strict generated
      `scrape-transaction-journal/e2` root. Old epoch-1 state refuses with an actionable
      restart recipe and is not migrated automatically; the public scrape plan, report and
      health-result roots remain byte-identical at epoch 1. Root and named-object member
      order is schema-declared; inline standard JTD discriminator arms use the pinned
      generator's deterministic canonical field order. @status:impl/done
7. @fact:HEALTH-PERSISTENCE-E2-TRANSITION The pre-public
      prepared-health snapshot and canonical transaction health evidence use the strict
      generated `scrape-prepared-health-snapshot/e2` and
      `scrape-verification-health-evidence/e2` roots. An old handwritten prepared-health
      shape refuses with the restart recipe rather than being guessed forward. Live file
      identities and separately journaled verifier bundle bytes remain outside the plan
      snapshot and are reattached only after their recorded digest, byte count, mode and
      path identity agree. The public scrape plan, report and custom health-result roots
      remain byte-identical at epoch 1; their health finding/report-row vocabulary has one
      generated shared authority. @status:impl/done
8. @fact:IMPL-F F — the bounded epoch-1 evidence includes
      transaction/store fault matrices, composed production recovery, real Rust
      Cargo/custom smokes, Windows races and explicit non-Windows fail-closed
      probes. Wider ecosystem and host-dogfood rows remain planned above. @status:impl/done

## 16. Foundational decisions {#decisions}

### 16.1 Contract over heuristics {#decision-contract}

[p72] @fact:DECISION-CONTRACT Decision. One
      strict project contract carries every policy choice; observation only
      evaluates it. @status:spec/done

[p73] @fact:WHY-CONTRACT Why. Generated,
      authored and accepted-product states can share names. Making policy data
      is the only way to keep execution deterministic without guessing. @status:spec/done

[p74] @fact:REJECT-CONTRACT Rejected.
      Delete-known-names, Git-ignore-as-ownership, prompt-per-file and LLM
      classification at execution time: each is order/environment dependent or
      non-reproducible. @status:spec/done

[p75] @fact:REVISIT-CONTRACT Revisit when.
      A stable package-contributed recipe protocol can compile into the same
      closed plan without executing package code during scrape. @status:spec/done

### 16.2 Typed rewrites over regex and shell {#decision-typed}

[p76] @fact:DECISION-TYPED Decision. Native
      parsers own source/manifests; literal exact-replace is the only textual
      escape hatch. @status:spec/done

[p77] @fact:WHY-TYPED Why. Identity,
      cardinality and erasure equivalence are mechanically provable only over
      syntax nodes and exact preimages. @status:spec/done

[p78] @fact:REJECT-TYPED Rejected. Regex
      source rewrites, arbitrary cleanup hooks and whole-file TOML/JSON
      regeneration: they damage product text or hide the changed surface. @status:spec/done

[p79] @fact:REVISIT-TYPED Revisit when. Add a
      typed adapter when a real unsupported format has a parser and preservation
      oracle. @status:spec/done

### 16.3 Built-in health plus explicit custom oracle {#decision-health}

[p80] @fact:DECISION-HEALTH Decision. Common
      ecosystems use declarative presets; unusual domain checks use a sealed
      custom verifier with structured argv and protocol. @status:spec/done

[p81] @fact:WHY-HEALTH Why. Standard
      operations should not require one-off scripts, while no finite preset
      catalogue can express every project's definition of healthy. @status:spec/done

[p82] @fact:REJECT-HEALTH Rejected. One shell
      string, after-only testing, silent missing test scripts, automatic retry
      and treating exit 0 as proof beyond the declared oracle. @status:spec/done

[p83] @fact:REVISIT-HEALTH Revisit when. A new
      ecosystem demonstrates a stable build/test vocabulary deserving a built-in
      adapter. @status:spec/done

### 16.4 Export default, recoverable in-place option {#decision-transaction}

[p84] @fact:DECISION-TRANSACTION Decision.
      Export is the safest delivery form; explicit in-place uses an external
      journal and same-volume quarantine with contract-last commit. @status:spec/done

[p85] @fact:WHY-TRANSACTION Why. Project
      `.vibe` cannot recover its own deletion, Git does not cover every
      file, and multi-file mutation has no filesystem-wide atomic rename.
      Journaled before/after states make interruption decidable. @status:spec/done

[p86] @fact:REJECT-TRANSACTION Rejected.
      Journal under project `.vibe`, Git reset as rollback, delete-first
      uninstall, blind recursive removal, external configurable journal, and
      cleaning quarantine before verified commit. @status:spec/done

[p87] @fact:REVISIT-TRANSACTION Revisit when.
      A platform offers a stronger atomic directory-tree primitive without
      weakening cross-platform recovery semantics. @status:spec/done

## 17. History {#history}

[p88] @fact:HISTORY-COMMISSIONED 2026-09-04: commissioned
    directly by the owner after auditing how Rust Specmark, TypeScript JSDoc and
    Go directive metadata behave when the Vibe tree disappears. The owner then
    extended the request to an explicit default/alternate contract and
    algorithmic standard/custom health checks, and ordered this feature ahead of
    every remaining lifecycle R task. @status:spec/done

[p89] @fact:HISTORY-EPOCH1-WINDOWS 2026-09-05:
    implemented and ratified the Windows epoch-1 product surface: generated
    plan/report wire, external journal/workspace, capability mutation, export,
    in-place contract-last, rollback/recovery, exact-copy health, Cargo and the
    narrow custom profile. Recorded the remaining manager-native lock, wider
    preset/custom, mixed-language and host-dogfood work as explicit planned
    scope. @status:impl/done

