Skip to content

feat(nkb): pattern dependency graph with broken-link check#18

Merged
wranngle merged 3 commits into
mainfrom
feat/nkb-graph
May 19, 2026
Merged

feat(nkb): pattern dependency graph with broken-link check#18
wranngle merged 3 commits into
mainfrom
feat/nkb-graph

Conversation

@wranngle
Copy link
Copy Markdown
Owner

Summary

Adds scripts/nkb-graph.mjs — emits a Mermaid graph of pattern→dependency
edges parsed from a ## Depends-on section in each workflow-patterns/*.md
doc. The --check flag exits non-zero when any pattern references a slug
with no matching .md file in the scanned directory.

This is the structural half of the citation-graph convention started in
round-1 PR #5 (feat(nkb): citation lint + Sources backfill on pattern docs):
PR #5 made every doc cite its external sources via ## Sources; this PR
makes every doc declare its internal cross-pattern dependencies via
## Depends-on, and proves they all resolve. Both lints share the same
fail-closed posture so CI can wire either as a required check.

The schema is minimal — ## Depends-on is followed by a bullet list of
slugs, one per line, where each slug is the basename of a sibling .md
in the same directory. A pattern with no dependencies either omits the
section entirely or leaves it empty. The existing voice-agent-elevenlabs- patterns.md doc parses cleanly under this schema with zero edges, so the
new convention is strictly additive — no backfill required on main.

Fixtures

fixtures/graph/{ok,broken}/ follows the same convention as the dedupe
fixture set (#15) and the stats fixture (#17):

  • ok/ — three-pattern chain (webhook-dedup-key → http-retry-idempotency → error-monitoring-fanout). All edges resolve.
  • broken/ — same chain plus a dangling edge to nonexistent-upstream.
    This is the negative-path fixture for --check.

Proof

Mermaid render of the ok fixture:

$ node scripts/nkb-graph.mjs --dir fixtures/graph/ok
\`\`\`mermaid
graph LR
  error_monitoring_fanout["error-monitoring-fanout"]
  http_retry_idempotency["http-retry-idempotency"]
  webhook_dedup_key["webhook-dedup-key"]
  http_retry_idempotency --> error_monitoring_fanout
  webhook_dedup_key --> http_retry_idempotency
\`\`\`

Fail-closed broken-link check:

$ node scripts/nkb-graph.mjs --dir fixtures/graph/broken --check
nkb-graph check: 1 broken link(s):
  - webhook-dedup-key → nonexistent-upstream (no such pattern)
$ echo $?
1

Real workflow-patterns/ directory on main (additive, doesn't regress):

$ node scripts/nkb-graph.mjs --check
nkb-graph check: ok — 1 pattern(s), 0 edge(s), 0 broken

tests/graph.bats (10 cases, all green locally):

$ bats tests/graph.bats
1..10
ok 1 graph: mermaid output lists every pattern in the ok fixture as a node
ok 2 graph: edges in mermaid mirror Depends-on declarations
ok 3 graph --check: ok fixture passes with exit 0
ok 4 graph --check: broken fixture fails with exit 1 and names the missing slug
ok 5 graph --check --format json: ok fixture reports ok:true, broken:[]
ok 6 graph --check --format json: broken fixture reports the from/to edge
ok 7 graph: --format json (no --check) dumps every pattern with its deps list
ok 8 graph: pattern with no Depends-on section produces zero edges from it
ok 9 graph: missing --dir target exits non-zero with stderr message
ok 10 graph: mermaid output marks missing dep edges with dotted-arrow annotation

The broken-link check (#4) is the central-promise test: it asserts both
the non-zero exit and that the offending edge (webhook-dedup-key → nonexistent-upstream) is named verbatim in the failure output.

Round-1 / round-2 dependencies

Sits next to the other scripts/nkb-*.mjs round-2 deliverables — submit
(#13), JSON-LD export (#14), dedupe (#15), sandbox runner (#16), adoption
stats (#17) — and will slot under the unified scripts/nkb.mjs dispatcher
established by round-1 #3 once that lands on main. Until then it is
invokable standalone as node scripts/nkb-graph.mjs. Citing round-1 #5
specifically because that PR establishes the precedent of a fail-closed
CI lint over workflow-patterns/*.md; this PR extends that pattern
along the internal-link axis.

Test plan

  • bats tests/graph.bats — all 10 outcome tests pass
  • node scripts/nkb-graph.mjs --check against real workflow-patterns/ exits 0
  • node scripts/nkb-graph.mjs --dir fixtures/graph/broken --check exits 1 and names the bad edge
  • Reviewer confirms ## Depends-on schema is acceptable to bolt onto existing pattern docs
  • Reviewer decides whether to wire --check into .github/workflows/lint.yml alongside the round-1 feat(n8n_knowledge_base): citation lint + Sources backfill on pattern docs #5 citation lint

@github-actions github-actions Bot added the pr-needs-issue PR has no Closes/Fixes/Resolves reference; auto-applied by pr-link-check label May 15, 2026
@github-actions
Copy link
Copy Markdown

This PR needs an issue link.

Add Closes #N / Fixes #N / Resolves #N to the description — or file an issue first via gh-issue.sh. Convention: every PR has an audit trail back to a problem statement.

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: a4cbc18cf9

ℹ️ 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 scripts/nkb-graph.mjs
Comment thread scripts/nkb-graph.mjs
Comment thread scripts/nkb-graph.mjs
@github-actions
Copy link
Copy Markdown

This PR needs an issue link.

Add Closes #N / Fixes #N / Resolves #N to the description — or file an issue first via gh-issue.sh. Convention: every PR has an audit trail back to a problem statement.

@wranngle wranngle enabled auto-merge (squash) May 19, 2026 03:06
@github-actions
Copy link
Copy Markdown

This PR needs an issue link.

Add Closes #N / Fixes #N / Resolves #N to the description — or file an issue first via gh-issue.sh. Convention: every PR has an audit trail back to a problem statement.

@github-actions
Copy link
Copy Markdown

This PR needs an issue link.

Add Closes #N / Fixes #N / Resolves #N to the description — or file an issue first via gh-issue.sh. Convention: every PR has an audit trail back to a problem statement.

1 similar comment
@github-actions
Copy link
Copy Markdown

This PR needs an issue link.

Add Closes #N / Fixes #N / Resolves #N to the description — or file an issue first via gh-issue.sh. Convention: every PR has an audit trail back to a problem statement.

Adds `scripts/nkb-graph.mjs` — emits a Mermaid graph of pattern→dependency
edges parsed from a `## Depends-on` section in each `workflow-patterns/*.md`
doc. The `--check` mode exits non-zero when any pattern references a slug
with no matching `.md` file in the scanned directory, so CI can fail-closed
on dangling references the same way round-1 #5 fails-closed on missing
`## Sources` sections.

Fixtures `fixtures/graph/{ok,broken}/` drive `tests/graph.bats` (10 cases):
the ok fixture is a three-pattern chain (webhook-dedup-key → http-retry-
idempotency → error-monitoring-fanout); the broken fixture adds a dangling
edge to `nonexistent-upstream`. The broken-link test is the central-promise
check — it asserts both the non-zero exit and that the offending edge is
named in the failure output.

`--format json` is supported both with and without `--check` so downstream
tooling (dashboards, lint jobs) can ingest the report without re-parsing
mermaid.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

This PR needs an issue link.

Add Closes #N / Fixes #N / Resolves #N to the description — or file an issue first via gh-issue.sh. Convention: every PR has an audit trail back to a problem statement.

1 similar comment
@github-actions
Copy link
Copy Markdown

This PR needs an issue link.

Add Closes #N / Fixes #N / Resolves #N to the description — or file an issue first via gh-issue.sh. Convention: every PR has an audit trail back to a problem statement.

@github-actions
Copy link
Copy Markdown

This PR needs an issue link.

Add Closes #N / Fixes #N / Resolves #N to the description — or file an issue first via gh-issue.sh. Convention: every PR has an audit trail back to a problem statement.

@github-actions
Copy link
Copy Markdown

This PR needs an issue link.

Add Closes #N / Fixes #N / Resolves #N to the description — or file an issue first via gh-issue.sh. Convention: every PR has an audit trail back to a problem statement.

@wranngle wranngle merged commit 70793ab into main May 19, 2026
13 checks passed
@wranngle wranngle deleted the feat/nkb-graph branch May 19, 2026 03:40
wranngle added a commit that referenced this pull request May 19, 2026
## Summary

Adds `scripts/nkb-graph.mjs` — emits a Mermaid graph of
pattern→dependency
edges parsed from a `## Depends-on` section in each
`workflow-patterns/*.md`
doc. The `--check` flag exits non-zero when any pattern references a
slug
with no matching `.md` file in the scanned directory.

This is the **structural** half of the citation-graph convention started
in
round-1 PR #5 (`feat(nkb): citation lint + Sources backfill on pattern
docs`):
PR #5 made every doc cite its external sources via `## Sources`; this PR
makes every doc declare its internal cross-pattern dependencies via
`## Depends-on`, and proves they all resolve. Both lints share the same
fail-closed posture so CI can wire either as a required check.

The schema is minimal — `## Depends-on` is followed by a bullet list of
slugs, one per line, where each slug is the basename of a sibling `.md`
in the same directory. A pattern with no dependencies either omits the
section entirely or leaves it empty. The existing
`voice-agent-elevenlabs-
patterns.md` doc parses cleanly under this schema with zero edges, so
the
new convention is strictly additive — no backfill required on `main`.

### Fixtures

`fixtures/graph/{ok,broken}/` follows the same convention as the dedupe
fixture set (#15) and the stats fixture (#17):

- `ok/` — three-pattern chain (`webhook-dedup-key →
http-retry-idempotency
  → error-monitoring-fanout`). All edges resolve.
- `broken/` — same chain plus a dangling edge to `nonexistent-upstream`.
  This is the negative-path fixture for `--check`.

### Proof

Mermaid render of the ok fixture:

```
$ node scripts/nkb-graph.mjs --dir fixtures/graph/ok
\`\`\`mermaid
graph LR
  error_monitoring_fanout["error-monitoring-fanout"]
  http_retry_idempotency["http-retry-idempotency"]
  webhook_dedup_key["webhook-dedup-key"]
  http_retry_idempotency --> error_monitoring_fanout
  webhook_dedup_key --> http_retry_idempotency
\`\`\`
```

Fail-closed broken-link check:

```
$ node scripts/nkb-graph.mjs --dir fixtures/graph/broken --check
nkb-graph check: 1 broken link(s):
  - webhook-dedup-key → nonexistent-upstream (no such pattern)
$ echo $?
1
```

Real `workflow-patterns/` directory on `main` (additive, doesn't
regress):

```
$ node scripts/nkb-graph.mjs --check
nkb-graph check: ok — 1 pattern(s), 0 edge(s), 0 broken
```

`tests/graph.bats` (10 cases, all green locally):

```
$ bats tests/graph.bats
1..10
ok 1 graph: mermaid output lists every pattern in the ok fixture as a node
ok 2 graph: edges in mermaid mirror Depends-on declarations
ok 3 graph --check: ok fixture passes with exit 0
ok 4 graph --check: broken fixture fails with exit 1 and names the missing slug
ok 5 graph --check --format json: ok fixture reports ok:true, broken:[]
ok 6 graph --check --format json: broken fixture reports the from/to edge
ok 7 graph: --format json (no --check) dumps every pattern with its deps list
ok 8 graph: pattern with no Depends-on section produces zero edges from it
ok 9 graph: missing --dir target exits non-zero with stderr message
ok 10 graph: mermaid output marks missing dep edges with dotted-arrow annotation
```

The broken-link check (#4) is the central-promise test: it asserts both
the non-zero exit and that the offending edge (`webhook-dedup-key →
nonexistent-upstream`) is named verbatim in the failure output.

### Round-1 / round-2 dependencies

Sits next to the other `scripts/nkb-*.mjs` round-2 deliverables — submit
(#13), JSON-LD export (#14), dedupe (#15), sandbox runner (#16),
adoption
stats (#17) — and will slot under the unified `scripts/nkb.mjs`
dispatcher
established by round-1 #3 once that lands on `main`. Until then it is
invokable standalone as `node scripts/nkb-graph.mjs`. Citing round-1 #5
specifically because that PR establishes the precedent of a fail-closed
CI lint over `workflow-patterns/*.md`; this PR extends that pattern
along the internal-link axis.

## Test plan

- [x] `bats tests/graph.bats` — all 10 outcome tests pass
- [x] `node scripts/nkb-graph.mjs --check` against real
`workflow-patterns/` exits 0
- [x] `node scripts/nkb-graph.mjs --dir fixtures/graph/broken --check`
exits 1 and names the bad edge
- [ ] Reviewer confirms `## Depends-on` schema is acceptable to bolt
onto existing pattern docs
- [ ] Reviewer decides whether to wire `--check` into
`.github/workflows/lint.yml` alongside the round-1 #5 citation lint

Co-authored-by: Cody Arnold <cody@wranngle.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
wranngle added a commit that referenced this pull request May 19, 2026
## Summary

Adds `scripts/nkb-graph.mjs` — emits a Mermaid graph of
pattern→dependency
edges parsed from a `## Depends-on` section in each
`workflow-patterns/*.md`
doc. The `--check` flag exits non-zero when any pattern references a
slug
with no matching `.md` file in the scanned directory.

This is the **structural** half of the citation-graph convention started
in
round-1 PR #5 (`feat(nkb): citation lint + Sources backfill on pattern
docs`):
PR #5 made every doc cite its external sources via `## Sources`; this PR
makes every doc declare its internal cross-pattern dependencies via
`## Depends-on`, and proves they all resolve. Both lints share the same
fail-closed posture so CI can wire either as a required check.

The schema is minimal — `## Depends-on` is followed by a bullet list of
slugs, one per line, where each slug is the basename of a sibling `.md`
in the same directory. A pattern with no dependencies either omits the
section entirely or leaves it empty. The existing
`voice-agent-elevenlabs-
patterns.md` doc parses cleanly under this schema with zero edges, so
the
new convention is strictly additive — no backfill required on `main`.

### Fixtures

`fixtures/graph/{ok,broken}/` follows the same convention as the dedupe
fixture set (#15) and the stats fixture (#17):

- `ok/` — three-pattern chain (`webhook-dedup-key →
http-retry-idempotency
  → error-monitoring-fanout`). All edges resolve.
- `broken/` — same chain plus a dangling edge to `nonexistent-upstream`.
  This is the negative-path fixture for `--check`.

### Proof

Mermaid render of the ok fixture:

```
$ node scripts/nkb-graph.mjs --dir fixtures/graph/ok
\`\`\`mermaid
graph LR
  error_monitoring_fanout["error-monitoring-fanout"]
  http_retry_idempotency["http-retry-idempotency"]
  webhook_dedup_key["webhook-dedup-key"]
  http_retry_idempotency --> error_monitoring_fanout
  webhook_dedup_key --> http_retry_idempotency
\`\`\`
```

Fail-closed broken-link check:

```
$ node scripts/nkb-graph.mjs --dir fixtures/graph/broken --check
nkb-graph check: 1 broken link(s):
  - webhook-dedup-key → nonexistent-upstream (no such pattern)
$ echo $?
1
```

Real `workflow-patterns/` directory on `main` (additive, doesn't
regress):

```
$ node scripts/nkb-graph.mjs --check
nkb-graph check: ok — 1 pattern(s), 0 edge(s), 0 broken
```

`tests/graph.bats` (10 cases, all green locally):

```
$ bats tests/graph.bats
1..10
ok 1 graph: mermaid output lists every pattern in the ok fixture as a node
ok 2 graph: edges in mermaid mirror Depends-on declarations
ok 3 graph --check: ok fixture passes with exit 0
ok 4 graph --check: broken fixture fails with exit 1 and names the missing slug
ok 5 graph --check --format json: ok fixture reports ok:true, broken:[]
ok 6 graph --check --format json: broken fixture reports the from/to edge
ok 7 graph: --format json (no --check) dumps every pattern with its deps list
ok 8 graph: pattern with no Depends-on section produces zero edges from it
ok 9 graph: missing --dir target exits non-zero with stderr message
ok 10 graph: mermaid output marks missing dep edges with dotted-arrow annotation
```

The broken-link check (#4) is the central-promise test: it asserts both
the non-zero exit and that the offending edge (`webhook-dedup-key →
nonexistent-upstream`) is named verbatim in the failure output.

### Round-1 / round-2 dependencies

Sits next to the other `scripts/nkb-*.mjs` round-2 deliverables — submit
(#13), JSON-LD export (#14), dedupe (#15), sandbox runner (#16),
adoption
stats (#17) — and will slot under the unified `scripts/nkb.mjs`
dispatcher
established by round-1 #3 once that lands on `main`. Until then it is
invokable standalone as `node scripts/nkb-graph.mjs`. Citing round-1 #5
specifically because that PR establishes the precedent of a fail-closed
CI lint over `workflow-patterns/*.md`; this PR extends that pattern
along the internal-link axis.

## Test plan

- [x] `bats tests/graph.bats` — all 10 outcome tests pass
- [x] `node scripts/nkb-graph.mjs --check` against real
`workflow-patterns/` exits 0
- [x] `node scripts/nkb-graph.mjs --dir fixtures/graph/broken --check`
exits 1 and names the bad edge
- [ ] Reviewer confirms `## Depends-on` schema is acceptable to bolt
onto existing pattern docs
- [ ] Reviewer decides whether to wire `--check` into
`.github/workflows/lint.yml` alongside the round-1 #5 citation lint

Co-authored-by: Cody Arnold <cody@wranngle.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-needs-issue PR has no Closes/Fixes/Resolves reference; auto-applied by pr-link-check

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant