Skip to content

Plan post-0.0.18 runtime control plane#175

Closed
harshanandak wants to merge 45 commits into
masterfrom
codex/v3-post-018-release-train
Closed

Plan post-0.0.18 runtime control plane#175
harshanandak wants to merge 45 commits into
masterfrom
codex/v3-post-018-release-train

Conversation

@harshanandak
Copy link
Copy Markdown
Owner

@harshanandak harshanandak commented May 19, 2026

Problem

Forge planning had two gaps on this branch: post-0.0.18 work was documented as a runtime control-plane direction but the tracked Beads snapshot did not contain the referenced release issues, and docs validation existed as a Forge-only command surface without enough grounding for adapter-driven docs linking/docstring coverage.

Root Cause

The planning branch was mixing design updates, early docs-validation implementation, and Beads runtime metadata. That made the PR hard to review because the release train, docs-validation gates, and skills-first agent packaging direction were not all tied back to tracked Beads issues and explicit validation.

Value

This PR makes the next public slices concrete: 0.0.16 gets docs linker/docstring coverage as a toggleable validation substage, and post-0.0.18 gets a tracked 0.0.19 through 0.0.25 release train for protected state, Beads/issue graph, local UI/TUI, hooks, memory projection, extensions, and scaled orchestration.

Beads

  • forge-30k: documentation link checker and docs-validation automation.
  • forge-2agy: post-0.0.18 release train epic.
  • forge-2agy.1 through forge-2agy.7: release slices 0.0.19 through 0.0.25.

Implementation Details

  • Added forge docs verify / forge docs detect as an early docs validation surface with markdown link checking, anchor checks, baseline support, and docstring coverage reporting.
  • Added .github/workflows/docs-validation.yml and .github/docs-link-baseline.json.
  • Fixed review feedback so docs detect --path validates the target project, local link containment uses root-relative checks instead of string-prefix checks, and fenced code links are ignored.
  • Updated release planning for docs validation adapters, local runtime control plane, protected Beads writes, hook/memory projections, and skills-first packaging.
  • Exported the tracked Beads issue snapshot so the referenced post-0.0.18 epic and children are present in .beads/issues.jsonl.

Security Review

  • Local path validation now rejects sibling-prefix escapes with path.relative containment checks.
  • Third-party skills from skills.sh/GitHub are documented as untrusted until reviewed, pinned, and permissioned.
  • Protected state planning keeps raw .beads, config, memory projection, hook, workflow, and lockfile writes behind Forge APIs.

Validation

  • git diff --check
  • node .\bin\forge.js docs verify --baseline .github/docs-link-baseline.json
  • bun test test/docs-command.test.js test/forge-docs-command.test.js
  • bun run lint
  • bun run check
  • Pre-push hooks passed with full suite: 772 pass, 22 skip, 0 fail

Known Limitations

Docstring coverage is currently reported and baseline-compatible, not enforced at an 80% project-wide threshold. That is intentional for this slice because existing repository coverage is much lower; enforcement should be introduced by mode (report, new-only, strict) and by project baseline.

Beads Dolt remote push is still blocked because the local Beads Dolt remote origin is not configured. The tracked JSONL snapshot now contains the release issues used by this PR.

Summary by CodeRabbit

  • New Features

    • Docs validation CLI: detect/verify with baseline read/write, min-docstring-coverage, JSON/pretty output, and CI workflow.
  • Documentation

    • Expanded roadmap, release-plan, and multiple research/design pages on runtime control plane, memory/UI, boards, skills, and docs-validation.
  • Tests

    • Extensive integration and unit tests for docs validation, baseline handling, CLI behaviors, and agent hook reporting.
  • Chores

    • Added docs-link baseline and updated repository markers.

Review Change Stack

@qodo-code-review
Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 41b2856312

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread bin/forge.js Outdated
Comment thread lib/docs-command.js Outdated
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

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

Adds a docs validation subsystem (library, CLI wiring, tests, CI baseline), many research and release-plan docs, enables Codex plugin hook capability and tests, and refreshes Beads backup/marker metadata.

Changes

Documentation Validation

Layer / File(s) Summary
Validation core
lib/docs-command.js
Implements Markdown discovery, link/anchor parsing and resolution, heading slug collection, AST-driven JS/TS export detection for docstring coverage, baseline load/write, and exports validateDocs, formatDocsValidation, writeDocsBaseline.
CLI integration
bin/forge.js
Wires `forge docs verify
Tests
test/docs-command.test.js, test/*
Adds comprehensive unit tests for Markdown link/anchor edge cases and docstring coverage patterns, plus subprocess integration tests for forge docs verify and forge docs detect.
CI & baseline
.github/workflows/docs-validation.yml, .github/docs-link-baseline.json
Adds GitHub Actions job that runs docs verification and ships a baseline JSON of known broken links used to suppress expected failures.

Research & Release Planning

Layer / File(s) Summary
Roadmap and references
docs/work/2026-04-28-skeleton-pivot/*
Adds and extends multiple release-plan and research documents reframing post-0.0.18 work toward a local runtime control plane and documenting docs-validation, protected-state, memory/projection, and skills-first proposals.
Design updates
docs/work/2026-04-03-setup-hardening-codex-parity/design.md
Normalizes repo-evidence links, clarifies Codex/Cursor routing guidance to use Forge runtime enforcement, and rewrites blast-radius touchpoints to repo-relative paths.
Research docs
docs/work/*/research/*
Adds multiple research/design documents covering evaluator synthesis, v3 runtime control-plane, orchestration, team runtime board inspiration, and docs-validation adapters/discovery.

Plugin Manifest and Housekeeping

Layer / File(s) Summary
Codex plugin and tests
lib/agents/codex.plugin.json, test/cleanup/plugin-catalog.test.js
Enables capabilities.hooks: true, adds capabilities.hookEvents ordered lifecycle names, and adds tests asserting the manifest fields.
Beads state updates
.beads/backup/backup_state.json, .beads/last-touched
Refreshes backup commit/timestamp/counts and advances the last-touched forge marker.

Estimated code review effort
🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested labels
codex

"A rabbit hops through docs at night,
Counting links till morning light.
Baselines saved and tests in tune,
Hooks enabled under moon.
Hooray, the validation blooms 🌷"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.29% 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
Title check ✅ Passed The PR title 'Plan post-0.0.18 runtime control plane' accurately reflects the main objective: documenting and planning post-0.0.18 release train work with concrete runtime control-plane direction and release slices.
Description check ✅ Passed The PR description covers all required template sections: Problem, Root Cause, Value, and Beads issue references; Implementation Details section includes Test Coverage and Security Review subsections; Self-Review Checklist is present but not checked off (this is acceptable for author submission).
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/v3-post-018-release-train

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

@harshanandak harshanandak force-pushed the codex/v3-post-018-release-train branch from 41b2856 to d2b63d9 Compare May 19, 2026 08:02
@github-actions
Copy link
Copy Markdown
Contributor

📦 Package Size Report

Size: 9MB (9679KB)
Threshold: 10MB
Status: ✅ Within threshold

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (2)
docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-team-runtime-board-inspiration.md (1)

7-7: ⚡ Quick win

Replace brittle line-number anchors with heading anchors.

Line-number references like :41 and :230 will break silently when release-plan.md is edited. Use markdown heading anchors instead (e.g., release-plan.md#0018-requirements) or semantic references (e.g., "as defined in the 0.0.18 requirements section").

♻️ Example refactor using heading anchors
-Forge's board work is not just a kanban surface. The current release plan says `0.0.18` should consume issue adapters, run state, evidence, and review packets to ship a team runtime dashboard without a Forge-owned orchestration layer (`docs/work/2026-04-28-skeleton-pivot/release-plan.md:41`). The explicit `0.0.18` surface includes `forge board` / dashboard, `IssueAdapter` SPI, and external orchestrator compatibility (`docs/work/2026-04-28-skeleton-pivot/release-plan.md:230`, `docs/work/2026-04-28-skeleton-pivot/release-plan.md:234`, `docs/work/2026-04-28-skeleton-pivot/release-plan.md:235`, `docs/work/2026-04-28-skeleton-pivot/release-plan.md:248`, `docs/work/2026-04-28-skeleton-pivot/release-plan.md:249`).
+Forge's board work is not just a kanban surface. The current release plan says `0.0.18` should consume issue adapters, run state, evidence, and review packets to ship a team runtime dashboard without a Forge-owned orchestration layer (see [release-plan.md#v0018-team-runtime-dashboard](../release-plan.md#v0018-team-runtime-dashboard)). The explicit `0.0.18` surface includes `forge board` / dashboard, `IssueAdapter` SPI, and external orchestrator compatibility.
🤖 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
`@docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-team-runtime-board-inspiration.md`
at line 7, The references to release-plan.md using fragile line-number anchors
(e.g., the `:41`, `:230`, `:234`, `:235`, `:248`, `:249` suffixes in the
paragraph mentioning `0.0.18`) should be replaced with resilient heading anchors
or semantic references; update each backlink to use a markdown heading anchor
(for example `release-plan.md#0018-requirements` or
`release-plan.md#0.0.18-requirements`) or rewrite the sentence to say “as
defined in the 0.0.18 requirements section” and ensure the target headings exist
(create/normalize headings like “0.0.18 requirements” or “0018-requirements” in
the release-plan document if needed) so edits won’t break the anchors.
docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-open-questions-memory-ui-beads-post-018.md (1)

278-283: ⚡ Quick win

Document performance measurement methodology.

The document cites specific performance metrics (e.g., "0.7s" for bd list, "0.9s" for forge status) without documenting the measurement methodology, hardware specs, or dataset characteristics. Consider adding a note about measurement conditions to help readers assess applicability to their environments.

📝 Suggested clarification

Add context such as:

Current local grounding (measured on [hardware spec] with ~260 issues):
- a full `bd list --all --limit 0` pass took roughly 0.7s
- `forge status --json` took roughly 0.9s

Or add a footnote explaining measurement conditions.

🤖 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
`@docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-open-questions-memory-ui-beads-post-018.md`
around lines 278 - 283, Add a brief measurement methodology note near the
performance bullets (the lines citing "0.7s" for `bd list --all --limit 0` and
"0.9s" for `forge status --json` and the mention of `.beads/issues.jsonl`) that
states the hardware spec, dataset size (~260 Beads issues / size of
`.beads/issues.jsonl`), how timing was measured (command used, number of
runs/median or mean), OS/runtime environment, and any caching or repo state
(cold vs warm) so readers can reproduce/assess the numbers; update the existing
bullet block to include this contextual sentence or add a short footnote
immediately after those bullets.
🤖 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 @.github/docs-link-baseline.json:
- Around line 253-421: The baseline .github/docs-link-baseline.json contains
machine-specific absolute Windows paths (e.g. targets like
"C:/Users/harsha_befach/Downloads/forge/.worktrees/.../bin/forge.js" referenced
from docs/work/2026-04-03-setup-hardening-codex-parity/design.md); replace those
absolute paths with repo-relative paths or stable placeholders (for example
"bin/forge.js" or "<worktree>/bin/forge.js") throughout the JSON so no local
user PII is stored, and regenerate the baseline using the same
link-checker/generator to ensure future runs produce repo-relative targets only.

In
`@docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-evaluator-synthesis-protected-state-release-train.md`:
- Line 79: The document’s date header (the document date) is inconsistent with
the in-text reference "Research on 2026-05-19"; either update the document date
to 2026-05-19 (or later) to match that reference, or replace the phrase
"Research on 2026-05-19" with a non-date identifier (e.g., the research report
title or "the research conducted on 2026-05-19") so the file's date and the
in-text reference are logically consistent; update the string "Research on
2026-05-19" accordingly and ensure the document date header is changed if you
choose the first option.

In
`@docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-open-questions-memory-ui-beads-post-018.md`:
- Line 94: Update the Codex plugin metadata so the hooks capability reflects
actual support: change the "hooks" flag in the codex.plugin.json metadata from
false to true and add/align the supported lifecycle events to include
SessionStart, UserPromptSubmit, PreToolUse, PermissionRequest, PostToolUse, and
Stop (ensure the "hooks" object/array lists these event names exactly as
expected by Codex CLI and matches the machine's .codex/hooks.json format);
verify the modified keys appear under the same top-level plugin descriptor
(codex.plugin.json) so the runtime recognizes hook support.

In
`@docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-v3-runtime-control-plane-plan.md`:
- Around line 268-301: Update the inaccurate statement about Cursor by replacing
"Cursor supports project/user rules and `AGENTS.md`" with "Cursor supports
project/user rules in `.cursor/rules` (e.g., `.cursor/rules/*.md` and
`.cursor/rules/*.mdc`)" and ensure AGENTS.md is not claimed as Cursor's rule
source; then change the Projection rules' wording so the lines about `CLAUDE.md`
delegating to `AGENTS.md` and Codex/Claude memory interactions are presented as
a Forge recommended architecture or design goal (not current harness behavior),
explicitly noting that Claude and Codex maintain separate memory systems
unless/until Forge implements delegation, and label all projection claims as
recommended strategy rather than established convention.

In
`@docs/work/2026-04-28-skeleton-pivot/research/2026-05-19-docs-validation-adapters-and-discovery.md`:
- Around line 173-180: Update the "## Release Placement" section so its version
claims exactly mirror release-plan.md: remove the assertion that docs-validation
discovery and adapter selection ship in 0.0.16 and instead reference the
template/config baseline and migrate dry-run baseline responsibilities (as in
release-plan.md) and, if needed, call out that docs-validation (forge-30k) is
separately tracked; for 0.0.21, change "toggle" and "status panel" wording to
match release-plan's UI/TUI scope (omit feature-specific claims unless the plan
lists them); and for 0.0.24, replace "docs adapters as extension-contributed
substages" with the release-plan's broader description of extension-contributed
components/third-party adapters without claiming a docs-specific substaging.
Ensure the updated text in the "## Release Placement" paragraph references the
exact version numbers (0.0.16, 0.0.21, 0.0.24) and the terms "docs-validation",
"forge-30k", "UI/TUI", and "extension-contributed components" so reviewers can
verify alignment with release-plan.md.

In `@lib/docs-command.js`:
- Around line 285-286: Wrap the JSON.parse call that reads the baseline file in
a try/catch so malformed JSON is handled explicitly: when reading the file at
variable resolved, catch the parse error and throw or return a clear,
descriptive Error that includes the filename (resolved) and the original parse
error message instead of letting the raw JSON.parse exception escape; keep the
subsequent logic that maps (parsed.brokenLinks || []) through brokenLinkKey and
returns a Set unchanged once parsing succeeds.
- Around line 161-163: The containment check using
resolved.startsWith(packageDir) can produce false positives for sibling paths;
replace it with a proper relative-path containment check (e.g. use path.relative
after path.resolve/path.normalize) so you compute rel =
path.relative(packageDir, resolved) and treat the target as outside only if rel
startsWith('..') or is equal to '..' (or contains path.sep-prefixed '..');
update the block that currently pushes to brokenLinks (referencing resolved,
packageDir, brokenLinks, relFile, line, rawTarget) to use this new check to
correctly detect links that escape the project root.

---

Nitpick comments:
In
`@docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-open-questions-memory-ui-beads-post-018.md`:
- Around line 278-283: Add a brief measurement methodology note near the
performance bullets (the lines citing "0.7s" for `bd list --all --limit 0` and
"0.9s" for `forge status --json` and the mention of `.beads/issues.jsonl`) that
states the hardware spec, dataset size (~260 Beads issues / size of
`.beads/issues.jsonl`), how timing was measured (command used, number of
runs/median or mean), OS/runtime environment, and any caching or repo state
(cold vs warm) so readers can reproduce/assess the numbers; update the existing
bullet block to include this contextual sentence or add a short footnote
immediately after those bullets.

In
`@docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-team-runtime-board-inspiration.md`:
- Line 7: The references to release-plan.md using fragile line-number anchors
(e.g., the `:41`, `:230`, `:234`, `:235`, `:248`, `:249` suffixes in the
paragraph mentioning `0.0.18`) should be replaced with resilient heading anchors
or semantic references; update each backlink to use a markdown heading anchor
(for example `release-plan.md#0018-requirements` or
`release-plan.md#0.0.18-requirements`) or rewrite the sentence to say “as
defined in the 0.0.18 requirements section” and ensure the target headings exist
(create/normalize headings like “0.0.18 requirements” or “0018-requirements” in
the release-plan document if needed) so edits won’t break the anchors.
🪄 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: CHILL

Plan: Pro

Run ID: a77e0565-43d8-4a24-b712-47e822aa989f

📥 Commits

Reviewing files that changed from the base of the PR and between ade8380 and 41b2856.

📒 Files selected for processing (15)
  • .beads/backup/backup_state.json
  • .beads/last-touched
  • .github/docs-link-baseline.json
  • .github/workflows/docs-validation.yml
  • bin/forge.js
  • docs/work/2026-04-28-skeleton-pivot/README.md
  • docs/work/2026-04-28-skeleton-pivot/release-plan.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-evaluator-synthesis-protected-state-release-train.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-open-questions-memory-ui-beads-post-018.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-team-runtime-board-inspiration.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-v3-runtime-agent-orchestration-research.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-v3-runtime-control-plane-plan.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-19-docs-validation-adapters-and-discovery.md
  • lib/docs-command.js
  • test/docs-command.test.js

Comment thread .github/docs-link-baseline.json Outdated
Comment thread lib/docs-command.js Outdated
Comment thread lib/docs-command.js Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d2b63d9b01

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lib/docs-command.js Outdated
@github-actions
Copy link
Copy Markdown
Contributor

Tests passed in https://github.com/harshanandak/forge/actions/runs/26084429157. @coderabbitai review

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
docs/work/2026-04-28-skeleton-pivot/README.md (1)

52-64: ⚡ Quick win

Add the docs-validation adapter research link to Design references.

Line 52 onward lists the new research set, but it omits 2026-05-19-docs-validation-adapters-and-discovery.md, which is part of this release-train planning thread and helps anchor the 0.0.16 adapter-driven validation direction.

Suggested diff
 - [research/2026-05-18-v3-runtime-agent-orchestration-research.md](./research/2026-05-18-v3-runtime-agent-orchestration-research.md) - agent orchestration, protected paths, ledger, and external runtime inspiration.
 - [research/2026-05-18-evaluator-synthesis-protected-state-release-train.md](./research/2026-05-18-evaluator-synthesis-protected-state-release-train.md) - evaluator synthesis for protected state, Beads control plane, and public release train.
+- [research/2026-05-19-docs-validation-adapters-and-discovery.md](./research/2026-05-19-docs-validation-adapters-and-discovery.md) - adapter-driven docs validation discovery, baseline modes, and projection strategy.
🤖 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 `@docs/work/2026-04-28-skeleton-pivot/README.md` around lines 52 - 64, Add the
missing docs-validation adapter research link to the "Design references" list by
inserting a new bullet for
research/2026-05-19-docs-validation-adapters-and-discovery.md; place it
alongside the other research entries (near the other research/... items such as
research/2026-05-18-open-questions-memory-ui-beads-post-018.md) so the list
includes "-
[research/2026-05-19-docs-validation-adapters-and-discovery.md](./research/2026-05-19-docs-validation-adapters-and-discovery.md)".
Ensure the formatting matches the existing Markdown list style and ordering
under the Design references section.
🤖 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
`@docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-open-questions-memory-ui-beads-post-018.md`:
- Around line 98-123: The stable Forge event list is missing the
forge.session.stop event referenced in the projection table; update the list of
events (where the events like forge.session.start, forge.prompt.submit,
forge.tool.before, etc. are declared) to include forge.session.stop so the table
mapping (which lists forge.session.stop -> Stop command hook) and any tests/hook
projection logic (e.g., SessionStart, Stop, PreToolUse, PostToolUse handlers)
are consistent; ensure the textual list and the projection table both mention
forge.session.stop.

In
`@docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-v3-runtime-control-plane-plan.md`:
- Around line 34-37: The doc currently contradicts itself about canonical write
authority for instruction/harness files: remove the ambiguity by picking a
single canonical source and update the lines referencing AGENTS.md, CLAUDE.md,
.cursor/rules, skills, commands, hooks, and "Native harness files" so they
consistently state which is the source of truth (e.g., the runtime source vs
AGENTS.md), and change the conflicting sentences around "Native harness files
remain generated views, not separate truth" and the paragraph that names
AGENTS.md as the instruction source so they both reflect the chosen canonical
source; ensure references to MCP config and generated outputs (Codex, Claude,
Cursor, OpenCode) explicitly note they are derived projections, or conversely
that AGENTS.md is authoritative and harness files are generated, depending on
the chosen authority.

---

Nitpick comments:
In `@docs/work/2026-04-28-skeleton-pivot/README.md`:
- Around line 52-64: Add the missing docs-validation adapter research link to
the "Design references" list by inserting a new bullet for
research/2026-05-19-docs-validation-adapters-and-discovery.md; place it
alongside the other research entries (near the other research/... items such as
research/2026-05-18-open-questions-memory-ui-beads-post-018.md) so the list
includes "-
[research/2026-05-19-docs-validation-adapters-and-discovery.md](./research/2026-05-19-docs-validation-adapters-and-discovery.md)".
Ensure the formatting matches the existing Markdown list style and ordering
under the Design references section.
🪄 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: CHILL

Plan: Pro

Run ID: a66d2c52-6c6c-48b8-8120-9f20d04f3159

📥 Commits

Reviewing files that changed from the base of the PR and between 41b2856 and d2b63d9.

📒 Files selected for processing (15)
  • .beads/backup/backup_state.json
  • .beads/last-touched
  • .github/docs-link-baseline.json
  • .github/workflows/docs-validation.yml
  • bin/forge.js
  • docs/work/2026-04-28-skeleton-pivot/README.md
  • docs/work/2026-04-28-skeleton-pivot/release-plan.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-evaluator-synthesis-protected-state-release-train.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-open-questions-memory-ui-beads-post-018.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-team-runtime-board-inspiration.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-v3-runtime-agent-orchestration-research.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-v3-runtime-control-plane-plan.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-19-docs-validation-adapters-and-discovery.md
  • lib/docs-command.js
  • test/docs-command.test.js
✅ Files skipped from review due to trivial changes (5)
  • .beads/last-touched
  • .github/workflows/docs-validation.yml
  • .beads/backup/backup_state.json
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-v3-runtime-agent-orchestration-research.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-19-docs-validation-adapters-and-discovery.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • test/docs-command.test.js
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-evaluator-synthesis-protected-state-release-train.md
  • bin/forge.js
  • .github/docs-link-baseline.json

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
cat lib/docs-command.js
echo "---FILE_SEPARATOR---"
cat bin/forge.js
echo "---FILE_SEPARATOR---"
cat .github/workflows/docs-validation.yml
echo "---FILE_SEPARATOR---"
cat test/docs-command.test.js
echo "---FILE_SEPARATOR---"
# Check for Windows-style paths in baseline
cat .github/docs-link-baseline.json | python3 -c "
import json, sys
data = json.load(sys.stdin)
windows_paths = [e for e in data.get('brokenLinks', []) if '\\\\' in e.get('target', '') or e.get('target', '').startswith('C:') or ('\\\\' in e.get('file', ''))]
print(f'Total broken links: {len(data.get(\"brokenLinks\", []))}')
print(f'Windows-style paths: {len(windows_paths)}')
for p in windows_paths[:5]:
    print(json.dumps(p))
"
echo "---FILE_SEPARATOR---"
# Check the test for any issues
cat test/forge-docs-command.test.js 2>/dev/null || echo "File not found"

Length of output: 185504


@github-actions[bot] — thanks for the CI confirmation. Here's the full review of PR #175.


Review Summary

The docs-validation infrastructure is well-structured overall, with a clean module boundary in lib/docs-command.js, solid test coverage, and a sensible baseline design. There are a few issues that need attention before merging.


🔴 Critical — CI will break immediately

.github/workflows/docs-validation.yml — non-existent action versions

- uses: actions/checkout@v6       # ❌ does not exist (latest: v4)
- uses: actions/setup-node@v6     # ❌ does not exist (latest: v4)

Both @v6 tags do not exist for either action. The workflow will fail at the checkout step on every run. Fix:

- uses: actions/checkout@v4
- uses: actions/setup-node@v4
  with:
    node-version: 24

🟠 High — Windows-local paths committed to baseline

.github/docs-link-baseline.json contains 29 entries with absolute developer-machine paths:

{
  "file": "docs/work/2026-04-03-setup-hardening-codex-parity/design.md",
  "target": "C:/Users/harsha_befach/Downloads/forge/.worktrees/setup-hardening-codex-parity/bin/forge.js",
  "reason": "Target file does not exist"
}

These are .worktrees/ paths from a local Windows checkout and will never resolve on the CI runner (Linux). They inflate the baseline permanently, masking real new regressions. The checkMarkdownLinks resolver uses path.resolve(path.dirname(file), ...) so on Linux these absolute Windows paths pass the path-containment guard and land in the baseline as permanent noise.

Recommendation: Strip all entries whose target starts with an absolute path or contains .worktrees/ before committing the baseline. A quick filter:

jq '.brokenLinks |= map(select(.target | test("^[A-Z]:|.worktrees") | not))' \
  .github/docs-link-baseline.json > /tmp/clean.json && mv /tmp/clean.json .github/docs-link-baseline.json

🟡 Medium — Anchor validation slug mismatch

lib/docs-command.jscollectAnchors applies slugHeading() (lowercases + strips punctuation + collapses spaces), but the comparison in checkMarkdownLinks only lowercases the anchor fragment:

// collectAnchors — stored value is slugHeading(heading)
anchors.add(slugHeading(match[2]));

// checkMarkdownLinks — checked value is only .toLowerCase()
if (!anchors.has(anchorPart.toLowerCase())) {  // ← should be slugHeading(anchorPart)

For a heading ## v0.0.19 the stored slug is v0019, but a link [x](#v0.0.19) produces anchorPart.toLowerCase() = "v0.0.19" — a miss that should be a hit. And conversely [x](#v0019) should pass but won't match the raw heading text check. The fix:

// lib/docs-command.js — checkMarkdownLinks, anchor check
if (!anchors.has(slugHeading(anchorPart))) {

🟡 Medium — Docstring coverage gate is effectively disabled in CI

.github/workflows/docs-validation.yml:

run: bun ./bin/forge.js docs verify --baseline .github/docs-link-baseline.json --min-docstring-coverage 0

--min-docstring-coverage 0 means the docstring check never fails in CI, making the coverage reporting informational-only. This is fine as a bootstrapping step, but worth noting that the gate needs to be raised once the codebase reaches an acceptable baseline coverage. Consider tracking this as a follow-up Beads issue.


🟢 Low — minor issues

lib/docs-command.jsvalidateDocs mutates its return object

links.allBrokenLinks = allBrokenLinks;   // mutates in place
links.knownBrokenLinks = allBrokenLinks.length - newBrokenLinks.length;
links.brokenLinks = newBrokenLinks;

checkMarkdownLinks returns links and validateDocs then adds three properties to it, which means callers of checkMarkdownLinks directly would get a different shape than callers who go through validateDocs. Consider assembling a new object in validateDocs rather than mutating the result.

lib/docs-command.jswalkFiles has no recursion depth limit

For extremely deep directory trees this could overflow the call stack. A simple maxDepth guard (e.g., 20) would prevent edge-case crashes.

bin/forge.js_checkWritePermission is dead code

Line with @private - Currently unused but kept for future permission validation — this function is never called. If it has no scheduled use it should be removed to keep the module clean.


✅ What looks good

  • lib/docs-command.js design is clean: link-checking, docstring coverage, and baseline diffing are properly separated.
  • Path-traversal containment check (!resolved.startsWith(packageDir)) is correct on POSIX.
  • writeDocsBaseline correctly writes allBrokenLinks (not the filtered set) so the baseline captures the full picture.
  • suppressDocsDetectOutput in main() correctly gates double-output for the detect sub-command.
  • Tests in test/docs-command.test.js cover the two core validation paths with proper temp-dir isolation and cleanup.
  • The slugHeading function itself is consistent — the issue is only in the comparison call site.

@github-actions
Copy link
Copy Markdown
Contributor

📦 Package Size Report

Size: 9MB (9710KB)
Threshold: 10MB
Status: ✅ Within threshold

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 951662a4d7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lib/docs-command.js Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
lib/docs-command.js (1)

266-266: 💤 Low value

Use optional chaining for previous.value.

Per static analysis, optional chaining improves readability and guards against unexpected undefined values.

♻️ Suggested change
-  if (!previous || previous.type !== 'CommentBlock' || !previous.value.trim().startsWith('*')) {
+  if (!previous || previous.type !== 'CommentBlock' || !previous.value?.trim().startsWith('*')) {
     return false;
   }
🤖 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 `@lib/docs-command.js` at line 266, Update the conditional to use optional
chaining on previous.value so it safely handles undefined values; replace the
current check that uses previous.value.trim().startsWith('*') with a chained
form like previous.value?.trim()?.startsWith('*') in the if condition (the line
containing the conditional with previous and previous.value) so the guard no
longer throws if previous.value is missing.
🤖 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
`@docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-open-questions-memory-ui-beads-post-018.md`:
- Around line 19-21: Remove the machine-specific absolute paths and username by
replacing occurrences of "Local Codex config:
`C:\Users\harsha_befach\.codex\config.toml`" and "Local Codex hooks:
`C:\Users\harsha_befach\.codex\hooks.json`" (and any similar `C:\Users\...`
strings) with a portable, non-PII placeholder such as "Local Codex config:
~/.codex/config.toml" and "Local Codex hooks: ~/.codex/hooks.json" or an
explicit template like "<user_home>/.codex/config.toml"; ensure all other
instances (the other occurrences mentioned in the comment) are updated
consistently and no local usernames remain in the document.
- Around line 353-413: The version-to-scope mapping under the headings
0.0.19–0.0.25 in this document conflicts with the canonical release plan; update
each numbered heading (0.0.19, 0.0.20, …, 0.0.25) so the titles and bullet
scopes exactly match the canonical release-plan (release-plan.md) for this PR,
replacing the current entries like "Local Control Plane Foundation" and "Beads
Scale UI" with the canonical names and scopes, and ensure any moved/renamed
items are copied verbatim from the release-plan to avoid divergence.

In `@lib/docs-command.js`:
- Around line 210-215: The anchor check uses a raw lowercased anchorPart but
collectAnchors stores headings via slugHeading(heading), so normalize anchorPart
the same way before lookup: call slugHeading(anchorPart) (or the same
normalization helper used inside collectAnchors) and use that result in the
anchors.has(...) check (update the conditional that currently does
anchors.has(anchorPart.toLowerCase()) to use the slugified value); reference
collectAnchors, slugHeading, and anchorPart to locate the change.

---

Nitpick comments:
In `@lib/docs-command.js`:
- Line 266: Update the conditional to use optional chaining on previous.value so
it safely handles undefined values; replace the current check that uses
previous.value.trim().startsWith('*') with a chained form like
previous.value?.trim()?.startsWith('*') in the if condition (the line containing
the conditional with previous and previous.value) so the guard no longer throws
if previous.value is missing.
🪄 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: CHILL

Plan: Pro

Run ID: 6a157fa5-989c-44c5-b868-7ae64767cb66

📥 Commits

Reviewing files that changed from the base of the PR and between d2b63d9 and 951662a.

📒 Files selected for processing (9)
  • .beads/issues.jsonl
  • bin/forge.js
  • docs/work/2026-04-28-skeleton-pivot/README.md
  • docs/work/2026-04-28-skeleton-pivot/release-plan.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-open-questions-memory-ui-beads-post-018.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-v3-runtime-control-plane-plan.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-19-skills-first-agent-packaging.md
  • lib/docs-command.js
  • test/docs-command.test.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • bin/forge.js

Comment thread lib/docs-command.js
@github-actions
Copy link
Copy Markdown
Contributor

Tests passed in https://github.com/harshanandak/forge/actions/runs/26085272957. @coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

Thanks for the CI pass confirmation. Triggering a full review now.

A quick note on the earlier 🔴 Critical item: based on updated information, actions/checkout@v6 and actions/setup-node@v6 appear to have been released (the checkout action changelog shows a "Clarify v6 README" entry dated 2025-12-01), so those action versions likely do exist now. I'll retract that critical finding — the workflow should be fine on that point. The remaining items (Windows-local paths in the baseline, anchor slug mismatch in slugHeading vs .toLowerCase(), and the disabled docstring coverage gate) stand as-is.

✅ Actions performed

Full review triggered.

@github-actions
Copy link
Copy Markdown
Contributor

📦 Package Size Report

Size: 9MB (9711KB)
Threshold: 10MB
Status: ✅ Within threshold

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (3)
docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-evaluator-synthesis-protected-state-release-train.md (1)

79-79: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix temporal inconsistency in date reference.

The document is dated 2026-05-18 (line 3) but references "Research on 2026-05-19" (line 79), creating a logical inconsistency. Update to "Recent research" or adjust the document date to 2026-05-19 or later.

🤖 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
`@docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-evaluator-synthesis-protected-state-release-train.md`
at line 79, Update the temporal mismatch by changing the in-text reference
"Research on 2026-05-19" to a consistent phrasing such as "Recent research" (or
update the document date header from "2026-05-18" to "2026-05-19") so the
document date and the research reference match; search for the literal string
"Research on 2026-05-19" and the header date "2026-05-18" in the file and make
the two values consistent.
docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-open-questions-memory-ui-beads-post-018.md (2)

19-21: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Remove machine-specific absolute paths and username from documentation.

Lines 19-21 (and also lines 36, 38, 90) expose local username/path (C:\Users\harsha_befach\...), which is both non-portable and a PII leak in committed documentation.

📝 Suggested rewrite
-- Local Codex config: `C:\Users\harsha_befach\.codex\config.toml`
-- Local Codex hooks: `C:\Users\harsha_befach\.codex\hooks.json`
+- Local Codex config: `~/.codex/config.toml` (machine-local example)
+- Local Codex hooks: `~/.codex/hooks.json` (machine-local example)

Apply similar changes to lines 36, 38, and 90.

🤖 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
`@docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-open-questions-memory-ui-beads-post-018.md`
around lines 19 - 21, Replace the machine-specific absolute paths that expose a
username (e.g. the strings "C:\Users\harsha_befach\.codex\config.toml" and
"C:\Users\harsha_befach\.codex\hooks.json") with portable, non-PII placeholders
such as "%USERPROFILE%\.codex\config.toml", "~/.codex/config.toml", or
"<user_home>/.codex/config.toml" (and similarly for hooks.json); apply the same
replacement to the other occurrences referenced in the comment (lines containing
those paths at lines 36, 38, and 90) and scan the document for any other
hardcoded usernames/absolute paths to convert to placeholders or relative
examples.

353-413: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Align version mapping with canonical release-plan.md in this PR.

The version-to-scope mapping (lines 353-413) conflicts with release-plan.md from this same PR. For example:

  • Line 353: "0.0.19: Local Control Plane Foundation" vs. release-plan.md: "0.0.19: Protected State Surfaces"
  • Line 362: "0.0.20: Safe Config Editing" vs. release-plan.md: "0.0.20: Issue Graph And Beads Control Plane"

This creates conflicting execution guidance. Update each heading and scope to match the canonical release-plan.md exactly.

🤖 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
`@docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-open-questions-memory-ui-beads-post-018.md`
around lines 353 - 413, Update the version-to-scope headings in this file so
they exactly match the canonical release-plan.md in this PR: replace headings
like "0.0.19: Local Control Plane Foundation", "0.0.20: Safe Config Editing",
etc. with the exact titles and scopes from release-plan.md (for example change
"0.0.19: Local Control Plane Foundation" → "0.0.19: Protected State Surfaces"
and "0.0.20: Safe Config Editing" → "0.0.20: Issue Graph And Beads Control
Plane"), ensuring every numbered heading and its bullet scope text mirrors
release-plan.md verbatim to remove the conflicting guidance.
🤖 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 @.github/workflows/docs-validation.yml:
- Around line 6-28: The workflow's trigger path lists in
.github/workflows/docs-validation.yml omit the baseline file so updates to
.github/docs-link-baseline.json won't run validation; update the paths arrays
under both push and pull_request in that file to include
'.github/docs-link-baseline.json' (add the entry alongside README.md,
CHANGELOG.md, etc.) so baseline-only edits trigger the docs-validation workflow.

In `@bin/forge.js`:
- Around line 4326-4329: The current parsing of --min-docstring-coverage
silently converts invalid inputs to 0; update the args parsing logic around
minCoverageIndex and minDocstringCoverage to explicitly validate the user value:
parse the token using Number (or parseFloat), confirm it is a finite number and
within the allowed range 0..100 (inclusive), and if the check fails emit a clear
CLI error (e.g., console.error/processLogger/error output) and exit with a
non-zero status instead of falling back to 0; keep the existing variable names
minCoverageIndex and minDocstringCoverage so you only change the
parsing/validation branch.

---

Duplicate comments:
In
`@docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-evaluator-synthesis-protected-state-release-train.md`:
- Line 79: Update the temporal mismatch by changing the in-text reference
"Research on 2026-05-19" to a consistent phrasing such as "Recent research" (or
update the document date header from "2026-05-18" to "2026-05-19") so the
document date and the research reference match; search for the literal string
"Research on 2026-05-19" and the header date "2026-05-18" in the file and make
the two values consistent.

In
`@docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-open-questions-memory-ui-beads-post-018.md`:
- Around line 19-21: Replace the machine-specific absolute paths that expose a
username (e.g. the strings "C:\Users\harsha_befach\.codex\config.toml" and
"C:\Users\harsha_befach\.codex\hooks.json") with portable, non-PII placeholders
such as "%USERPROFILE%\.codex\config.toml", "~/.codex/config.toml", or
"<user_home>/.codex/config.toml" (and similarly for hooks.json); apply the same
replacement to the other occurrences referenced in the comment (lines containing
those paths at lines 36, 38, and 90) and scan the document for any other
hardcoded usernames/absolute paths to convert to placeholders or relative
examples.
- Around line 353-413: Update the version-to-scope headings in this file so they
exactly match the canonical release-plan.md in this PR: replace headings like
"0.0.19: Local Control Plane Foundation", "0.0.20: Safe Config Editing", etc.
with the exact titles and scopes from release-plan.md (for example change
"0.0.19: Local Control Plane Foundation" → "0.0.19: Protected State Surfaces"
and "0.0.20: Safe Config Editing" → "0.0.20: Issue Graph And Beads Control
Plane"), ensuring every numbered heading and its bullet scope text mirrors
release-plan.md verbatim to remove the conflicting guidance.
🪄 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: CHILL

Plan: Pro

Run ID: 7682c026-f443-44ff-a7af-f65fd41aefab

📥 Commits

Reviewing files that changed from the base of the PR and between ade8380 and 951662a.

📒 Files selected for processing (17)
  • .beads/backup/backup_state.json
  • .beads/issues.jsonl
  • .beads/last-touched
  • .github/docs-link-baseline.json
  • .github/workflows/docs-validation.yml
  • bin/forge.js
  • docs/work/2026-04-28-skeleton-pivot/README.md
  • docs/work/2026-04-28-skeleton-pivot/release-plan.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-evaluator-synthesis-protected-state-release-train.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-open-questions-memory-ui-beads-post-018.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-team-runtime-board-inspiration.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-v3-runtime-agent-orchestration-research.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-v3-runtime-control-plane-plan.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-19-docs-validation-adapters-and-discovery.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-19-skills-first-agent-packaging.md
  • lib/docs-command.js
  • test/docs-command.test.js

Comment thread .github/workflows/docs-validation.yml
Comment thread bin/forge.js Outdated
@github-actions
Copy link
Copy Markdown
Contributor

📦 Package Size Report

Size: 9MB (9711KB)
Threshold: 10MB
Status: ✅ Within threshold

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8ea4d64dcd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lib/docs-command.js
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 `@lib/docs-command.js`:
- Around line 379-380: The baseline key for broken links currently omits the
line number causing overly-broad suppression; update the brokenLinkKey function
to include the item's line (e.g., return
`${item.file}\0${item.line}\0${item.target}\0${item.reason}`) so each
broken-link entry is unique per line, and verify callers that construct the
broken-link item (the objects passed into brokenLinkKey) provide a line
property.
- Around line 115-123: collectAnchors currently counts headings inside fenced
code blocks; modify collectAnchors to track whether we're inside a fenced block
(introduce a boolean like inFence) and toggle it when a line trimmed starts with
``` or ~~~, skipping processing for lines while inFence is true so
getMarkdownHeadingText and slugHeading are only invoked for real document
headings outside fences; ensure the fence-toggle uses continue to avoid treating
the fence line itself as content and that subsequent lines are ignored until the
closing fence.
🪄 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: CHILL

Plan: Pro

Run ID: dc20963e-d77f-44a6-b5b9-c26ffa57fa3f

📥 Commits

Reviewing files that changed from the base of the PR and between 951662a and 8ea4d64.

📒 Files selected for processing (9)
  • .github/docs-link-baseline.json
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-evaluator-synthesis-protected-state-release-train.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-open-questions-memory-ui-beads-post-018.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-v3-runtime-control-plane-plan.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-19-docs-validation-adapters-and-discovery.md
  • lib/agents/codex.plugin.json
  • lib/docs-command.js
  • test/cleanup/plugin-catalog.test.js
  • test/docs-command.test.js
✅ Files skipped from review due to trivial changes (3)
  • lib/agents/codex.plugin.json
  • .github/docs-link-baseline.json
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-19-docs-validation-adapters-and-discovery.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-evaluator-synthesis-protected-state-release-train.md

Comment thread lib/docs-command.js
Comment thread lib/docs-command.js Outdated
@github-actions
Copy link
Copy Markdown
Contributor

📦 Package Size Report

Size: 9MB (9711KB)
Threshold: 10MB
Status: ✅ Within threshold

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f9d33a9157

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lib/docs-command.js Outdated
@github-actions
Copy link
Copy Markdown
Contributor

📦 Package Size Report

Size: 9MB (9723KB)
Threshold: 10MB
Status: ✅ Within threshold

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dbd3ddeabf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lib/docs-command.js Outdated
@github-actions
Copy link
Copy Markdown
Contributor

📦 Package Size Report

Size: 9MB (9723KB)
Threshold: 10MB
Status: ✅ Within threshold

@github-actions
Copy link
Copy Markdown
Contributor

Tests passed in https://github.com/harshanandak/forge/actions/runs/26152364431. @coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

@github-actions CI pass confirmed ✅ — triggering a full review of PR #175. The following findings from prior passes remain open and unaddressed:

Severity Finding
🟠 High .github/docs-link-baseline.json — 29 entries with Windows-local absolute paths and .worktrees/ entries that will never resolve on CI (Linux), permanently masking real regressions. Strip with: jq '.brokenLinks |= map(select(.target | test("^[A-Z]:|.worktrees") | not))'
🟡 Medium lib/docs-command.jscheckMarkdownLinks — anchors stored via slugHeading(heading) but compared using only anchorPart.toLowerCase(). Fix: replace with slugHeading(anchorPart) at the comparison site.
🟡 Medium .github/workflows/docs-validation.yml--min-docstring-coverage 0 makes the docstring gate non-failing in CI. Track raising the threshold as a follow-up.
🟢 Low validateDocs mutates the checkMarkdownLinks return object; walkFiles has no recursion depth guard; _checkWritePermission in bin/forge.js appears unused.
✅ Actions performed

Full review triggered.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 40564b3a92

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lib/docs-command.js Outdated
@github-actions
Copy link
Copy Markdown
Contributor

📦 Package Size Report

Size: 9MB (9724KB)
Threshold: 10MB
Status: ✅ Within threshold

@github-actions
Copy link
Copy Markdown
Contributor

📦 Package Size Report

Size: 9MB (9724KB)
Threshold: 10MB
Status: ✅ Within threshold

@github-actions
Copy link
Copy Markdown
Contributor

Tests passed in https://github.com/harshanandak/forge/actions/runs/26154187688. @coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

@github-actions CI pass confirmed ✅ — triggering a full review of PR #175. The following findings from prior passes remain open and unaddressed:

Severity Finding
🟠 High .github/docs-link-baseline.json — 29 entries with Windows-local absolute paths and .worktrees/ entries that will never resolve on CI (Linux), permanently masking real regressions. Strip with: jq '.brokenLinks |= map(select(.target | test("^[A-Z]:|.worktrees") | not))'
🟡 Medium lib/docs-command.jscheckMarkdownLinks — anchors stored via slugHeading(heading) but compared using only anchorPart.toLowerCase(). Fix: replace with slugHeading(anchorPart) at the comparison site.
🟡 Medium .github/workflows/docs-validation.yml--min-docstring-coverage 0 makes the docstring gate non-failing in CI. Track raising the threshold as a follow-up.
🟢 Low validateDocs mutates the checkMarkdownLinks return object; walkFiles has no recursion depth guard; _checkWritePermission in bin/forge.js appears unused.
✅ Actions performed

Full review triggered.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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
`@docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-open-questions-memory-ui-beads-post-018.md`:
- Around line 422-423: Update the contradictory bullet in the "What is clear
now" list to stop implying Codex hooks are missing: change the line that
currently reads "Forge's Codex harness metadata should be updated because Codex
hooks now exist." to a statement that specifies refining per-event capability
metadata in lib/agents/codex.plugin.json (e.g., "Refine per-event capability
metadata in lib/agents/codex.plugin.json to reflect newly supported Codex
hooks") so it aligns with the earlier statement that Codex hook support is
already declared.

In `@lib/docs-command.js`:
- Around line 425-427: The code only emits missingReference for full-form
references (usage.hasFullReference); update the conditional that pushes into
links so it also handles unresolved shortcut references (e.g., when a usage
represents a shortcut/implicit reference rather than full form). Modify the
branch around usage.hasFullReference (in lib/docs-command.js where links.push({
missingReference: usage.rawLabel.trim(), index: offset + usage.labelStart }) is
called) to include the shortcut-check (such as usage.hasShortcutReference or the
appropriate flag on usage) or otherwise detect unresolved shortcut usages
(presence of usage.rawLabel and no resolved target) and push the same
missingReference object using usage.rawLabel.trim() and offset +
usage.labelStart. Ensure both full and shortcut unresolved references produce
missingReference entries.
🪄 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: CHILL

Plan: Pro

Run ID: 94481bf2-ac40-4b5c-82e0-8607ba758283

📥 Commits

Reviewing files that changed from the base of the PR and between ade8380 and e544ac9.

📒 Files selected for processing (21)
  • .beads/backup/backup_state.json
  • .beads/issues.jsonl
  • .beads/last-touched
  • .github/docs-link-baseline.json
  • .github/workflows/docs-validation.yml
  • bin/forge.js
  • docs/work/2026-04-03-setup-hardening-codex-parity/design.md
  • docs/work/2026-04-28-skeleton-pivot/README.md
  • docs/work/2026-04-28-skeleton-pivot/release-plan.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-evaluator-synthesis-protected-state-release-train.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-open-questions-memory-ui-beads-post-018.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-team-runtime-board-inspiration.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-v3-runtime-agent-orchestration-research.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-v3-runtime-control-plane-plan.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-19-docs-validation-adapters-and-discovery.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-19-skills-first-agent-packaging.md
  • lib/agents/codex.plugin.json
  • lib/docs-command.js
  • test/cleanup/plugin-catalog.test.js
  • test/docs-command.test.js
  • test/v2-fixture-corpus.test.js

Comment thread lib/docs-command.js Outdated
@github-actions
Copy link
Copy Markdown
Contributor

📦 Package Size Report

Size: 9MB (9770KB)
Threshold: 10MB
Status: ✅ Within threshold

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cbe81cfb10

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lib/docs-command.js Outdated
Comment thread lib/docs-command.js
@github-actions
Copy link
Copy Markdown
Contributor

Tests passed in https://github.com/harshanandak/forge/actions/runs/26156052169. @coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

@github-actions CI pass confirmed ✅ — triggering a full review of PR #175. The following findings from prior passes remain open and unaddressed:

Severity Finding
🟠 High .github/docs-link-baseline.json — 29 entries with Windows-local absolute paths and .worktrees/ entries that will never resolve on CI (Linux), permanently masking real regressions. Strip with: jq '.brokenLinks |= map(select(.target | test("^[A-Z]:|.worktrees") | not))'
🟡 Medium lib/docs-command.jscheckMarkdownLinks — anchors stored via slugHeading(heading) but compared using only anchorPart.toLowerCase(). Fix: replace with slugHeading(anchorPart) at the comparison site.
🟡 Medium .github/workflows/docs-validation.yml--min-docstring-coverage 0 makes the docstring gate non-failing in CI. Track raising the threshold as a follow-up.
🟢 Low validateDocs mutates the checkMarkdownLinks return object; walkFiles has no recursion depth guard; _checkWritePermission in bin/forge.js appears unused.
✅ Actions performed

Full review triggered.

@github-actions
Copy link
Copy Markdown
Contributor

📦 Package Size Report

Size: 9MB (9771KB)
Threshold: 10MB
Status: ✅ Within threshold

@sonarqubecloud
Copy link
Copy Markdown

@github-actions
Copy link
Copy Markdown
Contributor

Tests passed in https://github.com/harshanandak/forge/actions/runs/26156854040. @coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

@github-actions CI pass confirmed ✅ — triggering a full review of PR #175. The following findings from prior passes remain open and unaddressed:

Severity Finding
🟠 High .github/docs-link-baseline.json — 29 entries with Windows-local absolute paths and .worktrees/ entries that will never resolve on CI (Linux), permanently masking real regressions. Strip with: jq '.brokenLinks |= map(select(.target | test("^[A-Z]:|.worktrees") | not))'
🟡 Medium lib/docs-command.jscheckMarkdownLinks — anchors stored via slugHeading(heading) but compared using only anchorPart.toLowerCase(). Fix: replace with slugHeading(anchorPart) at the comparison site.
🟡 Medium .github/workflows/docs-validation.yml--min-docstring-coverage 0 makes the docstring gate non-failing in CI. Track raising the threshold as a follow-up.
🟢 Low validateDocs mutates the checkMarkdownLinks return object; walkFiles has no recursion depth guard; _checkWritePermission in bin/forge.js appears unused.
✅ Actions performed

Full review triggered.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1e3b53a32c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lib/docs-command.js
Comment on lines +583 to +585
const trimmed = line.trimStart();
if (!trimmed.startsWith('[')) {
return null;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Parse reference definitions inside block quotes

CommonMark allows link reference definitions inside block containers, but _getReferenceLinkDefinition only recognizes lines that begin directly with [ after left trim. A definition like > [guide]: docs/guide.md is therefore ignored, and both the definition line and [Guide][guide] usages are reported as missing references even when the target file exists. This creates false failures in forge docs verify for valid markdown files that keep reference definitions in quoted/listed sections.

Useful? React with 👍 / 👎.

Comment thread lib/docs-command.js
}

function getMarkdownHeadingText(line) {
const trimmed = line.trimStart();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Ignore indented ATX headings when collecting anchors

getMarkdownHeadingText uses trimStart(), so lines indented by 4+ spaces (which are indented code blocks in CommonMark) are still parsed as headings. That causes collectAnchors to add anchors from code examples, so links to nonexistent real headings can incorrectly pass when the matching text appears only inside indented code.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (1)
docs/work/2026-04-03-setup-hardening-codex-parity/design.md (1)

177-183: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix inconsistent ordered numbering in the agent list.

The list jumps from 3. OpenCode to 5. GitHub Copilot, which makes cross-reference and ranking unclear. Use consistent numbering.

Suggested patch
-5. **GitHub Copilot**
+4. **GitHub Copilot**
🤖 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 `@docs/work/2026-04-03-setup-hardening-codex-parity/design.md` around lines 177
- 183, The ordered list numbering is inconsistent: it jumps from "3. OpenCode"
to "5. GitHub Copilot"; update the list so numbering is sequential (e.g., change
"5. GitHub Copilot" to "4. GitHub Copilot") so the agent list and
cross-references remain clear; locate the entries titled "OpenCode" and "GitHub
Copilot" in the document and correct the numeric label to maintain continuous
ordering.
🤖 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 @.github/docs-link-baseline.json:
- Around line 215-1090: The baseline is too broad and includes
template/generated placeholders (e.g. "docs/reference/RESEARCH_TEMPLATE.md" and
"graphify-out/GRAPH_REPORT.md") which should be excluded; update the
.github/docs-link-baseline.json to remove entries for those files and narrow the
baseline to only actionable production docs paths (e.g. keep files under docs/
that are real content and exclude templates and generated outputs), and if you
have a link-checker config or generation script, add exclusion patterns for
"docs/reference/RESEARCH_TEMPLATE.md" and "graphify-out/**" so future baselines
don’t reintroduce these placeholders.

In @.github/workflows/docs-validation.yml:
- Around line 63-66: Before running the docs verification step that uses
"--baseline .github/docs-link-baseline.json", add a new workflow step (e.g.,
name: "Validate docs baseline portability") that scans
.github/docs-link-baseline.json for non-portable entries (absolute Windows paths
containing backslashes or drive letters like ^[A-Za-z]:\\, and references to
".worktrees/" or other CI-specific paths) and fails the job if any are found;
implement this as a small shell/Node script or one-liner (grep/awk/jq) invoked
before the existing "Run docs validation" step so the command "bun
./bin/forge.js docs verify --baseline .github/docs-link-baseline.json ..." only
runs when the baseline is portable.

In `@lib/docs-command.js`:
- Around line 845-860: getPublicDocTargets currently filters out private names
by testing target.name.startsWith('_'), but CommonJS qualified exports (e.g.
module.exports._hidden or exports.foo._hidden) produce dotted names so the
leading segment test fails; update the logic so the private check inspects only
the final identifier segment (e.g. split on '.' and check the last part) or
normalize names emitted by addDocTargetFromCommonJsExport/related helpers by
stripping "module.exports." and "exports." prefixes before adding targets;
modify getPublicDocTargets (or ensure addDocTargetFromCommonJsExport) to use the
last-dot segment when applying the startsWith('_') filter so qualified CJS
private members are excluded.
- Around line 631-637: The parent-directory check in isWithinRoot incorrectly
rejects names that merely start with '..' (e.g., "..baseline.json"); update the
condition to only treat a relative path as escaping when it is exactly '..' or
begins with '..' + path.sep. Concretely, in isWithinRoot (which calls
resolveRealPathForContainment), replace the relative.startsWith('..') test with
a check like (relative === '..' || relative.startsWith('..' + path.sep)) so
legitimate filenames that begin with '..' are allowed while actual upward
traversal is still prevented.

---

Duplicate comments:
In `@docs/work/2026-04-03-setup-hardening-codex-parity/design.md`:
- Around line 177-183: The ordered list numbering is inconsistent: it jumps from
"3. OpenCode" to "5. GitHub Copilot"; update the list so numbering is sequential
(e.g., change "5. GitHub Copilot" to "4. GitHub Copilot") so the agent list and
cross-references remain clear; locate the entries titled "OpenCode" and "GitHub
Copilot" in the document and correct the numeric label to maintain continuous
ordering.
🪄 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: CHILL

Plan: Pro

Run ID: ebd41c09-b814-47cb-8a06-879e42ca8e2a

📥 Commits

Reviewing files that changed from the base of the PR and between ade8380 and 1e3b53a.

📒 Files selected for processing (22)
  • .beads/backup/backup_state.json
  • .beads/issues.jsonl
  • .beads/last-touched
  • .github/docs-link-baseline.json
  • .github/workflows/docs-validation.yml
  • bin/forge.js
  • docs/work/2026-04-03-setup-hardening-codex-parity/design.md
  • docs/work/2026-04-28-skeleton-pivot/README.md
  • docs/work/2026-04-28-skeleton-pivot/release-plan.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-evaluator-synthesis-protected-state-release-train.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-open-questions-memory-ui-beads-post-018.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-team-runtime-board-inspiration.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-v3-runtime-agent-orchestration-research.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-18-v3-runtime-control-plane-plan.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-19-docs-validation-adapters-and-discovery.md
  • docs/work/2026-04-28-skeleton-pivot/research/2026-05-19-skills-first-agent-packaging.md
  • lib/agents/codex.plugin.json
  • lib/docs-command.js
  • packages/skills/README.md
  • test/cleanup/plugin-catalog.test.js
  • test/docs-command.test.js
  • test/v2-fixture-corpus.test.js

Comment on lines +215 to +1090
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 1,
"target": "Feature Name",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 7,
"target": "What we're trying to achieve - clear problem statement and goals",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 13,
"target": "Description of existing implementation",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 14,
"target": "Yes/No + reasoning",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 15,
"target": "What worked, what didn't",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 18,
"target": "name",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 19,
"target": "Description",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 20,
"target": "Low/Medium/High",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 21,
"target": "List any dependencies",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 25,
"target": "Available testing tools/helpers",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 26,
"target": "Current state - percentage, gaps",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 27,
"target": "What patterns are used - unit, integration, E2E",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 32,
"target": "URL",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 33,
"target": "Summary of best practice",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 34,
"target": "How it applies to our project",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 35,
"target": "What decision this influences",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 36,
"target": "How to apply",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 38,
"target": "URL",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 39,
"target": "...",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 42,
"target": "Description",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 43,
"target": "GitHub/SO/Blog URL",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 44,
"target": "How to avoid",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 45,
"target": "Changes to approach",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 46,
"target": "How common is this issue",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 48,
"target": "...",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 51,
"target": "name and version",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 52,
"target": "Relevant methods/patterns",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 53,
"target": "Version requirements, breaking changes",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 54,
"target": "Implementation details",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 55,
"target": "Code snippet",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 57,
"target": "...",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 60,
"target": "URL",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 61,
"target": "Who implemented this",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 62,
"target": "Production scale, users, data volume",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 63,
"target": "What they learned",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 64,
"target": "How it relates to our use case",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 66,
"target": "...",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 70,
"target": "Decision Title",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 71,
"target": "What we decided",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 72,
"target": "Why we chose this approach",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 73,
"target": "Research that supports this - links to sources",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 75,
"target": "Alternative 1",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 75,
"target": "Why rejected",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 76,
"target": "Alternative 2",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 76,
"target": "Why rejected",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 77,
"target": "What we're giving up, what we're gaining",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 78,
"target": "Low/Medium/High",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 78,
"target": "Risk description",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 80,
"target": "Decision Title",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 81,
"target": "...",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 86,
"target": "Scenario description",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 89,
"target": "What to verify",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 90,
"target": "Required test data/mocks",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 91,
"target": "List edge cases to cover",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 93,
"target": "...",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 96,
"target": "Scenario description",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 98,
"target": "What components are being tested together",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 99,
"target": "What to verify",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 100,
"target": "Database fixtures, API mocks",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 102,
"target": "...",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 105,
"target": "User flow scenario",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 107,
"target": "Step-by-step user actions",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 108,
"target": "What user should see/experience",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 109,
"target": "Complete test environment setup",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 111,
"target": "...",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 118,
"target": "High/Medium/Low",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 119,
"target": "Yes/No",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 120,
"target": "How addressed - RLS policies, permission checks",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 121,
"target": "Security test scenarios",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 122,
"target": "Links to security research",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 125,
"target": "High/Medium/Low",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 126,
"target": "Yes/No",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 127,
"target": "Encryption at rest/transit, key management",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 128,
"target": "Encryption tests",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 129,
"target": "Data protection requirements",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 132,
"target": "High/Medium/Low",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 133,
"target": "Yes/No",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 134,
"target": "Parameterized queries, input validation, sanitization",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 135,
"target": "SQL injection tests, XSS tests, command injection tests",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 136,
"target": "What libraries help prevent injection",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 139,
"target": "High/Medium/Low",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 140,
"target": "Key threats identified",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 141,
"target": "Patterns used - zero trust, defense in depth",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 142,
"target": "Security considerations in design",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 143,
"target": "Security design validation",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 146,
"target": "High/Medium/Low",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 147,
"target": "Yes/No",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 148,
"target": "CSP, HSTS, X-Frame-Options, etc.",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 149,
"target": "No sensitive info in errors",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 150,
"target": "No default/test credentials",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 151,
"target": "Configuration security tests",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 154,
"target": "High/Medium/Low",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 155,
"target": "Yes/No - tool used",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 156,
"target": "Count and severity from scan",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 157,
"target": "If vulnerabilities found",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 158,
"target": "Dependabot, Snyk, etc.",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 159,
"target": "Dependency security checks",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 162,
"target": "High/Medium/Low",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 163,
"target": "OAuth2/JWT/Session/etc.",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 164,
"target": "Secure/reviewed - timeout, rotation",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 165,
"target": "Requirements if applicable",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 166,
"target": "Required/Optional/Not applicable",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 167,
"target": "Rate limiting, account lockout",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 168,
"target": "Authentication tests, session tests",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 171,
"target": "High/Medium/Low",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 172,
"target": "Where implemented - signatures, checksums",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 173,
"target": "Yes/No",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 174,
"target": "Pipeline reviewed, secrets management",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 175,
"target": "Trusted sources, verification",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 176,
"target": "Integrity validation tests",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 179,
"target": "High/Medium/Low",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 180,
"target": "List what's tracked",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 181,
"target": "What's tracked for compliance",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 182,
"target": "Verified - no passwords/tokens in logs",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 183,
"target": "Security alerts configured",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 184,
"target": "Duration and compliance",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 185,
"target": "Logging tests, no sensitive data tests",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 188,
"target": "High/Medium/Low",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 189,
"target": "Where made in code",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 190,
"target": "Whitelist/validation rules",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 191,
"target": "Firewall rules, VPC",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 192,
"target": "User-controlled URLs",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 193,
"target": "SSRF prevention tests",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 197,
"target": "Specific risk for this feature",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 200,
"target": "How this could be exploited",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 201,
"target": "Specific solution",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 202,
"target": "Research source showing this risk",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 203,
"target": "Security test scenarios",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 204,
"target": "How to detect attacks",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 206,
"target": "Next risk",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 207,
"target": "...",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 226,
"target": "Additional security tests",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 227,
"target": "...",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 232,
"target": "Why this classification",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 236,
"target": "Number of files, systems involved, dependencies",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 237,
"target": "Without time, describe scope",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 240,
"target": "Independent tracks available?",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 241,
"target": "If yes, list potential parallel tracks",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 243,
"target": "Count",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 244,
"target": "List",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 245,
"target": "List",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 248,
"target": "Other features/modules",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 249,
"target": "Third-party libraries",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 250,
"target": "Any blocking dependencies",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 253,
"target": "Based on OWASP analysis",
"reason": "Reference link definition does not exist"
},
{
"file": "docs/reference/RESEARCH_TEMPLATE.md",
"line": 254,
"target": "When to address",
"reason": "Reference link definition does not exist"
},
{
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Narrow baseline scope to actionable docs paths only.

The committed baseline currently captures large volumes of template/generated placeholder “broken links” (for example in docs/reference/RESEARCH_TEMPLATE.md and graphify-out/GRAPH_REPORT.md). This weakens CI signal and can hide real link regressions in production docs.

Suggested direction
- # keep all docs in baseline generation
+ # exclude template/generated sources from baseline generation
+ # (apply in forge docs verify/detect config or workflow args), e.g.
+ # docs/reference/RESEARCH_TEMPLATE.md
+ # docs/work/**/graphify-out/**

Also applies to: 1691-1857

🤖 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 @.github/docs-link-baseline.json around lines 215 - 1090, The baseline is too
broad and includes template/generated placeholders (e.g.
"docs/reference/RESEARCH_TEMPLATE.md" and "graphify-out/GRAPH_REPORT.md") which
should be excluded; update the .github/docs-link-baseline.json to remove entries
for those files and narrow the baseline to only actionable production docs paths
(e.g. keep files under docs/ that are real content and exclude templates and
generated outputs), and if you have a link-checker config or generation script,
add exclusion patterns for "docs/reference/RESEARCH_TEMPLATE.md" and
"graphify-out/**" so future baselines don’t reintroduce these placeholders.

Comment on lines +63 to +66
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Run docs validation
run: bun ./bin/forge.js docs verify --baseline .github/docs-link-baseline.json --min-docstring-coverage "$MIN_DOCSTRING_COVERAGE"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add a baseline portability guard before running docs verification.

Line 66 trusts .github/docs-link-baseline.json as-is. Given the current PR context includes absolute Windows and .worktrees/ targets, CI can silently mask real regressions unless baseline hygiene is enforced.

Suggested workflow guard
       - name: Install dependencies
         run: bun install --frozen-lockfile
+      - name: Validate docs baseline portability
+        run: |
+          jq -e '
+            [.. | objects
+             | select(has("target"))
+             | .target
+             | select(type == "string")
+             | select(test("^[A-Za-z]:\\\\") or startswith("/") or contains(".worktrees/"))
+            ] | length == 0
+          ' .github/docs-link-baseline.json > /dev/null
       - name: Run docs validation
         run: bun ./bin/forge.js docs verify --baseline .github/docs-link-baseline.json --min-docstring-coverage "$MIN_DOCSTRING_COVERAGE"
🤖 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 @.github/workflows/docs-validation.yml around lines 63 - 66, Before running
the docs verification step that uses "--baseline
.github/docs-link-baseline.json", add a new workflow step (e.g., name: "Validate
docs baseline portability") that scans .github/docs-link-baseline.json for
non-portable entries (absolute Windows paths containing backslashes or drive
letters like ^[A-Za-z]:\\, and references to ".worktrees/" or other CI-specific
paths) and fails the job if any are found; implement this as a small shell/Node
script or one-liner (grep/awk/jq) invoked before the existing "Run docs
validation" step so the command "bun ./bin/forge.js docs verify --baseline
.github/docs-link-baseline.json ..." only runs when the baseline is portable.

Comment thread lib/docs-command.js
Comment on lines +631 to +637
function isWithinRoot(rootDir, candidatePath) {
const relative = path.relative(
fs.realpathSync.native(path.resolve(rootDir)),
resolveRealPathForContainment(candidatePath)
);
return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
node - <<'NODE'
const path = require('node:path');

for (const [impl, p, root, child] of [
  ['posix', path.posix, '/repo', '/repo/..baseline.json'],
  ['win32', path.win32, 'C:\\repo', 'C:\\repo\\..baseline.json'],
]) {
  const rel = p.relative(root, child);
  const currentCheck = rel === '' || (!rel.startsWith('..') && !p.isAbsolute(rel));
  console.log({ impl, root, child, relative: rel, currentCheck });
}
NODE

Repository: harshanandak/forge

Length of output: 319


🏁 Script executed:

# Find and examine the isWithinRoot function and its tests
git ls-files | grep -E "docs-command\.(js|test\.js)"

Repository: harshanandak/forge

Length of output: 140


🏁 Script executed:

# Check for test coverage of isWithinRoot
rg "isWithinRoot" --type js -A 5 -B 2

Repository: harshanandak/forge

Length of output: 2484


🏁 Script executed:

# Examine where isWithinRoot is used
rg "isWithinRoot" --type js

Repository: harshanandak/forge

Length of output: 455


🏁 Script executed:

# Check test coverage for isWithinRoot
rg "isWithinRoot" test/ -A 10 -B 2

Repository: harshanandak/forge

Length of output: 44


🏁 Script executed:

# Search for any files in the repo that might start with ..
find . -maxdepth 3 -type f -name "\..*" | head -20

Repository: harshanandak/forge

Length of output: 44


🏁 Script executed:

# Check what actual filenames exist in test fixtures or test data
find test/ -type f -name "*.json" -o -name "*.js" | head -30

Repository: harshanandak/forge

Length of output: 1021


🏁 Script executed:

# Search more thoroughly for isWithinRoot tests - check both test files
rg "isWithinRoot" test/ --type js

Repository: harshanandak/forge

Length of output: 44


🏁 Script executed:

# Look at the actual implementation and context around isWithinRoot
sed -n '620,650p' lib/docs-command.js

Repository: harshanandak/forge

Length of output: 1009


🏁 Script executed:

# Check what formatLinkTargetForReport and resolveMarkdownLink do
rg "function (formatLinkTargetForReport|resolveMarkdownLink)" lib/docs-command.js -A 10

Repository: harshanandak/forge

Length of output: 908


🏁 Script executed:

# Check the imports and understand path manipulation
head -50 lib/docs-command.js

Repository: harshanandak/forge

Length of output: 1437


🏁 Script executed:

# Check the test files for any tests related to isWithinRoot or path containment
cat test/docs-command.test.js | head -100

Repository: harshanandak/forge

Length of output: 4091


🏁 Script executed:

# Count lines to see if it's too large to read entirely
wc -l test/docs-command.test.js

Repository: harshanandak/forge

Length of output: 93


🏁 Script executed:

# Search for containment or root-related tests
rg "root|contain|escape|baseline" test/docs-command.test.js -B 2 -A 5

Repository: harshanandak/forge

Length of output: 10506


🏁 Script executed:

# Check if there are any edge case tests or .. patterns
rg "\.\." test/docs-command.test.js

Repository: harshanandak/forge

Length of output: 520


🏁 Script executed:

# Check if there are any test cases for filenames starting with .. inside the project root
grep -n "\.\.\w\|\.\.baseline" test/docs-command.test.js

Repository: harshanandak/forge

Length of output: 44


🏁 Script executed:

# Verify the actual behavior with a practical test case
node - <<'NODE'
const path = require('node:path');

// Simulate isWithinRoot logic
function isWithinRootCurrent(rootDir, candidatePath) {
  const relative = path.relative(rootDir, candidatePath);
  return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));
}

function isWithinRootProposed(rootDir, candidatePath) {
  const relative = path.relative(rootDir, candidatePath);
  return (
    relative === '' ||
    (!(relative === '..' || relative.startsWith(`..${path.sep}`)) && !path.isAbsolute(relative))
  );
}

const testCases = [
  ['/repo', '/repo/..baseline.json', 'File named ..baseline.json'],
  ['/repo', '/repo/../outside.json', 'Parent directory escape'],
  ['/repo', '/repo/..', 'Parent directory reference'],
  ['/repo', '/repo/../other/file.json', 'Parent directory with path'],
  ['/repo', '/repo/normal-file.json', 'Normal file'],
  ['/repo', '/repo', 'Same directory'],
];

console.log('Test Cases:');
for (const [root, candidate, description] of testCases) {
  const relPath = path.relative(root, candidate);
  const currentResult = isWithinRootCurrent(root, candidate);
  const proposedResult = isWithinRootProposed(root, candidate);
  const match = currentResult === proposedResult ? '✓' : '✗ DIFFERS';
  console.log(`${match} ${description}`);
  console.log(`  relative: '${relPath}' | current: ${currentResult} | proposed: ${proposedResult}`);
}
NODE

Repository: harshanandak/forge

Length of output: 587


🏁 Script executed:

# Check what real files might be named in the project
find test/fixtures -type f 2>/dev/null | head -20

Repository: harshanandak/forge

Length of output: 1160


🏁 Script executed:

# Look for any documentation or comments about the security intent of isWithinRoot
sed -n '600,680p' lib/docs-command.js

Repository: harshanandak/forge

Length of output: 2434


🏁 Script executed:

# Check what resolveRealPathForContainment does to understand the full context
sed -n '640,680p' lib/docs-command.js

Repository: harshanandak/forge

Length of output: 1259


🏁 Script executed:

# Search for any mention of path traversal security in comments or code
rg "traversal|escape|security|parent" lib/docs-command.js -B 2 -A 2

Repository: harshanandak/forge

Length of output: 1807


Fix overly-broad parent directory check in isWithinRoot().

relative.startsWith('..') rejects any path starting with .., including legitimate filenames like ..baseline.json. This check should only reject paths that actually escape the parent directory: .. alone or .. followed by a path separator.

Suggested fix
 function isWithinRoot(rootDir, candidatePath) {
   const relative = path.relative(
     fs.realpathSync.native(path.resolve(rootDir)),
     resolveRealPathForContainment(candidatePath)
   );
-  return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));
+  return (
+    relative === '' ||
+    (!(relative === '..' || relative.startsWith(`..${path.sep}`)) && !path.isAbsolute(relative))
+  );
 }
🤖 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 `@lib/docs-command.js` around lines 631 - 637, The parent-directory check in
isWithinRoot incorrectly rejects names that merely start with '..' (e.g.,
"..baseline.json"); update the condition to only treat a relative path as
escaping when it is exactly '..' or begins with '..' + path.sep. Concretely, in
isWithinRoot (which calls resolveRealPathForContainment), replace the
relative.startsWith('..') test with a check like (relative === '..' ||
relative.startsWith('..' + path.sep)) so legitimate filenames that begin with
'..' are allowed while actual upward traversal is still prevented.

Comment thread lib/docs-command.js
Comment on lines +845 to +860
function getPublicDocTargets(_source, ast) {
const targets = [];
const declarations = collectTopLevelDocDeclarations(ast);
for (const node of ast.program.body) {
if (node.type === 'ExportNamedDeclaration') {
addDocTargetsFromDeclaration(targets, node.declaration, node);
addDocTargetsFromExportSpecifiers(targets, node, declarations);
} else if (node.type === 'ExportDefaultDeclaration') {
addDocTargetsFromDeclaration(targets, node.declaration, node);
addDocTargetFromDefaultExportIdentifier(targets, node, declarations);
} else if (node.type === 'ExpressionStatement') {
addDocTargetFromCommonJsExport(targets, node, declarations);
}
}
return targets.filter((target) => !target.name.startsWith('_'));
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Qualified CommonJS names bypass the private-export filter.

module.exports = { _hidden() {} } becomes module.exports._hidden, so the final startsWith('_') check no longer excludes it. That will count intentionally-private CJS members toward docstring coverage.

Suggested fix
 function getPublicDocTargets(_source, ast) {
   const targets = [];
   const declarations = collectTopLevelDocDeclarations(ast);
   for (const node of ast.program.body) {
@@
     } else if (node.type === 'ExpressionStatement') {
       addDocTargetFromCommonJsExport(targets, node, declarations);
     }
   }
-  return targets.filter((target) => !target.name.startsWith('_'));
+  return targets.filter((target) => {
+    const exportedName = target.name.startsWith('module.exports.')
+      ? target.name.slice('module.exports.'.length)
+      : target.name;
+    return !exportedName.startsWith('_');
+  });
 }
🤖 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 `@lib/docs-command.js` around lines 845 - 860, getPublicDocTargets currently
filters out private names by testing target.name.startsWith('_'), but CommonJS
qualified exports (e.g. module.exports._hidden or exports.foo._hidden) produce
dotted names so the leading segment test fails; update the logic so the private
check inspects only the final identifier segment (e.g. split on '.' and check
the last part) or normalize names emitted by
addDocTargetFromCommonJsExport/related helpers by stripping "module.exports."
and "exports." prefixes before adding targets; modify getPublicDocTargets (or
ensure addDocTargetFromCommonJsExport) to use the last-dot segment when applying
the startsWith('_') filter so qualified CJS private members are excluded.

@harshanandak
Copy link
Copy Markdown
Owner Author

Closing this noisy mixed-scope PR after splitting it. Clean planning-only replacement: #176. Docs-validation/linker implementation preserved on branch codex/docs-validation-followup for a separate follow-up PR.

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.

1 participant