Uh oh!
There was an error while loading. Please reload this page.
fix(devx): assert that a published README's repo-relative targets exist - #10892
Conversation
…st (#10813) `check:published-readme-links` read the docs-site URLs a published README carries and said nothing about its repo-relative paths. `packages/runtime/README.md` linked six targets that are not in the tree, and a census across the whole published population found nine, in four packages. Nothing read them: the assertions above this one read ABSOLUTE urls, `check:published-readme-exports` reads fenced import lines, and the lychee lane never sees `packages/**/README.md`. Adds assertion 5 — a repo-relative destination must name something in the tree — to the existing gate rather than a second script, so it reuses that gate's population, extractor and classifier bucket. The gate's own header had already named this omission ("a different claim, owned by nothing here yet"). Deliberately only the decidable half. Whether a relative href means anything to a reader on npmjs.com is a separate question: npm renders the README outside the repo, so EVERY relative link is unresolvable there, including the 101 that are correct in-tree. Failing them all would be a ruling on link rewriting, not a scan, and this repo's published READMEs lean on the relative form throughout. Assertion 5 says GITHUB in its message for that reason. Vacuity is refused at the population level, never the document level: 18 of the 60 published documents carry no relative link at all, so per-document silence proves nothing. `run()` throws when the whole scan classifies nothing relative, the same way it already throws on zero links, and the green line prints the resolved count so a classifier that stopped recognising the bucket shows up as a number that fell. The six runtime targets were each traced to where the content went rather than deleted: the three MINI_KERNEL_*.md docs were removed from the repo root in January (d709ecc, 5051 deletions, nothing added) and the kernel reference is the docs site now; `examples/host/` became app-host, then apps/server, then apps/objectos, then moved to objectstack-ai/cloud; `examples/msw-react-crud/` became app-react-crud, then apps/console, and ships as `@object-ui/console`; `test-mini-kernel.ts` was a root scratch script whose successor is this package's own 179-file suite under `src/` — which is what the truncated bullet with the unterminated backtick was reaching for. The other three packages: `../../plugins/driver-sql` is stale since the driver moved to `packages/drivers/` (#5618); `plugin-org-scoping`, `service-tenant` and `service-marketplace` are in no directory of this repo, so those links are dropped and the names kept as code spans — the spelling those same files already use for a package they cannot point at in-tree. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DdCnBGcHeufjrq7drTD3wt
📓 Docs Drift CheckNothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 4 changed package(s)), so this run has no opinion about the docs. What this run could not see
Coarse fallback — 34 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
Uh oh!
There was an error while loading. Please reload this page.
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 32502313796 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
Fixes#10813
Verified at
cc222637a3— the gate union below was run on that exact commit.What was wrong
check:published-readme-linksread the docs-site URLs a published README carries and said nothing about its repo-relative paths.packages/runtime/README.mdlinked six targets that are not in the tree; a census across the whole published population found nine, in four packages.Nothing read them, and that is structural rather than accidental: assertions 1–4 of that gate read absolute URLs,
check:published-readme-exportsreads fenced import lines, and the lychee lane (check-links.yml) never seespackages/**/README.md. A relative href could name anything and ship to npm green.Assertion 5, in the existing gate rather than a second script
It reuses that gate's population (
publishedDocs), its extractor (extractLinks, all three link shapes) and itsrelativeclassifier bucket — which the gate already counted and labelled "not this gate's business". The gate's own header had named the omission: "whether a relative link resolves — that is a different claim, owned by nothing here yet." A second script would have grown a second population and a second extractor, which is exactly what that file argues against elsewhere.resolveRelativeTarget()strips the fragment and query, percent-decodes, and resolves against the document's own directory — the base GitHub uses to render a relative href in a blob. Four outcomes, not two:ok,missing,escapes(a climb above the repo root, kept separate because the remedy differs — an off-by-one in the../count, not a target that moved), andempty.The half this deliberately does not decide
Whether a relative href means anything to a reader on npmjs.com is a different question. npm renders the README outside the repo, so every relative link is unresolvable there — including the 101 that are perfectly correct in-tree, and this repo's published READMEs lean on the relative form throughout (
[`@objectstack/spec`](../spec)). Failing them all would be a ruling on link rewriting, not a scan. So assertion 5 says GITHUB in its message, and a self-test pin asserts that a correct relative link passes — so a later reader of the header cannot mistake the fence for a hole.Vacuity is refused at the population level, never the document level
18 of the 60 published documents carry no relative destination at all, so on nearly a third of the population this assertion is vacuous by construction — and per-document silence therefore proves nothing.
run()now throws when the whole scan classifies nothing relative, the same way it already throws on zero links (#4690). The green line prints the resolved count, so a classifier that quietly stopped recognising the bucket surfaces as a number that fell rather than as continued silence:Two ablations, each with the prediction stated before the run
1. Do the repairs actually close findings? Reverted all four READMEs to
origin/main, assertion 5 in place. Predicted: exactly 9dead-relative-target, 0escapes-repo, at nine named file:line pairs, and not on the three backticked bullets. Observed:✗ check:published-readme-links — 9 finding(s), all nine kindsdead-relative-target, at exactly those nine file:line pairs, and zero mentions of the code-span bullets. Mutation and restore each proven on disk by grep (MINI_KERNEL_GUIDE1→0,examples/app-showcase0→1, truncated bullet 1→0) rather than by an editor exit code.2. Are the new self-test pins load-bearing? Deleted assertion 5's branch from
checkDocument(if (kind === 'relative') continue;). Predicted: 12 failures — every pin readingfindingsorrelative-resolved, while the strip / discrimination / out-of-scope / vacuity pins stay correctly green. Observed:✗ check:published-readme-links --self-test — 12 failure(s), matching the predicted set pin for pin. Restored and re-proven on disk.One pin was rewritten mid-task for exactly this reason:
A5 SILENT on a ./ targetwas first written asfindings.length === 0 || stats.relative === 1, whose left branch is true for a resolver that does nothing. It is now two limbs against a package that really has asrc/.The six runtime targets — traced, not deleted
MINI_KERNEL_GUIDE.md,..._ARCHITECTURE.md,..._IMPLEMENTATION.mdd709ecce68, "Remove redundant markdown files" — 14 files, 5051 deletions, nothing added). The kernel reference is the docs site now, so the section is the same footer eight sibling READMEs already use.examples/host/examples/app-host→apps/server→apps/objectos→ split toobjectstack-ai/cloud(#1259). In-repo, an HTTP server in front of the runtime is@objectstack/plugin-hono-server+ the@objectstack/honoadapter.examples/msw-react-crud/examples/app-react-crud→apps/console→ ships as@object-ui/consolefrom another repo.test-mini-kernel.tstest-mini-kernel.js/.ts, added and removed in early prototyping). Its successor is this package's own suite — 179src/**/*.test.ts.The truncated bullet
- `packages/runtime/src/(unterminated backtick) was reaching for exactly that last successor; it is now a real pointer to it.The other three packages — file surface beyond the card, named here with its evidence
A gate cannot land red and this one refuses a baseline by design, so the six sibling findings had to be repaired for assertion 5 to ship. All four are published packages whose README is in the tarball, hence the changeset.
../../plugins/driver-sql×3 (adapters/hono,services/service-package×2) →../../drivers/driver-sql. Mechanical and pinned: the driver moved topackages/drivers/in feat(drivers): driver-turso 迁回本仓公开发布,五个 IDataDriver 统一收进 packages/drivers/ (#4645 Phase A) #5618 (06ba036270).plugin-org-scoping,service-tenant,service-marketplace(plugins/plugin-security×2,services/service-package×1) — in no directory of this repo. Link dropped, name kept as a code span: the prose claim is unchanged, only the pointer that resolves nowhere goes, and that is the spelling those same files already use for a package they cannot point at in-tree (@objectstack/driver-memory,@objectstack/driver-turso). Whether those three packages exist at all is the member-existence class (Five more published service READMEs document a.configure()entry point and classes that exist nowhere in the repo — the same defect class as #9517, unfixed by it #9532 / Hand-audit packages/runtime/README.md's 47 unread call sites — the one surface where a per-document read is priced to pay #10368), not this one — filed separately.Gates
All 19 run at
cc222637a3, exit codes captured before any pipe. 16 derived bynode scripts/pm/dispatch-gates.mjs(no path list passed — it takes its own change set from the merge base) +check:i18n(convention-triggered by theplugin-securityedit) +check:nul-bytes+check:published-readme-exports(the sibling gate in this family).Two needed a build before they said anything true, which is why they are reported here rather than skipped:
check:i18nfirst printedPREREQUISITE NOT MET — the workspace CLI is not built … Nothing was checked, andcheck:published-readme-exportsprinted 40+Build firstlines. After building, both are real verdicts:✓ check:published-readme-links — 173 outbound link(s) … 101/101 relative target(s) found in the tree.✓ check:published-readme-links --self-test — … all five assertions observed both FAILING and SILENTcheck-i18n-bundles: OK (9 package(s) — all bundles in sync, no undeclared authoring keys)— incl.plugins/plugin-security in sync (4 bundle(s))✓ check:published-readme-exports — 60 published document(s) across 77 workspace package(s); 214 import statement(s)✓ check-nul-bytes --self-test: 75 assertions over a temp git repo (real scan() path)✓ check-entry-guard self-test: 52 cases pass·✓ check:parse-guard self-test: 46 cases pass✓ slot-lookup ratchet holds: 107 unswept site(s) in 25 file(s), none new✓ No empty-frontmatter changeset introduced by this diff (1 declaring changeset(s) added).·✓ This diff introduces no major bump.OK: all 82 declared cross-package glob(s) …·OK: 13 package(s) read outside themselves, all declared✓ check:plugin-teardown-shape: 57 Plugin implementation(s) across 4407 source(s)·✓ affected-docs self-test: 323 cases pass.·✓ objectui-changeset-digest·✓ check-adr-0087-registration·check-test-source-alias --self-test OK·check-type-source-resolution --self-test OKConsole Pin Gateis red onmainfor an unrelated cross-repo reason (#10856) — non-blocking, not from this branch.Generated by Claude Code