Skip to content

Harden backup and restore: recursive discovery, content fidelity, safe targets (card 71) - #21

Merged
chrishonson merged 2 commits into
releasefrom
agent/card-71-recovery-fidelity
Oct 30, 2026
Merged

chrishonson merged 2 commits into
releasefrom
agent/card-71-recovery-fidelity

Conversation

@chrishonson

Copy link
Copy Markdown
Owner

Summary

Hardens Firestore backup and restore fidelity, validation, and target protection (card 71 RECOVERY):

  • Recursive discovery & phantom parent preservation (D1, D3): Discovers all root collections, subcollections, and subcollections under phantom parents. Preserves phantom parent semantics during backup and restore.
  • Extended Firestore codec & stable serialization (D2): Added support for GeoPoint, Buffer/Uint8Array bytes, DocumentReference, and non-finite numbers (NaN, Infinity, -Infinity). Enforces loud failure for unrecognized types and reserved __fs field keys. Introduced stableStringify for byte-identical recursive serialization regardless of key order.
  • V2 manifest format with checksums (D3): Schema metacortex-firestore-full-backup-v2 with per-collection SHA256 checksums, document counts, byte counts, and observed vector dimensions. Manifest is written last, ensuring partial runs never leave invalid manifests. Stale NDJSON files are removed automatically. Full backward compatibility with v1 manifests.
  • Strict pre-write archive validation (D4): validateArchive runs in dry-run and write mode before any target writes. Validates schema, file existence, SHA256 checksums, JSON syntax, unique IDs, tag decoding, and vector dimensions.
  • Safe target protection & replacement rules (D5): Refuses writes to production project my-brain-88870. Restoring to source project requires --target-prefix or explicit confirmation. Default write mode is upsert-only; --prune and --clear-target-collections require --confirm-project <target>. Aborts on vector model/dimension mismatches or unknown embedding spaces before any writes.
  • Content-fidelity verification (D6): Verifies restored document content equality and checksums instead of count-only checks. Reports differing IDs (missing, extra, changed capped at 20 each).
  • Interruption resilience (D5): Aborts on write failure with RESTORE INCOMPLETE: ... re-run the same command to finish; upserts are idempotent.
  • Portable archive hardening (D8): Added validatePortableArchive checking schema, IDs, content, retrieval text, metadata timestamps, and dangling superseded_by links before writes. Guarded live collection writes with --replace-live and --confirm-collection.
  • Comprehensive test suite: 11 required unit test cases in functions/test/recovery.test.ts using InMemoryMirrorStore, and real emulator tests in functions/test/recovery.emulator.test.ts exercising recursive discovery, backup, restore, real Firestore types, content corruption detection, and vector similarity search.
  • Updated documentation: Updated docs/FULL_BACKUP.md, docs/MEMORY_ARCHIVE.md, and appended the dated local verification record to metacortexplan.md.

🤖 Generated with Claude Code

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-30T15:30:20.145954Z c6caeab PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c6caeab2f1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

process.exit(1);
}

const config = loadConfig(process.env);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid requiring application secrets for full backups

On a backup or recovery host configured only with Firestore credentials, this new loadConfig() call aborts because config.ts requires both MCP_ADMIN_TOKEN and GEMINI_API_KEY. Neither secret is used by the full-backup operation, and the previous command worked without them. The same dependency was added to full restore, unnecessarily blocking recovery when application secrets are unavailable. Read and validate the embedding settings independently of the application's authentication and Gemini configuration.

Useful? React with 👍 / 👎.

Comment on lines +720 to +724
const expectedFileName = ndjsonFileName(entry.path);
if (entry.ndjson !== expectedFileName) {
problems.push(
`ndjson file name mismatch for ${entry.path}: expected ${expectedFileName}, got ${entry.ndjson}`
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Accept original filenames when validating v1 archives

For legacy archives containing collection IDs with spaces, Unicode, or other URI-escaped characters, this comparison rejects valid backups. The previous backup implementation used ${collectionId}.ndjson, whereas ndjsonFileName() now applies encodeURIComponent(). Although readManifest() normalizes v1 entries, it retains their original filenames, so a collection such as release notes always fails validation and cannot be restored. Validate legacy filenames using the v1 naming convention while retaining the encoded convention for v2.

Useful? React with 👍 / 👎.

Comment on lines +180 to +184
if (isDocumentReference(value)) {
const encoded: EncodedReference = {
__fs: "reference",
path: value.path
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve database identity in archived document references

If a document contains a reference to another project or named database, recording only value.path loses the referenced database's identity. Restore then resolves every reference through target.referenceFor(p), silently redirecting that external reference into the restore target. Content verification also encodes only the relative path, so it reports success despite the changed reference. Preserve the reference's project/database identity and distinguish external references from references intentionally migrated with the source database.

Useful? React with 👍 / 👎.

@chrishonson
chrishonson merged commit d050e74 into release Oct 30, 2026
7 checks passed
@chrishonson
chrishonson deleted the agent/card-71-recovery-fidelity branch October 30, 2026 16:02
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