Skip to content

Conversation

@jdoucett
Copy link
Contributor

Phase 2, Slice 2 — archive wiring (the append engine)

Wires the slice-1 primitives into an opt-in size_routing archive path. Default-off,
so an unset config is byte-for-byte the current whole-target behavior. Full suite
172 → 192 green.

Stacked on #18 (base = feat/routing-primitives). Merge #18 first; I'll rebase this
onto main after. Diff here is only slice-2 changes.

Config (load_config)

  • New keys: size_routing (bool), t_small (int, floored to 100 MB), shard_count
    (null = derive K at baseline), shard_target. All validated; config.example.json
    annotated.
  • Durability guard (RFC §2.4): when size_routing is on, refuse a log_dir under
    $HOME, a scratch path, or the ~/globus_archive_tmp default — the per-target manifest
    at {log_dir}/_vault/ must be shared + durable or reclaim can't find it (a purged
    scratch manifest → every routed target false-DRIFTs). routing_log_dir_ok().

Engine

  • enumerate_source_catalog_excluded — one walk → (survivor catalog, exclusion report); exclusion is applied once, before partitioning (routing partitions the
    survivors).
  • route_and_ship (LOCAL) — partition survivors → objects; skip-unchanged (the
    append win, also the resume mechanism); ship only changed/new objects through the
    unchanged make_zip_files → send_to_fortress chain (only_arcnames per object,
    exclude_spec=None); K frozen from the manifest after baseline; drop deleted slots;
    manifest written atomically after each shipped object (crash-safe resume).
  • __main__ — refuse size_routing + --globus up front (RFC §2.8); the size-routing
    branch replaces the whole-target Step 1/2 and emails a [SUCCESS] per-object summary.
  • object_project_name — per-object log/zip/tar stem (invariant RFC: incremental, split-source Fortress archiving (design only) #4).

Tests — tests/test_routing_wiring.py (20)

Durability guard (home/default/scratch rejected, Depot accepted), config validation,
survivor enumerator incl. exclusion drop, and route_and_ship: baseline ships all •
append ships only the new solo • solo change re-ships just that solo • shard member
change re-ships the whole shard • deleted big file drops its slot • K frozen across runs •
--fresh re-ships all • resume after a mid-run crash (persisted object skips on
re-run) • exclusion recorded in the manifest.

python3 -m unittest discover -s testsRan 192 tests … OK.

Important sequencing

Slice 3 (aggregate reclaim, verify_target) is REQUIRED before any routed target is
reclaimed
— reclaim dedups to the newest log = one object, so today a routed target
would false-DRIFT. Do not enable size_routing on a production config until #18 + this +
slice 3 are all in. (Full restore is the slice-5 capstone.)

🤖 Generated with Claude Code

Wires the slice-1 primitives into an opt-in size-routing archive path. Default-off,
so an unset config is byte-for-byte the whole-target behavior (full suite 172 -> 192).

Config (load_config): size_routing (bool), t_small (int, floored 100 MB), shard_count
(null=derive), shard_target. DURABILITY GUARD (RFC §2.4): when size_routing is on,
refuse a log_dir under $HOME / scratch / the ~/globus_archive_tmp default — the
per-target manifest at {log_dir}/_vault/ must be shared+durable or reclaim can't find
it (routing_log_dir_ok). config.example.json annotated.

Engine:
- enumerate_source_catalog_excluded: one walk -> (survivor catalog, exclusion report),
  the routing data source (exclusion applied once, before partitioning).
- route_and_ship (LOCAL): partition survivors -> objects; skip-unchanged (the append
  win + resume); ship changed/new objects via the SAME make_zip_files ->
  send_to_fortress chain (only_arcnames per object, exclude_spec=None); K frozen from
  the manifest after baseline; drop deleted slots; manifest written atomically AFTER
  EACH shipped object (crash-safe resume). object_project_name = per-object stem
  (invariant #4).
- __main__: refuse size_routing + --globus up front (RFC §2.8); size-routing branch
  replaces whole-target Step 1/2 and emails a [SUCCESS] summary.

Tests: tests/test_routing_wiring.py (20) — durability guard, config validation,
survivor enumerator (incl. exclusion drop), baseline/append/solo-change/shard-change/
delete/K-frozen/--fresh/resume-after-crash, exclusion recorded in manifest.

See docs/RFC_incremental_v2.md §2.5 (slice 2). Aggregate reclaim (slice 3) is REQUIRED
before a routed target is reclaimed, else verify() false-DRIFTs each object log.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign in to join this conversation on GitHub.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant