#2438

bug(windows): harden migration temporary allocation and prevent partial wing-name updates

Openfatkobraopened 1mo ago

Summary

mempalace/migrate.py contains two temporary-allocation paths that remain outside #2420:

  • a temporary directory used to construct a replacement palace
  • an adjacent temporary file used to publish the rewritten known_entities.json during wing-name migration

These paths need bounded failure behavior and migration-specific atomicity tests rather than being folded into the config fix.

Current paths

Full-palace migration

migrate() creates a staging palace through tempfile.mkdtemp() before importing drawers and swapping the replacement palace into position.

This path should be audited separately from mkstemp(), because the exact standard-library exception handling may differ, but it must still fail promptly and leave the original palace untouched when staging allocation cannot succeed.

Wing-name migration

migrate_wing_names() currently applies:

  1. drawer metadata updates
  2. closet metadata updates
  3. the topics_by_wing rewrite in known_entities.json

The registry rewrite allocates an adjacent temporary file through tempfile.mkstemp() and publishes it with os.replace().

If that allocation or publication fails after the collection updates, the migration can leave drawer/closet metadata normalized while topics_by_wing remains under the old keys.

Impact

Potential outcomes include:

  • excessive temporary-name retries on affected Windows/Python behavior
  • an apparently hung migration
  • a failed full-palace migration before staging begins
  • a partially applied wing-name migration across drawers, closets, and known_entities.json
  • mismatched search metadata and topic-registry keys

Desired behavior

Shared allocation behavior

  • use a bounded secure temporary allocator
  • retain exclusive creation
  • distinguish genuine collisions from access failures
  • clean up all temporary paths after failure
  • avoid duplicating the private helper introduced in #2420

Full-palace staging

  • fail before changing the original palace when staging allocation is unavailable
  • leave the original palace and its backup state intact
  • emit an actionable error naming the failed staging location
  • verify cleanup when construction fails after staging succeeds

Wing-name migration

The operation should not leave collections and the registry in different naming states.

A complete solution should either:

  • prepare and validate the registry replacement before mutating collection metadata, then publish it as part of a rollback-capable sequence; or
  • snapshot the affected collection metadata and restore it if registry publication fails.

Simply replacing tempfile.mkstemp() without addressing the partial-update order would be insufficient.

Regression coverage

Add tests proving that:

  • denied staging allocation leaves the original palace untouched
  • denied registry temporary allocation leaves drawers, closets, and topics_by_wing mutually consistent
  • an os.replace() failure does not leave a partially applied wing-name migration
  • the prior known_entities.json remains byte-for-byte intact after failure
  • no staging directory or temporary registry file is leaked
  • a genuine temporary-name collision is retried successfully
  • the normal successful migration remains idempotent

Relationship

Follow-up to #2420 and the review observation identifying the remaining migration allocation paths.

Related to #2358 because both involve known_entities.json, but this issue concerns temporary allocation and cross-store migration atomicity. #2358 concerns unreadable or malformed registry input.

Activity

0

No activity yet.