Skip to content

feat(core): client-minted bulk_id + leadbay_bulk_enrich_status composite#13

Merged
milstan merged 1 commit intomainfrom
milstan/bulk-enrich-tracker
Apr 21, 2026
Merged

feat(core): client-minted bulk_id + leadbay_bulk_enrich_status composite#13
milstan merged 1 commit intomainfrom
milstan/bulk-enrich-tracker

Conversation

@milstan
Copy link
Copy Markdown
Contributor

@milstan milstan commented Apr 21, 2026

Summary

Adds a BulkTracker interface + file-backed LocalBulkStore and a new leadbay_bulk_enrich_status composite so agents can poll a bulk contact enrichment by handle instead of looping per-lead. leadbay_enrich_titles now returns {bulk_id, launched_at, durability}, wrapped in a two-phase launch (pending → launched/failed) + sha256 idempotency key that guards against quota double-charge on restart or rapid re-launch. Store lives at ~/.leadbay/bulks.json with atomic writes (fsync fd + dir), in-process mutex, 30-day TTL, per-record corrupt-record isolation, symlink rejection, and loud-failure policy (throws unless LEADBAY_BULK_STORE_ALLOW_MEMORY=1). OpenClaw plugin uses InMemoryBulkStore (fs is sandboxed); MCP stdio gets file-backed durability.

Scoped and hardened via /autoplan with dual-voice CEO + Eng review. Taste defaults resolved at the final gate: include_contacts: false (cheap polls) + single BulkTracker interface (YAGNI on split). Status composite enforces strict UUIDv4 validation before any disk read (path-traversal/LFI defense) with a structured error taxonomy (BULK_INVALID_ID / BULK_NOT_FOUND / BULK_PENDING / BULK_LAUNCH_FAILED / BULK_STORE_UNAVAILABLE / BULK_TRACKER_UNAVAILABLE).

Test plan

  • pnpm -w build — all three packages compile
  • pnpm -r test — 123 tests passing (34 new: 23 store-layer + 11 composite-flow)
  • Store scenarios: happy path, reuse window, idempotency key ordering, concurrent collapse vs distinct, process restart persistence, file mode 0600, corrupt JSON resilience, symlink rejection, path-outside-HOME rejection, TTL boundary, factory loud-failure
  • Composite scenarios: launch → status → all_done flip, include_contacts opt-in, reuse short-circuit (no /launch POST), failed-launch → re-launch allowed, NO_CANDIDATES before tracker, UUIDv4 validation, pending/failed/missing-tracker error taxonomy, partial-failure progress honesty
  • Live smoke via MCP with LEADBAY_MCP_WRITE=1: leadbay_enrich_titles({titles:["CEO"]})bulk_idleadbay_bulk_enrich_status({bulk_id}) round-trip against api-us

🤖 Generated with Claude Code

Adds a BulkTracker interface + file-backed LocalBulkStore so agents can poll
a bulk enrichment by handle instead of per-lead. leadbay_enrich_titles now
returns {bulk_id, launched_at, durability} and a new leadbay_bulk_enrich_status
aggregates progress + contacts across the bulk's leads.

Two-phase launch (pending → launched/failed) plus a sha256 idempotency key
guards against quota double-charge on restart or rapid re-launch. Store lives
at ~/.leadbay/bulks.json by default with atomic writes (fsync fd + dir),
in-process mutex, 30-day TTL, per-record corrupt-record isolation, symlink
rejection, and a loud-failure fallback policy (throws unless
LEADBAY_BULK_STORE_ALLOW_MEMORY=1).

OpenClaw plugin uses InMemoryBulkStore (filesystem is sandboxed per-plugin);
MCP stdio deployments get the file-backed durability.

34 new tests (23 store-layer + 11 composite-flow); full workspace suite: 123
passing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@milstan milstan merged commit e5007bf into main Apr 21, 2026
1 check passed
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.

1 participant