LearnNewsExamplesServices
Frontmatter
id16041
titleSkill reference lint skips §1d and backticked targets
stateClosed
labels
bugaitesting
assigneesneo-gpt
createdAtJul 27, 2026, 4:37 AM
updatedAtJul 28, 2026, 8:00 PM
githubUrlhttps://github.com/neomjs/neo/issues/16041
authorneo-gpt
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJul 28, 2026, 8:00 PM

Skill reference lint skips §1d and backticked targets

Closed Backlog/active-chunk-10 bugaitesting
neo-gpt
neo-gpt commented on Jul 27, 2026, 4:37 AM

Context

PR #15997 corrected three live references from ticket-create-workflow.md §1c to §1d. The source target is unambiguous: §1c is the Agent OS Structure Map Gate, while §1d is the Ungraduated-Discussion Cross-Check. During exact-head review, removing inline-code backticks from the filename was expected to make those corrected references mechanically validated.

A direct positive/negative probe falsified that expectation. checkSkillReferenceIntegrity() returned [] for all four of these forms:

ticket-create-workflow.md §1d
ticket-create-workflow.md §1x
`ticket-create-workflow.md` §1d
`ticket-create-workflow.md` §1x

The valid and deliberately invalid digit-leading anchors are therefore indistinguishable to the lint.

The Problem

The skill-reference lint has two interacting silent-green paths:

  1. SECTION_REF_SOURCE accepts dotted numeric identifiers such as §5.1 or letter-first named identifiers such as §template-block, but not digit-leading alphanumeric identifiers such as §1d.
  2. Inline-code-wrapped filename targets are not associated with following prose refs. A backticked numeric ref can then fall back to the containing file and emit a misleading dangling-reference error, while an unqualified nonnumeric ref is skipped.

Heading extraction compounds the first gap: ### 1d. The Ungraduated-Discussion Cross-Check is indexed as numeric anchor 1, not 1d. Removing backticks alone therefore does not restore validation.

This is a false proof surface. A green Skill Manifest Lint currently cannot establish that a changed target.md §1d reference resolves, even when the target file exists.

The Architectural Reality

  • ai/scripts/lint/lint-skill-manifest.mjs:300-308 owns the accepted section-reference and target grammar.
  • ai/scripts/lint/lint-skill-manifest.mjs:314-329 owns heading-anchor extraction.
  • ai/scripts/lint/lint-skill-manifest.mjs:644-662 owns target resolution and dangling-reference reporting.
  • ai/scripts/lint/lint-skill-manifest.mjs:699-725 owns changed-line prose-reference validation and currently skips unqualified nonnumeric matches.
  • test/playwright/unit/ai/scripts/lint/lintSkillManifest.spec.mjs:619-741 covers dotted numeric and letter-first named references, but has no inline-code-target or digit-leading-alphanumeric controls.
  • #12493 introduced numeric reference-integrity coverage; #12582 extended it to named refs. Neither ticket covered §1d-shaped headings or inline-code target equivalence.
  • #11599 is not the owner: it proposes a broad semantic-heading migration and explicitly leaves historical positional refs out of scope.

Structure-map result: the existing owner is ai/scripts/lint/lint-skill-manifest.mjs, with the existing focused sibling spec under test/playwright/unit/ai/scripts/lint/. No new module or directory is needed.

The Fix

Repair the existing parser and focused spec in one PR:

  1. Give prose refs and heading extraction one shared accepted section-ID grammar that covers the live digit-leading alphanumeric form (§1d) without regressing dotted numeric (§5.1) or letter-first named (§template-block) forms.
  2. Normalize inline-code filename targets before target association so `target.md` §N and target.md §N have the same validation semantics.
  3. Never silently skip a target-qualified section token. A target that resolves but whose section token is unsupported or missing must produce an actionable error.
  4. Preserve --base changed-line ownership so newly recognized historical refs do not block unrelated PRs.
  5. Add positive and negative controls for each supported target/anchor family.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback / Edge Case Docs Evidence
Section-ID grammar and extractHeadingAnchors() in lint-skill-manifest.mjs Existing parser; live ticket-create-workflow.md headings; #12493 and #12582 Dotted numeric, letter-first named, and live digit-leading alphanumeric IDs are extracted and compared using one grammar Unsupported target-qualified tokens fail explicitly; they never disappear from coverage Update nearby JSDoc if the accepted grammar is named there Unit controls for §5.1, §template-block, §1d, and missing siblings
Prose target association in checkSkillReferenceIntegrity() Existing changed-line reference lint Inline-code and bare filename targets are semantically equivalent before section validation Numeric refs must not fall back to the containing file merely because the target is backticked Actionable lint error names source line, target, and section Direct probe above turns from [] into a failure for both §1x forms
lintSkillManifest.spec.mjs reference-integrity suite Existing focused tests from #12493/#12582 Locks positive/negative behavior across target formatting and anchor families Existing numeric, named, pointer, and changed-line tests remain green No new guide required unless syntax policy changes Focused Playwright unit run plus lint-skill-manifest --base origin/dev

Decision Record impact

aligned-with ADR 0008 — this repairs the existing skill-manifest enforcement layer and does not change Progressive Disclosure or skill-reference policy.

Acceptance Criteria

  • A bare ticket-create-workflow.md §1d reference resolves to the live ### 1d. heading.
  • A bare ticket-create-workflow.md §1x reference fails with an actionable dangling/unsupported section error.
  • The equivalent backticked target forms produce the same pass/fail results as the bare forms.
  • A backticked numeric target is validated against its named target file, never the containing source file.
  • Existing dotted-numeric and letter-first-named reference controls remain green.
  • Heading extraction and reference parsing share compatible grammar; a heading accepted as a target can be referenced, and a target-qualified token cannot be silently skipped.
  • --base changed-line ownership remains intact.
  • Focused tests cover valid and invalid bare/backticked numeric, named, and digit-leading alphanumeric references.
  • The PR records a focused unit invocation and node ai/scripts/lint/lint-skill-manifest.mjs --base origin/dev; do not use the default unscoped npx playwright test.

Out of Scope

  • Repo-wide heading migration or reopening #11599.
  • Changing the divergence-window rule delivered by #15997.
  • Rewriting every historical skill reference in the same PR.
  • General-purpose Markdown link validation outside .agents/skills/**.

Avoided Traps

  • Removing backticks only: falsified; §1d remains outside the accepted grammar.
  • Treating green lint as evidence that the ref was checked: the direct negative control proves the current green is vacuous.
  • Silently banning a live heading form: §1c/§1d are current workflow anchors. If the long-term heading convention migrates them, that belongs to #11599; the current enforcement must still be truthful.
  • Absorbing the repair into #15997: that PR has already exhausted two ordinary Request Changes cycles and its graduated rule is independent of this parser defect.

Related

Follow-up from #15996 / PR #15997. Extends #12493 and #12582. Related but not owned by #11599.

Retrieval Hint: lint-skill-manifest backticked target digit-leading section ref 1d silently skipped

Live latest-open sweep and A2A in-flight claim sweep: recorded immediately before creation.

tobiu referenced in commit 1a0ed60 - "fix(ai): validate live skill section-reference shapes (#16041) (#16102) on Jul 28, 2026, 8:00 PM
tobiu closed this issue on Jul 28, 2026, 8:00 PM