Skip to content

docs: add a doc/code audit, fix the one dead reference, document nine nodes - #1718

Open
ptlnextdoor wants to merge 11 commits into
rocketride-org:developfrom
ptlnextdoor:docs/RR-1717-docs-audit
Open

docs: add a doc/code audit, fix the one dead reference, document nine nodes#1718
ptlnextdoor wants to merge 11 commits into
rocketride-org:developfrom
ptlnextdoor:docs/RR-1717-docs-audit

Conversation

@ptlnextdoor

@ptlnextdoor ptlnextdoor commented Jul 29, 2026

Copy link
Copy Markdown

Closes part of #1717.

AGENTS.md co-locates docs with the code they document, but nothing checks that they still agree after a rename. This adds that check, then applies the fixes it can apply safely.

1. tools/docs_audit/ — the checker

doc → code. Every path a doc cites gets a class and the evidence behind it, not a boolean:

class meaning
VERIFIED resolves to a real path, or some file has that basename
PLACEHOLDER create-verb prose, scaffolding tree, or an illustrative example
HISTORICAL a changelog naming a deleted file is correct by definition
RUNTIME no file at rest, but source constructs the name
ORPHANED nothing found → review

Only ORPHANED is a deletion candidate, and it is reported, never auto-applied.

The classification isn't ceremony. The naive version of this tool — flag every cited path that isn't on disk — calls 68% of this repo's citations dead. Almost all of that is false, and acting on it deletes correct docs:

doc says on disk actually
Save this as `extract.pipe`: absent a file the reader creates
``Writes `version.docker.json``` absent built at runtime by apps/vscode/src/engine/docker/engine-docker.ts
``NOT: `.pipeline.json``` absent a counter-example — deleting it reintroduces the mistake the doc prevents

code → doc. STALE_PARAMS (generated table disagrees with services*.json), MISSING_PARAMS, MISSING_DOC. Two subtleties are handled, both of which silently corrupt results otherwise:

  • Profile groupings in fields (carrying object/properties rather than type) are not parameters. nodes:docs-generate omits them; counting them reported phantom drift on 8 clean nodes.
  • detect_segment and video_composer ship JSONC services.json. json.loads throws, and swallowing that made them look like they declared zero params. Fixing it took STALE_PARAMS from 4 → 18 — 14 nodes were hidden.
python3 tools/docs_audit/cli.py --root .
python3 tools/docs_audit/cli.py --root . --fail-on-orphaned   # CI gate

2. docs/README-n8n.md

The only ORPHANED citation of 385: it pointed readers at .context/n8n-test/ for run.sh and a WALKTHROUGH.md, none of which is tracked (and .context/ isn't gitignored). Now points at the real examples/n8n/ pipes.

3. READMEs for nine undocumented nodes

background_removal, caption, depth_estimate, detect, detect_segment, face_detection, pose_estimation, tool_google_workspace, video_composer.

Prose is grounded in each node's own services*.json description, lanes, and fields — not invented. tool_google_workspace additionally documents that every destructive capability (hard delete, public sharing) is a separate opt-in flag defaulting to false.

Deliberately not fixed here

The 18 STALE_PARAMS and the MISSING_PARAMS blocks regenerate via nodes:docs-generate, and AGENTS.md says never to hand-edit between the generated markers. That needs the engine build, so it needs a maintainer. The nine new READMEs therefore move MISSING_DOC 9 → 0 while showing up under MISSING_PARAMS until someone regenerates.

graph_falkordb is the one I'd look at first — its README documents the pre-rename tool_falkordb.* keys.

Verification

  • python3 -m pytest tools/docs_audit/test/ -q18 passed
  • ruff check + ruff format --check → clean
  • audit on this branch: 390 citations, 0 ORPHANED; MISSING_DOC 9 → 0

Every test named test_placeholder_*, test_counter_example_*, test_profile_groups_*, or test_jsonc_* pins a false positive an earlier revision of this tool actually produced. They're the reason the tool is trustworthy enough to act on — worth keeping.

I don't have the engine build locally, so builder docs:build hasn't been run against this.

Summary by CodeRabbit

  • Documentation

    • Added guides for background removal, image captioning, depth estimation, object detection, segmentation, face detection, pose estimation, Google Workspace tools, and video composition.
    • Documented configuration options, outputs, model profiles, and runtime requirements.
    • Updated n8n guidance with runnable examples and webhook setup instructions.
  • New Features

    • Added a documentation audit command for checking references and node coverage.
    • Reports verified, unresolved, historical, and placeholder references, plus missing or outdated documentation.
    • Supports human-readable and structured output with optional failure checks.

Adds a bidirectional documentation audit so doc cleanup is a review task
rather than an archaeology task after several rounds of renaming.

doc -> code: every path a doc cites is classified with the evidence behind
the verdict, not checked as a boolean. A naive "is this path on disk" test
calls 68% of this repo's citations dead; almost all of that is false, and
acting on it deletes correct docs. Files the reader is told to create,
names the code builds at runtime, changelog entries about deleted files,
and counter-examples ("NOT: `.pipeline.json`") all look identical to rot
under an exists-check. Only ORPHANED -- no path, no basename, no source
literal -- is a deletion candidate, and it is reported, never auto-applied.

code -> doc: nodes shipping Python with no README, READMEs with no
generated params block, and generated blocks that disagree with
services*.json. Profile groupings in `fields` (object/properties rather
than type) are excluded, since nodes:docs-generate omits them and counting
them reports phantom drift on every profile-based node.

Current state of this tree: 381 citations -> 380 accounted for, 1 genuine
dead reference; 14 code->doc gaps.

Every test named test_placeholder_*, test_counter_example_*, or
test_profile_groups_* pins a false positive an earlier revision produced.

Verified: pytest 16 passed; ruff check + format clean.
detect_segment/services.json and video_composer/services.json ship `//`
comments. json.loads raises on those, and the except branch treated the
node as declaring zero parameters -- so drift in any commented schema
could never surface.

Strips `//` line comments with quote-state tracking so a `https://` inside
a string value survives. Unmasks 14 further drifted nodes (STALE_PARAMS
4 -> 18), including graph_falkordb, whose README still documents the
pre-rename `tool_falkordb.*` keys.

Verified: pytest 18 passed; ruff check + format clean.
README-n8n.md pointed readers at `.context/n8n-test/` for `run.sh` and a
WALKTHROUGH.md. None of that exists in the tracked tree and `.context/`
is not gitignored, so no contributor can follow it. Points at the real
`examples/n8n/` pipes and the importable dispatch workflow instead.

Found by tools/docs_audit -- the only ORPHANED citation of 385.
background_removal, caption, depth_estimate, detect, detect_segment,
face_detection, pose_estimation, tool_google_workspace, and video_composer
each ship Python but had no README, contrary to the co-located
documentation rule in AGENTS.md.

Prose is grounded in each node's own services*.json description, lanes,
and field set -- not invented. tool_google_workspace additionally spells
out that every destructive capability (hard delete, public sharing) is a
separate opt-in flag defaulting to false.

The ROCKETRIDE:GENERATED:PARAMS block is deliberately NOT hand-written:
it is produced by nodes:docs-generate, which needs the engine build.
These nine therefore move from MISSING_DOC to MISSING_PARAMS until a
maintainer regenerates.
Copilot AI review requested due to automatic review settings July 29, 2026 03:40

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions github-actions Bot added docs Documentation module:nodes Python pipeline nodes labels Jul 29, 2026
@github-actions

Copy link
Copy Markdown
Contributor
🤖 Internal: Discord sync marker

Auto-managed by the Discord notification workflow. Stores the linked Discord message ID and forum thread ID. Do not edit or delete.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The pull request adds a documentation audit tool with citation and schema-coverage checks, tests and CLI reporting, nine node README files, and updated n8n workflow guidance.

Changes

Documentation audit and guides

Layer / File(s) Summary
Repository indexing and citation classification
tools/docs_audit/src/docs_audit/index.py, tools/docs_audit/src/docs_audit/citations.py, tools/docs_audit/src/docs_audit/__init__.py
Indexes repository paths and source literals, extracts documentation citations, and classifies citations with evidence.
Coverage checks, CLI reporting, and validation
tools/docs_audit/src/docs_audit/coverage.py, tools/docs_audit/src/docs_audit/cli.py, tools/docs_audit/cli.py, tools/docs_audit/test/*
Audits node README coverage and schema parameters, adds human-readable and JSON CLI output, and tests citation, JSONC, indexing, and coverage behavior.
Node, audit, and n8n documentation
nodes/src/nodes/*/README.md, tools/docs_audit/README.md, docs/README-n8n.md
Documents nine node interfaces, the audit tool, and runnable n8n example workflows with instance-specific webhook URLs.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related issues

  • rocketride-org/rocketride-server#1717 — The issue describes the documentation audit, n8n reference update, and missing node READMEs added by this pull request.

Possibly related PRs

Suggested reviewers: jmaionchi, rod-christensen, stepmikhaylov

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 63.83% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the documentation audit, dead-reference fix, and nine new node READMEs.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@nodes/src/nodes/caption/README.md`:
- Around line 8-9: Update the caption node README’s task documentation so the
declared default aligns with the allowed task values: either change the default
from “caption” to one of the documented granularities or add “caption” to the
allowed options, applying the same correction to both documented occurrences.

In `@nodes/src/nodes/depth_estimate/README.md`:
- Around line 14-16: Update the depth-estimate README wording from “afterwards”
to the American-English “afterward,” without changing the surrounding
explanation.

In `@nodes/src/nodes/tool_google_workspace/README.md`:
- Around line 23-30: Revise the “Destructive operations are opt-in” section to
avoid claiming that every irreversible or externally visible capability is
disabled by default. Limit the wording and examples to deletion and
public/domain-wide sharing, or explicitly document controls for Gmail send,
Drive writes, and Docs/Sheets batchUpdate if those controls exist.

In `@tools/docs_audit/src/docs_audit/cli.py`:
- Around line 17-21: Update _docs to use os.walk instead of root.rglob, pruning
excluded directory names in place before descending while preserving
DOC_SUFFIXES filtering and yielding non-excluded matching files. Follow the
directory-pruning approach used by CodeIndex.build().
- Around line 39-45: Validate the resolved root in main before building the
CodeIndex or running any audits. If root does not exist or is not a directory,
reject it with a nonzero exit status and an appropriate error message; otherwise
preserve the existing audit and fail-on-orphaned behavior.

In `@tools/docs_audit/src/docs_audit/coverage.py`:
- Around line 103-106: Update the schema-loading exception path in audit_node()
so OSError or JSONDecodeError produces an explicit schema-read/parse gap instead
of continuing with no data. Ensure the returned gap is propagated through the
audit result and rendered by the CLI, preserving normal processing for
successfully parsed schemas.

In `@tools/docs_audit/src/docs_audit/index.py`:
- Around line 82-96: Preserve leading dots when constructing repository-relative
paths in the directory scan loop. Update both the
`index.paths`/`index.basenames` entries and the `index._sources` key to use the
unmodified `rel_dir / name` POSIX path, removing the `.lstrip('./')` calls so
hidden paths such as `.github/...` and `.env` remain exact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 63e0fd3d-78bb-4c45-9f89-fb6895f70539

📥 Commits

Reviewing files that changed from the base of the PR and between 2cbd567 and 146bbe5.

📒 Files selected for processing (19)
  • docs/README-n8n.md
  • nodes/src/nodes/background_removal/README.md
  • nodes/src/nodes/caption/README.md
  • nodes/src/nodes/depth_estimate/README.md
  • nodes/src/nodes/detect/README.md
  • nodes/src/nodes/detect_segment/README.md
  • nodes/src/nodes/face_detection/README.md
  • nodes/src/nodes/pose_estimation/README.md
  • nodes/src/nodes/tool_google_workspace/README.md
  • nodes/src/nodes/video_composer/README.md
  • tools/docs_audit/README.md
  • tools/docs_audit/cli.py
  • tools/docs_audit/src/docs_audit/__init__.py
  • tools/docs_audit/src/docs_audit/citations.py
  • tools/docs_audit/src/docs_audit/cli.py
  • tools/docs_audit/src/docs_audit/coverage.py
  • tools/docs_audit/src/docs_audit/index.py
  • tools/docs_audit/test/__init__.py
  • tools/docs_audit/test/test_docs_audit.py

Comment thread nodes/src/nodes/caption/README.md Outdated
Comment thread nodes/src/nodes/depth_estimate/README.md Outdated
Comment thread nodes/src/nodes/tool_google_workspace/README.md Outdated
Comment thread tools/docs_audit/src/docs_audit/cli.py Outdated
Comment thread tools/docs_audit/src/docs_audit/cli.py
Comment thread tools/docs_audit/src/docs_audit/coverage.py
Comment thread tools/docs_audit/src/docs_audit/index.py Outdated
…its (rocketride-org#1718 review)

The tool_google_workspace README claimed "every irreversible or
externally-visible capability is gated behind its own flag and is off by
default." That is wrong for the second half. allowHardDelete /
allowDelete / allowPublicSharing are indeed opt-in booleans defaulting to
false, but the per-service `access` field defaults to `write` on Drive,
Calendar, Docs and Sheets (and `modify` on Gmail) — so creating files and
calendar events is on by default, and calendar writes send attendee
invitations. Reworked the section to separate the two mechanisms and say
which one actually bounds the agent day to day. Gmail's `send` really is
above the default, and is now called out as the exception rather than the
rule.

Also from review:
- caption: `task` prose said "short / detailed / more detailed" while the
  default is `"caption"`, leaving no way to map the words to the enum.
  Now names the actual values: caption, detailed_caption,
  more_detailed_caption.
- depth_estimate: "afterwards" -> "afterward" for American English.

Verified: pytest 18 passed; ruff clean.
…ng (rocketride-org#1718 review)

Four Major findings from review, three of which share one failure mode:
the tool returned success while silently doing no work.

- cli: a nonexistent --root produced no docs, no nodes, and exit 0 even
  under --fail-on-orphaned. A typo in a CI invocation was therefore a
  green build that never audited anything. Now exits 2 with a message.
- coverage: an unparseable services*.json was skipped, leaving zero
  declared params -- indistinguishable from a node with nothing to
  document, so real schema drift stayed hidden behind a clean report.
  Added an UNREADABLE gap kind, reported instead of swallowed; same for
  an unreadable README.
- index: `.lstrip('./')` strips a character SET, not a prefix, so `.env`
  was indexed as `env` and `.github/workflows/ci.yml` lost its leading
  dot. Citations to hidden files could be reported orphaned or matched
  only by basename. `Path('.') / name` is already clean, so the lstrip
  was both wrong and unnecessary.
- cli: _docs used rglob, descending node_modules and vendored trees in
  full before discarding what they yielded. Now os.walk with in-place
  pruning, matching CodeIndex.build.

Also added the __main__ guard: `python -m docs_audit.cli` previously
printed nothing and exited 0, the same silent-success trap as the --root
bug.

Verified: 21 passed (3 new regression tests), ruff clean, format clean.
Full run on this repo: 390 citations, 0 orphaned, 31 coverage gaps,
unchanged from before the fix.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tools/docs_audit/src/docs_audit/coverage.py (1)

171-174: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Detect stale parameters when the schema has no user-facing fields.

After the documented is None branch, documented is a set. If declared is empty but the generated block contains old rows, this return reports a clean node and hides stale documentation.

Remove the early return. Compare both sets so that an empty schema with documented rows produces STALE_PARAMS, while an empty schema with an empty table remains clean.

Proposed fix
-    if not declared:
-        return []
-
     undocumented = declared - documented
     phantom = documented - declared

Add a regression test for an empty schema with one documented parameter.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/docs_audit/src/docs_audit/coverage.py` around lines 171 - 174, Remove
the early `if not declared` return in the relevant coverage-checking function
after the `documented is None` branch, and always compare `declared` and
`documented`. Preserve clean results when both are empty, but return
`STALE_PARAMS` when an empty schema has documented rows; add a regression test
covering that case.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tools/docs_audit/src/docs_audit/cli.py`:
- Around line 18-28: Update the audit flow connecting _docs(), audit_doc(), and
main() so an OSError while reading a documentation file produces an explicit
unreadable finding or causes the CLI to return a non-zero status. Do not
silently omit failed files or treat them as empty results; ensure the failure is
visible in the collected audit outcome.

In `@tools/docs_audit/test/test_docs_audit.py`:
- Around line 216-227: Extend test_dotfile_paths_keep_their_leading_dot to
create a hidden .py file containing a distinctive literal, then assert
find_literal() returns evidence using its dotted path. Keep the existing
has_path() assertions and ensure the assertion exercises the _sources key used
by literal lookup.

---

Outside diff comments:
In `@tools/docs_audit/src/docs_audit/coverage.py`:
- Around line 171-174: Remove the early `if not declared` return in the relevant
coverage-checking function after the `documented is None` branch, and always
compare `declared` and `documented`. Preserve clean results when both are empty,
but return `STALE_PARAMS` when an empty schema has documented rows; add a
regression test covering that case.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4f238b24-03f8-49ea-9f51-cc397f1a4ae7

📥 Commits

Reviewing files that changed from the base of the PR and between b98c1eb and 0f7f527.

📒 Files selected for processing (4)
  • tools/docs_audit/src/docs_audit/cli.py
  • tools/docs_audit/src/docs_audit/coverage.py
  • tools/docs_audit/src/docs_audit/index.py
  • tools/docs_audit/test/test_docs_audit.py

Comment thread tools/docs_audit/src/docs_audit/cli.py
Comment on lines +216 to +227
def test_dotfile_paths_keep_their_leading_dot(tmp_path: Path) -> None:
"""Regression: `.lstrip('./')` strips a character SET, not a prefix, so
`.env` was indexed as `env` and citations to hidden files looked orphaned.
"""
(tmp_path / '.env').write_text('K=v\n', encoding='utf-8')
(tmp_path / '.github' / 'workflows').mkdir(parents=True)
(tmp_path / '.github' / 'workflows' / 'ci.yml').write_text('on: push\n', encoding='utf-8')

index = CodeIndex.build(tmp_path)
assert index.has_path('.env')
assert index.has_path('.github/workflows/ci.yml')
assert not index.has_path('env')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Cover hidden paths in the source-text index.

This test checks has_path() only. The change also updates the _sources key at Line 99. A regression there would pass this test and break find_literal() evidence for hidden source files.

Add a hidden .py file with a literal and assert that find_literal() returns the dotted path.

Proposed test extension
     (tmp_path / '.github' / 'workflows' / 'ci.yml').write_text('on: push\n', encoding='utf-8')
+    (tmp_path / '.github' / 'engine.py').write_text('version.docker.json\n', encoding='utf-8')

     index = CodeIndex.build(tmp_path)
     assert index.has_path('.env')
     assert index.has_path('.github/workflows/ci.yml')
     assert not index.has_path('env')
+    assert index.find_literal('version.docker.json') == ('.github/engine.py', 1)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def test_dotfile_paths_keep_their_leading_dot(tmp_path: Path) -> None:
"""Regression: `.lstrip('./')` strips a character SET, not a prefix, so
`.env` was indexed as `env` and citations to hidden files looked orphaned.
"""
(tmp_path / '.env').write_text('K=v\n', encoding='utf-8')
(tmp_path / '.github' / 'workflows').mkdir(parents=True)
(tmp_path / '.github' / 'workflows' / 'ci.yml').write_text('on: push\n', encoding='utf-8')
index = CodeIndex.build(tmp_path)
assert index.has_path('.env')
assert index.has_path('.github/workflows/ci.yml')
assert not index.has_path('env')
def test_dotfile_paths_keep_their_leading_dot(tmp_path: Path) -> None:
"""Regression: `.lstrip('./')` strips a character SET, not a prefix, so
`.env` was indexed as `env` and citations to hidden files looked orphaned.
"""
(tmp_path / '.env').write_text('K=v\n', encoding='utf-8')
(tmp_path / '.github' / 'workflows').mkdir(parents=True)
(tmp_path / '.github' / 'workflows' / 'ci.yml').write_text('on: push\n', encoding='utf-8')
(tmp_path / '.github' / 'engine.py').write_text('version.docker.json\n', encoding='utf-8')
index = CodeIndex.build(tmp_path)
assert index.has_path('.env')
assert index.has_path('.github/workflows/ci.yml')
assert not index.has_path('env')
assert index.find_literal('version.docker.json') == ('.github/engine.py', 1)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/docs_audit/test/test_docs_audit.py` around lines 216 - 227, Extend
test_dotfile_paths_keep_their_leading_dot to create a hidden .py file containing
a distinctive literal, then assert find_literal() returns evidence using its
dotted path. Keep the existing has_path() assertions and ensure the assertion
exercises the _sources key used by literal lookup.

…-drift class

_is_user_facing_param required a "type" key in addition to excluding
"object" entries. nodes:docs-generate only does the latter:

    if (field && field.object !== undefined) continue; // Skip profile definitions

So a field with no "type" -- which the generator emits with an empty Type
cell -- was rendered into the table but refused by the audit as declared,
and surfaced as "in docs but not in schema".

The generator decides what the table contains, so it is the only correct
oracle for this comparison; any stricter rule invents drift.

Measured on develop @ b8068d7 after regenerating the tables: 10 of the
remaining STALE_PARAMS findings were this false positive. With the rule
aligned, STALE_PARAMS goes 10 -> 0 and the surviving 13 findings are all
genuine (9 MISSING_DOC, 4 MISSING_PARAMS).

Verified: 22 passed (1 new regression test), ruff clean, format clean.
ptlnextdoor added a commit to ptlnextdoor/rocketride-server that referenced this pull request Aug 1, 2026
cloud_tts, landing_ai, tool_mem0 and tool_n8n were the only 4 of 112 node
READMEs without ROCKETRIDE:GENERATED:PARAMS markers, so nodes:docs-generate
skipped them by design and their schemas were never machine-checked.

Markers appended at the end, matching where the block sits in the other
108, then generated. The generator only writes between the markers, so each
file's hand-authored prose is untouched -- including the conceptual
Configuration tables (e.g. cloud_tts's profile/field/env-fallback table),
which explain where a setting comes from and are not something the
generated field dump replaces.

Audit on this branch is now: 399 citations, 0 orphaned, 9 gaps -- and all 9
are the MISSING_DOC nodes whose READMEs are written in rocketride-org#1718.
…ol on sibling repos

Ran the audit against rocketride-workshops and rocketride-benchmark. The
benchmark repo came back clean (114 citations, 0 orphaned). Workshops
reported 8 orphaned citations -- and all 8 were the tool's fault, in two
distinct ways:

- `.rocketride/docs/*` (4). The VS Code extension installs that directory
  into a *user's* workspace (apps/vscode/src/agents/agent-manager.ts). A doc
  telling a reader to open a file under it is correct precisely because the
  repo does not contain it. Now classified RUNTIME.

- `ARCHITECTURE.md` / `OWNERSHIP.md` (4). The citing line reads "Emits
  `ARCHITECTURE.md` and `OWNERSHIP.md` as inline content blocks" -- artifacts
  the workshop's agent produces at run time. "emit" was missing from the
  create-verb set, along with produce/output and the -s/-ed forms.

Third, found while fixing the above: classify() built its sibling path with
`.lstrip('./')`, the same character-set-vs-prefix bug already fixed in
index.py, so a citation to a dotfile was looked up with its leading dot
stripped.

Also reordered classify(): the runtime-literal lookup now runs before the
prose heuristics. Finding the name as a literal in source is hard evidence;
a create-verb nearby is a guess about intent. Both verdicts are protected so
nothing changes about what survives a cleanup, but the evidence a human
reads is strictly better. This is why "Writes `built_at_runtime.json`" is
RUNTIME again rather than PLACEHOLDER -- the existing test caught the
regression when the broader verb list shadowed it.

Verified: 24 passed (2 new regression tests), ruff clean, format clean.
rocketride-workshops orphans 8 -> 0; rocketride-server unchanged at 0.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tools/docs_audit/src/docs_audit/citations.py`:
- Around line 173-176: Update the citation matching in the surrounding audit
logic to pass the complete normalized token, rather than basename, to
index.find_literal before assigning RUNTIME. Add a regression case covering two
distinct paths with the same basename, ensuring a literal for one path does not
satisfy the other.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6b56ef34-921b-4a79-8380-4e94df41598b

📥 Commits

Reviewing files that changed from the base of the PR and between b57869f and 852cc0a.

📒 Files selected for processing (2)
  • tools/docs_audit/src/docs_audit/citations.py
  • tools/docs_audit/test/test_docs_audit.py

Comment thread tools/docs_audit/src/docs_audit/citations.py Outdated
…— the keys were wrong

The 9 node READMEs added in this PR documented their config with
hand-maintained tables. Every field name in them was missing its node
prefix, so they named configuration that does not exist:

  documented          actual
  maxEdge             background_removal.maxEdge
  task                caption.task
  threshold           detect.threshold
  crf / fps           composer.crf / composer.fps

video_composer is the worst case: its schema prefix is `composer.`, not the
node's directory name, so a reader could not have guessed it. Anyone copying
these into a pipe config would get a silently broken node.

AGENTS.md already says schema tables are generated and must not be
hand-edited; these were the only node docs not following that, which is also
why a hand-written table could drift this far in the first place.

Replaced with ROCKETRIDE:GENERATED:PARAMS blocks from nodes:docs-generate,
and prefixed the same keys where they appear in surrounding prose. Enum
*values* (`caption`, `detailed_caption`, `more_detailed_caption`) are left
bare -- they are values, not keys.

The generated descriptions are also better than what they replace: e.g.
depth_estimate.maxEdge now documents the upsample-back behavior and the
VRAM/sharpness tradeoff, which the hand-written row omitted.

MISSING_PARAMS on this branch: 13 -> 4. The remaining 4 (cloud_tts,
landing_ai, tool_mem0, tool_n8n) are fixed in rocketride-org#1773.

Verified: 24 passed, ruff clean. Generator itself untouched on this branch —
the --force flag used to run it here lives in rocketride-org#1773.
…UNTIME

From review on rocketride-org#1718: matching find_literal() on the basename alone let a
source occurrence of a common final segment protect an unrelated path.

The reviewer's suggested fix — pass the complete token — over-corrects. Measured
against develop, full-token-only turns 5 correct citations into ORPHANED:

  .workspace/global.json   built by packages/shell-api/versions/v0.d.ts:3455
  build/state.json         built by scripts/lib/download.js:42  (x4 citations)

Both are real runtime artifacts that code refers to by filename while the doc
supplies the directory. So: try the whole token first, and fall back to the
basename only when it carries a file extension. That drops the meaningless
protections (a citation ending in a bare English word) and keeps the real ones.

Repo verdicts are unchanged at 32 RUNTIME / 0 ORPHANED, but the *evidence* is
now sound. Before, `tools/list` was protected because the word "list" appears
somewhere in source; it now matches the literal "tools/list" in
nodes/test/tool_mcp_client/stub_mcp_server.py.

Two regression tests added, per the review: one that an extensionless segment
is not evidence, one that the extension-bearing fallback still protects.

Known limit, now documented in the code: find_literal scans raw source text, so
a path merely mentioned in a comment counts as evidence. I hit this while
writing the fix — naming real paths in my own explanatory comment made the tool
cite that comment as proof. The comment no longer names any real path. Properly
narrowing this needs per-language comment stripping, which is a bigger change
than this fix.

Verified: 26 passed, ruff clean, format clean.
…tations from it

From review on rocketride-org#1718.

audit_doc() caught OSError and returned [], so a doc that could not be read
dropped out of the run silently: no verdict, no gap, no error, exit 0. A
permission or I/O failure was indistinguishable from a file containing no
citations, and the audit reported success while having skipped it.

This is the third instance of one shape in this tool, and I had already fixed
the other two without noticing the pattern: a mistyped --root produced an empty
audit that passed, and an unparseable services*.json produced zero declared
params that looked clean. Same failure mode each time — the tool reporting
success for work it did not do.

Now yields a single UNREADABLE_DOC verdict carrying the file and the errno
type, printed above the verdict table and failing the run unconditionally —
not only under --fail-on-orphaned, since being unable to read a doc is a
failure to audit rather than a finding about citations.

Named UNREADABLE_DOC rather than UNREADABLE because coverage.py already exports
UNREADABLE for a node's schema/README; importing both into cli.py collided
(ruff F811). Distinct concepts, distinct names.

Verified end to end:
  tree with an unreadable doc -> exit 1, file listed
  same tree readable          -> exit 0
  this repo                   -> exit 0, unchanged

27 passed (1 new regression test, skipped when running as root since mode bits
do not apply), ruff clean, format clean.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs Documentation module:nodes Python pipeline nodes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants