chore: guard README local links and refresh tile-01 vendor metadata

- Add config/scripts/check-readme-local-links.mjs: every local src/srcset/href
  in README.md and docs/readme/*.md must resolve to a tracked file. Runs in the
  ungated root_directory_guard job so docs-only diffs (which skip static_analysis)
  still catch a deleted docs-site or feature-wall asset the README embeds.
- Refresh tile-01.recorded-at.json to what vendor-feature-wall-assets.mjs now
  emits for the tab-split source path.
- Drop the pr-19217 evidence prose that cited the removed screenshots.
This commit is contained in:
Neil
2026-09-12 15:40:05 -07:00
parent 9351e0e967
commit 08ac840da2
6 changed files with 255 additions and 7 deletions
+6
View File
@@ -276,6 +276,12 @@ jobs:
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: node .github/scripts/check-root-directory-entries.mjs "$BASE_SHA" "$HEAD_SHA"
# Why here: the READMEs embed media owned by docs/site and resources/onboarding,
# and the classifier skips static_analysis for docs-only diffs. This job runs
# on every PR and needs no install.
- name: Check README local links
run: node config/scripts/check-readme-local-links.mjs
typecheck:
needs: [code_paths]
if: needs.code_paths.outputs.typecheck == 'true'
+102
View File
@@ -0,0 +1,102 @@
import { execFileSync } from 'node:child_process'
import { readdirSync, readFileSync } from 'node:fs'
import path from 'node:path'
import process from 'node:process'
import { pathToFileURL } from 'node:url'
// Why: the READMEs embed media from trees other jobs own (docs-site public media,
// generated feature-wall tiles), and the docs-only classifier skips the whole CI
// matrix for one of them. GitHub renders only committed files, so this checks the
// git index rather than the working tree.
const TRANSLATED_README_DIR = path.join('docs', 'readme')
const EXTERNAL_TARGET = /^(?:[a-z][a-z0-9+.-]*:|#|\/\/)/i
const HTML_ATTRIBUTE = /\b(?:src|srcset|href)\s*=\s*"([^"]*)"/g
const MARKDOWN_LINK = /!?\[[^\]]*\]\(([^)\s]+)(?:\s+"[^"]*")?\)/g
function readmeFiles(root) {
const translated = readdirSync(path.join(root, TRANSLATED_README_DIR))
.filter((name) => name.endsWith('.md'))
.sort()
.map((name) => path.posix.join('docs', 'readme', name))
return ['README.md', ...translated]
}
// Why only the referenced paths: a full `git ls-files` of this repo overflows the
// default child buffer; asking about a few dozen pathspecs stays bounded.
function trackedFiles(root, candidates) {
if (candidates.length === 0) {
return new Set()
}
const stdout = execFileSync(
'git',
['--literal-pathspecs', 'ls-files', '-z', '--', ...candidates],
{ cwd: root, encoding: 'utf8' }
)
return new Set(stdout.split('\0').filter(Boolean))
}
function* localTargets(markdown) {
for (const match of markdown.matchAll(HTML_ATTRIBUTE)) {
// Why: srcset is a candidate list ("a.gif 1x, b.gif 2x"); each entry starts with a URL.
for (const candidate of match[1].split(',')) {
const target = candidate.trim().split(/\s+/)[0]
if (target) {
yield target
}
}
}
for (const match of markdown.matchAll(MARKDOWN_LINK)) {
yield match[1].replace(/^<|>$/g, '')
}
}
function resolveTarget(readme, target) {
const bare = target.split(/[?#]/)[0]
if (!bare) {
return null
}
const resolved = path.posix.normalize(
path.posix.join(path.posix.dirname(readme), decodeURIComponent(bare))
)
return resolved.startsWith('../') ? null : resolved
}
function collectLinks(root) {
const links = []
for (const readme of readmeFiles(root)) {
const markdown = readFileSync(path.join(root, readme), 'utf8')
for (const target of new Set(localTargets(markdown))) {
if (EXTERNAL_TARGET.test(target)) {
continue
}
links.push({ readme, target, resolved: resolveTarget(readme, target) })
}
}
return links
}
export function findBrokenReadmeLinks(root) {
const links = collectLinks(root)
const candidates = [...new Set(links.map((link) => link.resolved).filter(Boolean))]
const tracked = trackedFiles(root, candidates)
return links.filter(({ resolved }) => resolved === null || !tracked.has(resolved))
}
export function main(root = process.cwd()) {
const broken = findBrokenReadmeLinks(root)
if (broken.length > 0) {
console.error(`README local link check failed with ${broken.length} broken link(s):`)
for (const { readme, target, resolved } of broken) {
console.error(
`- ${readme}: ${target} -> ${resolved ?? 'outside the repository'} is not tracked`
)
}
return 1
}
console.log('README local link check passed.')
return 0
}
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
process.exit(main())
}
@@ -0,0 +1,138 @@
import { execFileSync } from 'node:child_process'
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import path from 'node:path'
import { afterEach, describe, expect, it, vi } from 'vitest'
import { parse } from 'yaml'
import { findBrokenReadmeLinks, main } from './check-readme-local-links.mjs'
const projectDir = path.resolve(import.meta.dirname, '../..')
const tempDirs = []
function git(cwd, args) {
return execFileSync('git', args, { cwd, encoding: 'utf8' }).trim()
}
function writeFiles(root, files) {
for (const [relativePath, contents] of Object.entries(files)) {
const target = path.join(root, relativePath)
mkdirSync(path.dirname(target), { recursive: true })
writeFileSync(target, contents)
}
}
function makeFixture(files, { untracked = {} } = {}) {
const root = mkdtempSync(path.join(tmpdir(), 'orca-readme-links-'))
tempDirs.push(root)
git(root, ['init', '--quiet'])
git(root, ['config', 'user.email', 'readme-links-test@example.com'])
git(root, ['config', 'user.name', 'README Links Test'])
writeFiles(root, files)
git(root, ['add', '-A'])
git(root, ['commit', '--quiet', '-m', 'fixture'])
writeFiles(root, untracked)
return root
}
const validReadmes = {
'README.md': [
'<img src="resources/build/icon.png" />',
'<picture><source srcset="docs/site/public/docs/tab-split.gif" type="image/gif"><img src="resources/onboarding/feature-wall/tile-01.poster.jpg" /></picture>',
'<a href="docs/readme/README.ja.md">日本語</a>',
'<img src="https://img.shields.io/badge/x-y-z" />',
'[Contributing](.github/CONTRIBUTING.md) [Docs](https://example.com/docs) [Top](#top)',
'![hero](docs/assets/hero%20image.jpg "Hero")'
].join('\n'),
'docs/readme/README.ja.md': [
'<img src="../../resources/build/icon.png" />',
'<source srcset="../site/public/docs/tab-split.gif">',
'<a href="../../README.md">English</a> <a href="README.ja.md#top">self</a>',
'[LICENSE](../../LICENSE)'
].join('\n'),
'resources/build/icon.png': 'png',
'resources/onboarding/feature-wall/tile-01.poster.jpg': 'jpg',
'docs/site/public/docs/tab-split.gif': 'gif',
'docs/assets/hero image.jpg': 'jpg',
'.github/CONTRIBUTING.md': 'contributing',
LICENSE: 'mit'
}
afterEach(() => {
vi.restoreAllMocks()
while (tempDirs.length > 0) {
rmSync(tempDirs.pop(), { force: true, recursive: true })
}
})
describe('README local link check', () => {
it('accepts the checked-in READMEs', () => {
vi.spyOn(console, 'log').mockImplementation(() => {})
expect(main(projectDir)).toBe(0)
})
it('accepts local links in every supported shape', () => {
expect(findBrokenReadmeLinks(makeFixture(validReadmes))).toEqual([])
})
it('reports a deleted media file for the root and translated READMEs', () => {
const { 'docs/site/public/docs/tab-split.gif': _gif, ...files } = validReadmes
vi.spyOn(console, 'error').mockImplementation(() => {})
const root = makeFixture(files)
expect(findBrokenReadmeLinks(root)).toEqual([
{
readme: 'README.md',
target: 'docs/site/public/docs/tab-split.gif',
resolved: 'docs/site/public/docs/tab-split.gif'
},
{
readme: 'docs/readme/README.ja.md',
target: '../site/public/docs/tab-split.gif',
resolved: 'docs/site/public/docs/tab-split.gif'
}
])
expect(main(root)).toBe(1)
expect(console.error).toHaveBeenCalledWith(
expect.stringContaining('README.md: docs/site/public/docs/tab-split.gif')
)
})
// Why: GitHub renders the commit, so a file that only exists on disk is broken.
it('reports a referenced file that exists on disk but is not tracked', () => {
const { 'resources/build/icon.png': icon, ...files } = validReadmes
const root = makeFixture(files, { untracked: { 'resources/build/icon.png': icon } })
expect(findBrokenReadmeLinks(root).map((link) => link.resolved)).toEqual([
'resources/build/icon.png',
'resources/build/icon.png'
])
})
it('reports a link that escapes the repository', () => {
const root = makeFixture({
...validReadmes,
'docs/readme/README.ja.md': '<img src="../../../outside.png" />'
})
expect(findBrokenReadmeLinks(root)).toEqual([
{ readme: 'docs/readme/README.ja.md', target: '../../../outside.png', resolved: null }
])
})
// Why the ungated job: static_analysis is skipped for docs-only diffs, which is
// exactly the kind of PR that deletes a docs-site GIF the README embeds.
it('runs on every PR through the ungated guard job and in the lint script', () => {
const { scripts } = JSON.parse(readFileSync(path.join(projectDir, 'package.json'), 'utf8'))
const workflow = parse(readFileSync(path.join(projectDir, '.github/workflows/pr.yml'), 'utf8'))
const guardJob = workflow.jobs.root_directory_guard
const step = guardJob.steps.find((candidate) => candidate.name === 'Check README local links')
expect(guardJob.if).toBeUndefined()
expect(guardJob.needs).toBeUndefined()
expect(step.run).toBe('node config/scripts/check-readme-local-links.mjs')
expect(scripts['check:readme-local-links']).toBe(
'node config/scripts/check-readme-local-links.mjs'
)
expect(scripts.lint).toContain('pnpm run check:readme-local-links')
})
})
+3 -2
View File
@@ -2,7 +2,8 @@
Validated on September 7, 2026 in a background Electron dev instance of
`pr19217-review-r2`, based on `ce1024096b` with the source-adapter refactor.
CDP app identity confirmed the checkout; screenshots show the full hidden renderer.
CDP app identity confirmed the checkout; CDP screenshots of the full hidden renderer
were reviewed at the time and are not retained here.
The command output is the real `orca worktree ps --json` response reduced to status,
agent state, provider, and pane key for readability.
@@ -34,7 +35,7 @@ targeted lint and diff checks passed. Ablating the runtime call to enumerate
retained history caused the executable call-site test to fail with two rows where
one was expected; restoring the live accessor passed both call-site tests.
Live screenshots prove Codex working and closure on macOS. Claude provider turns,
Codex working and closure were observed live on macOS. Claude provider turns,
approval/input states, live Windows/Linux/WSL/SSH/relay/mobile scenarios and
release-scale latency/heap measurements remain unverified. Existing tests cover
remote/WSL evidence, monitoring precedence and lifecycle cases. The existing
+2 -1
View File
@@ -13,7 +13,7 @@
"audit:perf": "oxlint --config config/oxlint-performance-audit.json --format json src",
"test:perf:contracts": "vitest run --config config/vitest.performance.config.ts",
"format": "oxfmt --write .",
"lint": "oxlint && pnpm run audit:code-quality:native && pnpm run audit:code-quality:type-aware && pnpm run check:reliability-gates && pnpm run check:max-lines-ratchet && pnpm run check:ts-nocheck-ratchet && pnpm run check:runtime-electron-ratchet && pnpm run verify:rpc-params-catalog && pnpm run verify:bundled-skill-guides && pnpm run verify:skill-bundle-manifest && pnpm run verify:localization-catalog && pnpm run verify:localization-runtime-catalog && pnpm run verify:localization-extraction && pnpm run verify:localization-coverage",
"lint": "oxlint && pnpm run audit:code-quality:native && pnpm run audit:code-quality:type-aware && pnpm run check:reliability-gates && pnpm run check:max-lines-ratchet && pnpm run check:ts-nocheck-ratchet && pnpm run check:runtime-electron-ratchet && pnpm run check:readme-local-links && pnpm run verify:rpc-params-catalog && pnpm run verify:bundled-skill-guides && pnpm run verify:skill-bundle-manifest && pnpm run verify:localization-catalog && pnpm run verify:localization-runtime-catalog && pnpm run verify:localization-extraction && pnpm run verify:localization-coverage",
"audit:code-quality": "pnpm run audit:code-quality:native && pnpm run audit:code-quality:type-aware && pnpm run audit:react-doctor",
"audit:code-quality:native": "oxlint --config config/oxlint-code-quality-native-plugins.json src config tests mobile --deny-warnings",
"audit:code-quality:type-aware": "oxlint --type-aware --config config/oxlint-code-quality-type-aware.json src config tests --deny-warnings",
@@ -34,6 +34,7 @@
"check:max-lines-ratchet": "node config/scripts/check-max-lines-ratchet.mjs",
"check:ts-nocheck-ratchet": "node config/scripts/check-ts-nocheck-ratchet.mjs",
"check:runtime-electron-ratchet": "node config/scripts/check-runtime-electron-ratchet.mjs",
"check:readme-local-links": "node config/scripts/check-readme-local-links.mjs",
"build:orcad": "node config/scripts/build-orcad.mjs",
"build:orcad-prebuilds": "node config/scripts/build-orcad-prebuilds.mjs",
"smoke:orcad-terminal": "node config/scripts/ensure-native-runtime.mjs --runtime=node && pnpm run build:cli && pnpm run build:orcad && node config/scripts/runtime-serve-terminal-smoke.mjs --target orcad",
@@ -1,6 +1,6 @@
{
"recordedAtUnixSeconds": 1778710735,
"recordedAtIso": "2026-05-13T22:18:55.000Z",
"sourceGif": "docs/assets/feature-wall/parallel-worktrees.gif",
"sourcePoster": "docs/assets/feature-wall/parallel-worktrees.jpg"
"recordedAtUnixSeconds": 1788159085,
"recordedAtIso": "2026-08-31T06:51:25.000Z",
"sourceGif": "docs/site/public/docs/tab-split.gif",
"sourcePoster": "docs/site/public/docs/posters/tab-split.jpg"
}