A fixed eight-step DAG, not a freeform model call.
The outreach engine's runtime entry, runOutreachLogic in src/lib/outreach/logic-runtime.ts:64-71, walks the same eight steps on every send, each one delegating to one of eleven skills under skills/<name>/.
pre_check_suppression
→ resolve_greeting
→ draft_v1
→ critique_v1
→ refine_loop
→ send_invariant
→ render_email
→ deliver
Every run terminates in one of six recorded statuses:
The DAG's shape is mirrored in a human-readable LOGIC.md contract, logic/outreach.logic.md, and a drift-detection test (tests/drift-detection.test.ts) parses that contract and compares its step names, needs, and branch conditions verbatim against the TypeScript runtime; the build fails if the two diverge. A second, independent LOGIC.md contract, logic/voice-qualify.logic.md, governs a separate voice-agent qualify, decide, book flow. Terminal statuses and every step's verdict and duration are persisted as a structured trace to engagements.logic_trace (migration 022), surfaced in the admin console.
The application runs on Next.js 16 and React 19 against Supabase Postgres with row-level security, sending through Resend and drafting through NVIDIA NIM. A standalone Python worker handles lead scraping and scoring, and a standalone Python voice agent handles outbound calls. Contract tooling is published as devDependencies: @covenant-md/cli and @covenant-md/core at ^1.0.0, @logic-md/cli and @logic-md/core at ^1.5.0, the same contract families documented at COVENANT.md and LOGIC.md.
Every figure below traces to a git command, a file count, or a line citation.
Two rows have a documented internal contradiction in the project's own docs. Rather than smoothing it over, this page states both readings and which one it uses; see the notes below the table.
| Metric | Value | Evidence |
|---|---|---|
| Total commits | 325 | git log --oneline | wc -l |
| First commit | 2026-04-25, 5101508 "chore: initial commit — docs and reference materials" | git log --reverse --format='%ad %h %s' --date=short | head -1 |
| Last commit | 2026-07-24, a9e2a4a "docs: record the self-serve onboarding arc in STATUS + CHANGELOG" | git log --format='%ad %h %s' --date=short | head -1 |
| Commit authors | Rainier Potgieter 323, Operator 2 | git shortlog -sn --all |
| Git tags / releases | 0 | git tag -l (empty) |
| Commits by month | Apr 2026: 14, May: 122, Jun: 159, Jul: 30 | git log --format='%ad' --date=short | cut -c1-7 | sort | uniq -c |
| Tracked files (total) | 587 | git ls-files | wc -l |
| TypeScript LOC | 25,737 lines / 207 files (excl. .d.ts) | git ls-files | grep -E '\.ts$' | grep -v '\.d\.ts$' | xargs wc -l |
| TSX LOC | 7,427 lines / 55 files | git ls-files | grep -E '\.tsx$' | xargs wc -l |
| Python LOC | 7,316 lines / 48 files (worker/, voice/, python-webscrape/) | git ls-files | grep -E '\.py$' | xargs wc -l |
| SQL LOC (migrations) | 4,381 lines / 53 files | git ls-files | grep -E '\.sql$' | xargs wc -l |
| Markdown LOC | 20,803 lines / 154 files | git ls-files | grep -E '\.md$' | xargs wc -l |
| JS/MJS LOC | 3,491 lines (16 .mjs scripts, 1 server.js) | git ls-files | grep -E '\.(mjs|js)$' | xargs wc -l |
| Vitest tests (self-reported, latest) | 593 | STATUS.md:23 (dated 2026-07-24) |
| Vitest call sites (grep-counted, independent) | 528 it( + 8 test( + 2 it.each() groups, 61 files | git ls-files | grep -E '\.(test|spec)\.(ts|tsx)$' | xargs grep -ohE "\b(it|test)(\.each\([^)]*\))?\(" | sort | uniq -c |
| Worker (Python) pytest functions | 50 | git ls-files | grep -E '^worker/tests/.*\.py$' | xargs grep -c "def test_" |
| Voice (Python) pytest functions | 51 | git ls-files | grep -E '^voice/tests/.*\.py$' | xargs grep -c "def test_" |
| Covenanted skills | 11 (11 SKILL.md + 11 COVENANT.md) | git ls-files | grep -E '^skills/.*(SKILL|COVENANT)\.md$' | wc -l |
| Supabase migrations | 53, spanning 001_leads_table.sql to 20260724000000_046_onboarding_selfserve.sql | ls supabase/migrations | wc -l |
| API routes (route.ts) | 8 | find src/app/api -name route.ts |
| LOGIC.md contracts | 2: logic/outreach.logic.md, logic/voice-qualify.logic.md | ls logic/ |
| Published package deps for contracts | @covenant-md/cli / core ^1.0.0, @logic-md/cli / core ^1.5.0 (devDependencies) | package.json:36-39 |
| .db files in repo tree | 2, both inside the gitignored sa-lead-pipeline/ subtree | find . -name "*.db"; cross-checked against .gitignore:45,48 |
| sa-lead-pipeline local SQLite row counts | pipeline.db: businesses 2074, pipeline_runs 38, reviews 0. admin_leads.db: leads 1253 | sqlite3 -readonly ... "SELECT COUNT(*) ..." |
| Live tenant lead-row counts (self-reported, not independently verified) | ss-leader 11,874; kamel-potteries 1,305; ccs-pos 3,614 | STATUS.md:8-9, cross-referenced by CHANGELOG.md |
| Deploy target (Next.js app) | cPanel + Phusion Passenger, lead.singlesource.co.za, booted by server.js | DEPLOY.md:1-3 |
| Deploy target (scrape worker) | Render, two services (ss-leader-scrape-worker, ss-leader-scrape-cron) | render.yaml:12-31, DEPLOY.md:74-97 |
STATUS.md reports two different Vitest totals in the same file: 593 at line 23 (dated 2026-07-24) and 549 in its own gates section at lines 100 to 101, stale relative to line 23 and never reconciled in the document. This page uses 593, the later and more current figure, and separately verifies scale through the grep-counted call-site row above, which is independent of either self-reported number.
README.md and CLAUDE.md both state the Next.js application deploys to Render, served at lead.singlesource.co.za. DEPLOY.md gives an explicit cPanel plus Phusion Passenger target for that same URL, is the more detailed and more recently structured account, and flags the cPanel cron residue from any earlier scrape attempt as legacy. This page follows DEPLOY.md; only the separate Python scrape worker deploys to Render.
One drafting engine, one cross-channel funnel, two ingestion paths.
The Next.js 16 App Router app (src/app/) serves a public marketing, pricing, and checkout surface, a per-tenant admin console under src/app/t/[tenant]/admin/{leads,outreach,pipeline,settings}, and a 9-step self-serve onboarding wizard under src/app/onboarding/. Server code lives under src/lib/, split into outreach/ (31 files: the drafting-and-send engine, including logic-runtime.ts, logic-expr.ts, nim-client.ts, resend-client.ts, and WhatsApp and Zernio-calling variants), orchestration/ (the cross-channel state machine: journey.ts, consent.ts, callback-queue.ts, router.ts, send-hook.ts), billing/, booking/, onboarding/ (AI document extraction via unpdf and mammoth), admin/, and supabase/ (SSR client factories).
Above the email pipeline, HARNESS.md specifies a cross-channel funnel: a per-lead journey state machine, per-channel consent gates, an inbound-signal routing table, and a callback-queue lifecycle, implemented in src/lib/orchestration/ and held in lockstep with the spec by tests/harness-drift.test.ts. Channels: email (cold, POPIA legitimate-interest basis plus opt-out) and WhatsApp via Zernio plus voice calls (warm opt-in only; no cold path exists in the routing table). The standalone voice/ Python package runs a second LOGIC.md-governed qualify, decide, book flow and shares a Google Calendar client with the email and booking path.
Data flows into the businesses table from two paths: the vendored, read-only lead-pipeline/ and sa-lead-pipeline/ Python stacks (Google Places discovery, Playwright enrichment, scoring), and scripts/import-leads.mjs, a CSV importer with three-layer dedup and a confidence-tiered name-write gate. A separate standalone Python worker/ (Python 3.12, asyncio, deployed to Render) runs its own claim-and-execute scrape loop against pipeline_jobs rows, independent of the vendored pipelines. Persistence is Supabase Postgres with row-level security and tenant_id scoping across tenant-owned tables; 53 migrations run from 001_leads_table.sql (initial schema) to 20260724000000_046_onboarding_selfserve.sql (storage buckets and document metadata for self-serve onboarding).
Five decisions visible in the commit history.
Monolith-to-DAG refactor
no behaviour changeBefore what the repo's own docs call "Prompt J," the entire outreach pipeline lived inline in a single roughly 1,100-line server-action file, outreach-actions.ts, that built prompts, called NIM, validated, critiqued, refined, gated sends, and rendered email in one place, with no record of how a given draft was reached. It was refactored, without changing behaviour, onto three layers: eleven covenanted skills, a DAG runtime, and a LOGIC.md contract kept honest by a drift test.
Rebrand from a prior client project
May-Jun 2026The repository's early history is a differently branded product built for a named client, RH Improvers (rhimprovers.co.za). Commits through May and June 2026 systematically rename brand tokens, environment variables, and UI copy from that client to SS Leader and SingleSource AI. The old client's Supabase project reference and tenant config remain in immutable historical migrations (007, 013, plus the RH config set) but are net-removed by migration 026; the documented live-database invariant checked at go-live is zero RH Improvers rows.
git log; CLAUDE.md:61-68; supabase/migrations/20260602010000_026_remove_rh_tenants.sqlAnti-hallucination by construction, not by prompting
two validatorsThe drafter is constrained to write one paragraph into an owner-verbatim template rather than a full email, and a tenant's validator_config (banned phrases and patterns, required phrases) is enforced twice: once as the drafter's non-throwing advisory check, and again as a send-time hard, throwing gate. The codebase's own documentation describes this as "two validators, not merged."
Purpose narrowed, then partially reversed
held locallySTATUS.md records a 2026-07-19 decision not to pursue self-serve SaaS "for now," with tenants hand-provisioned instead. Five days later, on 2026-07-24, held locally and not yet pushed as of the last commit, a full self-serve onboarding arc shipped anyway: one-command tenant provisioning (scripts/provision-tenant.mjs) and a 9-step wizard with AI document pre-fill.
Split deploy targets, not one platform
docs disagreeThe Next.js application deploys to cPanel and Phusion Passenger, while the Python lead-scrape worker deploys separately to Render as two services. README.md and CLAUDE.md both state the application itself deploys to Render, served at lead.singlesource.co.za, which contradicts DEPLOY.md's explicit cPanel target for the same URL. DEPLOY.md is the more detailed and more recently structured account, and explicitly flags the cPanel cron residue from any earlier scrape attempt as legacy; this page follows DEPLOY.md.
Four months, 325 commits, one rebrand in the middle.
Project scaffold: Next.js init, Supabase leads table, initial contact API, all under the pre-rebrand client identity.
Bulk of core buildout: outreach drafting, review and critique, tenant config, and the engagement rename and refactor in migration 009.
Rebrand from the prior client identity to SS Leader and SingleSource AI across brand tokens, environment variables, and database config; RH-tenant removal in migration 026; the outreach-to-covenant, skill, and DAG refactor documented in docs/architecture/outreach-as-logic.md.
Cross-channel funnel build across briefs 026 to 039: WhatsApp send and inbound via Zernio, an email-reply intent classifier, voice callback drain, booking plus Google Meet, a release-readiness audit in brief 037, and off-limits-boundary documentation hardening in brief 038.
Lead-scoring completeness (score_v3 across all seven axes), an operator-triggered backfill, the hook system opened from a closed union to tenant-defined strings, drafter resilience (bounded parse-retry, an expanded model chain), and the self-serve onboarding wizard in migration 046, held locally as of the last commit.
What this dossier does not cover.
- This dossier covers only the ss-leader repository as committed to its own git history.
- It excludes the vendored, gitignored
lead-pipeline/andsa-lead-pipeline/Python subtrees, each its own separate git repository and read-only per project policy, from the LOC and test metrics above, though their two local SQLite databases are reported in the Hard numbers table. - No production Supabase database was queried for this dossier. The live tenant row counts above are self-reported in project documentation, not independently verified against a live database.
- Several claims in STATUS.md, including migrations 042 through 046 and the self-serve onboarding arc, are explicitly marked as held locally and not yet applied to the live database as of the last commit. They are reported here as documented, not as deployed.
Evidence: compiled from the ss-leader repository on 2026-08-03. Every number on this page traces to a file path or command output in the source tree. Last updated: 2026-08-03.