Skip to content

fix(docs-audit): derive package roots from the filesystem, not a special-cased regex - #4206

Merged
os-zhuang merged 1 commit into
mainfrom
claude/docs-drift-mapper-nesting-bug-v56kpb
Jul 30, 2026
Merged

fix(docs-audit): derive package roots from the filesystem, not a special-cased regex#4206
os-zhuang merged 1 commit into
mainfrom
claude/docs-drift-mapper-nesting-bug-v56kpb

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes #4162.

Problem

affected-docs.mjs derived changed-package roots with a regex that special-cased only packages/plugins/*. The 30 packages nested under the other six container directories (services/, connectors/, apps/, qa/, triggers/, adapters/) collapsed into their container, whose missing package.json left name = null — so the npm-name matching arm never fired for them. Any doc that names @objectstack/service-automation but never the repo path was a guaranteed miss (content/docs/automation/flows.mdx is one), the exact direction the tool promises to avoid ("over-inclusion is preferred over misses").

Fix

  • Package root = deepest ancestor directory with a package.json, resolved from the filesystem. No hardcoded container list replaces the special case — a list would silently fail again on container dir number eight (排查「手抄 spec 清单 + "keep in sync" 注释」模式:一天内确认三例,全部曾静默漂移 #3786's pattern). A deleted package falls back to the coarse packages/<x> token so path matching still works.
  • Second arm, from the issue thread: <packageRoot>/scripts/** is build/verification tooling and no longer counts as an implementation change (feat(spec): check:generated — report every stale artifact in one run #4183 flagged 106 docs for a diff whose only code change was a new check script). Kept deliberately narrow: package.json and src/scripts/** stay counted. Publication check done — no package's files allowlist ships scripts/; three plugins ship a lone i18n-extract.config.ts only for lack of a files field (tooling, not runtime).
  • --self-test now pins the derivation and both classifiers (32 hermetic cases via an injected fake tree), closing the guard-of-the-guard hole — the original self-test pinned only isTestFile. Includes the issue's two invariants: a container directory must never come out as a package root; packages/x/package.json is implementation while packages/x/scripts/y.ts is not.
  • Exclusions stay non-silent: summary line notes + scriptFilesSkipped alongside testFilesSkipped in --json.

Verified against real history

scenario old new
#4161's commit (service-automation + spec) attributed to the directory name packages/services attributed to @objectstack/service-automation; flows.mdx now hits via the right package
synthetic service-automation-only change 6 docs, all about other services (via the packages/services path token), flows.mdx absent the 4 right docs, flows.mdx included
#4183's commit (check script + package.json registration) 106 docs 106 docs (the package.json change keeps packages/spec counted, by design) + explicit "1 tooling script(s) excluded" note
scripts-only change 106 docs 0 docs, exclusion reported

node scripts/docs-audit/affected-docs.mjs --self-test → 32 cases pass; the drift workflow already runs it before computing the mapping.

🤖 Generated with Claude Code

https://claude.ai/code/session_01J2x8Tie9WT1VgWFifqMKrR


Generated by Claude Code

…ial-cased regex (#4162)

The drift mapper special-cased only `packages/plugins/*`, so the 30
packages nested under the other six container dirs collapsed into their
container — whose missing package.json killed the npm-name matching arm.
A doc naming `@objectstack/service-automation` but never the repo path
was a guaranteed miss (`automation/flows.mdx` on a service-automation-
only change). The root is now the deepest ancestor with a package.json,
with no hardcoded container list to drift out of sync.

Also from the issue thread: `<packageRoot>/scripts/**` is build tooling,
not documented behaviour, and no longer counts as an implementation
change (#4183); `package.json` and `src/scripts/**` stay counted. Both
the derivation and the classifiers are now pinned by `--self-test`.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J2x8Tie9WT1VgWFifqMKrR
@vercel

vercel Bot commented Jul 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Jul 30, 2026 3:17pm

Request Review

@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation ci/cd tooling labels Jul 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

No hand-written docs reference the 0 changed package(s). ✅

@os-zhuang
os-zhuang marked this pull request as ready for review July 30, 2026 15:22
@os-zhuang
os-zhuang merged commit 64489f8 into main Jul 30, 2026
16 checks passed
@os-zhuang
os-zhuang deleted the claude/docs-drift-mapper-nesting-bug-v56kpb branch July 30, 2026 15:22
os-zhuang added a commit that referenced this pull request Jul 31, 2026
…never got (#4219)

The drift comment on #4161 was computed by the mapper bug #4206 fixed: the
service-automation change collapsed to `packages/services`, so these four
docs were attributed to the wrong package — and a service-automation-only
diff would have reported none of them. Re-derived with the fixed mapper and
audited against the implementation.

flows.mdx carries the #4161 axis itself: a `runAs:'user'` run that resolved
no trigger user has its data operations refused. Also documents `node.type`
as an open string checked against the live registry (ADR-0018), the script
executor as naming a callable with logger-backed `email`/`slack` markers,
the `.strict()` shells, and six previously undocumented node keys.

implementation-status.mdx gains the real `/api/v1` route prefixes, the
memory driver's actual `InMemoryDriver.supports` matrix, and the ADR-0090 D3
`Role` -> `Position` rename — which ratchets the role-word baseline down by
one, so that gate-mandated update ships here too.

Gates: docs build, check:doc-authoring, check:role-word, check:nul-bytes,
check:release-notes, check:skill-examples (198 prose examples).


Claude-Session: https://claude.ai/code/session_01J2x8Tie9WT1VgWFifqMKrR

Co-authored-by: Claude <noreply@anthropic.com>
os-zhuang added a commit that referenced this pull request Jul 31, 2026
#4248) (#4262)

20 of the 49 publishable packages declared no `files` field, so npm fell back
to packing the whole package directory. `npm pack --dry-run` on
@objectstack/plugin-webhooks listed 21 files -- 15 under src/, three of them
unit tests, plus the build-time scripts/i18n-extract.config.ts. dist/ lands on
top of that at publish time rather than instead of it.

Each now declares ["dist", "README.md"], matching the 29 packages that already
did. Nothing a consumer imports moves: every main / types / exports target in
all 20 already resolved inside dist/.

The other half is the gate. check:published-files (wired into the
always-required lint job) holds every non-private workspace package to four
invariants: DECLARED, SUFFICIENT (covers every entry point, so tightening a
whitelist cannot ship a package that fails to resolve), MINIMAL (admits no
test, test-harness config or build script), and REGISTERED (anything beyond
dist + README.md carries a reason, reconciled in both directions).

MINIMAL also closes an assumption #4206 rested on: that no package publishes
scripts/ as runtime code held, but it held by hand-checking three packages.
It is now checked on every PR.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd documentation Improvements or additions to documentation size/m tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

docs-drift mapper 把 30 个嵌套包全部塌成父目录:只特判了 plugins,导致真实漏报(automation/flows.mdx 就是其中一个)

2 participants