Skip to content

feat(erasure): inventory c-batch-2 + group-b backup variants + SQLite sidecars (#1468) - #2490

Merged
jinon86 merged 3 commits into
mainfrom
feat/1468-inventory-cbatch2-groupb-variants
Oct 23, 2026
Merged

jinon86 merged 3 commits into
mainfrom
feat/1468-inventory-cbatch2-groupb-variants

Conversation

@jinon86

@jinon86 jinon86 commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

Why

The owner approved node-by-node prune-expired cleanup on #1468 (2026-10-23), but ccc-erasure-apply.py refuses every node: a read-only fleet scan (12 nodes, origin/main planner fed over stdin, no remote writes) found 7–110 unclassified files per node, 408 normalized patterns. 88 of them are harness artifacts that appeared after #2066; 21 are sensitive backup variants the group-b patterns miss (so they would be kept forever).

What

  • 7 new classes (schemas/memory-artifact-inventory.v1.json, 50 → 59 incl. splits): nunchi.gotgan_store (body-bearing, handled like mempalace.palace), nunchi.jev_review_ledger, nunchi.feed_receipts, nunchi.feed_status, state.skill_listing_policy, bot.jev_skill_advice_config, skill.review_zai_env (live credential config → always retain).
  • Existing classes extended: nunchi batch logs / runtime locks / seen-state / runtime state, state runtime locks / rotated logs / installer records / distill runtime / self-update state / skill-autosave state / skill manifests.
  • Group-b widened, anchored: .env.bak.* / .env.bak-* / .env.pre-*, sessions.json.bak-*, crontab.bak[.-]* (bot dir, ~/.claude/state, ~/.nunchi), crontab-backup-<digit>*.txt; new state.memory_facts_backups; new state.cert_backups (kept by the key-file rule + explicit retain).
  • Deliberately NOT group b: bare sessions.json.bak / tasks.json.bak — they are the bridge's previous-good recovery copies (bridge/session/store.py, bridge/core/task_ledger.py), now registered as live.
  • Planner: sqlite_sidecars flag — -wal/-shm/-journal follow their DB (live DB ⇒ sidecars live; in a retention class a sidecar shares the DB's verdict). Prevents a WAL under a live DB from aging out on its own.
  • Built-in key-file protection unchanged. Docs + changelog fragment.

Verification (re-run independently)

ccc_erasure_retention_test.py 32/32 (was 22) · ccc-erasure-planner.test.sh 50/50 (was 43) · ccc-erasure-apply.test.sh OK · ccc-erasure-handoff.test.sh 16/16 · ccc-security-audit.test.sh 18/18 · ruff/shellcheck clean · canon-node-name-scan baseline. Two new tests verified to fail when the sessions pattern is made greedy or the sidecar live-claim is removed.

Local plan on one node: unclassified 84 → 48; the only delete targets are group-b backups (.env 3, sessions 4, crontab 3). Nothing deleted.

Still blocking (owner policy pending on #1468)

Operator one-off files (ad-hoc scripts, handover notes, one-time logs), producer-less files, and backups the inventory already marks as owner decisions (wiki-candidates.md.bak*, working-state.md.bak*). Each node's actual run still needs its own approval.

Refs #1468

🤖 Generated with Claude Code

… sidecars (#1468)

Prerequisite for the owner-approved prune-expired cleanup: the 2026-10-23
read-only fleet scan found the same harness-written files on most nodes, and
each one was an unknown-artifact blocker.

- New classes: nunchi.gotgan_store (verbatim transcript store, body-bearing
  index like mempalace.palace), nunchi.jev_review_ledger (cursors/advisory
  verdicts, no bodies), nunchi.feed_receipts (sha256 path keys + inode
  fingerprints), nunchi.feed_status, state.skill_listing_policy,
  bot.jev_skill_advice_config, skill.review_zai_env (live credential config,
  retain on every request).
- Extended classes: nunchi cron logs/locks/dedup state/runtime markers,
  state locks, rotated *.log.N[.gz], autosave cron history (installer
  record), distill scope/toggles, self-update pending activation, autosave
  prescreen/curator/seen ledgers, repo manifests.
- Group b widened, anchored: .env.bak[.-]*, +0900 stamps, crontab.bak.*,
  crontab-backup-<digit>*.txt, ~/.nunchi crontab backups; new
  state.memory_facts_backups (last-copy guarded) and state.cert_backups
  (explicit retain; pem is a key token).
- Suffix-less sessions.json.bak / tasks.json.bak are the bridge's
  previous-good recovery copies (read back on primary corruption): classified
  with their live classes, never group b.
- Planner: sqlite_sidecars flag — -wal/-shm/-journal follow their DB;
  sidecars of any live-claimed file are claimed live; in a retention class a
  sidecar shares its DB's verdict.

Operator one-offs and producer-less files stay blockers pending an owner
policy decision. Nothing is deleted by this change.

Tests: retention 22→32, planner.test.sh 43→50; apply/handoff/security-audit
unchanged and green.

Refs #1468 #873

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jinon86
jinon86 requested a review from seoseo-ai as a code owner October 23, 2026 06:52
…guard (#1468)

Owner decision 2026-10-23 (option 1): operator one-off files directly under
the harness state dir (CCC_STATE_DIR -> ~/.claude/state) that match no other
inventory class become the operator-scratch retention class
(state.operator_scratch): kept 90 days, then eligible at the existing
prune-expired -> ccc-erasure-apply.py (ERASURE_APPLY=1) boundary.

- Planner: inventory-driven fallback_scope (fallback, not a regex): the
  unknown-artifact sweep hands would-be blockers in the scope roots to the
  class; other classes always win; one directory level only; orphan SQLite
  sidecars stay blockers.
- scheduler_guard: files named by the crontab (CCC_CRONTAB_CMD seam), the
  agent-cron task store or systemd unit files are retained at any age; any
  unreadable source keeps every scratch file and is reported in a body-free
  scheduler_guard block.
- Live claims, key-file rule, symlinks, max(mtime,ctime) age and the
  lengthen-only env knob still apply first. Decommission gates scratch like
  group b; audience/user/cache requests never target it.
- ~/.nunchi and the bot data dir get no fallback (private memory and
  credentials): unknown files there still block.
- New class state.timed_test_notify_state for the timed-test scan's notify
  dedup state (a real producer that would otherwise age out as scratch).
- Tests, docs (Operator scratch subsection) and changelog fragment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jinon86

jinon86 commented Oct 23, 2026

Copy link
Copy Markdown
Contributor Author

Added: operator-scratch fallback class (owner decision 2026-10-23, option 1) — commit 4384c279

  • state.operator_scratch: fallback, not a pattern — a file directly under the harness state dir that matches no other class becomes scratch instead of a blocker (files matching a real class keep it). Kept 90 days (max(mtime, ctime); env may only lengthen), then prune-expired / node-decommission → delete through the same apply boundary + per-node approval. Not targeted by audience/user/cache requests.
  • Scope: state dir only. ~/.nunchi (private memory) and the bot data dir (credentials) get no fallback — unknown files there stay blockers.
  • Scheduler guard: a scratch file referenced by the crontab, the agent-cron task store, or systemd unit/drop-in files (abs/real/~/$HOME/%h forms or bare name) is retain (scheduler-referenced). Any unreadable source → every scratch file retain (scheduler references unreadable) + body-free scheduler_guard status in the plan.
  • Rule order: live claims → key-file → symlink → scheduler guard → age. Orphan SQLite sidecars stay blockers.
  • Extra class state.timed_test_notify_state (live notify state written by timed_test_deadline_scan.py, would otherwise age out as scratch). Inventory text that called *.bak copies "owner-decision blockers" updated.

Verification (re-run independently): retention 43 OK (11 new) · planner 57/0 · apply OK · handoff 16/0 · security audit 18/0 · ruff clean · changelog ok · canon-node-name-scan baseline. New tests fail when the fallback, name matching, or the guard is disabled (19 / 2 / 5 failures).

Local read-only plan (one node): blockers 48 → 2 (one in ~/.nunchi, one in the bot dir); scratch 45 = 4 eligible now · 40 retain-until (earliest 2026-10-27) · 1 scheduler-referenced · 0 key files.

Known limit (safe default): ccc-erasure-apply.py refuses a run whose targets are not owner-only; 24/45 scratch files here are 0644/0755, so an apply would currently be refused. Left as-is (fail-safe); to be decided before the first per-node run.

@seoseo-ai seoseo-ai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved after exact-head validation and fresh operator authorization using the relay-held seoseo-ai credential.

@jinon86
jinon86 added this pull request to the merge queue Oct 23, 2026
Merged via the queue into main with commit cfedf84 Oct 23, 2026
14 checks passed
@jinon86
jinon86 deleted the feat/1468-inventory-cbatch2-groupb-variants branch October 23, 2026 08:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants