Skip to content

chore(graphify): refresh knowledge graph - #718

Merged
mforce merged 1 commit into
mainfrom
chore/graphify-refresh-2026-09-08
Sep 8, 2026
Merged

mforce merged 1 commit into
mainfrom
chore/graphify-refresh-2026-09-08

Conversation

@mforce

@mforce mforce commented Sep 8, 2026

Copy link
Copy Markdown
Owner
Metric Before After Delta
Nodes 12922 14360 +1438
Edges 30330 32222 +1892
Files tracked 1221 1371 +150
  • Built at commit: 3870acd0e20fdaa819a504bbe32ad79a2a814776 → 389e3c80b8eb1a92474c81bdcaef2281abed6916
  • Staleness closed: 63 commit(s) behind HEAD
  • Semantic re-extraction pending for 1076 file(s). This refresh is the free AST pass; clearing that backlog needs the paid pass and is a separate, deliberate run.

VERDICT: refreshed

Notes

  • Rebuild path: graphify update . (AST-only, no model calls). Commit range closed: 3870acd0..389e3c80 (63 commits).
  • Only graphify-out/ is in this PR; the derived JSON is not meant to be read. The table above is the review.
  • Rebuild warnings: 17 JSON config files produced zero nodes (expected, retried on next run); 2 nodes from 1 file kept fail-closed because it left the scan corpus but still exists on disk.
  • Semantic-pending count is a report, not a task: clearing it is the paid pass and a separate deliberate run.
  • A refresh is not a review: this verifies the graph was rebuilt at a known commit, nothing about the code it indexed.

AST-only `graphify update .` rebuild; closes 3870acd..389e3c8 (63 commits).

| Metric | Before | After | Delta |
|---|---:|---:|---:|
| Nodes | 12922 | 14360 | +1438 |
| Edges | 30330 | 32222 | +1892 |
| Files tracked | 1221 | 1371 | +150 |

- Built at commit: `3870acd0e20fdaa819a504bbe32ad79a2a814776` → `389e3c80b8eb1a92474c81bdcaef2281abed6916`
- Staleness closed: 63 commit(s) behind HEAD
- Semantic re-extraction pending for **1076** file(s). This refresh is the free AST pass; clearing that backlog needs the paid pass and is a separate, deliberate run.

VERDICT: refreshed
@coderabbitai

coderabbitai Bot commented Sep 8, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: e60162b6-1cc4-4de0-829f-1a8eb45b0584


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@mforce
mforce merged commit 11ba6b7 into main Sep 8, 2026
8 checks passed
@mforce
mforce deleted the chore/graphify-refresh-2026-09-08 branch September 8, 2026 19:30
mforce added a commit that referenced this pull request Sep 12, 2026
…uests (#783)

Skips `Image build + Trivy scan` and `Web typecheck, test, and build` on
pull requests that change nothing but documentation. `Build and test` is
untouched, because four of its guards are load-bearing on a
markdown-only change.

Closes #782

## The question is inverted, on purpose

The gate does not ask "which jobs does this change need". That is a
hand-maintained list of what someone thought of, which is the shape
`AGENTS.md`'s guard rules tell you to avoid. It asks **"does this pull
request contain literally nothing but documentation"**, so a path nobody
has classified is code by default and the full suite runs.

That also resolves the issue's decision 3, which warned that deriving
one shared trigger condition for both jobs would be the easy mistake. It
would be, for a *positive* trigger set. For this predicate a single
shared condition is correct by construction, because "contains nothing
but documentation" is safe for both jobs at once.

## Fail-closed in one direction only

A wrong `false` costs four minutes of runner time. A wrong `true` skips
the image build and the Trivy scan on a change that needed them. So
every failure path answers `false`:

- The classify step short-circuits to `docs_only=false` on any event
that is not `pull_request`, without consulting git.
- It runs without `set -e`, and a git failure, a node failure or an
unreadable stdin all land on `docs_only=false` with the step still
green.
- The jobs test `needs.changes.outputs.docs_only != 'true'`, not `==
'false'`. If the gate produces no output at all, the jobs run.
- `!cancelled()` is what lets that condition be evaluated when the gate
job itself failed.

## `publish` cannot be starved of an image

`publish` declares `needs: [build-and-test, web, image]`, and per #351 a
merge that produces no image leaves a release draft that can never be
promoted. Two separate protections, because the first one alone was not
enough:

The gate never fires outside `pull_request`, so a push to `main` runs
`web` and `image` exactly as before. And `changes` carries
`continue-on-error: true`, because `publish`'s `if:` uses no status
function and therefore carries an implicit `success()` over its whole
ancestor chain — so a `changes` job that failed for any reason would
have skipped `publish` on `main` even though `web` and `image` ran and
passed. That hole was introduced by adding `needs: [changes]` and is
closed by making the gate unable to fail.

The classifier's self-tests therefore run in their own
`classifier-self-test` job with no dependents, since a
`continue-on-error` job cannot fail a run and a guard that cannot fail a
run is not a guard.

`ci.yml`'s diff is 134 added lines and **zero removed**. `publish`'s
`needs` and `if:` are byte-identical.

## Three corrections found before this was pushed

The diff went to an adversarial reviewer first, per the "Writing a
guard" rule. It broke the first design in three places, each verified
against the repository rather than accepted on argument.

**`specs/**` is not documentation here.**
`web/src/routes/helpGlossary.test.ts:23` reads
`../specs/product/GLOSSARY.md` from disk and fails when a spec term is
renamed out from under the in-app glossary (#657). That test runs in the
`web` job, one of the two this gate skips, so a specs-only pull request
would have skipped the guard written for specs-only pull requests.
Carving out that single file would work today and fail silently the
first time a second web test reads a second specs path, so the whole
tree is code.

**`--name-only` hides a rename's source.** `diff.renames` defaults to
true, so `git mv src/Cluckwork.Domain/Common/Result.cs docs/Result.cs`
arrives as the single path `docs/Result.cs` and classified as
documentation while a source file was deleted. Measured on this
repository, not reasoned about. `--no-renames` is now in the workflow,
an end-to-end test performs that exact `git mv`, and a second test reads
`ci.yml` and asserts the flag is on the classifying `git diff`, because
the module and the workflow each held a copy of that contract.

**The gate reopened the publish hazard**, covered above.

## Verification

16 `node:test` cases, and 13 mutations applied by script, run, and
restored with a byte-identical diff check. Every mutation went red and
every test went red under at least one. They include `every` to `some`
(the "are any docs changed" bug the issue names), dropping the
empty-list check, dropping the trailing slash so `docsomething/x.cs`
matches `docs/`, letting any `*.md` count as root documentation, and
removing `--no-renames` from `ci.yml`. One earlier mutation survived,
and the code was fixed rather than the claim: the unreadable-stdin catch
was unreachable through an async iterator, so the CLI now reads fd 0
with `readFileSync`.

Against real history: PR #768 answers `true`, PR #779 answers `false`
(it is the mixed case, carrying `AGENTS.md` and two `docs/` files beside
lock files and tooling), and release PR #542 answers `false` because
`version.txt` is not root markdown. Six of the seven documentation-only
PRs the issue measured answer `true`; the seventh is #718, ten
`graphify-out/` files, excluded deliberately.

The push path was demonstrated rather than argued: the classify step's
`run:` block was extracted from the parsed YAML and executed with the
event name forced, and `push` and `workflow_dispatch` both write
`docs_only=false` and exit 0 without touching git.

## One question the issue asked that could not be answered

It named "establish which status checks are required" as the blocking
first step. It could not be read: this repository has no rulesets and
classic branch protection returns 403 for a personal access token. It
turns out not to matter, and the decision record says why. A job skipped
by `if:` reports as *skipped*, which satisfies a required check, whereas
a workflow skipped by `on.pull_request.paths` leaves its check in
`Expected` forever and blocks the merge. The mechanism chosen here is
safe either way, so the unknown is dissolved rather than deferred.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **CI Improvements**
- Documentation-only pull requests now skip the web and image CI jobs,
reducing validation time.
- Changes are classified conservatively; ambiguous or failed detection
continues to run the affected checks.
  - Build and test validation remains enabled for all changes.

- **Documentation**
- Added a decision record describing documentation-only pull request
handling, its scope, and safeguards.
  - Updated the decisions index with the new record.

- **Tests**
- Added comprehensive coverage for documentation-change detection and CI
behavior.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: mforce <cleyva@clvc.net>
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.

1 participant