Recording only — OBSERVATION class. ⛔ Not claimed, no assignee, no domain:*, no type. Found while implementing #11598 (converging the os init scaffold on the registry's NAME.TYPE.ts spelling). Dedup run at filing: two searches, no duplicate.
Nothing here is reported as broken. This records that a rationale several landed cards lean on is narrower than it reads, and that the load path it names has no measured consumer in this tree.
The rationale in question
packages/cli/src/utils/metadata-file-name.ts's docblock — the derivation #11071 built on, and quoted again in packages/cli/test/generate-file-name-registry-parity.test.ts:
MetadataPlugin._loadFromFileSystem primes every registered type by globbing that type's filePatterns, and that is the default (eager) bootstrap whenever no compiled artifact is configured. A scaffold whose name matches none of those patterns still type-checks, still passes os validate and still publishes, with nothing anywhere reporting that it was skipped — the silent-strip shape ADR-0063's retirement of os g agent closed (#10359).
Every clause of that is true for a project that boots eager with no artifact source. What it does not say is how many projects this repo scaffolds, ships or dogfoods actually boot that way.
What was measured
1. Three real scaffolds, compiled with the real os compile (tsx packages/cli/bin/run-dev.js compile), reading dist/objectstack.json back:
| scaffold | compile exit | objects in the artifact |
|---|
old spelling src/objects/my_app_item.ts (matches zero object patterns) | 0 | ["my_app_item"] |
same, plussrc/objects/probe.object.ts (matches the pattern) not re-exported from the barrel | 0 | ["my_app_item"] |
new spelling src/objects/my_app_item.object.ts | 0 | ["my_app_item"] |
Row 1: the pattern-matching-nothing file is loaded. Row 2 is the discriminator — a file spelled exactly the way the registry declares, in the same directory, is not loaded when the barrel does not name it. So for these projects the glob is not consulted at all; the barrel's module specifier is the whole load path.
2. Why, mechanically.packages/runtime/src/standalone-stack.ts hands MetadataPlugin an artifactSource: { mode: 'local-file', path: artifactPath }, which routes _bootstrap to _loadFromLocalFile and never to _loadFromFileSystem. Its own comment says so: "Source-file scanner OFF — declarative metadata is loaded from the compiled artifact, not from yaml/json files on disk."os dev and os serve both boot that way, and os init's generated package.json wires every script through them.
3. The population. Every objectstack.config.ts tracked in this repo declares its objects in code rather than leaving them to the glob:
$ for f in $(git ls-files '*objectstack.config.ts'); do
grep -q "import \* as objects\|from './src/objects" "$f" || echo "$f"
done
packages/drivers/driver-memory/objectstack.config.ts
packages/plugins/plugin-auth/objectstack.config.ts
packages/plugins/plugin-hono-server/objectstack.config.ts
packages/plugins/plugin-security/objectstack.config.ts
packages/services/service-i18n/objectstack.config.ts
— and each of those five declares objects: from a named import too (plugin-auth: objects: authIdentityObjects), or declares no objects at all. The barrel-importing majority (examples/app-crm, create-objectstack's blank starter, everything os init writes) is the same shape. Zero configs in this tree rely on filePatterns to find their metadata.
Why it is worth recording
Two things follow, neither of them a defect on its own:
What a picker-up might do (⛔ not a prescription — routing is triage's)
Options, roughly ascending in cost: amend the metadata-file-name.ts docblock to state the precondition (eager bootstrap, no artifact source) so the rationale stops reading as universal; or decide whether the eager glob path should have a dogfood at all, which is a scope question and probably the startup-focus answer is "no", in which case saying so beside the registry is the cheaper close.
Provenance
Measured on origin/main at c804f0ca5 while implementing #11598 (PR #12073) · the rationale quoted is from #11071 · #10359 is the silent-strip ruling both descend from.
Generated by Claude Code
Recording only — OBSERVATION class. ⛔ Not claimed, no assignee, no
domain:*, no type. Found while implementing #11598 (converging theos initscaffold on the registry'sNAME.TYPE.tsspelling). Dedup run at filing: two searches, no duplicate.Nothing here is reported as broken. This records that a rationale several landed cards lean on is narrower than it reads, and that the load path it names has no measured consumer in this tree.
The rationale in question
packages/cli/src/utils/metadata-file-name.ts's docblock — the derivation #11071 built on, and quoted again inpackages/cli/test/generate-file-name-registry-parity.test.ts:Every clause of that is true for a project that boots eager with no artifact source. What it does not say is how many projects this repo scaffolds, ships or dogfoods actually boot that way.
What was measured
1. Three real scaffolds, compiled with the real
os compile(tsx packages/cli/bin/run-dev.js compile), readingdist/objectstack.jsonback:compileexitsrc/objects/my_app_item.ts(matches zeroobjectpatterns)["my_app_item"]src/objects/probe.object.ts(matches the pattern) not re-exported from the barrel["my_app_item"]src/objects/my_app_item.object.ts["my_app_item"]Row 1: the pattern-matching-nothing file is loaded. Row 2 is the discriminator — a file spelled exactly the way the registry declares, in the same directory, is not loaded when the barrel does not name it. So for these projects the glob is not consulted at all; the barrel's module specifier is the whole load path.
2. Why, mechanically.
packages/runtime/src/standalone-stack.tshandsMetadataPluginanartifactSource: { mode: 'local-file', path: artifactPath }, which routes_bootstrapto_loadFromLocalFileand never to_loadFromFileSystem. Its own comment says so: "Source-file scanner OFF — declarative metadata is loaded from the compiled artifact, not from yaml/json files on disk."os devandos serveboth boot that way, andos init's generatedpackage.jsonwires every script through them.3. The population. Every
objectstack.config.tstracked in this repo declares its objects in code rather than leaving them to the glob:— and each of those five declares
objects:from a named import too (plugin-auth:objects: authIdentityObjects), or declares no objects at all. The barrel-importing majority (examples/app-crm,create-objectstack'sblankstarter, everythingos initwrites) is the same shape. Zero configs in this tree rely onfilePatternsto find their metadata.Why it is worth recording
Two things follow, neither of them a defect on its own:
os initscaffoldsNAME_item.tswhile the registry declares*.object.ts— after #11071 the same project gets both spellings #11598 was filed on the reading thatos initmight be generating a file the project never loads. It is not — row 1 above. The card's own "what is NOT established" section had flagged exactly this, and it was right. A future card that reasons "filename matches no pattern ⇒ silently skipped" from the docblock alone will over-claim the same way, because the docblock states the mechanism without stating its precondition.filePatternsis a declared surface with no dogfood. The registry declares**/*.object.ts(and 26 other types' patterns) as the discovery contract, and this repo exercises it nowhere end-to-end: no example, no scaffold, no starter boots through_loadFromFileSystem. Whether that path still works on a real project is not something anything in this tree measures. The convergenceos gwritesNAME.tsfor six generators while the type registry declaresNAME.TYPE.ts— #11025 closed it forskillalone #11071 andos initscaffoldsNAME_item.tswhile the registry declares*.object.ts— after #11071 the same project gets both spellings #11598 landed is still right on its own terms — one CLI teaching one spelling, and the examples and registry already agreeing on it — but it is a consistency property, not the discoverability property the docblock frames it as.What a picker-up might do (⛔ not a prescription — routing is triage's)
Options, roughly ascending in cost: amend the
metadata-file-name.tsdocblock to state the precondition (eagerbootstrap, no artifact source) so the rationale stops reading as universal; or decide whether the eager glob path should have a dogfood at all, which is a scope question and probably the startup-focus answer is "no", in which case saying so beside the registry is the cheaper close.Provenance
Measured on
origin/mainatc804f0ca5while implementing #11598 (PR #12073) · the rationale quoted is from #11071 · #10359 is the silent-strip ruling both descend from.Generated by Claude Code