Lossless Changelog
component

Section Files Stop Being Rewritten at Assembly — Semantic Citation IDs Survive

Citation assembly was rewriting section files. Section files now stay the durable source of truth and keep their semantic IDs.

Michael StatonMusic Editoraugmented with Claude Code (Opus 4.7)
improve(citation-assembly): preserve semantic citation IDs at assembly
docs(readme): add DataroomHQ + GPGPT to Similar Services
new(gated-publishers): add Deloitte (deloitte.com + www2.deloitte.com/insights)

The 2026-05-26 assembler hardening fixed three bugs but left a fourth
behavior in place that mattered just as much: citation_assembly was
rewriting section files in place with run-dependent numeric IDs.
Section files were no longer durable — running the assembler twice on
the same memo would orphan any citation whose definition lived in
1-research/ rather than in the section itself, because the section
file's IDs had been mutated to numbers the foundational citations no
longer matched.

* src/agents/citation_assembly.py — renumber_citations() now returns
  the old→new ID map instead of writing it back into the section
  files. The map is applied in memory only when the final draft is
  concatenated. Section files stay as the writer wrote them, keeping
  their semantic IDs (`[^chroma-site]`, `[^github-2018]`, etc.) and
  remaining safe to re-assemble against a different 1-research/ set.

* README.md — Similar Services section adds DataroomHQ and GPGPT.
  Both are commercial vendors in the private-markets data-room +
  memo-generation space. The orchestrator is open source and the
  CLI-and-Python surface won't fit every reader; surfacing the two
  most relevant commercial alternatives at the README level gives
  commercial-intent traffic a direct exit.

* src/validation/gated_publishers.yaml — adds Deloitte as an
  analyst-category gated publisher (deloitte.com and
  www2.deloitte.com/insights). Joins the existing analyst-firm
  entries so research that surfaces Deloitte URLs gets routed
  through the same gated-source handling as the other consultancy
  publishers.

No agent prompts changed. No outline YAML changed. The assembler's
external interface is unchanged; only the side-effect on section
files moved.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Changelog — 2026-05-28_01

The behavior change that mattered

citation_assembly.py previously did two things at once: it walked all section files, computed a global numbering, and (this is the part that caused pain) wrote that numbering back into the section files. After the first assembler run, the section file's citations were no longer the semantic IDs the writer had produced — they were the numeric IDs that run had assigned. The next assembler run would then see the numbers, renumber them again against a possibly-different set of foundational citations from 1-research/, and silently orphan any citation whose definition had moved.

The fix is structural, not algorithmic. renumber_citations() still computes the old→new mapping, but it returns the mapping instead of writing it back. The mapping is applied in memory only when the final draft is concatenated. Section files stay as the writer wrote them — the semantic IDs survive, the section file remains safe to re-assemble against a different 1-research/ set, and the assembler stops having a side effect on the source of truth.

Why this matters for codified-source mode

The codified-source mode (curated Sources.md per memo) was always going to compound this bug. Foundational citations defined in 1-research/ are exactly the codified-source case — the writer references them by semantic ID and expects them to exist in the research files, not in the section. Once the section file's IDs got renumbered, the codified definitions stopped resolving. Fixing the side effect was a prerequisite for codified mode to be production-safe.

Similar Services additions

The orchestrator's README has carried a Similar Services section for a while as a courtesy to readers who land here looking for a hosted product rather than a CLI to run themselves. DataroomHQ and GPGPT are the two most relevant commercial vendors in the private-markets + memo-generation space; adding them to the README means commercial traffic has somewhere to go without having to fish around for alternatives. The fuller list still lives on memopop-site.

Gated publishers: Deloitte

Deloitte joins the existing analyst-firm entries in gated_publishers.yaml. The orchestrator already routes McKinsey, Bain, BCG, and a few others through the gated-source handling for the consultancy-publisher category. Deloitte was an obvious omission that surfaced when a recent research run pulled www2.deloitte.com/insights URLs that the gated-source classifier ignored.

What didn't change

  • No agent prompts.

  • No outline YAML or template.

  • The assembler's external interface (function signature, where it reads from, what it writes to disk for the final draft) is unchanged. Only the in-place rewriting of section files is gone.

What's next

  • Re-run a previously-flaky memo through the assembler and confirm re-assembly produces identical output (idempotence test).

  • Codified-source mode (Sources.md per memo) can move forward now that the section-file mutation is gone — the orphaning failure mode it would have hit is closed.

References

  • src/agents/citation_assembly.py — the changed file

  • src/validation/gated_publishers.yaml — Deloitte entry

  • README.md — Similar Services additions

  • changelog/2026-05-26_01.md — the assembler hardening this entry sits on top of