PageSourceSearch

https://app.leadcognition.io/assets/source-map-builder-evidence-first-tlkt2SB4.js

js leadcognition.io collected 2026-10-08 23:15:42 UTC 25,036 bytes, 2 lines download raw bytes

1const e='# Source Map Builder v4 — Evidence-First\n\n> Status: **spec / not implemented**. Author: 2026-07-24 session.\n> Supersedes nothing yet. Extends the LC-469 evidence ranking that lands with `feat/lc-1117-integration`.\n\n## Naming\n\n**v4** is the source-map builder generation, chosen to sit unambiguously after the existing\n`discover-source-v2.ts` (v2) and the `v3` app-rewrite branch. Modules are named `discover-source-v4.*`\nand the Inngest function `source-map-build-v4`. v4 ships **alongside** v2 behind an org-level flag —\nit is not a rewrite of `discover-source-v2.ts`, and both must be runnable on the same org so their\noutput can be scored against each other (see Comparison harness).\n\n## Why — measured evidence, not intuition\n\nEvery requirement below traces to a production measurement taken 2026-07-24 across five customer orgs\n(AskUI, Expanso, Aikido, Partner Way/Joinvinci, Reply.io).\n\n### The lead-count formula\n\n`people ≈ sources × avg_users_per_repo` — accurate to <10% on all five orgs.\n\n| Org | Sources | avg users/repo | people (actual) |\n|---|--:|--:|--:|\n| AskUI | 24 | 30 | 692 |\n| Expanso | 9 | 942 | 7,946 |\n| Aikido | 58 | 997 | 51,059 |\n| Partner Way | 54 | 175 | 9,300 |\n| Reply.io | 58 | — | 10,138 |\n\nCustomer lead volume is therefore set almost entirely at source-selection time. **The builder is the\nsingle highest-leverage component in the product.**\n\n### Popularity does not predict yield\n\n| Repo | Stars | People found (90d) |\n|---|--:|--:|\n| `RasaHQ/rasa` | 21,265 | **8** |\n| `botpress/botpress` | 14,822 | **1,419** |\n\n1.4× the stars, 177× fewer developers. The builder currently ranks on `log1p(stars)`\n(`discover-source-v2.ts` tie-break) and gates on `>=50 stars OR >=10 forks`. Both measure the repo;\nthe product sells developer reach.\n\n### Star farms poison inventory\n\nContributor share of 90-day actors, measured:\n\n| Repo | Org | People | % contributors |\n|---|---|--:|--:|\n| `KeygraphHQ/shannon` | Aikido | 1,405 | **1%** |\n| `swisskyrepo/PayloadsAllTheThings` | Aikido | 827 | **1%** |\n| `oomol-lab/open-connector` | Reply.io | 3,372 | **1%** |\n| `TakSec/google-dorks-bug-bounty` | Aikido | 42 | **0%** |\n| `aquasecurity/trivy` | Aikido | 1,242 | 12% |\n\nThe distinction that matters is **not** low contributor ratio by itself — `trivy` at 12% is healthy,\nbecause a stargazer on a competing *product* is expressing evaluation intent. The bad case is\n**content repos** (awesome-lists, tutorials, cheatsheets, payload/dork collections, `*-skills`\nrepos), whose stargazers are students and hobbyists, not buyers.\n\nAlso measured: `marcusquinn/aidevops` on Reply.io produced **94,923 signals from 156 people** — one\nperson\'s monorepo firehose, 58% of that org\'s entire signal volume.\n\n### Recency is a quality axis, not just a cost axis\n\nPeople with a signal in the last 3 months:\n\n| Org | All-time | Active <3mo | Kept |\n|---|--:|--:|--:|\n| Aikido | 51,073 | 9,176 | **18%** |\n| Reply.io | 10,138 | 7,361 | 73% |\n| Partner Way | 9,300 | 8,350 | 90% |\n| Expanso | 7,951 | 6,871 | 86% |\n| AskUI | 695 | 695 | 100% |\n\nAikido was the only org backfilled at 12 months. Its 41,897 stale people average **1.5 signals each**;\nthe 9,176 active carry 61% of all signal at **11.0 each**. Deep backfill bought dead contacts.\n\n`org_lead_data` has **no date filter**, so recency must be applied as a filter, never by deleting\nsignals (which would destroy the trend history the product sells).\n\n### Dead and mislabeled sources ship today\n\n- Partner Way had **6 sources with zero signals ever** (removed 2026-07-24).\n- `is_competitor` / `is_first_party` drift from `source_category` on **29 + 9** rows repo-wide\n  (GH #2875). Partner Way had 20 competitor sources invisible to the UI; Reply.io 9 first-party.\n- `source_category` is **never written by the automated pipeline** — the only non-null values in\n  production arrived via manual PATCH.\n\n## Do not rebuild — what already exists\n\n| Capability | Status | Where |\n|---|---|---|\n| Builder runs inside Inngest (`step.run`) | **Done** | #2852, `workflows/discover-source-map.ts` |\n| Evidence-aware ranking, quality gate | **Done** | #2869, `rankEvidenceAwareSources` |\n| Buyer evidence from our own signals | **Done** | #2869, `loadSourceBuyerEvidence` |\n| `evidenceText`, `icpComponents` populated | **Done** | #2869 |\n| Zero-activity floor (archived / 12mo / maintainer-only) | **Done** | `meetsActivationFloor` |\n| Auto-generated category views | **Built, unshipped** | `discover-generated-views.ts` (c9c25b358, LC-1121) |\n| Grounded retrieval (LLM emits search terms, GitHub Search retrieves) | **Done** | LC-658 |\n\nv4 **extends** these. It does not re-implement them.\n\n## Gaps v4 closes\n\n| # | Gap | Today |\n|--:|---|---|\n| G1 | No real contributor measurement for never-before-seen candidates | `loadSourceBuyerEvidence` reads our own `signals`; unseen repos fall back to `log(stars)` |\n| G2 | No contributor-vs-stargazer gate | No contributor count exists anywhere in the pipeline |\n| G3 | No deterministic content-repo filter | Regexes live in dead `discover-phase1.ts`; v2 has only LLM prompt text |\n| G4 | `source_category` never auto-populated | Blocks G5 **and** makes LC-1121\'s generated views a silent no-op |\n| G5 | `is_competitor`/`is_first_party` derived from acquisition channel | `discover-activation.ts:388,400` |\n| G6 | `evidenceUrl`, `activationDecision` never written | Manual PATCH only |\n| G7 | Builder LLM defaults to `gpt-4o` (2024 model) | `LLMAPI_DISCOVER_V2_MODEL` unset in prod |\n| G8 | No realtime progress | `sourcemap_build` reserved at `realtime.ts:90`, zero publishers |\n| G9 | No quality measurement of builds | No scores, no experiments, no regression signal |\n| G10 | MCP tool path still synchronous | `routes/tools.ts:400` untouched by the lane |\n\n## Architecture\n\n```\ninngest.createFunction({\n  id: "source-map-build-v4",              // -vN bump on step restructure (see gotcha)\n  singleton:   { key: "event.data.orgId", mode: "skip" }
1,\n  cancelOn:    [{ event: "discover/source-map.cancel", match: "data.sessionId" }],\n  throttle:    { limit: N, period: "1d" },   // platform-level cost ceiling\n  concurrency: { limit: 2, key: "event.data.orgId" },\n  retries: 2,\n}, { event: "discover/source-map.build" }, async ({ event, step, publish }) => {\n```\n\n| Step | Primitive | Notes |\n|---|---|---|\n| `plan` | `step.ai.infer` | **Opus 4.8**, structured output. Product/ICP reasoning, search terms, owners |\n| `retrieve` | parallel `step.run` **per query** | GitHub Search. One step per query = per-item retry |\n| `prefilter` | `step.run` | G3 content regex + archived/stale. Deterministic, pre-LLM, pre-spend |\n| `yieldProbe` | `step.run` | **G1/G2.** ONE batched BigQuery scan over ALL candidates |\n| `rank` | `step.ai.infer` **per batch** | **Opus 4.8**, structured output. Extends `rankEvidenceAwareSources` |\n| `gate` | `step.run` | G2 ratio gate + zero-yield rejection |\n| `persist` | `step.run` | **G4/G5/G6** — full metadata, category as source of truth |\n| `views` | `step.run` | Reuses `upsertGeneratedViews()` from LC-1121 |\n| `score` | `step.score` | **G9** — yield-based quality score |\n\n`publish(orgActivityChannel(orgId).status({ jobType: "sourcemap_build", ... }))` after every step — **G8**.\n\n### The yield probe is the core idea (G1/G2)\n\nBigQuery cost is **per date-window, not per repo** — dry-run measured, 2026-07-24:\n\n```sql\nSELECT actor.login, type, repo.name FROM `githubarchive.day.202605*`\nWHERE repo.name IN (<6 repos>)\n-- totalBytesProcessed: 8,468,996,889  (8.47 GB)\n```\n\n8.47 GB per month-window **whether the IN list holds 6 repos or 600**. So a single batched 90-day\nprobe measures every candidate for ~$0.16–0.30. This makes measured selection strictly cheaper than\nthe current guess-from-stars approach, which pays the same backfill cost *after* choosing wrong.\n\nPer candidate the probe returns:\n\n```ts\ntype YieldProbe = {\n  fullName: string;\n  people: number;          // distinct non-bot actors, 90d\n  contributors: number;    // distinct actors with a meaningful (non-Watch/Fork) event\n  stargazers: number;\n  contributorRatio: number;   // contributors / people\n  signalsPerPerson: number;   // firehose detector (aidevops = 608)\n};\n```\n\nBot exclusion must anchor on `[bot]` suffix and `-bot` delimiter, never bare `bot` (LC-774 —\nover-matched real humans: talbot, abbot).\n\n### Gates (G2/G3)\n\n```ts\n// G3 — deterministic, runs BEFORE any LLM spend. Ported from discover-phase1.ts.\nconst CONTENT_REPO = /\\b(awesome[- ]|cheat[- ]?sheet|tutorial|roadmap|100[- ]days|\n  payloads?[- ]all|google[- ]dorks|interview[- ]questions|learn[- ]|-skills$|study[- ]guide)/i;\n\n// G2 — applied AFTER the yield probe\nreject if contributorRatio < 0.05\n  AND NOT isFirstParty\n  AND NOT (isCompetitorProduct && people >= 200)   // trivy @ 12% must survive\nreject if people === 0                              // zero measured yield\nflag   if signalsPerPerson > 100                    // monorepo firehose → review, don\'t auto-activate\n```\n\nThe competitor-product carve-out is essential: stargazers on a rival *product* are evaluation intent\n(`snyk/cli`, `aquasecurity/trivy`). Stargazers on a *content* repo are not. G3 separates the two\ndeterministically so G2 can be strict without discarding real intent.\n\n### Reuse the existing taxonomies — do NOT invent new ones\n\nTwo **orthogonal** taxonomies already exist and are canonical. v4 must consume both; inventing a\nthird of either is how #2875-class drift starts.\n\n**Axis 1 — `source_category`: relationship to the customer.** SEVEN values, defined in code *and*\nenforced by the database:\n\n```\nnative_connector | competitor | integration_platform | multi_tool | adjacent | first_party | known_customer\n```\n\n| Where | What |\n|---|---|\n| `packages/shared/src/discover.ts:67-75` | `discoverSourceCategorySchema` (Zod) + `DiscoverSourceCategory` |\n| `packages/shared/src/filters.ts:77-85` | `sourceCategoryFilterSchema` — an existing **duplicate** of the same 7 values |\n| `packages/db/drizzle/migrations/0062_lc1088_source_metadata.sql:50-57` | live Postgres CHECK constraint |\n\nImport `discoverSourceCategorySchema`; never hand-author this list. Note `known_customer` currently\nhas **zero rows in production** but is permitted by the constraint and read by\n`buyer-value-persistence.ts` and `lead-filters.ts:254` — deriving the enum from observed data (as\nthis spec\'s first draft did) silently drops it. *Data shows what exists; only the schema shows what is\npermitted.* Follow-up worth doing: collapse the `filters.ts` / `discover.ts` duplication into one\nexported enum (see #2875).\n\n**Axis 2 — `FINE_CATEGORIES`: market category.** 37 slugs from **LC-990** (commit `0fdd6cc8e`,\n2026-06-23, "canonical category taxonomy — shared spine for source-map × dossier"):\n\n| Where | What |\n|---|---|\n| `packages/shared/src/categories.ts:48-86` | `FINE_CATEGORIES` — 37 
1slugs + parent mapping + aliases |\n| `packages/shared/src/categories.ts:90-182` | `resolveFineCategory`, `resolveStarCategory`, `classifyCategory` — deterministic regex fallback, **no LLM** |\n| `packages/shared/src/deanon/star-signals.ts:3-10` | `StarCategory` parent axis: `observability, devtools, cloud-native, data-engineering, security, ai-ml, databases` |\n| `apps/server/src/data/discover-snapshots/categories.json` | 5,472 lines, 37 snapshots, 6–20 source repos each |\n| `apps/server/src/lib/category-source-repos.ts:1-21` | `sourceReposForCategory(slug)` |\n| `apps/server/src/lib/category-cache.ts` | 24h DB cache (`category_source_cache`, LC-1962) |\n\nSample slugs: `ai-search-and-rag`, `ai-coding-agents`, `developer-testing-and-qa`,\n`gpu-and-ml-infrastructure`, `browser-automation`, `application-security`, `data-pipelines`,\n`mcp-developer-tools`, `authentication-infrastructure`, `llm-gateway-and-proxy`,\n`workflow-orchestration-and-task-queues`, `crm-and-workflow-automation`.\n\n**CORRECTION (2026-07-24, after review): `FINE_CATEGORIES` must NOT constrain source selection.**\n\nAn earlier revision of this section claimed that "0 of 203 sources resolve to a canonical slug" was a\ndefect to fix. That was wrong, and acting on it would have destroyed the most valuable map we have.\n\n`FINE_CATEGORIES` was generated by `discover-category-snapshot-export.ts` from **YC company tags** —\nit is a YC-startup-shaped vocabulary. Verified against the 37 slugs:\n\n```\nslugs matching automotive|embedded|hmi|vehicle|can|hardware|cockpit|hil : NONE\nslugs AskUI would be forced into                                        : browser-automation,\n                                                                          developer-testing-and-qa\n```\n\nThose two are the **exact categories LC-1116\'s design explicitly excludes** ("Playwright, Cypress,\nSelenium, API-test, unit-test, load-test … are excluded from initial activation"). AskUI sells\nautomotive IVI / HIL / embedded-HMI test automation and is *not* a web-testing company. Forcing its\nsources into the canonical vocabulary would relabel the map as the thing the customer isn\'t.\n\n**The niche tags are the product moat, not noise.** AskUI has the highest employer density of all five\norgs — 88 named employers from 692 people (12.7%), surfacing BMW AG, Bosch, Ford, CARIAD, Keysight —\nprecisely because its sources are automotive-specific rather than generic QA.\n\n**The real defect is that only a human can currently produce niche tags.**\n\n| Org | Tag origin | Result |\n|---|---|---|\n| AskUI | hand-written `packages/db/scripts/lc1116-askui-source-map.ts` | `automotive-platforms`, `can-diagnostics`, `embedded-hmi`, `hil-system-test`; evidence 100% distinct |\n| Expanso | automated pipeline | `["integration_platform"]` (an echo of `source_category`); 9 sources share 3 evidence strings (38% distinct) |\n\nSo v4\'s highest-value job is to make the **plan** step (Opus 4.8) derive the customer\'s own niche\nvocabulary from their site + ICP, and tag every source against it — replacing the bespoke-script\nrequirement. This is the same conclusion as brain idea `idea-2026-07-08-001` (source ICP-fit should\nmeasure buyer-**audience**, not topic relevance; GH #2357/#2358): a niche tag is an audience claim,\nwhich is why a generic topical vocabulary cannot substitute for it.\n\n**Four axes, separated.** `source_tags` currently mashes three of these into one array:\n\n| Axis | Example | Role in v4 |\n|---|---|---|\n| **Niche tags** — per-customer, LLM-generated at plan time | `automotive-platforms`, `can-diagnostics` | **PRIMARY.** Drives targeting and generated views |\n| Provenance / quality marker | `qualifying-source`, `research-source` | Own field — not a category, must stop living in `source_tags` |\n| Relationship | `first_party`, `competitor` | Already `source_category`; stop echoing it into tags |\n| Canonical rollup | `developer-testing-and-qa` | **Optional, nullable.** Cross-customer analytics + the existing category-lead-loader only. NEVER a selection constraint or a view axis |\n\n**Generated views therefore group by niche tag, not `source_category`.** LC-1121\'s\n`deriveGeneratedViews()` groups by `source_category` (≤7 relationship buckets);
1 the hand-built\n`lc1124-*` views (Aikido "SCA & container scanning", "Cloud & IaC security"; AskUI "CAN &\ndiagnostics", "Embedded HMI") are niche-tag views. That is the axis to generate from.\n\n**Revised metadata eval metrics** — "% canonical" is the wrong metric and is replaced by:\n\n| Metric | Definition | Baseline |\n|---|---|---|\n| anti-pattern exclusion | zero activated sources match the customer\'s declared exclusion list (AskUI: web/browser testing) | would have caught the original 45-source Cypress/Selenium map |\n| taxonomy discrimination | niche tags partition sources into >1 group and no tag equals `source_category` | Expanso fails (1 echo tag) |\n| evidence distinctness | `distinct(evidence_text) / count` | AskUI 1.00, Partner Way 0.88, Reply.io 0.53, Expanso **0.38** |\n| ICP dimension independence | `categoryFit != audienceFit` on most rows | AskUI **0/24** (script wrote one value into both) |\n| `evidence_url` present | non-null | 24/203 (AskUI only) |\n\nOther live enums on adjacent axes, for completeness (do not conflate): `discoverRepoBucketSchema`\n(`verified-first-party | strong-match | adjacent-market`), `discoverActivationDecisionSchema`\n(`active | activate | path_only | first_party_audience | known_customer | review_deactivate`),\n`discoverPatternTypeSchema` (`literal | wildcard`), and `discoverRepoSourceSchema` (acquisition\nchannel — the field #2875 wrongly derives `is_competitor` from). `companies.tech_categories` is an\nopen free-text vocabulary, is 11–25% wrong, and its LLM classifiers are FROZEN — do not use it here.\n\n### Classification as single source of truth (G4/G5)\n\n`source_category` is written from the LLM\'s `relationship` output, and the booleans become derived:\n\n```\nsource_category ∈ { first_party, competitor, adjacent, integration_platform, ecosystem }\nis_first_party  := source_category = \'first_party\'      -- generated/derived, never hand-set\nis_competitor   := source_category = \'competitor\'\n```\n\nThis closes GH #2875 at the source rather than backfilling drift forever, **and** it is the\nprecondition for LC-1121\'s generated views to produce anything at all.\n\n## Evals (G9)\n\nInngest shipped these; use the primitives, not the pre-1.0 AgentKit framework\n(`@inngest/agent-kit` is 0.13.2).\n\n| Primitive | Status | Use |\n|---|---|---|\n| `step.score()` | Beta (2026-06-30) | Attach yield-based quality score per build |\n| `group.experiment()` | **GA** (2026-06-23) | A/B models + prompts on live traffic |\n| `createDefer` | Beta (2026-06-05) | Score after the 30-day yield window closes |\n\n**We have objective ground truth** — rare for an eval. Scores need no LLM judge:\n\n```ts\nstep.score({ name: "median_source_yield",     value: median(activated.map(s => s.people)) });\nstep.score({ name: "pct_zero_yield_sources",  value: zeroYield / activated.length });\nstep.score({ name: "median_contributor_ratio",value: median(activated.map(s => s.contributorRatio)) });\nstep.score({ name: "pct_content_repos",       value: contentRepoCount / activated.length });\n```\n\nLabeled regression examples from production, all measured:\n\n| Repo | Must be | Why |\n|---|---|---|\n| `botpress/botpress` | **selected** | 1,419 people |\n| `RasaHQ/rasa` | rejected/low | 8 people despite 21k stars |\n| `KeygraphHQ/shannon` | **rejected** | 1% contributors |\n| `swisskyrepo/PayloadsAllTheThings` | **rejected** | content repo, 1% |\n| `aquasecurity/trivy` | **selected** | 12% ratio but real competitor product |\n| `chatwoot/chatwoot` | **selected** | 319 people, correct ICP for Joinvinci |\n| `marcusquinn/aidevops` | **flagged** | 608 signals/person firehose |\n\n`group.experiment()` settles the model question empirically instead of by argument:\n`gpt-4o` (current) vs `claude-opus-4-8` vs `claude-fable-5`, scored on `median_source_yield`.\n\nInngest has no golden-dataset/offline-batch harness. If that\'s wanted later, **Langfuse**\n(MIT, self-hostable) fits the existing Hetzner/Coolify pattern.\n\n## Models (G7)\n\nVerified available on the LLMAPI gateway 2026-07-24 (253 models). `gpt-5.6`/"Sol" and `opus-5` are\
1n**not** on the gateway.\n\n| Stage | Model | $/M in | $/M out | Rationale |\n|---|---|--:|--:|---|\n| `plan` | `claude-opus-4-8` | 5.00 | 25.00 | One call, deep product reasoning, highest leverage |\n| `rank` | `claude-opus-4-8` | 5.00 | 25.00 | Ranking decides the whole product\'s inventory; quality over cost |\n\nOpus 4.8 on **both** stages, by decision 2026-07-24. A cheaper rank model was considered and\nrejected: ranking is the step that actually selects sources, and source selection determines customer\nlead volume outright (see the lead-count formula). `claude-fable-5` remains the fallback if Opus\ncapacity or latency becomes a problem — swap via `LLMAPI_DISCOVER_V4_RANK_MODEL`.\n\nBoth support native structured outputs — removes the hand-rolled JSON parse that currently throws\n(`discover-source-v2.ts`). Avoid Gemini here (`structured_outputs: false`).\n\nMeasured cost today: **14 source-map generations = $1.24 total ($0.089 each)**. Projected v4 with Opus on both\nstages: ~$0.60-0.90 LLM + ~$0.30 probe. Against a $299/mo customer whose entire value rests on source quality,\nthis is not a cost decision.\n\n**G7 is shippable immediately and independently**: set `LLMAPI_DISCOVER_V2_MODEL=claude-opus-4-8`\nin Coolify. No code, no deploy.\n\n## Sequencing — must not fork the in-flight lane\n\n`feat/lc-1117-integration` is 77 files / +10,495 / 4 ahead / 2 behind main, with **no PR to main**,\nand depends on unpushed commit `c9c25b358`. v4 branches from it only after it lands.\n\n```\n1. LC-1135  drizzle snapshot repair          ← blocks all migration authoring\n2. LC-1121  push c9c25b358 + migration 0066\n   └── G4 (populate source_category) MUST ride along, or generated views ship as a no-op\n3. LC-1123  buyer readiness\n4. LC-1118  full acceptance\n5. integration → main\n6. v4        branch from main once integration has landed\n```\n\nIndependent of the above, any time: **G7** (env var), **G3** (content regex, XS), **G5** (#2875).\n\n## Niche-tag assignment must be semantic, never keyword-matched\n\nRecorded 2026-07-24 after a measured failure. A first implementation of `assignNicheTags` matched a\nniche slug to a source when the slug\'s words (length >= 4) appeared in the source\'s name, description,\ntopics, or language. Run against all 203 production sources with AskUI\'s real LC-1116 taxonomy, it\nfailed in **both** directions at once:\n\n**False positives — 22 non-AskUI sources tagged automotive**, because `hil-system-test` yields the\nEnglish words `system` and `test`:\n\n| Source | Wrongly tagged | Matched on |\n|---|---|---|\n| `swisskyrepo/PayloadsAllTheThings` | `hil-system-test` | "Pen**test**" |\n| `projectdiscovery/nuclei` | `hil-system-test` | "**test**" |\n| `bacalhau-project/bacalhau` | `hil-system-test` | "**system**" |\n| `TakSec/google-dorks-bug-bounty` | `hil-system-test` | "**test**" |\n\n**False negatives — AskUI\'s entire CAN & diagnostics group got no tag**, because `can-diagnostics`\nyields only `diagnostics` (`can` is 3 chars) and none of these descriptions contain that word:\n\n```\nlinux-can/can-utils        "Linux-CAN and SocketCAN user-space applications"\ncantools/cantools          "CAN bus tools"\nhardbyte/python-can        "Controller Area Network support for Python developers"\npylessard/python-udsoncan  "Python implementation of the UDS ISO-14229 standard"\ncommaai/opendbc            "Python API and DBC data for vehicle signals"\n```\n\n**Root cause: a repo\'s vocabulary is not its category\'s vocabulary.** `can-utils` *is* CAN\ndiagnostics and contains neither word. This is not fixable with a stopword list or word-boundary\nregex — the approach is wrong. It is the same error class as the first contributor-ratio gate: a\nmechanical proxy substituted for a semantic judgment. It is also precisely why LC-1116 required a\nhuman.\n\n**Therefore:** the rank-step LLM assigns niche slugs (it already sees every repo in the batch, so the\nmarginal cost is ~zero and the judgment is semantic). Deterministic code does **validation only** —\n`validateNicheAssignments` keeps 
1slugs that exist in the taxonomy, collects invented ones in\n`unknownSlugs`, honours the LLM\'s `isAntiPattern` flag, and puts anything with zero valid slugs into\n`untagged` for human review. Prefer untagged over guessed.\n\n## Risks\n\n- **Inngest step restructure breaks in-flight runs** — bump the function id (`-vN`) before reordering\n  `step.run()` calls. See `gotcha_inngest-step-restructure-breaks-inflight`.\n- **BQ daily cap is advisory only** — observed 2026-07-24: `Daily cap exceeded (log-only): current\n  92.86 GB, projected 129.89 GB, cap 100.00 GB`, and it proceeded. A runaway probe is not stopped.\n  Enforce via Inngest `throttle` rather than relying on the cap.\n- **Bun SQL double-encodes jsonb** — `${JSON.stringify(x)}::jsonb` stores a jsonb *string*; filters go\n  silently inert. Use `::text::jsonb`, verify with `jsonb_typeof`, and read back through a *different*\n  connection. See `gotcha_bun-sql-jsonb-double-encode`.\n- **Bun SQL flattens JS arrays** — `= ANY(${arr})` produces `malformed array literal`. Pass as JSON\n  and `jsonb_array_elements_text`.\n- **Shrinking a customer\'s list is customer-visible** — Aikido\'s correct source map is ~85% smaller\n  than today\'s. Ship as a filter (reversible), communicate before, never as silent deletion.\n';export{e as default};
2//# sourceMappingURL=source-map-builder-evidence-first-tlkt2SB4.js.map

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.