feat(pipeline): skip extraction when the source has not changed (#105) #109
Closed
mathias
wants to merge 2 commits from
agent/105-source-drift into main
pull from: agent/105-source-drift
merge into: :main
:main
:fix/pipeline-writes-158
:fix/edit-path-io-192
:fix/create-regular-188
:fix/guard-special-179
:fix/linkcheck-keeps-write-178
:fix/write-dir-redirect-173
:fix/tunnel-detect-174
:fix/pipeline-root-157
:w3/154-mcp-auth-wiring
:fix/tunnel-traversal
:test/in-brain-targets-171
:fix/brain-scan-root-157
:fix/graph-wiki-root-157
:fix/vectorstore-root-157
:fix/notes-root-157
:fix/search-root-157
:fix/brainwide-root-157
:fix/raw-symlinks-153
:feat/symlink-tripwire-157
:fix/rest-auth-149
:fix/123-brain-edit-envelope-check
:feat/106-page-aware-extraction
:fix/105-source-drift-on-main
:fix/104-surface-merge-conflicts-on-main
:agent/b1-compile-on-ingest
:agent/104-surface-merge-conflicts
:agent/105-source-drift
:agent/107-loud-unconfigured-alerting
:feat/brain-read-edit
:fix/capture-i1-refusal-names-target
:renovate/configure
:feat/consolidate-single-harness
:icebox/cmd-routing
:feat/brain-pending-promote
:fix/close-session-classification-refresh
:fix/capture-summarywriter
No Reviewers
Labels
Clear labels
agent/ready
blocked/client
blocked/supplier
blocked/upstream
risk/high
risk/low
risk/medium
size/l
size/m
size/s
size/xs
status:dispatch
status:dispatched
status:review
status:reviewing
type/chore
type/decision
type/docs
type/feat
type/fix
type/ops
type/research
type/test
Meets the agent-ready contract; authorizes unattended execution
Waiting on the client
Waiting on a supplier
Waiting on an upstream project or vendor
Irreversible, security-relevant, or control plane
Reversible, local, test-covered
Touches shared state, deploys or data
Too big - split it
Under two days
Under half a day
Under an hour
Maintenance, no behaviour change
Human decision required; never agent/ready
Documentation only
New capability
Corrects broken behaviour
Infrastructure, deploy, runtime
Investigate; output is a finding, not code
Test coverage only
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: mathias/hyperguild#109
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #105. Stacked on #103 — base is
agent/b1-compile-on-ingest, notmain, because the hash lives in frontmatter that only survives a re-ingest because of #103's merge. Review #103 first; this retargets tomainautomatically once that lands.What
Ingest stamps
source_hash— sha256 of the ingested body, frontmatter excluded — onto the source page, and checks it before doing any work. An unchanged source returns early with zero LLM calls.Cost and signal, not correctness
Worth being precise, because the plan had this the other way round. #103 already made a re-ingest byte-identical, so repeating one was harmless — just not free: a full extraction over every chunk to produce a result that merges to nothing.
Building this first would have put idempotency in the guard rather than in the write. The write has to be safe on its own; this is an optimisation on top.
The second half is signal: "this source changed since we ingested it" is information the corpus doesn't have today, and it's the natural input to
half_life(brain#21) — avolatilenote whose source has changed is the highest-value re-verification candidate there is.Three deliberate choices
Body-only hashing. A re-crawl that stamps a new fetch date hasn't changed the source. Hashing the whole file would re-extract the corpus every time a crawler ran. Tested:
TestRun_FrontmatterOnlyChangeIsNotDrift.Absence means extract. No page, no field, unreadable file → extract. A missed skip costs one extraction; a wrong skip loses an update silently, and silence is the failure mode this repo keeps paying for (#100).
The skip is reported.
Result.Skippedplus a warning naming the hash. A run that does nothing must say so, or "the pipeline is fine" and "the pipeline stopped working" look identical — the same argument as #107.The frontmatter-ownership question, settled
#105 asked where the hash should live given #103 made the on-disk block win wholesale. Answer: keep it in frontmatter (survives a corpus move, human-visible) and make ownership explicit.
wiki.Mergenow refreshes a namedgeneratorOwnedset —last_updated,source_hash— and keeps everything else on disk. An allowlist, not a carve-out: a field nobody has thought about stays human-owned by default, which is the safe direction.That also retires the
last_updatedlimitation #103 shipped with, and it's tested against the fields that matter — a human-fixedtitleand the claim envelope (half_life,claim_provenance) both survive regeneration.Tests
Red-first.
TestRun_SkipsExtractionWhenTheSourceIsUnchangedandTestRun_FrontmatterOnlyChangeIsNotDriftfailed by extracting twice;TestRun_ReExtractsWhenTheSourceBodyChangedpassed from the start (today it always extracts) and guards against over-skipping.TestMerge_GeneratorOwnedFrontmatterFieldsAreRefreshedfailed on frozen fields.Call-counting stub rather than an HTTP fixture, so "did it call the model" is asserted directly.
task checkexit 0, full suite green.Note on the rebase
I first branched this off
mainand the helper insertion silently no-opped, becausemaindoesn't have #103's function that my anchor targeted. Caught by the build, not by review. Rebased onto the B1 branch and resolved the append-vs-append test conflicts by keeping both sides.Risk: LOW — the new early return only fires on an exact hash match, and every unknown state falls through to today's behaviour.
Superseded by #126: same commit, rebased onto current
main(this branch's base,agent/b1-compile-on-ingest, merged as #103 with two review-driven fixes on top that this branch predates). Closing rather than force-pushing a rewrite over this branch.Created via git-mcp on behalf of @mathias
Pull request closed