Skip to content

Stop requesting the citation sidecar, and delete the 353 broken ones (#249) - #388

Merged
realmarcin merged 2 commits into
mainfrom
fix/249-drop-broken-citation-sidecars
Aug 16, 2026
Merged

Stop requesting the citation sidecar, and delete the 353 broken ones (#249)#388
realmarcin merged 2 commits into
mainfrom
fix/249-drop-broken-citation-sidecars

Conversation

@realmarcin

Copy link
Copy Markdown
Contributor

Closes #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 isn't in this repo

research_trait.py only passes --separate-citations to the external deep-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 does not read them — it excludes them from its report glob (#259). Pages unaffected
the manifest no reference
--verify the one real dependency ↓

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

Two comments this made false, also fixed

The --verify 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 — 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 --verify assert sidecar existence. That part is now moot, exactly as #249 predicted when it said to decide this one first.

just qc green · 540 tests pass · ruff clean · history record per #325.

…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>

@culturebot-reviewer culturebot-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_PATTERNS from run_trait_graph_audit.py over the 353 sidecars as they exist on main: zero underscore-form, zero lowercase-prefix, zero double-prefix hits. Extracting every PREFIX:local token from the sidecars also yields a set that is entirely contained in the surviving reports — all canonical METPO:100xxxx/GO:00xxxxx/CHEBI:xxxxx. So --verify finds 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 bibliography plus its References block — 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/...w link 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-citations and citations_file have no remaining references outside the two updated comments; all five build_command call sites in tests/test_research_trait.py were updated with the signature. pages/, dashboard/, reports/trait_graph_audit_manifest.tsv, README.md and docs/ reference the sidecars nowhere.
  • History record validates. just validate-history on the new record: No issues found. Omitting actors[].model matches every other record under history/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>
@realmarcin
realmarcin merged commit 2dc4857 into main Aug 16, 2026
5 checks passed
@realmarcin
realmarcin deleted the fix/249-drop-broken-citation-sidecars branch August 16, 2026 00:52
realmarcin added a commit that referenced this pull request Aug 16, 2026
* 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Citation sidecars are a broken text extraction: every one of 353 has malformed entries and duplicate references

1 participant