feat(legacymove): clear wiki/sources and raw/ leftovers of the retired layout, with archive and rollback (#209) #213
Open
mathias
wants to merge 5 commits from
wt/legacy-move into main
pull from: wt/legacy-move
merge into: :main
:main
:wt/client-pattern
:wt/legacy-move
:wt/web-clip
:wt/watcher-write-safety
:wt/wing-layout
:wt/inbox-zero
:fix/pipeline-writes-158
:fix/edit-path-io-192
:fix/create-regular-188
:fix/guard-special-179
:fix/linkcheck-keeps-write-178
:fix/write-dir-redirect-173
:fix/tunnel-detect-174
:fix/pipeline-root-157
:w3/154-mcp-auth-wiring
:fix/tunnel-traversal
:test/in-brain-targets-171
:fix/brain-scan-root-157
:fix/graph-wiki-root-157
:fix/vectorstore-root-157
:fix/notes-root-157
:fix/search-root-157
:fix/brainwide-root-157
:fix/raw-symlinks-153
:feat/symlink-tripwire-157
:fix/rest-auth-149
:fix/123-brain-edit-envelope-check
:feat/106-page-aware-extraction
:fix/105-source-drift-on-main
:fix/104-surface-merge-conflicts-on-main
:agent/b1-compile-on-ingest
:agent/104-surface-merge-conflicts
:agent/105-source-drift
:agent/107-loud-unconfigured-alerting
:feat/brain-read-edit
:fix/capture-i1-refusal-names-target
:renovate/configure
:feat/consolidate-single-harness
:icebox/cmd-routing
:feat/brain-pending-promote
:fix/close-session-classification-refresh
:fix/capture-summarywriter
No Reviewers
Labels
Clear labels
agent/ready
blocked/client
blocked/supplier
blocked/upstream
risk/high
risk/low
risk/medium
size/l
size/m
size/s
size/xs
status:dispatch
status:dispatched
status:review
status:reviewing
type/chore
type/decision
type/docs
type/feat
type/fix
type/ops
type/research
type/test
Meets the agent-ready contract; authorizes unattended execution
Waiting on the client
Waiting on a supplier
Waiting on an upstream project or vendor
Irreversible, security-relevant, or control plane
Reversible, local, test-covered
Touches shared state, deploys or data
Too big - split it
Under two days
Under half a day
Under an hour
Maintenance, no behaviour change
Human decision required; never agent/ready
Documentation only
New capability
Corrects broken behaviour
Infrastructure, deploy, runtime
Investigate; output is a finding, not code
Test coverage only
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: mathias/hyperguild#213
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Sprint #209, PR-C. Refs #209 #205. Risk: medium by label, but it is a tool that DELETES live data when run with
-apply; the dry run is the default. Mathias will see the dry-run table before any apply.What
cmd/legacymove+internal/legacymove:Plan: inwiki/sources/,type: video|articlepages move towiki/<wing>/sources/(defaultweb-clip, wing/hall stamped, body and links byte-preserved);tunnel-candidates-*(AutoTunnel review logs that were ingested as "sources") are deleted; notes/projects/untyped pages are left. A page whose slug is used elsewhere is skipped.PlanRaw: inraw/, an original is deleted with its.processedmarker only if it HAS the marker AND a byte-identical copy (SHA-256) exists underraw/processed/; a marker with no note is deleted; an unmarked note, a note whose archive copy differs, andtunnel-candidates-*(AutoTunnel's own queue) are never touched.Apply: archives every page it touches intoarchive/wing-migration-<date>/originals/(path flattened, soraw/x.mdandwiki/sources/x.mdcannot collide) and amanifest.jsonrewritten after every step; creates destinations O_EXCL; removes the source only after.Rollbackrestores byte for byte and refuses to overwrite.raw/, so the watcher never ingests it.concepts/andentities/are the shared layer and are not touched.Evidence
go vet,go test -race ./...exit 0, 0 FAIL, lint 0. Mutation-checked: junk guard, type filter, slug collision, no-overwrite, archive-before-change, action gate, identical-copy check, marker requirement, tunnel exemption, orphan-marker rule, archive-key flattening. Two of my mutants failed to compile (unused variables) and were redone as valid ones.Review ask (this deletes files on a live, Syncthing-shared, git-synced tree)
By execution: (1) can
PlanRawever select a note that is still unprocessed or whose archive copy is not byte-identical, including a hash collision-free path (hardlinks, symlinks inraw/orraw/processed/, a symlinked processed dir, a file replaced between Plan and Apply)? (2)Applyagainst a changing tree (the watcher running): a file that changed between Plan and Apply — is the archived copy the bytes that were deleted? (it reads, archives, then removes: is there a window where the removed file differs from the archived one?); (3)Rollbackafter a partial Apply (manifest written per step), rollback twice, rollback when a destination was edited; (4) path handling: names with newlines/unicode/.., archive key collisions after flattening (a/b__cvsa__b/c); (5) the 16 moves: any link or graph consequence (slug unchanged); (6) anything that deletes outsideraw/andwiki/sources/.🤖 Generated with Claude Code
Created via git-mcp on behalf of @mathias
Independent review pass 1 (pr-gatekeeper agent, by execution): BLOCK. Do not run
-applyon the live brain until the next pass. Findings and resolution at the head above (tests first, mutation-checked):-2,-3).Result.Changed).wing:/hall:would get duplicate keys;type:inside a nested/block-scalar line or an unterminated block classified a page. Fixed: such pages are not moved.PlanRawcases (1-byte difference, symlinked archive dir/file, copy only underraw/failed/) are all skipped; nothing outsideraw/andwiki/sources/can be deleted; symlinks and..refused;-applyoff by default; the live dry run is read-only.Gate:
go vet ./...,go test -race ./...exit 0, 0 FAIL, lint 0. A second pass follows before any apply; you will see the dry-run table first.Created via git-mcp on behalf of @mathias
Independent review pass 2 (pr-gatekeeper agent, by execution): not blocked, clear for a dry run and for apply at
b66b45b(the reviewer found nothing that violates: delete only after a byte-for-byte archive, never overwrite, rollback restores exactly and never deletes user data).Re-verified by execution: each pass-1 repro is fixed and flipping the fix turns a test red (SHA check, name-length guard, wing/hall key skip, edited-moved-copy rollback, target-exists preflight; the archive-dir uniqueness mutants did not compile or hung, but the behaviour was confirmed: an existing
archive/wing-migration-2026-10-20gave-2). Attacks that held: A->B->A bytes (moved, correct), empty SHA (untouched, in Changed), plan for another dir (Changed or error, nothing touched), duplicate delete (error, manifest consistent, rollback restores), a late destination (source kept, destination untouched, no manifest entry), symlinkedarchive/(refused, nothing written outside).archive/is not read by search, vector sync, graph sync or brain_get/read (denied prefix); the watcher walks onlyraw/. Performance: 1000 notes plan in 83 ms, apply 2000 deletes 199 ms.Low items left (not changed): (1) the manifest is rewritten with a truncating write, so a kill mid-write could leave a short
manifest.json(originals are still archived, so nothing is lost but one-command rollback would be); (2) a failed first item leaves an archive with originals and no manifest; (3) a page edited between the SHA read and the remove is deleted, with the archive holding the planned bytes (milliseconds, documented); (4) one failed item aborts the run (re-plan and re-run is safe, fresh archive each time); (5) rollback trusts the manifest, bounded to deleting a file byte-identical to a stamped archived original. Not verified: concurrent Apply runs, live-brain contents beyond the dry run,-rollback ../x.Gate:
go vet ./...,go test -race ./...exit 0, 0 FAIL, lint 0.Created via git-mcp on behalf of @mathias
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.