Stop requesting the citation sidecar, and delete the 353 broken ones (#249) - #388
Conversation
…249) Every one of the 353 `<report>.md.citations.md` sidecars was malformed: 194 broken markdown-link tails, 2,770 stray trailing commas, 332 of 353 listing the same reference two or three times over, and entries that are PaperQA internal keys resolving to nothing outside the provider. All 353 also re-emitted the ~55-line rendered prompt already stored in the report's own `template_variables` front matter. 1.6 MB, 35,058 lines. #249 offered two fixes and recommended dropping the sidecar. Taken. THE BROKEN EXTRACTOR IS NOT IN THIS REPO. research_trait.py only passes `--separate-citations` to the external deep-research-client, so TraitMech's only choice is whether to ask for the file. Removing the flag is the whole fix here. CHECKED WHAT CONSUMES THEM BEFORE DELETING 353 FILES: render_trait_pages.py does not read them — it EXCLUDES them from its report glob (#259). Pages unaffected. the manifest no reference. --verify the one real dependency, below. `run_trait_graph_audit.py --verify` globs every .md under research/ for malformed CURIEs, and its comment justified including sidecars because "the sidecar echoes the rendered prompt, so a bad identifier in the trait's own front matter shows up there too". That rationale IS the redundancy #249 complains of, and I verified it rather than assuming: across every sidecar, ZERO CURIE-shaped tokens appear that are not also in their report. Coverage is unchanged; the artifact count simply halves. reports carrying a malformed CURIE: 0 (0 matches; scanned 707 -> 354) targets 353 · already-researched 353 · pending 0 · manifest gaps 0 Also corrected two comments this made false — the sidecar rationale above, and render_trait_pages.py's "only the dot form can occur here today". That exclusion STAYS: _edison_capture can still emit the hyphen form `<stem>-citations.md`, which is a properly parsed reference list rather than a regex over prose, and is untouched by this change. Note for #244, which proposed making `--verify` assert sidecar existence: that part is now moot, exactly as #249 predicted it would be. 540 tests pass - just qc green - ruff clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Approving. I checked the load-bearing claim rather than taking it on trust, and it holds.
Verified independently
- No audit coverage is lost. Ran all three
MALFORMED_CURIE_PATTERNSfromrun_trait_graph_audit.pyover the 353 sidecars as they exist onmain: zero underscore-form, zero lowercase-prefix, zero double-prefix hits. Extracting everyPREFIX:localtoken from the sidecars also yields a set that is entirely contained in the surviving reports — all canonicalMETPO:100xxxx/GO:00xxxxx/CHEBI:xxxxx. So--verifyfinds exactly what it found before, over 354 artifacts instead of 707. - No source is lost. Spot-checked
ecology/mutualism: the sidecar's 49 entries are a strict degradation of the report's## DOI-first bibliographyplus itsReferencesblock — the report carries author, title, journal, year, DOI and the PaperQA key→DOI mapping, while the sidecar carries bare keys, duplicated DOIs,...w](https://doi.org/...wlink tails and trailing commas. The header of the sidecar is verbatim the rendered prompt. - Deletion scope is exact.
git diff main...HEAD -- research/is 353 files, all*.md.citations.md, nothing else.find research -name '*citations*'is now empty; 354 reports remain. - No dangling consumers.
--separate-citationsandcitations_filehave no remaining references outside the two updated comments; all fivebuild_commandcall sites intests/test_research_trait.pywere updated with the signature.pages/,dashboard/,reports/trait_graph_audit_manifest.tsv,README.mdanddocs/reference the sidecars nowhere. - History record validates.
just validate-historyon the new record: No issues found. Omittingactors[].modelmatches every other record underhistory/infrastructure/, so that's the convention, not a gap.
On keeping the render_trait_pages.py exclusion — right call, and the rewritten comment is honest that it currently matches nothing. Worth noting the guard is more defensive than the comment implies: _edison_capture's stem is {slug}-edison-{job} and enrich_edison_response.py keys off *-meta.yaml, neither of which the falcon reports have, so nothing today can produce a -citations.md that matches the {slug}-deep-research-*.md glob. That's an argument for keeping it, not against — just don't let a future reader conclude the hyphen branch is live and reason from that.
🔵 One comment the sweep missed, and I'd leave it alone: scripts/_edison_capture.py:21 still describes {stem}-citations.md as "matches the falcon citations.md sidecar", a cross-reference to the artifact this PR deletes. But that file is vendored byte-identical across the Mech repos (research_trait_edison.py:9), so editing it here to fix a docstring would cost more than the staleness does. Mentioning it so it isn't mistaken for an oversight.
I could not run pytest or just qc in this environment, so the 540-tests-pass and ruff-clean claims are unverified by me and rest on CI.
Comment density and the history record are in keeping with the repo. No data, CURIEs or evidence snippets are touched by this change.
From review of this PR. research_trait.py:121 described the client surface as "one research call, a markdown answer, and a citations sidecar" — an output this entry point no longer produces, three lines from the code that stopped producing it. Same "a comment outlives the change it described" class as #372, #377 and #379. Also filed #389 from the same review, not fixed here: the independent reviewer declined to fix a stale docstring in _edison_capture.py because that file is documented as vendored byte-identical across the Mech repos. The conclusion was right, the reason was not — measured, it differs by 160 lines from CommunityMech and 32 from MediaIngredientMech, of 527. There is no byte-identity left to protect, which makes it a third instance of #209's class and a cross-repo decision rather than an edit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* Make --verify check emptiness and walk disk-to-manifest (#244) #244 named three gaps beyond the manifest-to-disk existence check. ONE IS MOOT. It asked that the citation sidecar be asserted alongside each artifact; #388 deleted all 353 as a broken regex over report prose — exactly what #249 predicted when it said to decide that issue first. EXISTENCE IS NOT NON-EMPTINESS. `.exists()` passes for a zero-byte file, so a truncated write, a process killed mid-flush, or a provider returning an empty body all read as success. The floor is set FROM THE CORPUS rather than guessed: the smallest real report is 20,785 bytes, so 1 KiB leaves a 20x margin and cannot fail on real data. DISK TO MANIFEST. A report with no `ok` row was invisible, while still suppressing the call that would have produced it — resume keys on the artifact existing. Blocking from the start, with one named exception (cellulolysis-deep-research-codex.md, #245) using the same escape idiom as audit_biolink_curies.py's ALLOWED_UNBACKED, so adding one is a reviewed change. It is harmless today only because its `-codex` suffix is not the `-falcon` name resume looks for, which is luck rather than design. Scoped to `.md` deliberately: a `-meta.yaml` from `--dry-run` also lives under research/traits and represents NO research (status: dry-run, cost: None, task_id: None — #246), so counting it would let a plan nobody paid for satisfy an existence check. FOUND WHILE PROBING, and worth more than the feature: the counters were PER ROW. The manifest is append-only and 342 of the 353 artifacts carry two `ok` rows apiece — the original sweep and the re-run after its output was lost — so 700 rows describe 353 files, and a single truncated report was reported as TWO. Both counters now dedupe per artifact, which is how the invariants are phrased and how the adjacent CURIE scan already reported. Extracted ok_outputs / missing_artifacts / undersized_artifacts / orphan_reports as pure functions so the gates are testable, in scan_malformed_curies' style. Eight tests, each making a gate FIRE, on the argument that file already states: "a gate whose corpus is already clean is exactly the kind that can be silently broken". Probed by hand first — an injected orphan and a truncated artifact were both caught, tree restored clean. 548 tests pass - just qc green - ruff clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Match the orphan gate to its own invariant (#397) From the dispatched review of this PR, and the finding is in this PR's own new code. orphan_reports globbed every `*.md` under research/traits. But the harm it exists to prevent — a file suppressing a call that was never paid for — needs resume to be looking for that filename, and resume keys on `output_path()`: `{slug}-deep-research-{default provider}.md`. Two documented workflows write outside that namespace and record nothing: `just research-trait --provider openai` (README) and `just research-trait-edison` (justfile). The first documented non-falcon run after merge would have turned `just qc` red, remediable only by adding a filename to a constant. THE EXCEPTION LIST CONTAINED THE REFUTATION. It justified excluding cellulolysis-deep-research-codex.md because "-codex is not the name resume looks for". That generalises to every non-default provider — the gate was blocking on files structurally incapable of causing the harm. Narrowed to the resume namespace, so: - the exception list is GONE entirely, and the codex file needs no naming, which is a better outcome for #245 too — it is a tidiness question, not an integrity one; - re-probed: an injected `-falcon` orphan fires, an `-openai` one does not. Also took three smaller notes from the same review: the justfile recipe comment described only the pre-#244 checks; `manifest ok rows with a missing artifact:` still said "rows" after being deduped to artifacts (this PR's own headline finding, applied to the wrong line); and two of the four report blocks lacked the `... and N more` tail the other two carry. 548 tests pass - just qc green - ruff clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Closes #249.
Every one of the 353
<report>.md.citations.mdsidecars was malformed — 194 broken markdown-link tails, 2,770 stray trailing commas, 332 of 353 listing the same reference two or three times over, and entries that are PaperQA internal keys resolving to nothing outside the provider. All 353 also re-emitted the ~55-line rendered prompt already stored in the report's owntemplate_variablesfront matter. 1.6 MB, 35,058 lines.#249 offered two fixes and recommended dropping the sidecar. Taken.
The broken extractor isn't in this repo
research_trait.pyonly passes--separate-citationsto the externaldeep-research-client. TraitMech's only choice is whether to ask for the file — so removing the flag is the whole fix on this side. Worth knowing before anyone goes looking for a regex to repair.What consumes them — checked before deleting 353 files
render_trait_pages.py--verifyrun_trait_graph_audit.py --verifyglobs every.mdunderresearch/for malformed CURIEs, and its comment justified including sidecars because "the sidecar echoes the rendered prompt, so a bad identifier in the trait's own front matter shows up there too."That rationale is the redundancy #249 complains of — and I verified it rather than assuming. Across every sidecar, zero CURIE-shaped tokens appear that are not also in their report. Coverage is unchanged; the artifact count simply halves:
Two comments this made false, also fixed
The
--verifysidecar rationale above, andrender_trait_pages.py's "Only the dot form can occur here today".That exclusion stays.
_edison_capturecan still emit the hyphen form<stem>-citations.md— a properly parsed reference list rather than a regex over prose — which this change doesn't touch. Removing the guard because the current tree has no matches is how it comes back silently.Knock-on
#244 proposed making
--verifyassert sidecar existence. That part is now moot, exactly as #249 predicted when it said to decide this one first.just qcgreen · 540 tests pass · ruff clean · history record per #325.