Skip to content

body-links-drift fires on links that exist, and on tokens that can never be linked #446

Description

@explosivebit

Summary

body-links-drift fires on artifacts whose links do exist, and names targets that are already linked. The rule also names non-artifact tokens (invariant numbers) that can never satisfy it, so the warning is unclosable by design.

Found on forgeplan 0.34.0 while shaping an ADR in a real project.

Reproduction

ADR-008 has five links, all created via forgeplan link:

$ forgeplan graph | grep "ADR-008 -->"
    ADR-008 -->|based_on| ADR-004
    ADR-008 -->|based_on| PRD-001
    ADR-008 -->|based_on| RFC-001
    ADR-008 -->|informs| SPEC-002
    ADR-008 -->|informs| SPEC-004

Its ## Related Artifacts section mentions exactly those five, plus a few invariant numbers from the parent RFC. Validation:

$ forgeplan validate ADR-008
! [SHOULD] body-links-drift: Body's `## Related Artifacts` table mentions
  ADR-004, I-1, I-3, I-6, I-8, I-9, PRD-001, RFC-001, SPEC-002, SPEC-004
  but frontmatter `links:` array doesn't reference them.

Every artifact ID in that list is linked. The graph proves it in the same workspace, same moment.

Two separate problems in one warning

1. False positive on linked targets. ADR-004, PRD-001, RFC-001, SPEC-002, SPEC-004 are all present as edges. The rule appears to read the markdown projection's links: frontmatter rather than the graph, and the projection does not carry them — so the check disagrees with forgeplan graph about the same artifact.

Re-running after the links landed produced the warning verbatim, still naming ADR-004. That is the part that matters: the operator's natural response ("add the link") does not clear it, so the signal teaches them to ignore it.

2. Unsatisfiable tokens. I-1, I-3, I-6, I-8, I-9 are invariant numbers from RFC-001's body, not artifact IDs. There is nothing to link them to. The rule asks for an action that cannot be performed, and its own remedy text ("Run: forgeplan link …") does not apply.

Why this is worth fixing rather than muting

A SHOULD-level warning that cannot be cleared by doing what it asks is worse than no warning: it trains people to skip the validate output, and the next finding — a real one — goes with it. In this project the same warning sat on the artifact through activation, and the only way to tell "false positive" from "genuinely missing link" was to read forgeplan graph by hand and diff it against the message.

Suggested direction

  • Resolve mentions against the graph, not the projection frontmatter — or make the projection carry the edges, so the two agree.
  • Restrict ID extraction to known artifact-kind prefixes, so I-3 and similar in-body references are not treated as link candidates.
  • If a mention is deliberately incidental, the existing "remove the table row" escape hatch is fine — but it should not be the only way out for targets that are, in fact, linked.

Environment

  • forgeplan 0.34.0 (Homebrew, macOS arm64)
  • Workspace with 28 artifacts, 30 edges

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions