Skip to content

docs(cli): state the precondition the filePatterns glob-discovery rationale carries - #12168

Merged
os-trump merged 2 commits into
mainfrom
claude/issue-12075-filepatterns-precondition
Aug 25, 2026
Merged

docs(cli): state the precondition the filePatterns glob-discovery rationale carries#12168
os-trump merged 2 commits into
mainfrom
claude/issue-12075-filepatterns-precondition

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Fixes #12075

Prose only. metadata-file-name.ts's docblock stated the glob-discovery mechanism without its precondition, so the rationale several landed cards lean on read as a universal property of the platform. It now states the precondition, and the finding's second question gets its recorded disposition.

What the docblock claimed, and what it claims now

The old paragraph derived the generated filename from the registry's filePatterns and justified it with MetadataPlugin._loadFromFileSystem globbing every registered type "whenever no compiled artifact is configured". Every clause was true; the missing half was how many projects this repo scaffolds, ships or dogfoods actually boot that way.

Re-measured on origin/main at a11c1a57d — not inherited from the card

The card was measured at c804f0ca5. Everything below was re-derived from scratch; three figures came back sharper than the card's, and one correction is noted under the ownership fence.

1. The branch condition. MetadataPlugin.start (packages/metadata/src/plugin.ts:340-396) reaches _loadFromFileSystem on exactly one arm: bootstrap is eager (the default, this.options.config?.bootstrap ?? 'eager') and options.artifactSource is unset. An artifact source routes eager to _loadFromLocalFile; lazy and artifact-only never glob at all. _loadFromFileSystem (line 836) then calls manager.loadMany(entry.type, { patterns: entry.filePatterns }) per registry row, so the mechanism itself is exactly as described.

2. Nothing in this repo takes that arm — stronger than the card, which measured only standalone-stack.ts. There are exactly two non-test new MetadataPlugin(...) sites in the tree, and both pass an artifact source:

site argument
packages/runtime/src/standalone-stack.ts:712 artifactSource: { mode: 'local-file', path: artifactPath }
packages/cli/src/commands/serve.ts:2332 (dev HMR) artifactSource: { mode: 'local-file', path: hmrArtifactPath }

os dev compiles and spawns serve; os serve and os start boot from the compiled artifact; os init writes dev: 'objectstack dev', start: 'objectstack compile && objectstack serve', build: 'objectstack compile', validate: 'objectstack validate'.

3. The population. All nine tracked objectstack.config.ts files declare their metadata in code — a barrel (import * as objects from './src/objects') or a named import (objects: authIdentityObjects) — or declare no objects at all. Zero rely on filePatterns. No config sets bootstrap or artifactSource either.

4. The discriminator, re-derived statically rather than by re-running the card's three compiles: packages/cli/src/commands/compile.ts builds dist/objectstack.json from loadConfig and nothing else — the file contains no glob, no readdir, no filePatterns reference. So a *.object.ts in the scaffold's own object directory does not reach the artifact when the barrel omits it, while a file matching no pattern does as soon as the barrel names it. Independent corroboration in the tree: packages/cli/test/init-scaffold-file-name-registry-parity.test.ts (#11598) already records the same end-to-end measurement.

The bounce clause did not trigger. Nothing measured the eager path as broken — only as unreachable from anything this repo boots. _loadFromFileSystem is intact and internally consistent; it has no caller here. The loader was not touched.

The ownership fence — where the third sentence went, and why

Triage asked for the no-dogfood disposition "beside the registry's filePatterns declaration". Measured, that declaration is in packages/spec, not in packages/metadata*:

  • packages/spec/src/kernel/metadata-plugin.zod.ts:220 declares the field; lines 666-1122 declare the values in DEFAULT_METADATA_TYPE_REGISTRY.
  • packages/metadata/src/metadata-manager.ts:2486 and packages/metadata-protocol/src/protocol.ts:11343 read entry.filePatterns; neither declares it.

packages/spec is read-only for this card, so the sentence was written on the CLI's own read of filePatterns instead — a new "Why filePatterns gets no end-to-end dogfood" section in metadata-file-name.ts, naming the spec-side location it is not being written at. The half deliberately not written is filed unlabelled as #12165. Triage's instruction was neither dropped nor executed on another lane's file.

Verification

Verified at 8ddfb855, the final commit on this branch.

  • pnpm --filter @objectstack/spec build — exit 0. Measured as the parity test's only workspace dependency: metadata-file-name.ts imports @objectstack/spec/kernel; generate.ts imports @oclif/core, chalk and two relative modules whose only workspace import is @objectstack/spec.
  • pnpm --filter @objectstack/cli exec vitest run --maxWorkers=2 test/generate-file-name-registry-parity.test.ts — exit 0, 37 passed (37), 1 file.
  • pnpm lintfull repo, not narrowed (eslint . --no-inline-config): exit 0, no findings.
  • Eleven build-free gates from node scripts/pm/dispatch-gates.mjs, each exit code captured before any pipe, all exit 0: check:nul-bytes (OK (scanned 6734 text file(s) ... no raw ASCII control bytes)), check:cli-test-child-env, check:published-files, check:slot-lookup (baseline key set verified against a11c1a5: no files added), check:test-source-alias, check:type-check-coverage, check:type-source-resolution, check:query-options-erasure, check:engine-double-contract, check:cross-package-test-inputs (OK: 16 package(s) read outside themselves, all declared), check:where-matcher.

No red-before state was manufactured: the change is prose, and the parity test asserts a property this PR does not move.

Declared narrowing: pnpm --filter @objectstack/cli typecheck was not run

It needs the 56-package dependency closure built. The shared verify lock returned queue-timeout (exit 99 — nothing ran) on five attempts totalling 21 minutes of queue wait, so that build was not spent. The narrowing is measured rather than asserted — a scan of both files' non-trivia token streams at a11c1a57d vs 8ddfb855 (comments are trivia and never become nodes tsc checks), aligned-diffed:

  • packages/cli/src/utils/metadata-file-name.ts — 149 → 149 tokens, 0 differing tokens. Entirely comment trivia; tsc --noEmit cannot observe it.
  • packages/cli/test/generate-file-name-registry-parity.test.ts — 261 → 263 tokens; the whole difference is three string-literal texts, two of them split into 'a' + 'b' (hence the added PlusToken and the +2 count). No identifier, type, signature, import or control-flow token moved.

Both changed messages sit in expect(value, message) argument position and are evaluated eagerly on every assertion, so all three ran in the green 37/37. Every changed byte was additionally parsed by the ESLint TypeScript parser in the full-repo run above. CI runs the real typecheck on the real closure.

check:type-check-debt --re-measure is likewise CI's — it refuses outright on an unbuilt worktree, and that refusal means not measured, never not applicable.

Changeset

skip-changeset. The diff is comment text plus three assertion-message strings; it publishes nothing and changes no behaviour, no public surface and no schema. The token measurement above is the evidence that there is nothing to release.

Out-of-scope findings (unlabelled, unassigned, deduped, back-linked)

Within the two files this card owns, two assertion messages that restated the same over-claim were corrected alongside the docblock (nothing globs it, so whatever it writes is invisible to the loader, and it would validate, publish and never load). They are the only code-adjacent text in these files that asserted the unqualified form.

Environment note

The container's REST channel for GitHub was unavailable from this seat (GITHUB_TOKEN is the literal string proxy-injected; gh is not installed; a GET /repos/.../issues returns "GitHub access is not enabled for this session"). Dedupe searching and the label write therefore went through the MCP GitHub tools rather than the prescribed additive POST .../labels curl.


Generated by Claude Code

…ionale carries

`metadata-file-name.ts`'s docblock derived the generated filename from the
registry's `filePatterns` and justified it with `MetadataPlugin._loadFromFileSystem`
globbing every registered type. Every clause was true, but the precondition was
missing, so the rationale read as a universal property of the platform.

Re-measured on origin/main: `_loadFromFileSystem` is reached on exactly one
branch — `bootstrap: 'eager'` (the default) AND no `artifactSource` — and both
non-test `new MetadataPlugin(...)` sites in this repo configure an
`artifactSource: { mode: 'local-file' }`, so nothing this repo boots takes it.
All nine tracked `objectstack.config.ts` files declare their metadata in code or
declare none; `os compile` builds the artifact from `loadConfig` alone and globs
nothing. The derivation still stands, as a consistency property rather than the
discoverability property the old wording framed.

Also records the disposition on the second question the finding raised: no
end-to-end dogfood is minted for the eager path. Stated on the CLI's own read of
`filePatterns` rather than beside the registry declaration, which lives in
`packages/spec` and is not this package's to annotate.

Comment-only: no behaviour, no public surface, no schema.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HbG3rGVLjZStHQxHDtzJdJ
@github-actions

github-actions Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️ 1 changed file(s) yielded no anchor (packages/cli/src/utils/metadata-file-name.ts), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/cli/src/utils/metadata-file-name.ts) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 23 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 2c4c59ed20caf4f6cde3c979ae9205ee69e04256packageMentionDocs.

@github-actions github-actions Bot added the tests label Aug 25, 2026
@os-trump
os-trump marked this pull request as ready for review August 25, 2026 14:57
@os-trump
os-trump added this pull request to the merge queue Aug 25, 2026
Merged via the queue into main with commit 419cd8f Aug 25, 2026
34 checks passed
@os-trump
os-trump deleted the claude/issue-12075-filepatterns-precondition branch August 25, 2026 15:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate tests

Projects

None yet

2 participants