Skip to content

Roadmap lint cannot check a Blocked-by decision anchor in a non-Markdown file #3567

Closed

Description

@clabonte

Problem

A project that keeps decisions as entries in YAML files can declare it in .specfuse/layout.yml:

decisions:
  style: entries
  location: decisions
  link: "{location}/{domain}.yaml#{id}"

The roadmap lint then passes a typo in the fragment of a Blocked-by link:

**Blocked by.** [pricing-is-per-sat](../decisions/billing.yaml#pricing-is-per-sat) — awaiting signature.

_check_blocked_by in specfuse/loop/lint_roadmap.py checks that the file exists and sits under decisions.location, but checks the fragment only for Markdown targets (target.suffix == ".md"). A renamed or withdrawn decision passes the same way, so the one check that ties a blocker to a specific decision is off for the projects style: entries was added for.

Proposed

  • Add an opt-in decisions.entryKey naming the key that holds an entry's id. Without it, behavior stays as today.
  • Report a missing fragment as an ERROR under status: blocked, worded like the Markdown finding: … points at '<file>', which has no anchor '<id>'.
  • A decision still under review links to the file with no fragment, or to its PR; both already pass. The link gains its #id when the entry lands.
  • If the target's shape cannot be read for entryKey, report a clear finding, never a silent pass.

Notes for the fix

  • Do not parse the whole file with _miniyaml. It rejects block scalars and flow mappings by design (literal/folded block scalars unsupported), and decision files can hold both. The loop has no runtime dependencies, so scan lines for entryKey: <value>, and use stdlib json for JSON.
  • Rows not in blocked never reach these link checks; a leftover Blocked-by block already gets a WARN, which covers a forgotten unblock.
  • specfuse/loop/layout.py also changes in FEAT-LOOP-2026-0249: changelog fragments so concurrent PRs stop conflicting #3566, so start after that merges. Size: one bug fix.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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