Repository navigation
feat: prove the URL path end to end, and give it a UI - #23
Merged
Merged
Conversation
Three things: a seam test, the bug it found, and the form that makes any of this reachable by a human. The seam test. Every piece of the URL-first path had unit tests and none of them proved the pieces compose, so `crawl_site` moves out of the server's tick into `packages/pipeline/src/crawl.ts` — a seam nothing can call is a seam nothing can test. `crawl.test.ts` then drives the real queue, the real handler and the real chain, and asserts a URL goes in and a person, a score and a recommendation come out. The bug it found. `upsertPerson` deduped only on GitHub's numeric platform id, which a crawl never has: a company page gives `github.com/alexchen`, not the id. Every re-crawl of the same site therefore created a fresh copy of everyone on it. It now matches on the platform id first and falls back to the handle. Handles are renameable and a freed-and-reused handle could match the wrong person, which is why the original avoided them — but that only compares against handles already linked to somebody with evidence, and the alternative was guaranteed duplicates on every crawl. Corrupting the queue beats risking it, so the fallback stays. The UI. `AddByUrl` on /prospects: one URL per line up to a hundred, posting to `by-url` and then polling `batches/:id` with a progress bar. It lists only the failures — ninety-nine successes are noise, and the failures are the reason anyone opens it. The GitHub handle form stays below it for the developer-tooling wedge. Ran live against stripe.com and vercel.com through the HTTP API on a local stack: 202 with a batch id, the duplicate deduped by host, an `ftp://` entry rejected, both jobs claimed and completed in one tick, `Stripe` and `Vercel` identified from json-ld and links. Both produced zero people. That is the honest result and not a defect: homepages describe companies rather than naming individuals, and the model half that would read the prose is capped until 2026-09-01. The mechanism is proven; the yield is not, and will not be until a working key exists. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
feat: prove the URL path end to end, and give it a UI
Three things: a seam test, the bug it found, and the form that makes any
of this reachable by a human.
The seam test. Every piece of the URL-first path had unit tests and none
of them proved the pieces compose, so
crawl_sitemoves out of theserver's tick into
packages/pipeline/src/crawl.ts— a seam nothing cancall is a seam nothing can test.
crawl.test.tsthen drives the realqueue, the real handler and the real chain, and asserts a URL goes in and
a person, a score and a recommendation come out.
The bug it found.
upsertPersondeduped only on GitHub's numericplatform id, which a crawl never has: a company page gives
github.com/alexchen, not the id. Every re-crawl of the same sitetherefore created a fresh copy of everyone on it. It now matches on the
platform id first and falls back to the handle. Handles are renameable
and a freed-and-reused handle could match the wrong person, which is why
the original avoided them — but that only compares against handles
already linked to somebody with evidence, and the alternative was
guaranteed duplicates on every crawl. Corrupting the queue beats risking
it, so the fallback stays.
The UI.
AddByUrlon /prospects: one URL per line up to a hundred,posting to
by-urland then pollingbatches/:idwith a progress bar.It lists only the failures — ninety-nine successes are noise, and the
failures are the reason anyone opens it. The GitHub handle form stays
below it for the developer-tooling wedge.
Ran live against stripe.com and vercel.com through the HTTP API on a
local stack: 202 with a batch id, the duplicate deduped by host, an
ftp://entry rejected, both jobs claimed and completed in one tick,StripeandVercelidentified from json-ld and links.Both produced zero people. That is the honest result and not a defect:
homepages describe companies rather than naming individuals, and the
model half that would read the prose is capped until 2026-09-01. The
mechanism is proven; the yield is not, and will not be until a working
key exists.
Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com