Skip to content

docs(plans): design doc for the hadron coding lint group (#325) - #326

Merged
shadowbrush merged 2 commits into
mainfrom
claude/coding-lint-plan
Jul 30, 2026
Merged

docs(plans): design doc for the hadron coding lint group (#325)#326
shadowbrush merged 2 commits into
mainfrom
claude/coding-lint-plan

Conversation

@shadowbrush

@shadowbrush shadowbrush commented Jul 30, 2026

Copy link
Copy Markdown
Member

Design-ahead plan doc for #325, per the CLAUDE.md convention that substantial features get a docs/plans/ doc bundled for review. Nothing is implemented — the doc exists to settle the open questions before code, because the surface as filed produces a >50% false-positive rate.

Refs #325. My audit notes are in this comment; this turns them into a reviewable design.

The five decisions that need your review

1. Membership rule — the load-bearing one. The issue scopes to "every node under the review parent", but that parent legitimately has non-checklist neighbours: the router, the tasks that consume the tree, a meta backlog, pattern nodes. I implemented its checks verbatim and ran them:

Scope rule Findings Real False
As filed (all inbound edges) 9 4 5
Proposed (review tag, no meta tag, not isRunnable) 3 3 0

A loc-prefix rule doesn't work either — review:backlog sits under review: and is explicitly meta. The node metadata separates them cleanly; the doc has the table.

2. "Label isn't a loc" checks the wrong field. review:input-type-graphql-type:rel:review is that edge's loc, not its name — the name is empty. Edge locs are slugified from names, so :rel: is the derived fallback when the name is empty: a symptom, not a defect class. There's exactly 1, not the batch of 5 implied. Replaced with an empty-label check.

3. New check for a dangling endpoint — on opposite ends per subcommand. The live review tree has an edge to tasks:build-review-coverage, which is absent from the node listing and unreadable (node get → exit 4). Note the two subcommands look at opposite ends: review lint walks incomingEdges, so the far endpoint is the source; preflight lint walks outgoing routes, where it is the target. Hence check-node-resolves (warning — an unreadable node cannot be tested against the membership predicate, so membership is indeterminate) and route-target-resolves (error — a route to a dead node actively misroutes). Either way reported as unavailable, never dropped.

4. Preflight action-phrasing is a warning. 24 of 71 mmdata routes fail it immediately; as an error the command is red until someone relabels 24 edges, which trains people to ignore it. spec lint already treats convention violations as warnings.

5. --fix needs no server work. The ⚠️ hazard in the issue is MCP-side. This repo already has hadron edge update over updateEdge(edgeRef:) with per-field omitempty — one edge, one field, sibling edges untouched. hadron-server#835 is not a dependency.

Also recorded

Repo constraints whoever implements it will hit: TestAgenticUsageDocumentsEveryCommand gates new leaves on the embedded agentic-usage.md; spec lint exits 5 (exitcode.Silent(exitcode.Conflict)), not 1; the #23 pagination requirement. And no GraphQL changes are neededGetNode, the node listing, NodeBatch, and UpdateEdge all already exist.

Note on the motivation

The portal's "7 of 24" doesn't reproduce — 25 inbound edges, all carrying real conditions, 0 suspect. It looks fixed between the audit and filing. The mmdata four are all confirmed real. Worth weighing before sizing, since the portal case was half the stated motivation.

Docs-only; one new file, no code.

🤖 Generated with Claude Code

Design-ahead plan for #325, written after auditing the live memories. Nothing
is implemented; the doc exists to settle the open questions before code,
because the surface as filed produces a >50% false-positive rate.

Five decisions resolved against live data:

1. Membership rule. The issue scopes to "every node under the review parent",
   but that parent legitimately has non-checklist neighbours (the router, the
   consuming tasks, a meta backlog, pattern nodes). Implementing its checks
   verbatim gives 9 findings on mmdata, 5 of them false. Proposed rule — has
   the `review` tag, no `meta` tag, not isRunnable — yields 3 findings, all
   real, zero false positives.
2. "Label isn't a loc" checks the wrong field: the `:rel:` string is the edge's
   derived loc, not its name, and appears when the name is empty. Replaced with
   an empty-label check; `:rel:` becomes corroboration in the message.
3. Added target-resolves as an error — the live review tree has a dangling edge
   to tasks:build-review-coverage, which lists but cannot be read.
4. Preflight action-phrasing is a warning: 24 of 71 mmdata routes fail it on day
   one, and spec lint already treats convention violations as warnings.
5. --fix uses the existing `edge update`/updateEdge path, so the MCP whole-node
   hazard doesn't apply and server#835 is not a dependency.

Also records the repo constraints whoever implements it will hit: the
agentic-usage completeness gate, spec lint's exit 5 (not 1), and the #23
pagination requirement. No GraphQL changes are needed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

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

Copy link
Copy Markdown

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: 5eef9aec0a

ℹ️ 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 docs/plans/coding-command-group.md Outdated
Comment on lines +246 to +248
- **Read-only live smoke test** against `micromentor.org::mmdata` and
`hadronmemory.com::hadron-portal`: expect 3 errors + the `format-sources`
warning on the former, clean on the latter.

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 Include the dangling-edge error in the smoke expectation

The audit describes three label errors and separately adds the dangling tasks:build-review-coverage relationship as a target-resolves error, so the proposed live smoke test should expect four errors plus the format-sources warning. Leaving the expectation at three permits the new resolution check to be omitted or implemented against the wrong endpoint; because review relationships are incomingEdges, the unresolved remote endpoint is their source (internal/api/queries/nodes.graphql:195-205), not the already-resolved review target.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Both halves confirmed, and the endpoint point is the more valuable one — fixed in 93dc240.

Endpoint direction: you're right, and the rule name was wrong. Verified in the source rather than taking it on trust — incomingEdges selects source (nodes.graphql:195-205), and edge/ls.go:81-84 reads e.Source for the incoming direction. So on the review side the far endpoint is the check node, and the target is review itself, which cannot dangle. A rule named target-resolves was checking the one endpoint that is resolved by construction. Split into:

  • check-node-resolves — review side, the edge's source
  • route-target-resolves — preflight side, where outgoing routes make target genuinely correct

Smoke expectation: agreed it was incomplete, resolved differently than proposed. I made the review-side rule a warning, so it's 3 errors + 2 warnings rather than 4 errors. Reasoning: when the endpoint can't be read, the Decision-1 membership predicate can't be evaluated on it either — the linter doesn't know it's a checklist item. tasks:build-review-coverage sits beside tasks:review-changes, which is readable and is excluded as a runnable task, so it's most likely a non-member; erroring would fail a build over a node that shouldn't be linted at all. It's still reported as unavailable per CLAUDE.md, just as an indeterminate-membership warning rather than an asserted defect. Happy to reconsider if you think a dangling edge is worth failing on regardless of what it points at.

I also replaced the bare count with an enumerated table of all five expected findings — the count is precisely what let the omission slip through, so counting again seemed like the wrong fix.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds a design-ahead implementation plan for the proposed hadron coding command group (refs #325), focusing on linting the review checklist tree and preflight router with rules calibrated against observed live-memory data.

Changes:

  • Introduces a new docs/plans/ design doc defining the proposed coding review lint and coding preflight lint surfaces.
  • Records five key design decisions (membership predicate, label-empty vs :rel: heuristic, target-resolves check, warning/error split, and --fix implementation via updateEdge).
  • Documents expected output/exit-code conventions and test strategy aligned with existing spec lint patterns.
Comments suppressed due to low confidence (1)

docs/plans/coding-command-group.md:219

  • This parenthetical looks like a file path but spec/lint.go doesn't exist in the repo (the file is internal/cmd/spec/lint.go). Updating the reference avoids confusion for implementers.
- Mirror `lintFindingDTO` (`spec/lint.go`) — node loc, rule, severity, message —

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/plans/coding-command-group.md Outdated
| `label-present` | error | the empty label (Decision 2) |
| `label-is-condition` | error | `child-of`, `applies-when`, `related`, bare `Applies when` |
| `target-resolves` | error | dangling / unreadable target (Decision 3) |
| `description-has-trigger` | warning | second blind spot in `find_nodes` output |

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in 93dc240 — now hadron_find_nodes, matching CLAUDE.md and the tool's registered name.

Comment thread docs/plans/coding-command-group.md Outdated

Wired in [`internal/cmd/root.go`](../../internal/cmd/root.go) alongside the other
groups. Rule engines take plain structs and injected fetch functions, so they
unit-test without a server — the pattern `spec/lint.go` uses.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in 93dc240 — corrected to internal/cmd/spec/lint.go in both places, and made them relative links (../../internal/cmd/spec/lint.go) so they resolve from docs/plans/.

Worth noting the existing plan docs get this wrong too — spec-command-group.md links [internal/cmd/root.go](internal/cmd/root.go), which 404s from that directory. Not fixing those here to keep this PR to one change, but it's a real papercut across docs/plans/.

…tation

Review follow-ups on the coding-lint design doc:

- Decision 3 named its rule `target-resolves` for both subcommands, but the two
  walk opposite ends of their edges. `review lint` reads `incomingEdges`, whose
  far endpoint is `source` (nodes.graphql:195-205; edge/ls.go:81-84 reads
  e.Source for the incoming direction) — the target is `review` itself and
  cannot dangle, so the rule as named checked the one safe endpoint. Split into
  `check-node-resolves` (review, source) and `route-target-resolves`
  (preflight, target).
- Set the review-side rule to warning rather than error, and say why: when the
  endpoint can't be read, the Decision-1 membership predicate can't be
  evaluated on it either. The live instance, tasks:build-review-coverage, sits
  beside the readable tasks:review-changes that the predicate excludes as a
  runnable task — so it is probably a non-member, and erroring would fail a
  build over a node that shouldn't be linted. It is still reported as
  `unavailable`, never dropped.
- The smoke expectation said "3 errors + the format-sources warning", silently
  dropping the dangling endpoint the same doc had just introduced. Replaced the
  count with an enumerated table of all five findings, since the bare count is
  what hid the omission.
- Corrected `spec/lint.go` to internal/cmd/spec/lint.go (2×) and `find_nodes`
  to hadron_find_nodes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@shadowbrush
shadowbrush merged commit dd38e34 into main Jul 30, 2026
4 checks passed
@shadowbrush
shadowbrush deleted the claude/coding-lint-plan branch July 30, 2026 15:19
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.

2 participants