Read the mosquito bundle's renamed effort field (unblocks the weekly refresh) - #68
Conversation
The mosquito release merged upstream on 2026-08-05 rebuilt every site bundle with an effort_week table that emits effort_days instead of trap_nights, so the 2026-08-09 scheduled refresh failed closed at the first site (ABBY) and published nothing. Canonical artifacts and both live surfaces were unaffected. This is not a pure rename: old trap_nights summed trapHours/24 over every trap row, new effort_days sums it only over rows the source marks valid (occurred, usable duration, usable identity). Same unit, QC screened population, so a refreshed denominator can shrink and mosq_activity can rise where unusable deployments existed. Mosquito rows are descriptive context and enter no pooled vote, so no inferential claim changes. cascade_mosq_effort_field() resolves whichever field the bundle publishes, preferring effort_days exactly as the producing app does, failing closed when neither exists and refusing a bundle set that mixes bases. cascade_mosq_effort_note() appends the QC-screened sentence to the published mosq_trap_nights codebook entry only when the build actually read effort_days, so the caveat travels with the number. The independent recomputation in test_helpers.R resolves the same two names literally rather than calling the build helper, keeping that check independent. Also adds report-only scripts/report_mosq_effort_delta.R and wires it into the refresh job summary, plus a publish dispatch input (default true) that can only narrow publication, so a dry run can show the value deltas before anything is committed to master. Note for review: data/cascade_meta.rds records build_script_md5 and source_adapters_md5, so the exact-reproduction gate is expected to fail on this source head until the artifact family is regenerated with scripts/rebuild_all.R and promoted as a direct child. Under CI's pinned siblings the adapter falls back to trap_nights, so only those two recorded hashes should move. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CP23xFrMeWj7PS4i19aH7Q
The rebuild-contracts red on this head is global.R's build-logic
lineage guard firing on source("global.R"), not the byte-reproduction
gate; every later step skipped, so the run yields no evidence about
whether any value moved.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CP23xFrMeWj7PS4i19aH7Q
CI blocker — not fixable from a source-only change
It failed at the first step, That is Consequence for reviewing this PR: every later step skipped — sibling fetch, rebuild, byte gate, manifest compare. So this run produced no evidence about whether any value moves. My expectation that only the two hashes move under pinned siblings is still just a code-reading claim; treat it as unverified until a regeneration says otherwise. Why I am not pushing a fixThe guard is fail-closed by design and there is no source-only way past it — the artifact family has to be regenerated. That needs To unblock
The weekly refresh stays red until step 3 lands. Nothing is at risk in the meantime: the live app and Pages continue serving the last good family, and the failed refresh wrote no bytes. Generated by Claude Code |
Rebuilt with scripts/rebuild_all.R on the pinned contract (R 4.5.2,
OpenBLAS 0.3.26 Haswell/one thread, RSPM noble 2026-07-15 closure
installed with pak) against the seven sibling commits recorded in the
artifact's own source lock. All 9/9 stages passed and promoted.
Every scientific component is byte-identical to the committed baseline:
annual (510x54), pooled (12x20), priors, signals, codebook (52x7),
site_meta (46x24), suite_links (552x33). Only the recorded build-code
lineage moved - build_script_md5, source_adapters_md5, and the
local_build_inputs row carrying them - which propagates into
cascade.rds$meta, search_index.rds$source_bundle_md5, and manifest.json.
data/neon-cascade-codebook.csv is unchanged, confirming the conditional
effort note kept the base sentence because the pinned mosquito bundle
still publishes trap_nights.
This clears the boot-integrity guard that failed run 31318332872
("cascade.rds build-logic lineage differs from the running source").
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CP23xFrMeWj7PS4i19aH7Q
Promoting the regenerated family tripped the registered-baseline tripwires: phenology-v2-seal1-synthetic and discharge-feasibility-f1- offline both assert the five canonical SHA-256 values, and rebuild-contracts asserts them inline. Re-registers cascade, search, meta and manifest (codebook unchanged) across ci.yml, discharge-f1-inventory.yml, test_phenology_adapter_v2.R, discharge_f1_contract.py, verify_discharge_f1_inventory.py and the three live spec tables. Editing DISCHARGE-FEASIBILITY-SPEC.md changed its own registered identity, so SPEC_SHA256 and SPEC_BLOB are re-registered in the three discharge files as well. Dated handoff receipts and prototypes/ are deliberately untouched: the former are history, the latter records the artifact it was derived from. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CP23xFrMeWj7PS4i19aH7Q
The agent container is content-correct but not byte-compatible with CI. Decisive test: a clean worktree at unmodified master 0f61ee6, rebuilt here with the same pinned siblings, failed to reproduce master's own committed artifacts. readRDS comparison shows identical content with a 9-byte compressed-stream difference (110113 CI vs 110122 here); no gzip/xz/bzip2 level reproduces CI's bytes. Restores data/, manifest.json, the five gate registries and the three spec tables to the master values. The hashes announced in the two preceding handoff entries are withdrawn - they came from a non-conforming builder and must not be registered. The source change stands: under pinned siblings the full contract suite passed here, including the mosquito effort-calendar recomputation at 416 site-years, and the codebook regenerated byte-identical. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CP23xFrMeWj7PS4i19aH7Q
I tried the regeneration here. It doesn't hold up — reverted.Correcting my earlier comment: I said this container couldn't regenerate the family because it had no R. It turned out to be the same OS as CI (Ubuntu 24.04.4 noble), so I installed the pinned contract — R 4.5.2 from Posit r-builds, OpenBLAS 0.3.26 Haswell/one-thread, the closure installed with pak from the CI then failed at the byte gate, and it was right to. The decisive test
The delta is environmental and pre-existing, nothing to do with the mosquito change. Comparing CI's Byte-identical content, a ~9-byte difference in the compressed stream. What the exercise did proveThe adapter change is correct. Under the pinned siblings the full contract suite passed here, including The real blocker is a process gap, and it's your callA build-code change necessarily changes the recorded lineage, so Three options:
I'd suggest (1) now to unblock the weekly refresh, and (3) when there's time. Nothing is degraded meanwhile: the failed refresh wrote no bytes, the canonical family is untouched, and both live surfaces serve it normally. Generated by Claude Code |
A build-code change necessarily rewrites the recorded build lineage, so rebuild-contracts cannot go green on a source-only head: the family must be regenerated by a builder whose bytes match this CI runner. There was no in-CI way to obtain one from a PR branch, since refresh-data.yml is restricted to master. This workflow rebuilds on the same runtime as rebuild-contracts (same runner, R version, dependency pins, action SHAs, OpenBLAS kernel and thread width) and uploads the four data artifacts, manifest.json and a SHA-256 receipt for reviewed promotion. It is read-only: contents: read, no persisted credentials, and no commit, push or deploy step. It omits only the global.R boot guard (which fails by design on the head being regenerated) and the byte gate (bytes are expected to move); every other contract still runs inside rebuild_all.R. The siblings input selects pinned (lineage-only, values must not move) or current (adopts upstream data, exercises the effort_days path). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CP23xFrMeWj7PS4i19aH7Q
Regenerated by regenerate-artifacts.yml run 31323917044 on this head with siblings=pinned, so the bytes come from the CI runner and satisfy the byte contract the agent container could not. Verified against the run's own SHA-256 receipt before promotion. Values did not move: annual, codebook, pooled, priors, signals, site_meta and suite_links are identical to the committed baseline; meta differs only in build_script_md5, source_adapters_md5 and the local_build_inputs row carrying them, and search_index only in source_bundle_md5. The codebook is byte-identical, confirming the conditional effort note held the base sentence on the trap_nights path. Re-registers the canonical set across the eight live registries and moves the spec authority chain that follows from editing DISCHARGE-FEASIBILITY-SPEC.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CP23xFrMeWj7PS4i19aH7Q
The incident
Scheduled refresh
31298345511(2026‑08‑09) failed inrebuildwith:validate-artifactsandpublishskipped, so no artifact byte was written. Canonical SHA‑256 remain cascade47b98e48…/ searcha11a072d…/ meta00120c52…, and both live surfaces stayed up on the last good family. The fail-closed guard did its job.Not related to the cover release —
docs/is outside the build surface.Root cause
The Mosquito release merged upstream as
fdb9aa1(2026‑08‑05) rebuilt every site bundle underR/mos_bundle_contract.R, whoseeffort_weeknow emitseffort_days,opportunities, andzero_catches— notrap_nights. Every mosquito site has the new schema; ABBY is just alphabetically first. Timeline fits exactly: 08‑02 refresh succeeded on old bundles → release merged 08‑05 → 08‑09 refresh failed.This is not a pure rename
trap_nightseffort_daysifelse(trapHours > 0, trapHours/24, 0)ifelse(valid_effort, trapHours/24, 0)occurred & duration_ok & identity_okSame unit, QC-screened population. The refreshed denominator can only shrink, so
mosq_activity(catch ÷ trap-nights) can only rise, on site-years that contained unusable deployments. Mosquito rows are descriptive context and enter no pooled vote, so no inferential claim changes — but published descriptive values will move, which is why the delta preview below exists.What this PR changes (source only)
cascade_mosq_effort_field()resolves whichever field the bundle publishes, preferringeffort_daysexactly as the producing app does; fails closed when neither exists, and refuses a bundle set that mixes bases.cascade_mosq_effort_note()appends the QC-screened sentence to the publishedmosq_trap_nightscodebook entry only when the build actually readeffort_days— so the caveat travels with the number, and the byte gate stays meaningful under pinned siblings.test_helpers.Rresolves the same two names literally rather than calling the build helper, keeping that adversarial check independent.scripts/report_mosq_effort_delta.R, wired into the refresh job summary, plus apublishdispatch input (defaulttrue) that can only ever narrow publication — so a dry run shows the value deltas before anything reaches master.Expected CI state — please read before judging the red
data/cascade_meta.rdsrecordsbuild_script_md5andsource_adapters_md5, so editing the builder or the adapters necessarily changes the regenerated meta. The exact-reproduction gate is expected to fail on this source head.Under CI's pinned siblings the adapter falls back to
trap_nights, socascade.rds,search_index.rdsand the codebook text should be byte-identical and only those two recorded hashes should move. Please confirm that from the run log before promoting.Next step (needs R — I don't have it in this container)
Rscript --vanilla scripts/rebuild_all.Rwith the seven sibling clones present.refresh-data.ymlwithpublish=falseand read the mosquito delta report before letting a scheduled run publish.🤖 Generated with Claude Code
https://claude.ai/code/session_01CP23xFrMeWj7PS4i19aH7Q
Generated by Claude Code