Repository navigation
Add king-scrape update for incremental corpus refresh (ADR-0014) - #51
nelsonmfinda wants to merge 2 commits into
Conversation
|
Hey Nelson, took a careful read through. Strong PR, the audit + update What stood out as good:
What I need before I merge:
A couple of things I noticed but I am leaving to your judgment. If
On the `setdefault` fix you flagged in the description, splitting Let me know how you want to play the e2e and I will move on the merge |
|
Ran the e2e you proposed in my earlier review against I consolidated feedback across your four open PRs (#51, #52, #53, #54) into that issue and suggested unifying them into one PR rather than juggling four with overlapping cli.py edits. Open to whichever shape works on your side. Happy to run the e2e again on whatever you ship. |
* fix(db): make insert_documentation an upsert (closes #48) * fix(scraper): one chunk failure no longer aborts enrich batch (#47) * refactor(scraper): promote URL canonicalisation to shared helper New module ``king_context.scraper.url_utils`` exposes ``canonicalize_url``, lifted verbatim from ``audit._canonicalize``. ``audit.py`` re-exports the private name for compatibility with its own callsites. Pure refactor, no behaviour change. Sets up shared use from ``update.py`` in a follow-up commit where URL diff parity between corpus_urls and fresh_urls needs the same normalisation. * fix(scraper): chunk_pages reads real URL from page sidecar chunk_pages used md_file.stem as source_url, so every chunk produced by the scraper carried slug-form URLs like docs-example-com-quickstart instead of the real https://docs.example.com/quickstart. Pre-existing since the chunk module landed; the consequence surfaced in #51 as noisy added_urls / removed_urls diffs when update compared corpus_urls (slug-form, written by this path) against fresh_urls (real URLs, from the provider). Fix: read the real URL from the page sidecar fetch.py writes alongside each <slug>.md as <slug>.meta.json. When the sidecar is absent or unreadable (legacy _temp/ from pre-#46 scrapes), fall back to the slug so existing work directories continue to chunk. Backward compat at the corpus boundary: committed data/*.json files keep their slug-form URLs until the next refresh writes through the new path. The audit command's URL canonicalisation absorbs the transient mismatch in the meantime. Four new tests cover the sidecar-present, sidecar-missing, sidecar-malformed, and url-key-missing branches. * feat(scraper): king-scrape update (ADR-0014) + cache bypass + 6 fixes * fix(scraper): _resolve_source_url handles explicit null _meta
Summary
king-scrape update <name>. Refetches upstream of an indexed corpus, rechunks, reuses every section whose chunked content is byte identical to the previous scrape. Only new or changed chunks hit the LLM, so a typical refresh costs cents instead of dollars. The integrity unit is the chunk'scontent_hashfrom ADR-0012; reused sections carry forwardkeywords,use_cases,tags,prioritybut adopt freshtitle,path,urlso an upstream page reorganisation is reflected.Related issue
Closes #18
Type of change
How it was tested
pytest -q
725 passed, 1 skipped
24 tests in
tests/test_scraper/test_update.py:_section_hash(with and without_meta),_resolve_source_url(meta vs base_url fallback),_build_reuse_index,_plan_updateclassification + added/removed URL_section_hash(with and without_meta),_resolve_source_url(meta vs base_url fallback),_build_reuse_index,_plan_updateclassification + added/removed URL diffs,_materialise_reused(carries enrichment, takes fresh identity),_interleave_in_chunk_orderorderingpages/,chunks/,enriched/,manifest.jsonall wiped; safe on clean dir--corpus-pathbypasses lookup, missing path returns 1,--providerflag overrides env, user-abort returns 1, missing corpus returns 1Haven't run a live update against a real corpus in this PR. Happy to do that as part of review if you want; the audit subcommand from #N (PR 2) plus this one is the natural pair to demo on
data/elevenlabs-api.json.Checklist
pytest)docs/and/orREADME.mdif behavior changed (new "Refresh an indexed corpus" section indocs/CLI_GUIDE.md, command overview row, ADR-0014 added under.king-context/adr/, CHANGELOG entry)Additional notes
A few choices worth flagging:
auditfrom Add king-scrape audit subcommand for corpus drift #49 (PR 2): a four-lineif argv[1] == "update":branch incli.main. No argparse subparser refactor. Two subcommands now use this dispatch; a third would justify the refactor.pages/,chunks/,enriched/,manifest.jsonwiped). Without this, two distinct critical bugs fire: staleenriched/batch_*.jsontriggers the resume logic inenrich.pyand silently returns OLD enriched chunks instead of fresh ones; and orphanpages/*.mdfrom URLs no longer accepted by thefilter survive
chunk_pagesand resurface as "reused" sections in the new corpus. Both bugs surfaced in the senior code review pass before push and are now covered by tests. At 10x corpora the reset matters more, not less; cheap and unconditional is the right call.ValueErrorbefore writing and the originaldata/<name>.jsonis untouched. Tested.os.replace. An interrupted update never leaves a partial JSON file indata/<name>.json.fetch_pagesgains aforce_refresh=Truekeyword arg. Update calls it withTrueso changed upstream pages are actually re-downloaded instead of being skipped by the existing slug-presence resume logic. Provider Protocols (ADR-0010) are untouched: this is a pipeline-side flag.enrich_chunksis not called at all (saves one disk-stat round trip and is unambiguously correct). Tested.UpdateReport.lost = 3, a warning prints, and the CLI summary includeslost 3. Pre-fix this was a silent drop.--corpus-pathflag for non-standard layouts (CI artifacts, monorepo subprojects). Bypasses the defaultdata/<name>.jsonand.king-context/data/<name>.jsonlookup.--providerflag overrides env. Existingcli.run_pipelineusessetdefaultand silently ignores the flag whenSCRAPE_PROVIDERis already set; new code in update fixes thatfootgun for its own surface (
os.environ["SCRAPE_PROVIDER"] = ...). Stage-specific envs (SCRAPE_DISCOVER_PROVIDER,SCRAPE_FETCH_PROVIDER) still take precedence per ADR-0009. The same fix should land incli.run_pipelineas a follow-up, but that's out of scope here.auto_seed=Falseon the export. Update writes back to the corpus committed in the repo, not to the local indexed MCP store. After a successful update, refresh the local index withkctx index .king-context/data/<name>.json(orkctx index --all). Matches the project's existing ethos: indexed retrieval state is reproducible from the JSON committed in the repo, never the source of truth.Independent of
auditfunctionally; the two compose well as a pair (audit to see drift, update to act on it). ADR-0014 records the rationale and rejects the alternatives (page-level reuse, full rescrape under a flag, diff-against-audit-report, mutate corpus in place without atomic write).