Document crawl execution and result accounting as current behavior - #1365
Open
hmishra2250 wants to merge 2 commits into
Open
Document crawl execution and result accounting as current behavior#1365hmishra2250 wants to merge 2 commits into
hmishra2250 wants to merge 2 commits into
Conversation
…vior
Rewrites the crawl coverage section to describe what the crawl endpoints
report today, without implying the records are complete.
- Renames "Coverage and determinism" to "Execution and result accounting"
and drops every "coverage receipt" / "proof of coverage" framing.
- States that `total` = completed + active + queued + backlog and excludes
failed jobs, so `completed == total` on a finished crawl does not mean
every discovered page succeeded
(apps/api/src/controllers/v2/crawl-status.ts:215-245).
- Documents the real `next` contract: `next` is also emitted whenever
status is not `completed`, so it can be present on terminal failed and
cancelled crawls. Removes the "only fully read once next is absent" loop
guidance, which never terminates on a failed crawl, and gives the
terminal condition as status in {completed, failed, cancelled}
(crawl-status.ts:324-331).
- Lists all four statuses including `cancelled`
(apps/api/src/controllers/v2/types.ts:1477-1505). openapi.json:2810-2813
still lists three; that is tracked as a separate Core/OpenAPI fix and is
deliberately not edited here.
- map.mdx: "exhaustive enumeration" becomes "more thorough recursive
discovery with auditable result and error records"; the pointer to the
`links` scrape format is kept.
- maxConcurrency: 1 caps in-flight requests per the configuration
reference ("maximum concurrent scrapes") and does not remove run-to-run
variation; the determinism claim is dropped.
- Get Crawl Errors: notes the list may omit some failure classes (Core
currently drops SCRAPE_RACED_REDIRECT_ERROR,
apps/api/src/controllers/v2/crawl-errors.ts:44-77) and that the error
code used for EXTERNAL_LINK is not yet in the published schema.
Addresses OB-02 and the developer read D1-D8.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…section Core clamps rather than rejects: apps/api/src/controllers/v2/crawl.ts:248-252 sets `finalCrawlerOptions.limit = Math.min(remainingCredits, finalCrawlerOptions.limit)`, with a comment naming checkCreditsMiddleware as the actual 402 source (insufficient credits to start at all, not limit-vs-credits). The new "What the crawler is scoped to reach" section restated the pre-existing (unverified) 402 claim from line 68 a second time; that restatement is removed here since this branch's whole thesis is documenting only what's confirmed against Core. Line 68 itself is left untouched per review guidance (pre-existing elsewhere on main). Added as item 5 to the Core PR proposal in scratchpad/product-prs/D3-crawl-coverage-v2.md so line 68 gets reconciled too. D3 nit 1, FINAL-REVIEW-docs-mcp.md.
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Automations to automatically generate PRs for you. |
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.
Summary
The crawl docs presented
completedandtotalas a coverage receipt, told callers to page untilnextis absent, listed three crawl statuses where Core returns four, and describedmaxConcurrency: 1as removing run-to-run variation. Each of those is contradicted by Core. Thisbranch rewrites the section to describe what the endpoints actually report, with a Core file and
line behind every behavioral claim, and states plainly that none of the records is a guarantee of
completeness.
Why (evidence)
Source reports: Developer-bank positioning read
(
analysis/loop/run/DEVELOPER-POSITIONING-READ.txt, 2026-08-31) and Weekly Deep InsightsDI-2026-08-30-WEEKLY(2026-08-30).Findings: the developer read's verdict, "The developer bank rejects Firecrawl on PROOF OF COVERAGE".
14 of 59 named traces carry a negative, decline or competitor-advantage verdict, 10 of them in the
interactbucket, including 9 of 10interactive_traversalprompts. Hypothesis H1: adocumented coverage receipt on actions-bearing scrapes converts the decline. Adjudications: D7
TRUE (map is not exhaustive, in Firecrawl's own words), D8 STALE, D2 STALE, and D1, D3, D5
owner-required. OB-02-completeness-objection-is-first-party, grade A minus in the 2026-09-03
review: "quotable verbatim from Firecrawl's own docs, with no coverage contract alongside it."
Verified evidence:
docs.firecrawl.dev/features/crawl"Crawl results may vary between runs of thesame configuration" and "By default, crawl ignores sublinks that are not children of the URL you
provide";
/features/map"This endpoint prioritizes speed, so it may not capture all websitelinks"; developer traces VDEV-201 ("All are convenient and all have the same silent-truncation
failure mode"), VDEV-210, VDEV-213, VDEV-222 ("less control over scroll termination, which is the
crux of your task"), VDEV-226 ("you need exhaustive link enumeration with an audit trail") and
VDEV-953 ("reintroduce exactly the silent-partial-result problem").
Core verification, read-only, each statement checked against source:
apps/api/src/controllers/v2/crawl-status.ts:215-245computestotal = completed + active + queued + backlog. The stats map carries a distinctfailedbucketthat is never summed (
apps/api/src/services/worker/nuq-fdb/queue.ts:1230-1251).crawl-status.ts:324-331:next = (outputBulkA.total ?? 0) > start + iteratedOver || outputBulkA.status !== "completed" ? <url> : undefined.The second disjunct emits
nextfor every non-completedstatus, including terminalfailedandcancelled.apps/api/src/controllers/v2/types.ts:1477-1505:status: "scraping" | "completed" | "failed" | "cancelled".cancelledis reachable viasc?.cancelledatcrawl-status.ts:233-237.apps/api/src/controllers/v2/crawl-errors.ts:44-77returnsnullforerror?.code === "SCRAPE_RACED_REDIRECT_ERROR", plus a.filter(x => x.failedReason)and amode !== "single_urls"drop.(
apps/api/src/lib/concurrency-limit.ts:244-262,apps/api/src/services/worker/nuq-fdb/queue.ts:439-455). Surviving variation sources: bulk sitemapkickoff
scrape-worker.ts:1296-1341, nested sitemap fan-out:1506-1512, priority dequeue:590-595, finish-time result orderingnuq-fdb/queue.ts:1291-1300.delay > 0forcingconcurrency to 1 is confirmed at
concurrency-limit.ts:248-251andqueue-jobs.ts:381-384.types.ts:1110and:1148:limitdefault isz.number().prefault(10000).crawl-status.ts:291:bytesLimit = 10485760.Final verdict: APPROVE per the resolution addendum to
review-grounding/FINAL-REVIEW-docs-mcp.md(the review body records APPROVE-WITH-NITS; the acted-onnit was resolved in commit
0ce9a8ed).Changes
features/crawl.mdx. The section## Coverage and determinismbecomes## Execution and result accounting, and its opener states that the section describes what theendpoints currently report and that "None of these records is a guarantee of completeness." The
strings "coverage receipt" and "proof of coverage" return 0 hits repository-wide.
totalrow becomes "completedplus the pages still in flight: active, queued, andbacklogged. Failed pages are not counted.", with a new
<Warning>explaining whycompleted == totalis uninformative: a terminal crawl has active, queued and backlog at zero, sothe counters converge whether or not pages failed, and failed pages are enumerated only by Get
Crawl Errors.
statusrow lists four values includingcancelled.nextrow states it is also emitted wheneverstatusis notcompleted, and the old<Warning>is replaced by a new### Paging through resultssubsection. Behavior contract: theterminal condition is the status field, not the absence of
next. The documented loop is pollGET /v2/crawl/{id}untilstatusis one ofcompleted,failedorcancelled; whilenextispresent and the last page returned a non-empty
dataarray, follow it; stop whennextis absentor a page returns no new documents.
EXTERNAL_LINKisreworded off the undocumented field name, and a new
<Note>states the list is not guaranteed tobe a complete enumeration because some internal failure classes are filtered out before the
response is built, and that
EXTERNAL_LINKis returned today but is not yet part of the publishedschema. Per the "public docs, no internals" rule the note names the behavior, not the internal
error constant.
maxConcurrency: 1bullet no longer claims determinism. It cites this repo's ownconfiguration table (
features/crawl.mdx:325, "Maximum concurrent scrapes") and states thatcapping in-flight requests reduces timing-dependent interleaving but does not remove run-to-run
variation, because sitemap discovery is enqueued outside the cap, nested sitemaps are fetched as
independent jobs, and the returned
dataarray is ordered by finish time rather than discoveryorder. The caveats cross-reference at
:359was retargeted and "how to make a run reproducible"softened to "more reproducible".
section's
limitbullet (commit0ce9a8ed), because Core clamps rather than rejects:apps/api/src/controllers/v2/crawl.ts:248-252,finalCrawlerOptions.limit = Math.min(remainingCredits, finalCrawlerOptions.limit), withcheckCreditsMiddlewarenamed as the actual 402 source.features/map.mdx:142. "If you need exhaustive enumeration rather than a fast approximation"becomes "If you need more thorough recursive discovery with auditable result and error records
rather than a fast approximation", pointing at the renamed section. The
linksscrape-formatpointer is preserved verbatim.
api-reference/endpoint/crawl-get.mdxandapi-reference/endpoint/crawl-get-errors.mdxcalloutsrewritten to state the
totalexclusion and the incompleteness of the error list directly, ratherthan deferring to a "coverage receipt".
#coverage-and-determinismwas retargeted to#execution-and-result-accountingin allfour referring locations:
features/crawl.mdx:359,features/map.mdx:142,api-reference/endpoint/crawl-get.mdx:7,api-reference/endpoint/crawl-get-errors.mdx:7.openapi.jsonand its mirrorapi-reference/v2-openapi.jsonwere deliberately not edited; theyare recorded as Core/OpenAPI defects below.
Diffstat: 4 files changed, 89 insertions, 1 deletion.
Verification
Independent re-verification against Core during final review confirmed every statement above, and
separately confirmed the stale artifacts the branch declines to touch:
CrawlStatusResponseObj.status.descriptioninapi-reference/v2-openapi.jsonstill reads "Can bescraping,completed, orfailed", andCrawlErrorsResponseObjhas nocodeproperty, itserrors.items.propertiesbeing exactlyid,timestamp,url,error.EXTERNAL_LINKappears inthe OpenAPI file exactly once, in the
allowExternalLinksprose at line 1793, not in the errorsschema, so the page's claim that it is not yet published is accurate.
Grep negative controls: "coverage receipt" and "proof of coverage" return 0 hits across
*.mdx,*.mdand*.jsonin the worktree; "exhaustive enumeration" is gone frommap.mdx.Anchors. All new intra-page anchors resolve:
#execution-and-result-accounting(:245),#paging-through-results(:269),#failed-and-blocked-pages(:283),#configuration-reference(:323),#event-types(:208), plus/features/scrape#scrape-formats(## Scrape Formatsat:138) and/rate-limits. The renamedanchor introduced no dangling references: all four in-repo links were retargeted in the same commit,
and no localized tree referenced it.
mintlify broken-linksunder Node 22 (the default Node 26.4.0 is rejected by the CLI): 208 brokenlinks repo-wide, all pre-existing, and zero in any file this branch touches. Filtering the report for
features/crawl.mdx,features/map.mdx,api-reference/endpoint/crawl-get.mdxandapi-reference/endpoint/crawl-get-errors.mdxreturns no entries. The only non-localized Englishfiles in the report are unrelated and pre-existing:
api-reference/v1-endpoint/llmstxt.mdx,api-reference/v2-introduction.mdx,features/alpha/llmstxt.mdx.mint validate: the same 17pre-existing locale snippet warnings, no touched file.
Core was not modified. No localized file was touched.
Not in this PR
A Core PR, drafted but not filed. Title:
fix(api): correct crawl status/errors OpenAPI schema and drop silent error-class filter. Scope:apps/api/openapi.json(mirrored tofirecrawl-docs/api-reference/v2-openapi.json) andapps/api/src/controllers/v2/crawl-errors.ts. Five items:apps/api/openapi.json:2810-2813: three values, noenum, while Corereturns four. The same schema object contradicts itself two properties later, since
completedAt.descriptionnamescancelledas a terminal state, and sibling schemas in the samefile already carry
cancelledin a realenum. Fix: add"enum": ["scraping", "completed", "failed", "cancelled"].CrawlStatusResponseObj.total.descriptionsays "The total number of pages that were attempted tobe crawled", which is wrong. Fix: describe it as completed plus in-flight, excluding failed. v1 is
byte-identical at
apps/api/src/controllers/v1/crawl-status.ts:205-222and needs the sametreatment.
CrawlErrorsResponseObjomitscode, which the response type declares (types.ts:1520-1531) andthe controller populates. Clients rely on
EXTERNAL_LINK, a field the spec denies exists.crawl-errors.ts:44-77silently dropsSCRAPE_RACED_REDIRECT_ERROR. Combined with item 2, such apage appears in neither the counters nor the error list. Preference order: stop filtering; or move
those URLs into a third explicitly named array; or at minimum document the omission.
features/crawl.mdx:68, already onorigin/mainand left untouched here, claims a 402 rejectionwhen remaining credits cannot cover the
limit. Core clamps instead(
crawl.ts:248-252). Fix: correct the doc line once Core confirms the clamp is intended, or makeCore reject if the clamp was unintentional.
Also noted for whoever picks that up: the DB-backed fallback branch (
crawl-errors.ts:78-159, usedonce the Redis crawl record has expired) derives
timestampfromcreated_atrather than finishtime, so
timestampsemantics differ between the two paths.Remaining docs nits, not acted on: "auditable" in
map.mdxis slightly warmer than the samebranch's own Note admitting the error list is incomplete; and the new scope section restates the
limitdefault of 10000, which also appears at line 68 and in the configuration table.Out of scope entirely:
/extractand scrapeactionshave no documented partial-result signalanywhere (developer read D1, D3, D5). That is a product decision, not a docs one.
Links
Files changed:
features/crawl.mdxfeatures/map.mdxapi-reference/endpoint/crawl-get.mdxapi-reference/endpoint/crawl-get-errors.mdxEvidence packet:
agent-experience-deepinsights-cleanroom/artifacts/deep-insights-sep3-verification-20260904/