prospector/src
Natalie f6e72bf41f feat(prospector): serial core complete — 6 prototype backend reads (stream/bookings + augments for backfill/voice/dashboard/autopilot) + macsync client reads + api.ts clients
- New sliced modules stream/, bookings/ (thin, real macsync + audit/drafts data, tests, READMEs).
- Augments to tasks/corrections/reports for the rest (cohorts, alignment, dashboard KPIs).
- Extended MacsyncClient with listInboundMessages/listCalls/listCalendarEvents.
- Typed web api.ts for all 6 (shapes from services + prototype).
- Wired modules. All gates pass (type, 301 tests, web build).
- Prepares Waves A/B (views now have data).
2026-06-29 21:49:15 -04:00
..
audit feat(bilingual): add columns + audit/prospects capture + Triage/Detail toggle+dual render (designs/ + LP parity; UI unification foundation). Per MIGRATION-PLAN Phase 1. 2026-06-29 09:22:00 -04:00
auth refactor: restructure to src/ app + @packages/mcp-prospector; off-Claude default; MCP 2026-06-29 06:39:13 -04:00
bookings feat(prospector): serial core complete — 6 prototype backend reads (stream/bookings + augments for backfill/voice/dashboard/autopilot) + macsync client reads + api.ts clients 2026-06-29 21:49:15 -04:00
campaigns feat(service): outbound campaign builder (facets / preview / launch) 2026-06-29 07:49:42 -04:00
classify feat(prospector): on-demand DO GPU fleet + model-boss enrich (Hosts) 2026-06-29 15:59:01 -04:00
clients feat(prospector): serial core complete — 6 prototype backend reads (stream/bookings + augments for backfill/voice/dashboard/autopilot) + macsync client reads + api.ts clients 2026-06-29 21:49:15 -04:00
config docs: correct deploy target (black dead -> DO droplet) + on-demand GPU lifecycle 2026-06-29 07:22:29 -04:00
corrections feat(prospector): serial core complete — 6 prototype backend reads (stream/bookings + augments for backfill/voice/dashboard/autopilot) + macsync client reads + api.ts clients 2026-06-29 21:49:15 -04:00
engine feat(compose): duplicate-send guard on the canonical cockpit send path 2026-06-29 09:11:37 -04:00
engine-svc refactor: restructure to src/ app + @packages/mcp-prospector; off-Claude default; MCP 2026-06-29 06:39:13 -04:00
entities feat(prospector): runtime config for GPU idle auto-teardown 2026-06-29 18:24:47 -04:00
gpu feat(prospector): runtime config for GPU idle auto-teardown 2026-06-29 18:24:47 -04:00
health refactor: restructure to src/ app + @packages/mcp-prospector; off-Claude default; MCP 2026-06-29 06:39:13 -04:00
inbound feat(prospector): auto-runner task queue + peer-network backend 2026-06-29 15:24:42 -04:00
intros feat(prospector): auto-runner task queue + peer-network backend 2026-06-29 15:24:42 -04:00
marketplace feat(prospector): auto-runner task queue + peer-network backend 2026-06-29 15:24:42 -04:00
markets feat(markets): tour-market selector + per-market stats dashboard 2026-06-29 08:03:57 -04:00
pastebin feat(service): operator roster + detail + manual draft/send/screen surface 2026-06-29 07:43:45 -04:00
peers feat(prospector): auto-runner task queue + peer-network backend 2026-06-29 15:24:42 -04:00
prospects feat(bilingual): add columns + audit/prospects capture + Triage/Detail toggle+dual render (designs/ + LP parity; UI unification foundation). Per MIGRATION-PLAN Phase 1. 2026-06-29 09:22:00 -04:00
providers feat(prospector): auto-runner task queue + peer-network backend 2026-06-29 15:24:42 -04:00
reports feat(prospector): serial core complete — 6 prototype backend reads (stream/bookings + augments for backfill/voice/dashboard/autopilot) + macsync client reads + api.ts clients 2026-06-29 21:49:15 -04:00
runner feat(prospector): enhance backend+MCP per MISSING_REQUIREMENTS.md (P0 gaps: real raw classify, booking triad+takeover verdict, composition+confidence, send safety floors incl vendor/human/known, structured returns; add /prospector/classify + mcp tool; richer inbound+runner+gate+people signals; update docs). Builds/tests green. Per PLAN.md + docs/features/mcp/MISSING_REQUIREMENTS.md. 2026-06-29 07:30:08 -04:00
scheduler feat(prospector): auto-runner task queue + peer-network backend 2026-06-29 15:24:42 -04:00
settings feat(prospector): runtime config for GPU idle auto-teardown 2026-06-29 18:24:47 -04:00
stream feat(prospector): serial core complete — 6 prototype backend reads (stream/bookings + augments for backfill/voice/dashboard/autopilot) + macsync client reads + api.ts clients 2026-06-29 21:49:15 -04:00
tasks feat(prospector): serial core complete — 6 prototype backend reads (stream/bookings + augments for backfill/voice/dashboard/autopilot) + macsync client reads + api.ts clients 2026-06-29 21:49:15 -04:00
app.module.ts feat(prospector): serial core complete — 6 prototype backend reads (stream/bookings + augments for backfill/voice/dashboard/autopilot) + macsync client reads + api.ts clients 2026-06-29 21:49:15 -04:00
main.ts feat(web+service): serve web/dist same-origin from the NestJS backend 2026-06-29 08:40:01 -04:00
README.md docs(prospector): document task queue, peer network, GPU fleet + Hosts 2026-06-29 16:06:03 -04:00

src — Prospector backend (NestJS)

The AFK auto-send + operator backend. Feature-sliced: one NestJS module per domain, wired in app.module.ts. Conventions live in ../docs/STANDARDS.md; src/markets/ is the reference module. Each feature documents itself in its own README.md (added/refreshed when the module is built or materially changed).

Feature modules (with routes, features, consumers, ground truth)

All routes prefixed /prospector unless noted. Controllers are thin (HTTP only); logic in services + pure modules. Feature-sliced per STANDARDS.md (markets/ reference). No unnecessary duplication (e.g. pure reports/reports.ts#buildReport reused by reports.service + markets; prospects.segment used across; engine pure shared).

Module Key Routes (methods) Features UI / MCP / Other Consumers Ground Truth (drills down)
health/ GET /health Liveness/readiness (public, no auth) Health checks, deploy scripts health.module.ts, main.ts bootstrap
auth/ (global guard) Service-token auth for all /prospector + /internal (bypass via @Public) All controllers, MCP (token), inbound webhook, clients auth/service-token.guard.ts, public.decorator.ts
settings/ GET/PUT /settings Kill-switch (GO/PAUSE/AWAY mode) + draft_engine ControlView ModeControl, MCP prospector_get/set_mode, runner/scheduler settings.service + entity (singleton id=1), designs for UI
runner/ (internal) AFK decision: state machine → Gate-2 → mode/outcome/holdReason/template Scheduler, inbound process, compose (manual), MCP via reports/activity runner.service (pure decide/gate2 from engine), engine/{state,gate,scam,...}.ts (pure, tested)
engine/ + engine-svc/ (via classify/runner) Pure: fast-classifier, atoms, booking, scam-screen, gate, mr-number, state, send-guard Classify service, runner, inbound, prospects compose engine/*.ts (pure, co-located tests e.g. fast-classifier.test, gate.test), designs for bilingual/qual
inbound/ POST /internal/inbound Mac-sync webhook: inbound → people signals → classify → runner decide → audit/dispatch (or hold) Mac-sync server (webhook), tests inbound.service (process), dto, prospects/compose + audit.record; ground: macsync.client, designs/main-view for flow
classify/ POST /classify Structured classify (text or handle): fast + composition (mr/people/human) + booking + qual verdict Triage toolbar (visible), MCP prospector_classify, inbound classify.service + engine-svc, dto; reuses engine pure + clients
audit/ GET /activity, /held-queue, /digest Decision audit trail (sends/holds), held backlog, time-window digest (+ mac health) Control (ActivityFeed/Digest/HeldQueue), Queue, MCP (prospector_activity/held/digest) audit.service (record from runner/inbound/compose, queries on prospect_drafts entity)
corrections/ POST/GET /corrections Teach-loop: record corrections (vetting + tuning data); list recent Detail correction form, Reports (Patterns), MCP prospector_correction corrections.service + entity, dto; designs/detail + reports-dashboard for teach
pastebin/ GET /pastebin 🌹 canon templates (live from macsync Notes) PastebinView, Triage/Detail/Queue draft (apply), MCP prospector_pastebin, compose.render pastebin.service (fetch/parse via macsync.client), entity? no (dynamic); designs/pastebin-panel.html (sync note), LP handoff for macsync
prospects/ GET /prospects (q=seg/market), GET /prospects/:handle, POST /draft, POST /send, POST /mr-request Roster (segmented life/dates/digital + market E.164 buckets), detail (thread+MR+signals+booking), manual draft (pastebin), send (outbox+dedupe guard), MR request TriageView (list+toolbar+sidebar), DetailView, Queue (release), Campaigns (preview), MCP (prospector_list/thread/draft/send/mr) prospects.service (rollup from prospect_drafts entity + people/mr clients), compose.service, segment.ts (pure), dto; designs/main-view.html (toolbar/bi/roster), detail-view.html; entity prospect-draft
reports/ GET /reports?days= 4 operator reports (funnel, volume, by-seg/market/classif, backlog) + reuse for markets ReportsView (fused 4 + bi), Markets (stats reuse), MCP prospector_reports, Triage sidebar reports.service (uses prospects.rollup() + volume SQL), pure reports.ts#buildReport (reused, unit-tested); designs/reports-dashboard.html (4 tables/filters/bi/drills); entity prospect_drafts
markets/ GET /markets, GET /market-stats?market&days Tour-stop markets (selector + live counts), per-market (peak hours/days, conv by hour, byLocality, funnel) MarketsView, MCP prospector_markets markets.service + registry/tour-window/stats/locality/timezone (pure, tests), reuses reports.buildReport; designs + CLAUDE for tour vs campaign market distinction; entity via prospects
campaigns/ GET /campaigns/facets, GET /campaigns, POST /campaigns, POST /campaigns/preview Outbound campaigns: facets (seg/market/classif), audience preview (matched + samples), launch (to queue/enqueue), history CampaignsView (chips/filter/preview/launch), Triage/Reports integration points campaigns.service + match.ts (pure filter), dto, entity prospect-campaign; prospects for targeting; designs index for outbound; migration 0005
scheduler/ (internal cron) AFK heartbeat / follow-up tick (triggers runner) + drains the task queue (advanceBatch) every 30s Background auto (GO mode), tasks/ scheduler.service; reuses runner + tasks.advancement
tasks/ GET/POST /tasks, GET /tasks/log, DELETE /tasks/history, POST /tasks/bulk/{run,cancel}, GET /tasks/:id, PATCH /tasks/:id/{run,cancel,escalate,abort,requeue} Auto-runner work queue: typed tasks (classify→draft→send children, backfill fan-out), priority + lifecycle state machine, batch claim (FOR UPDATE SKIP LOCKED); inbound enqueues a task on every hold; mutable layer separate from immutable prospect_drafts QueueView (console: board/bulk/log), scheduler (advanceBatch/30s) tasks.service (read model + transitions) + advancement.service (4 pipelines, reuse classify/runner/pastebin/audit), task-state.ts + task-priority.ts (pure, tested); designs/queued-tasks.html; entities prospector-task + prospector-task-log; migration 0007
providers/ GET /provider-graph?q&minMr Cross-provider attestation graph (Report 1): per-handle rollup of peer attestations → composite (mean) MR + contributing providers + signals summary; read-only over provider_attestations (written by peers exchange) ReportsView (cross-provider section) providers.service (load rows) + graph.ts#buildProviderGraph (pure aggregation/filter/sort, tested); entity provider-attestation; migration 0009
intros/ GET /intros?status, PATCH /intros/:id, GET /intros/:id/thread Warm-intro negotiation (Report 2): peer-proposed intros worked through a validated state machine (proposed→accepted→booked/declined/withdrawn), derived outcome + turn count ReportsView (warm section), IntroThreadView intros.service (validated read-modify-write) + intro-state.ts (pure isValidTransition/deriveOutcome, tested); proposals written by peers; entity warm-intro; migration 0010
marketplace/ GET/POST /marketplace, PATCH /marketplace/:id Overflow routing (Report 4): route a prospect to a registered peer; graphScore peer-fit derived from the local attestation graph + latest classification; best-effort peer delivery, accept/reject loop ReportsView (marketplace section) marketplace.service (derive inputs, persist, PeerClient.sendRouting) + graph-match.ts (pure score/flag, tested); imports PeersModule one-way (cycle break); entity marketplace-routing; migration 0011
peers/ GET/POST/DELETE /prospector/peers, POST /peers/:id/ping; /internal/peers/{health,attestation,intro,routing,routing/:externalId/status} Peer registry (trusted sister instances, dual outbound/inbound tokens) + two-direction exchange protocol; /internal/peers/* gated by per-peer PeerInboundGuard (not the operator token); idempotent inbound on externalId; consent gates (attestation needs known prospect; intro/routing land as drafts) Control PeerRegistry panel; PeerClient consumed by marketplace; inbound writes provider/intro/routing rows peers.service + peer-inbound.service (repo writes, no feature-svc deps → cycle break) + peer-auth.ts (pure constant-time, tested) + peer.client + peer-inbound.guard; entity prospector-peer; migration 0008
gpu/ GET /gpu/status, POST /gpu/provision, POST /gpu/teardown On-demand DO GPU droplet lifecycle (DO v2 API) + model-boss enrich: async classifyRich / draftReply behind the fast gate (additive, null-on-failure → fast/pastebin fallback); @Interval idle self-teardown; boots clean with no DO/model-boss secrets HostsView; consumed by tasks/advancement (enrich classify/draft) + classify (handle enrich) gpu.service (lifecycle, idle teardown) + gpu-enriched-classify.service + model-boss.client + do-droplet.client + gpu-status.ts/prompts.ts (pure, tested); designs/hosts-do-gpu.html; entity gpu-droplet; migration 0012

Notes on routes:

  • All /prospector/* (except /internal) protected by service-token guard (injected by fronting proxy in prod; dev via vite proxy).
  • /internal/peers/* are @Public to the service-token guard but gated instead by the per-peer PeerInboundGuard (inbound token → pins req.peer); /internal/inbound is the macsync webhook.
  • Static web/dist served at / (PWA hash routing, no SPA fallback needed).
  • /docs : Swagger (non-prod).
  • Bilingual fields (original_inbound_text, translated_inbound_text, detected_lang) on prospect_drafts (migration 0006); surfaced in prospects responses, used in Triage/Detail/Reports.

UI Features (web/ PWA - hash nav, drills to routes above)

  • Triage (default/home): Segmented roster + search + bi toggle/dual + toolbar (classify/MR/pastebin refresh) + sidebar (funnel + mini queue + GPU info) + counts. Drills to Detail/Queue. Ground: designs/main-view.html + index.html (bi/OCR).
  • Detail (/prospect/:handle): Thread (bubbles bi), composer (draft from 🌹 + send), side MR + correction teach. Ground: designs/detail-view.html.
  • Queue: Task console — board of typed work items (classify/draft/send/backfill) with priority + status, per-item run/cancel/escalate/abort/requeue + bulk run/cancel + per-task log + history clear; runner auto-advances. Ground: designs/queued-tasks.html + tasks/ module.
  • Campaigns: Facets chips + age filter + preview (matched) + launch + history. Ground: new extension, fuses prospects targeting.
  • Reports: Funnel + volume chart + the 4 contracted report sections — cross-provider attestation graph (providers/), warm-intros (intros/), auto-qual + bi draft, marketplace overflow routing (marketplace/) — + by seg/market/backlog + bi toggle. Drills to Triage and IntroThreadView (single warm-intro thread, accept/decline/withdraw/book). Ground: designs/reports-dashboard.html + LP Experiments/Patterns/Actions.
  • IntroThread (/intro/:id): One warm-intro negotiation thread — status transitions + notes, derived outcome/turns. Ground: intros/ module + Reports warm section.
  • Markets: Tour selector + stats (peak, conv, locality) + reused funnel. Ground: designs/markets.html + markets/ pure + CLAUDE tour-market distinction.
  • Pastebin: List templates + sync btn. Ground: designs/pastebin-panel.html.
  • Hosts: DO GPU fleet — droplet status/provision/teardown + model-boss reachability + idle timeout; status only (no live GPU %). Ground: designs/hosts-do-gpu.html + gpu/ module.
  • Control: Mode kill-switch + digest + activity terminal + held + peer registry panel (register/list/ping/soft-remove sister instances) + PWA install prompt. Ground: designs/control.html + peers/ module + PWA handoff.
  • Shared: mac-window styling, PWA standalone (manifest/sw, titlebar hide), hash routing, usePoll, api client (types drill to backend DTOs/responses).

MCP Tools ( @packages/mcp-prospector - thin adapter over routes/services above; full legacy cockpit parity + new ): prospector_submit_inbound, _activity, _held_queue, _digest, _correction, _get_mode, _set_mode, _classify, _draft, _send, _thread, _list, _pastebin, _reports, _mr, _markets. Ground: mcp index/client (maps to /prospector/* or /internal), designs + LP mcp-prospector/README (tools list), engine for classify. The holistic-buildout surfaces (tasks, provider-graph, intros, marketplace, peers, gpu) are PWA/REST-only — no new MCP tools; agents drive the existing classify/draft/send flow and the task queue advances them.

Shared / Ground Truth Layers (drills down)

  • Data model (entities + migrations): prospect_drafts (audit, bi cols post-0006), prospect-correction, prospector-settings, prospect-campaign, prospector-task + prospector-task-log (0007), prospector-peer (0008), provider-attestation (0009), warm-intro (0010), marketplace-routing (0011), gpu-droplet (0012). Source: migrations/0001-0012*.sql + entities/*.entity.ts (TypeORM). Prospects rollup from drafts; tasks are the mutable work layer over the immutable drafts trail.
  • Pure logic (no I/O, unit-tested): engine/* (classify/gate/scam/state/mr/booking/send-guard), prospects/segment, reports/reports.ts (buildReport reused), markets/* (registry/stats etc.), campaigns/match.ts, tasks/{task-state,task-priority}, providers/graph, intros/intro-state, marketplace/graph-match, peers/peer-auth, gpu/{gpu-status,prompts}.
  • IO/Services: .service.ts (DB/clients + call pure).
  • UI client: web/src/api.ts (types + fetchers drill to routes).
  • Designs (visual/behavior contract): designs/*.html (10, PWA-only: index, main-view, detail-view, reports-dashboard, queued-tasks, pastebin-panel, campaigns, markets, control, hosts-do-gpu — ios-prospector-tab removed) — open in browser; all JS mutations, bi, tables, sims.
  • Standards/Defn: docs/PROSPECTOR.md (unified definition — read first), docs/STANDARDS.md (sliced, pure/IO, reuse, tests, READMEs), CLAUDE.md (read defn/designs first, verif, commits), docs/MIGRATION_FROM_LP.md (LP-removal context).
  • Tests: co-located *.test.ts + reports.test etc. (pure logic).
  • Clients: macsync (outbox/notes), mrnumber, people (signals).
  • No duplication: Reuse across (reports pure in markets; engine in classify/runner/inbound; prospects rollup for reports/campaigns/targeting; audit for multiple feeds).

Organization notes: Feature modules own their surface + docs. Cross via index/Module. Bilingual added without dup (cols + capture in inbound/audit/prospects). MCP is adapter (no logic). PWA is client of routes. Everything traces to entities + pure + designs for truth.

See also: docs/MIGRATION_FROM_LP.md (LP removal), deploy.md, each module's code + (add READMEs on material change per STANDARDS).

Shared

Path Purpose
entities/ TypeORM entities mirroring ../migrations/*.sql; export via index.ts.
clients/ Outbound clients (people-service, Mr. Number, macsync).
config/ TypeORM/database config.
main.ts / app.module.ts Bootstrap + module composition root. main.ts also serves the built web/dist PWA same-origin (useStaticAssets); the API stays under /prospector. Override the dist path with PROSPECTOR_WEB_DIST.

Layering rule

controller (HTTP only) → service (I/O + orchestration) → pure modules (domain logic, unit-tested, no DB). Cross-module access goes through a feature's index.ts or its *Module — never a deep internal import.