diff --git a/CHANGELOG.md b/CHANGELOG.md index b16c5b7..3ccccba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -119,6 +119,7 @@ This project uses a Keep a Changelog-style structure. Until a tagged release is ### Fixed +- The README link to the agent orchestration reference no longer points at a generated path that is missing on GitHub. `tests/markdown-links.test.mjs` keeps relative links in tracked Markdown resolvable. - Current audit timestamps accept and preserve RFC 3339 offsets consistently. History, artifact input order, and fix-lease expiry compare actual instants without losing fractional precision; invalid legacy calendar values are rejected without rewriting frozen schemas. - Claude installation uses the existing exclusive-copy routine for staging as well as activation, avoiding a native `fs.cpSync` crash observed on Windows with Node 22.19.0. - Human findings no longer require a remediation plan when the reviewer records the required finding details; later plans preserve the original finding. diff --git a/README.en.md b/README.en.md index a38d8f2..15b3b92 100644 --- a/README.en.md +++ b/README.en.md @@ -218,8 +218,7 @@ For a new run, use `init` with `--inspection-mode quick|detailed --inspection-pu - [Report formats, HTML accessibility, and verification boundaries](docs/report-formats.md) - [Architecture, responsibilities, artifacts, and bilingual glossary](docs/architecture-and-glossary.md) - [Browser-based Web inspection and network boundaries](docs/web-inspection.md) -- [Agent orchestration for Codex](shared/skill/references/agent-orchestration.md) -- [Agent orchestration for Claude](claude/skills/information-accessibility-practice/references/agent-orchestration.md) +- [Agent orchestration for Codex and Claude](shared/skill/references/agent-orchestration.md) - [Standards assessment and evidence levels](shared/skill/references/standards-assessment.md) - [Security policy](SECURITY.md) - [Contribution guide](CONTRIBUTING.md) diff --git a/README.md b/README.md index e9d2f72..4dfff3c 100644 --- a/README.md +++ b/README.md @@ -218,8 +218,7 @@ https://example.com/ - [レポート形式、HTMLアクセシビリティ、検証境界](docs/report-formats.md) - [アーキテクチャ、役割、成果物、日英用語集](docs/architecture-and-glossary.md) - [実Web検査とbrowser/network境界](docs/web-inspection.md) -- [Codex向けagent orchestration](shared/skill/references/agent-orchestration.md) -- [Claude向けagent orchestration](claude/skills/information-accessibility-practice/references/agent-orchestration.md) +- [CodexとClaude向けagent orchestration](shared/skill/references/agent-orchestration.md) - [規格assessmentと証拠レベル](shared/skill/references/standards-assessment.md) - [セキュリティ方針](SECURITY.md) - [コントリビューション手順](CONTRIBUTING.md) diff --git a/release-files.json b/release-files.json index a7247ab..4e5a75f 100644 --- a/release-files.json +++ b/release-files.json @@ -396,6 +396,7 @@ "tests/interaction-browser-e2e.test.mjs", "tests/interaction-supervision.test.mjs", "tests/jis-procedure-reuse.test.mjs", + "tests/markdown-links.test.mjs", "tests/module-dependency.test.mjs", "tests/multi-agent-forward.test.mjs", "tests/network-address.test.mjs", diff --git a/tests/markdown-links.test.mjs b/tests/markdown-links.test.mjs new file mode 100644 index 0000000..bfd31d9 --- /dev/null +++ b/tests/markdown-links.test.mjs @@ -0,0 +1,55 @@ +import assert from "node:assert/strict"; +import fs from "node:fs"; +import path from "node:path"; +import { execFileSync } from "node:child_process"; +import test from "node:test"; +import { fileURLToPath } from "node:url"; + +const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); + +function trackedFiles() { + return execFileSync("git", ["ls-files", "-z"], { cwd: root, encoding: "utf8", shell: false }) + .split("\0") + .filter(Boolean); +} + +function localLinks(markdown) { + const links = []; + let inFence = false; + for (const [index, line] of markdown.split(/\r?\n/u).entries()) { + if (line.startsWith("```")) inFence = !inFence; + if (inFence) continue; + for (const match of line.matchAll(/\[[^\]]+\]\((?[^)]+)\)/gu)) { + const target = match.groups.target.trim(); + if (/^(?:https?:|mailto:|#)/iu.test(target)) continue; + links.push({ line: index + 1, target }); + } + } + return links; +} + +function targetExists(target, file, tracked) { + const clean = target.split("#", 1)[0].split("?", 1)[0]; + if (!clean) return true; + const resolved = path.posix.normalize(path.posix.join(path.posix.dirname(file), clean)); + return tracked.has(resolved) || [...tracked].some((entry) => entry.startsWith(`${resolved}/`)); +} + +test("every relative Markdown link in tracked files resolves", (t) => { + let tracked; + try { + tracked = new Set(trackedFiles()); + } catch (error) { + t.skip(`git unavailable or not a work tree: ${error.message}`); + return; + } + + const broken = []; + for (const file of [...tracked].filter((entry) => entry.endsWith(".md"))) { + const markdown = fs.readFileSync(path.join(root, file), "utf8"); + for (const { line, target } of localLinks(markdown)) { + if (!targetExists(target, file, tracked)) broken.push(`${file}:${line} -> ${target}`); + } + } + assert.deepEqual(broken, [], `broken relative Markdown links:\n${broken.join("\n")}`); +});