Files
Maven/cmd/mavend/wipe.go
T
claude 82d9a3324e wipe: one command empties the box and leaves it standing (V-494)
There was no documented way to repair a poisoned box. Two invented facts
written during QA disabled world answering for every later turn (V-470), and
revert voids the SQL row while leaving the vector behind (V-493). This is the
operation that undoes both.

Store.Wipe drops every table sqlite_master reports and rebuilds from schema.sql
plus the migrations, rather than deleting from a hand-written list. A list has
to be edited whenever a table is added, and the once it is not, the wipe leaves
personal data behind while reporting success. It vacuums afterwards, because
free pages still hold readable text.

mavend -wipe prints every table and its row count and exits. That alone is a
dry run and answers what a QA session actually asks: what is on this box. It
deletes only with -confirm-wipe. Two flags, because the destructive reading of
one flag is the reading a mistyped command gets.

Nothing outside the database moves. Config, models, passkeys.json and the
encryption key are files.

QA isolation and onboarding are the other two thirds of V-494 and are not here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SoL7EBdYC5Mhz3DJd49GJy
2026-08-05 20:51:46 +04:00

46 lines
1.5 KiB
Go

package main
import (
"context"
"fmt"
"io"
"github.com/kami/maven/internal/store"
)
// runWipe implements the -wipe flag: it prints what the database holds, and
// removes it only when the operator also passed -confirm-wipe (Vikunja #494).
//
// Two flags rather than one, because the destructive reading of a single flag
// is the reading a mistyped command gets. Without the confirmation this is a
// dry run that costs nothing and answers the question a QA session actually
// has — what is on this box right now.
//
// It runs before any daemon component is wired, so nothing is writing while
// the tables go. The daemon exits afterwards rather than serving a store it
// just emptied, because every component that read the old rows at boot would
// still be holding them.
func runWipe(ctx context.Context, st *store.Store, out io.Writer, confirmed bool) error {
counts, err := st.WipeCounts(ctx)
if err != nil {
return fmt.Errorf("wipe: read counts: %w", err)
}
total := 0
for _, c := range counts {
total += c.Rows
fmt.Fprintf(out, " %-24s %d\n", c.Table, c.Rows)
}
fmt.Fprintf(out, " %-24s %d rows in %d tables\n", "TOTAL", total, len(counts))
if !confirmed {
fmt.Fprintln(out, "\nnothing was deleted. pass -confirm-wipe to delete all of it.")
fmt.Fprintln(out, "config, models, passkeys and the encryption key are files and are never touched.")
return nil
}
if err := st.Wipe(ctx); err != nil {
return err
}
fmt.Fprintf(out, "\nwiped. %d rows gone, the schema is intact, mavend knows nobody.\n", total)
return nil
}