Repository navigation
Documentation drift and dead-code polish deferred from PR #295 #296
Description
Four items found while cleaning up the orphaned Step 1 Phase 2 scripts in #295. None was folded into that PR: each needs a decision rather than an edit, and burying a decision inside an unrelated cleanup is how it stops being visible. All four are recorded in #295's commit messages; this issue exists so they are not only recorded there.
None of these is currently red. Nothing below is enforced by a test, which is precisely why they drifted.
1. CLAUDE.md Quick Info counts are badly stale — needs a counting basis, not just new numbers
| Claim | CLAUDE.md says |
Actual |
|---|---|---|
langgraph_engine/ Python files |
244 | 253 |
| Repo-wide Python files | 395 | 492 |
| Test files | 45 (37 unit, 4 integration, 3 e2e, 1 load) | 99 (90 top-level, 5 integration, 3 e2e, 1 load) |
README.md disagrees with CLAUDE.md on the last figure, claiming 44 in two places (the badge and the directory tree).
The blocker is not arithmetic. "Test files" needs a definition before the number means anything: 90 top-level test_*.py, or 99 including integration/, e2e/ and load/, or 56 "total Python files in tests/" as README.md counts elsewhere. The three sources currently use three different bases, which is how they diverged without anyone noticing.
#295's deletions moved these by 3 and 1. The remaining gap long predates the branch.
Worth copying: docs/README.md carries per-folder counts that are correct, because tests/test_docs_index_matches_the_tree.py enforces them against a live enumeration of the tree. The same technique applied to the Quick Info table would make this class of drift impossible rather than merely fixed once.
2. CLAUDE.md documents the wrong default for ENABLE_CI
The integration-flags table lists ENABLE_CI with default 0/false. The workflow does the opposite:
CI_FLAG="${{ vars.ENABLE_CI }}"
echo "ci_enabled=${CI_FLAG:-true}" >> "$GITHUB_OUTPUT"The default is true — CI runs unless the repo variable explicitly disables it. As written, the table tells a reader that CI is off by default, which is the opposite of what the pipeline does. Worth auditing the neighbouring flags in the same table while in there, since this one was never checked against its implementation.
3. langgraph_engine/helper_nodes/ has no importers
Verified by repo-wide grep on 2026-08-07: zero importers anywhere outside the package itself. CLAUDE.md already describes it as "Orphaned package -- no live importers anywhere in the repo (confirmed by repo-wide grep); kept internally consistent but scheduled for removal in a follow-up cleanup".
Same shape as the three scripts removed in #295, so the same procedure applies: map the blast radius first. Expect the package's own tests to go with it, and check whether any contract, registry or doc entry names it before deleting.
4. verify_orchestration_prompt() has no production caller
Its sibling verify_orchestrator_result() was deleted in #295 because it encoded a false premise — a str signature for a value that has always been a dict. This one was deliberately kept: it also has no production caller, but orchestration_prompt genuinely is a str, so the contract it encodes is true.
That makes it a real choice rather than an oversight: either wire it in at the point Step 1 stores orchestration_prompt, or remove it and its tests. Leaving it indefinitely is the one option that gets worse over time, since a correct-but-uncalled validator looks like coverage that does not exist.
Suggested order
3 and 4 are self-contained and can be done independently. 1 and 2 both touch CLAUDE.md and are better done together, with 1 gated on the counting-basis decision.
🤖 Generated with Claude Code
Activity
piyushmakhija28 commentedon Aug 7, 2026
Item 1 is done — #297, merged as
1afcecf, CI 6/6 green on py3.10 and py3.11.Two corrections to what this issue originally said about it, recorded because both changed the shape of the work:
The counting basis was not actually ambiguous. I wrote that the blocker was deciding what "test files" means. It isn't: the claim's own breakdown —
45 (37 unit, 4 integration, 3 e2e, 1 load)— pins the basis exactly, and it maps one-to-one onto the real100 (91 unit, 5 integration, 3 e2e, 1 load). Both documents were using the same basis and had simply drifted to different wrong values. So this was mechanical, not a decision.One drift was missed here entirely.
README.mdclaimsdocs/holds 156 files; it holds 255. That is the largest single error of the set and it is not listed above — it surfaced only while writing the enforcement test, which is itself an argument for the enforcement over the audit.Final tally, all now checked by
tests/test_doc_counts_match_the_tree.py:langgraph_engine/*.py*.pytest_*.pydocs/filesThe call-graph figures (
578 classes, 3,985 methods) and the13 serversMCP count are deliberately left unchecked — the first needs a full AST build per test run and would churn on any code change, the second describes repositories that cannot be enumerated from this one.Still open: items 2, 3 and 4. Item 2 (
ENABLE_CIdocumented default) touchesCLAUDE.mdand is now the only remaining doc-accuracy item; items 3 (helper_nodes/) and 4 (verify_orchestration_prompt) are self-contained and independent of each other.🤖 Generated with Claude Code
chore: delete the orphaned helper_nodes package, keeping its two corr…
feat(orchestration): run verify_orchestration_prompt on what Step 1 e…
fix: implement FORCE_GRAPH_REBUILD, which five documents already prom…
piyushmakhija28 commentedon Aug 7, 2026
All four items are done. Every PR merged with 6/6 CI green on py3.10 and py3.11.
1afcecfhelper_nodes/f1bff7cverify_orchestration_prompt38e4572ENABLE_CI/ flags tabled18e1a8Three things this issue got wrong
Recording these because the next person to open a similar issue will make the same three mistakes, and because two of them changed what the work actually was.
Item 1's blocker did not exist. This issue said the counting basis needed deciding before the numbers could be fixed. It didn't: the claim's own breakdown —
45 (37 unit, 4 integration, 3 e2e, 1 load)— pins the basis exactly, and maps one-to-one onto the real100 (91 unit, 5 integration, 3 e2e, 1 load). Both documents were already using the same basis and had simply drifted to different wrong values. Mechanical, not a decision.Item 2 was not a one-line fix. It was filed as correcting
ENABLE_CI's documented default. Auditing the rest of the flags table found something else:FORCE_GRAPH_REBUILDwas described in five documents and read by no code sincea43595b(2026-03-28).RUNBOOK_STALE_GRAPH.mdOption B instructs an operator toexport FORCE_GRAPH_REBUILD=1while recovering from a stale-graph incident, and that command did nothing. A wrong default confuses a reader; a recovery procedure that silently fails is consulted precisely when something has already gone wrong. It is now implemented, which also made ADR-002, the deployment guide and the troubleshooting guide true as written — none needed editing.The largest single error in this issue is one the issue never mentioned.
README.mdclaimeddocs/held 156 files; it holds 255. That surfaced while writing the enforcement test, not while auditing.The pattern worth keeping
The audit that produced this issue missed all three. The enforcement test caught what the audit could not, and has since paid for itself three more times without anyone looking for it:
helper_nodes/deletion (Delete the orphaned helper_nodes package, keeping its two corrections #298) → 253/493 → 248/488None of those were noticed by hand. Enforcement beats audit, and
tests/test_docs_index_matches_the_tree.pyhad already demonstrated that before any of this started — its counts were the only ones in the repository that were still correct.A second pattern, from items 3 and 4
Both were "zero-caller" cleanups and they resolved in opposite directions, which is the point:
helper_nodes/(Delete the orphaned helper_nodes package, keeping its two corrections #298) was deleted — but only after a function-by-function content diff found two documentation corrections that existed nowhere else, with the stale text in the liveorchestrator.py. A blindgit rmwould have discarded both silently.verify_orchestration_prompt()(Run verify_orchestration_prompt on what Step 1 emits #299) was wired in rather than deleted, because unlike its already-removed sibling it encoded a true contract."No callers" is a prompt to investigate, not a verdict.
Closing.
🤖 Generated with Claude Code