fix(links): a directory link is not a missing file, so a tracked dir now resolves
`checkInternalLinks` compared a link's resolved target only against `present` (tracked files), so `[x](dir/)` was always LINK-INTERNAL-MISSING even when every file under it was tracked. Reported by portfolio-optimiser-claude with a minimal repro; the same defect inflated ERROR counts in voyage, linkedin-studio and portfolio-optimiser — 12 of the org's 71 measured ERRORs were this one check, not twelve repo problems. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uwwfdmrfnp7FuGQ4z25RKH
This commit is contained in:
parent
0945e88598
commit
3c2a535297
7 changed files with 50 additions and 5 deletions
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "repo-standard",
|
||||
"version": "0.1.1",
|
||||
"version": "0.1.2",
|
||||
"description": "Per-repo gate for the open/ presentation standard: README first screen, install block, files required by the repo's class, and dead repo references.",
|
||||
"author": {
|
||||
"name": "Kjell Tore Guttormsen"
|
||||
|
|
|
|||
17
CHANGELOG.md
17
CHANGELOG.md
|
|
@ -4,6 +4,22 @@ All notable changes to this project are documented here.
|
|||
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/);
|
||||
versioning is [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.1.2] — 2026-08-03
|
||||
|
||||
### Fixed
|
||||
|
||||
- `checkInternalLinks` compared a link's resolved target only against
|
||||
`present` — the set of tracked *files* — so a link to a directory
|
||||
(`[x](dir/)`) was reported `LINK-INTERNAL-MISSING` even when every file
|
||||
under that directory was tracked. A directory was never a member of that
|
||||
set to begin with. Reported by `portfolio-optimiser-claude` (coord
|
||||
20260803T194933Z) with a minimal repro; confirmed and traced to the same
|
||||
defect in `voyage`, `linkedin-studio` and `portfolio-optimiser` — 12 of the
|
||||
71 ERROR findings measured across the org on 2026-08-03 were this one check,
|
||||
not twelve separate repo problems. Fixed by deriving the set of directories
|
||||
that actually contain a tracked file from `present` itself, and letting a
|
||||
link that resolves to one of them pass.
|
||||
|
||||
## [0.1.1] — 2026-08-03
|
||||
|
||||
Documentation only. No behaviour change: `scripts/` and `register/` are
|
||||
|
|
@ -117,5 +133,6 @@ First release. Covers the checks that a single repository can answer on its own.
|
|||
- No hook ships in this release. A blocking gate has to be precise enough not to
|
||||
fail a correct repository first.
|
||||
|
||||
[0.1.2]: https://git.fromaitochitta.com/open/repo-standard/src/tag/v0.1.2
|
||||
[0.1.1]: https://git.fromaitochitta.com/open/repo-standard/src/tag/v0.1.1
|
||||
[0.1.0]: https://git.fromaitochitta.com/open/repo-standard/src/tag/v0.1.0
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ checks that surface in one repository and reports what it finds.
|
|||
|
||||
*AI-generated: all code produced by Claude Code through dialog-driven development.*
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "repo-standard",
|
||||
"version": "0.1.1",
|
||||
"version": "0.1.2",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"engines": {
|
||||
|
|
|
|||
|
|
@ -578,6 +578,14 @@ function linkLevelFor(path) {
|
|||
// deliberately out — a check that is sometimes wrong teaches people to ignore it.
|
||||
export function checkInternalLinks({ files, present }) {
|
||||
const have = new Set(present ?? []);
|
||||
// `present` holds tracked FILES only, so a link to a directory — `[x](dir/)`
|
||||
// — never has a member to match even when every file under it is tracked.
|
||||
// Derive the directories a tracked file actually lives in from the same set.
|
||||
const haveDirs = new Set();
|
||||
for (const p of have) {
|
||||
const parts = String(p).split('/');
|
||||
for (let i = 1; i < parts.length; i++) haveDirs.add(parts.slice(0, i).join('/'));
|
||||
}
|
||||
const findings = [];
|
||||
for (const [path, text] of Object.entries(files ?? {})) {
|
||||
stripCode(text).split('\n').forEach((line, i) => {
|
||||
|
|
@ -600,7 +608,7 @@ export function checkInternalLinks({ files, present }) {
|
|||
});
|
||||
continue;
|
||||
}
|
||||
if (!have.has(resolved)) {
|
||||
if (!have.has(resolved) && !haveDirs.has(resolved)) {
|
||||
findings.push({
|
||||
level: linkLevelFor(path),
|
||||
code: 'LINK-INTERNAL-MISSING',
|
||||
|
|
|
|||
|
|
@ -637,6 +637,26 @@ test('a genuinely missing sibling file is still an ERROR', () => {
|
|||
assert.equal(f.some((x) => x.code === 'LINK-INTERNAL-MISSING' && x.level === 'ERROR'), true);
|
||||
});
|
||||
|
||||
// Reported by portfolio-optimiser-claude (coord 20260803T194933Z): `present` is
|
||||
// the set of tracked FILES, so a directory link never has a member to match,
|
||||
// even when every file under it is tracked. `have` never contained a directory
|
||||
// to begin with — the fix derives one from `present`, it does not loosen it.
|
||||
test('a link to a directory that is genuinely tracked resolves', () => {
|
||||
const f = checkInternalLinks({
|
||||
files: { 'README.md': 'See [dir](runs/s10/) and [file](runs/s10/a.json).' },
|
||||
present: ['README.md', 'runs/s10/a.json'],
|
||||
});
|
||||
assert.equal(f.some((x) => x.code === 'LINK-INTERNAL-MISSING'), false);
|
||||
});
|
||||
|
||||
test('a link to a directory with no tracked files under it is still an ERROR', () => {
|
||||
const f = checkInternalLinks({
|
||||
files: { 'README.md': '[ghost](docs/ghost/)' },
|
||||
present: ['README.md'],
|
||||
});
|
||||
assert.equal(f.some((x) => x.code === 'LINK-INTERNAL-MISSING' && x.level === 'ERROR'), true);
|
||||
});
|
||||
|
||||
test('a required heading present at the wrong level says so', () => {
|
||||
// llm-security has `### Install` nested under `## Quick Start`. The contract
|
||||
// wants it at level 2 — the finding should name that, not just "missing".
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ description: >-
|
|||
"fiks install-blokka", "finn døde repo-referanser", "gjør repoet presentabelt".
|
||||
Trigger when someone is about to release, publish, or hand over a repository
|
||||
and wants its public surface to hold up.
|
||||
version: "0.1.1"
|
||||
version: "0.1.2"
|
||||
---
|
||||
|
||||
# repo-standard — the per-repo gate
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue