Skip to content

fix(memory): back up the default store in the scheduled sweep - #11494

Merged
bolichen97 merged 1 commit into
mainfrom
fix/scheduled-memory-backup-default-store
Sep 17, 2026
Merged

bolichen97 merged 1 commit into
mainfrom
fix/scheduled-memory-backup-default-store

Conversation

@bolichen97

Copy link
Copy Markdown
Collaborator

Problem / Motivation

The daily memory backup skips the default store. heartbeat.py called back_up_all_stores(..., private_only=True), and memory_backup.py skipped every store that is not a member V2 silo. The default Global V1 store, the one every install has, was enumerated and then skipped on every run. An install with no crew member had no automatic memory backup at all. One with members backed up only the small member silos.

On the reporting host: nine member stores each had a fresh backup of about 4 KB, and the 11.8 MB default store carrying every memory the assistant uses had none. Its ~/.kiro/crew/backups directory did not exist.

Why it matters

Memory is the one thing here that cannot be rebuilt from anywhere else. The module's own header says so and names the incident it exists for: a 36 MB store that became 29 bytes with nothing to restore from. That incident was the default store. The sweep protected everything except the store it was written for.

What changed (motivation → approach → change)

The scheduled sweep now copies every active store: the default store first, then declared named V1 stores, then active member V2 stores.

Store Before After
default (Global V1) 🟥 enumerated, skipped 🟩 daily rotating copy
named V1 🟥 enumerated, skipped 🟩 daily rotating copy
active member V2 🟦 daily rotating copy 🟦 daily rotating copy
archived member 🟦 not visited 🟦 not visited

🟩 added · 🟨 changed · 🟥 removed · 🟦 unchanged

The private_only knob is removed rather than flipped. It arrived with the Memory V2 change and nothing in that history states a reason for excluding V1; the spec asserted the exclusion without one, and the module docstring argued the opposite. After the fix no caller wants a member-only sweep: the heartbeat and kirocrew memory backup go through the same loop. Everything downstream already handled the default store. backup_dir_for places its copies under <home>/backups/, the sandbox already masks that directory, the fail-soft loop was written so one broken silo cannot cost the default store its copy, and the 20-hour freshness guard still stops a restart loop from taking a copy every boot.

A config knob (memory.backup_private_only) was considered and rejected: there is no known reason to want the default store left out, so a switch would only make the gap opt-in again.

Text now matches behaviour: the memory.backup_enabled help in config/sections.py, its row in configuration.md, the regenerated config-baseline.json, and the backup sections of memory-skills-hooks.md and slack-gateway.md.

Tests

test/test_memory_resources.py:

  • test_scheduled_backup_pass_copies_the_default_store — runs HeartbeatService._back_up_memory() against a real home and asserts a restorable copy of the default store lands in backup_dir_for(default), with the written semantic row readable from it. This is the regression pin; prove.py confirms it fails with the old call restored.
  • test_automatic_backups_cover_default_and_named_v1_and_preserve_archived_backups — the sweep with the heartbeat's call shape copies default, named V1 and active member stores (backed_up: 3), prunes only their own directories, and leaves an archived member's backups byte-identical.
  • test_first_eligible_heartbeat_schedules_one_backup_without_blocking_ticks — now pins that the scheduled call passes only should_stop, no narrowing keyword.

Related backend set: 21,150 passed. Config baseline test passes on the regenerated file.

Manual verification

N/A — unit coverage sufficient: the heartbeat test exercises the real executor path and the real SQLite backup API against a temporary home.

Related Issues

no linked issue: internal ticket P514524379.

Pattern harvest

Rule candidate: review-prompt
Pattern: "a filter parameter added to a shared loop is hardcoded by its only production caller, so the loop's fail-soft branch for the excluded case is unreachable"

Checklist

  • At most two commits (one is the norm), with a Conventional Commits title (feat|fix|docs|refactor|perf|test|chore|ci|build|revert: ...)
  • Existing tests pass and new tests added for new functionality
  • Self-review completed; code follows project style guidelines
  • Documentation updated (if applicable)
  • No secrets, credentials, or internal references in the diff

The daily backup pass called back_up_all_stores(private_only=True), so
the default Global V1 store was enumerated and then skipped on every
run. An install with no crew member had no automatic memory backup at
all, and one with members backed up only the small member silos while
the largest store, the one every install has and the one that cannot be
rebuilt from anywhere else, had no copy.

Drop the private_only knob: the heartbeat and the CLI now share one
sweep over the default store, declared named V1 stores and active V2
stores. The fail-soft loop, backup_dir_for and the sandbox mask of
<home>/backups already handled the default store; only the caller
excluded it. The setting's description, the memory spec and the
generated config baseline now say what the sweep covers.

sim: https://t.corp.amazon.com/P514524379
@bolichen97
bolichen97 requested a review from a team as a code owner September 17, 2026 09:09
@bolichen97

Copy link
Copy Markdown
Collaborator Author

Intent: The daily scheduled memory backup copies the default Global V1 store (and named V1 stores), not only member V2 silos, so every install has an automatic copy of the one store that cannot be rebuilt.
Not a goal: No change to backup format, placement, retention, the manual dashboard/CLI backup paths, restore, or the snapshot bundle; no new config knob.

@github-actions github-actions Bot added the readiness: checking Automated validation is still running label Sep 17, 2026
@github-actions

Copy link
Copy Markdown
Contributor

GPT 5.6 Review — ✅ no blocking findings

GPT 5.6 completed its review of 21cfcfa690b83d13f0e74eba4336f0431bf7a842 and found no blocking issues.

This comment is updated in place on each push.

Review details

No findings.
[GPT-REVIEWED] 21cfcfa

False positive or not applicable? A repository writer can comment:
/ai-review override gpt 21cfcfa690b83d13f0e74eba4336f0431bf7a842: <one-sentence reason>

@github-actions

Copy link
Copy Markdown
Contributor

Design Review (Fable 5) — ✅ PASS

Design-level review of 21cfcfa690b83d13f0e74eba4336f0431bf7a842 — updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

Design-Verdict: PASS

Verify disk headroom: the daily sweep now retains up to backup_keep copies of the largest store, a cost the old sweep never paid.

[DESIGN-REVIEWED] 21cfcfa

@github-actions

Copy link
Copy Markdown
Contributor

First Principles Review (Fable 5) — ✅ PASS

Premise-level review of 21cfcfa690b83d13f0e74eba4336f0431bf7a842 — why this exists and whether the shipped surface is the smallest honest version. Updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

First-Principles-Verdict: PASS

Verify the one unverifiable claim: that the Memory V2 change's history truly records no reason for excluding V1 from the sweep — the reversed spec pin "V1 backups remain manual" rests on it.

What this change ships

Inventory (5 items) — 5 justified

Intent: give every install a daily restorable copy of its memory, including the default store the sweep enumerated and skipped — a FIX.

  1. The daily scheduled sweep now takes a rotating copy of the default store — justified
  2. Declared named V1 stores also join the daily sweep, same root cause (the filter skipped all non-member stores) — justified
  3. The private_only parameter is deleted from back_up_all_stores (a subtraction; zero remaining references, grepped private_only: 0 hits) — justified
  4. Config help, configuration.md, baseline, and both specs rewritten to match the new coverage, same commit — justified
  5. Test pinning "automatic backups preserve V1" replaced by pins on full coverage, plus a fails-on-base regression test — justified

[FIRST-PRINCIPLES-REVIEWED] 21cfcfa

@github-actions

Copy link
Copy Markdown
Contributor

Opus 4.8 Review — ✅ no blocking findings

Reviewed 21cfcfa690b83d13f0e74eba4336f0431bf7a842 — this comment is updated in place on each push.

Review details

No findings.

[OPUS-REVIEWED] 21cfcfa

Verdict parsed from the review's SHA-scoped output markers for commit 21cfcfa690b83d13f0e74eba4336f0431bf7a842.

False positive or not applicable? A repository writer can comment:
/ai-review override fable 21cfcfa690b83d13f0e74eba4336f0431bf7a842: <one-sentence reason>

@github-actions github-actions Bot added readiness: passed Eligible automated validation passed for the current revision and removed readiness: checking Automated validation is still running labels Sep 17, 2026
@bolichen97
bolichen97 enabled auto-merge (squash) September 17, 2026 10:12
@bolichen97
bolichen97 merged commit 4ca1a5c into main Sep 17, 2026
81 checks passed
@bolichen97
bolichen97 deleted the fix/scheduled-memory-backup-default-store branch September 17, 2026 20:58
@github-actions github-actions Bot removed the readiness: passed Eligible automated validation passed for the current revision label Sep 17, 2026
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