feat: add lychee offline module and CI lane - #11
Merged
Conversation
Add the lychee module — a decoupled lychee.toml (full fragment checking + repo-agnostic path excludes), good/bad fixtures, and lychee.test.sh on the shell harness. Wire a standards ci.yml lychee lane (the ci-workflows lychee-offline composite action, SHA-pinned) that runs --offline so only local file links and #anchors are checked — deterministic — plus a local lychee-fixtures job, both folded into ci-status; bump all action pins to the same ci-workflows commit. Broaden the markdown self-lint exclusion to fixtures/*/bad so intentionally broken fixtures (e.g. lychee's bad anchor, which markdownlint MD051 also flags) are not linted by sibling tools. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
kyle-sexton
added a commit
that referenced
this pull request
Jul 8, 2026
## Problem The `owner/repo#N` tracker-reference rule let the **owner** segment contain `.`, so a bare domain with a numeric fragment in a comment — e.g. `// see foo.com/bar#3` or `# example.com/page#2` at a space/start boundary — was misread as a cross-repo issue reference and flagged. The existing leading-boundary `.`/`-` exclusion only caught hosts *embedded* in a longer URL (preceded by `/` or `.`, e.g. `https://example.com/page#2`), not hosts at a word boundary — so the adjacent comment's claim that dotted hosts were handled was only half true. ## Fix A GitHub **owner** login (user or org) may contain only alphanumerics and hyphens — never a `.` or `_` (GitHub username rules; ≤39 chars, no leading/trailing/double hyphen). So the owner character class is restricted from `[A-Za-z0-9._-]` to `[A-Za-z0-9-]`. The **repo** segment keeps `.`/`_` because repository names legitimately allow them. A dotted host can no longer be read as an owner. Verified against the module test suite (`comment-hygiene.test.sh`), which I extended: the regression guard now covers **bare** domains (`foo.com/bar#3`, `example.com/page#2`, `sub.example.com/path#9`) alongside the existing scheme'd-URL cases. Genuine refs — including hyphenated owners (`melodic-software/app#123`, `owner-name/repo#7`) — still match. - `shellcheck -x`: clean. - Module test: **12/12 pass** (test #11 now guards the bare-domain false positive; #12 confirms hyphenated owners still flag). ## Propagation This library is vendored downstream: - **ci-workflows** carries a byte-identical copy (its comment-hygiene action self-test sources it) — a sync PR follows. - Consuming repos (e.g. `kyle-sexton/github-iac`) re-copy on their next standards sync. ## Separate follow-up (not fixed here) While committing I found the **local lefthook `shellcheck` hook diverges from CI**: CI passes `--rcfile modules/shellcheck/.shellcheckrc` (which sets `external-sources=true`), but the local hook relies on root `.shellcheckrc` auto-discovery, and standards has no root copy — so the hook emits `SC1091` for any script that `source`s another (e.g. `comment-hygiene.test.sh`) and can't be committed without `SHELLCHECK_OPTS=--external-sources`. That's a pre-existing dogfooding gap in standards' own tooling, orthogonal to this fix, and touches the root-stub/sync-manifest model — flagging for a maintainer decision rather than fixing inline. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Changes are limited to comment-scan regex behavior and ShellCheck config; no runtime auth, data, or production paths. > > **Overview** > **Comment-hygiene** tightens the `owner/repo#N` tracker rule so dotted hosts in comments (e.g. `foo.com/bar#3`, `example.com/page#2`) are no longer treated as cross-repo issue refs. The **owner** segment no longer allows `.` (GitHub logins cannot contain dots); the **repo** segment still allows `.` and `_`, and `_` remains in the owner class for GitHub Enterprise Managed User logins (e.g. `mona-cat_octo/repo#12`). Tests add bare-domain regression cases and an EMU owner positive case. > > A **root `.shellcheckrc`** is added as the repo’s ShellCheck ruleset (aligned with `modules/shellcheck/`), so local hooks that auto-discover config from the repo root can resolve `source`d scripts with `external-sources=true` and the same optional checks as CI’s `--rcfile` path. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 76df493. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Jul 15, 2026
kyle-sexton
added a commit
that referenced
this pull request
Jul 15, 2026
…on governance (#123) ## Summary Closes decisions **#27**, **#63**, and **#65** from the [Decisions Log](https://claude.ai/code/artifact/232ecdce-8316-4880-8c0a-dc3c7dcf3a63) (evidence/rationale: https://claude.ai/code/artifact/3160ae0e-c02f-4619-8de3-60d73faa1100). ### #63 metadata-standards-copy-vs-cite-doctrine Decision: **keep the "copy" adoption path, require back-link + drift-check.** Adds `distribution/governance-process.md`. `conventions/README.md` already documents two adoption paths for reasoning-only prose — copy into the consumer's tree, or point at this repo. The copy path stays available (prose has no runtime coupling to enforce reconciliation the way `sync-manifest.yml` does), but a copy now carries two mandatory requirements: - **Back-link** — every copied file cites its exact canonical source (repo + path, inline header where the format allows it), using the same stable-anchor citation discipline `reference-dont-duplicate.md` already prescribes for the "Expose" file role. - **Drift-check** — the adopting repo owns a periodic diff of its copy against the current canonical source, with a named owner and trigger, mirroring the recheck-trigger discipline `documentation-and-citations.md` already requires for time-bound external claims. The doc is explicit that this is distinct from a `managed` `sync-manifest.yml` component, which already reconciles automatically and deliberately carries no downstream receipt — the back-link/drift-check burden applies only where nothing else keeps a copy current. ### #65 naming-cross-doc-reconciliation-process-ownership Decision: **establish a standing cross-reference review step for normative-doc changes.** Same doc adds the standing process step: before a change to a normative doc (`naming.md`, `process/issue-tracker.md`, `review/code-quality.md`, and any other file in the catalog stating a rule another doc cites or assumes) merges, a cross-reference check confirms no other doc now contradicts it. Ownership is named explicitly rather than left implicit: `required_approving_review_count` stays at `0` org-wide (decision #11, single-maintainer), so there is no independent blocking reviewer to gate this. The step is documented as a **self-review checklist item the author performs before merge**, with a documented future automation path — extending the periodic cross-plugin-source consistency check (decision #37, for `claude-code-plugins`) to this repo's own normative docs once that check exists, so the control stops depending solely on author diligence. `conventions/README.md` gets a new "Changing a normative file" pointer to this requirement; `distribution/README.md` gets a pointer alongside its existing `THREAT-MODEL.md` reference. ### #27 tooling-gov-conventions-graduate-to-enforced Decision: **graduate mechanically-checkable rules into sync-manifest-tracked components.** Reviewed every file under `conventions/` against `enforceability-tiers.md`'s deterministic/detect-then-judge/reasoning-only split. Finding: **no ungraduated deterministic rule exists to graduate.** Every deterministic (mechanically-checkable) rule already points to its owning component instead of restating it: | Convention area | Deterministic rule | Owning component | Tracked in `sync-manifest.yml`? | |---|---|---|---| | Secrets (`review/security.md`) | no secrets in source | `gitleaks` | yes | | Comments (`review/code-quality.md`) | debt markers / tracker provenance | `comment-hygiene` | yes (`comment-hygiene-action`) | | Citations (`documentation-and-citations.md`) | cited URL resolves | link check | yes (`lychee`) | | TypeScript/JS (`review/overlays/typescript.md`) | lint/format/import order, type correctness | `biome`, `tsconfig` | **no** — deliberately native-package (`extends`) adoption per `distribution/README.md`'s ownership model, not exact materialization | | Python (`review/overlays/python.md`) | lint/format, type correctness | `ruff`, `pyright` | yes | | .NET (`review/overlays/dotnet.md`) | analyzers, code style, banned symbols | `dotnet-analysis` | yes | | Container build (`container-supply-chain.md`) | Docker Build checks, OSV scans | *(none yet)* | **no** — the convention itself explicitly defers this pending live-consumer admission evidence per `docs/component-lifecycle.md`; graduating it without that evidence would violate the same lifecycle contract | | PR titles (`review/code-quality.md`) | Conventional Commits format | *(ci-workflows `pr-title.yml`)* | out of this repo's materialization surface — owned by `ci-workflows`, per README.md's ownership boundaries | | Naming (`naming.md`), label/issue-tracker usage (`process/issue-tracker.md`), duplication (`reference-dont-duplicate.md`) | — | — | self-declared reasoning-only; no deterministic subset exists to graduate | No `sync-manifest.yml` change is included. The one adjacent orphan noticed in passing — `components/lefthook-typescript` exists, is fully built, but is not registered in `sync-manifest.yml` for any target — is tooling infrastructure, not a `conventions/` rule, and assigning it to a target's `managed:` list is a separate adoption decision requiring its own admission evidence; flagging it here for a follow-up rather than folding it into this PR. ## Test plan - [x] `npx markdownlint-cli2` — 0 errors across the full repo (71 files, including the new/changed docs) - [x] `lychee` — 21/21 links OK on the changed files (0 errors) - [x] `typos` — clean on the changed files - [x] `lefthook` pre-commit (typos, editorconfig, gitleaks, markdownlint) — all passed at commit time - [ ] Maintainer confirms the #27 classification table before merge — no code/config changed, so this PR is prose-only and carries no behavioral risk 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
kyle-sexton
added a commit
that referenced
this pull request
Jul 15, 2026
… style (#124) ## Summary Codifies six open decisions from the org's issue/PR consistency assessment into `conventions/process/issue-tracker.md`: - **#9** `entities-governance-doc-topology-reference-style` — abstracts the personal-vs-org repo-topology prose (no more named `melodic-software/github-iac` / `kyle-sexton/github-iac` links); points at `github-iac`'s `GovernedRepositories.cs` as the sole source of truth for which repositories are governed and how. - **#23** `entities-closing-keyword-house-style-convention` — codifies native GitHub closing keywords (`Closes`/`Fixes`/`Resolves` `#N`) as the default house style, with `provisioning`'s stricter requirement (native keyword plus a manual `## Related` section, per decisions #58/#59) as the one named exception. - **#25** `naming-issue-title-vocabulary-governance` — codifies issue titles as free text with no enforced prefix vocabulary (no `[CC]`-style conventional-commit tags), documenting the existing silence as a deliberate choice. - **#45** `entities-assignee-claiming-guidance-relevance` — keeps the existing assignee-plus-lease claiming guidance but marks it explicitly deferred, with an activation trigger (required reviewers / multi-maintainer assignment contention). - **#48** `metadata-codeowners-adoption` — adds a one-line note that CODEOWNERS adoption is deferred, contingent on decision #11 (`required_approving_review_count` staying at 0 org-wide) — CODEOWNERS is inert without required reviews. - **#49** `comments-codify-human-conventions` — codifies three optional documented conventions: a 🤖 footer marking bot-authored comments, citing evidence when closing on it, and a 🔒 marker for claimed issues (explicitly framed as the lightweight interim signal until #45's mechanism activates). Decisions Log: https://claude.ai/code/artifact/232ecdce-8316-4880-8c0a-dc3c7dcf3a63 ## Test plan - [x] `lefthook run pre-commit` — typos, editorconfig, gitleaks, markdownlint all pass - [x] Grepped the file for residual `kyle-sexton`/named `github-iac` repo references — none remain - [ ] Human review of tone/placement against the rest of the process conventions 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add the lychee module — a decoupled lychee.toml (full fragment checking +
repo-agnostic path excludes), good/bad fixtures, and lychee.test.sh on the
shell harness. Wire a standards ci.yml lychee lane (the ci-workflows
lychee-offline composite action, SHA-pinned) that runs --offline so only local
file links and #anchors are checked — deterministic — plus a local
lychee-fixtures job, both folded into ci-status; bump all action pins to the
same ci-workflows commit.
Broaden the markdown self-lint exclusion to fixtures/*/bad so intentionally
broken fixtures (e.g. lychee's bad anchor, which markdownlint MD051 also flags)
are not linted by sibling tools.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com