You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 31baf09
Browse filesBrowse the repository at this point in the historyBrowse files
docs(kernel): document the plural reads' failure posture on the metadata-service contract page (#16261)
`content/docs/kernel/contracts/metadata-service.mdx` documented the SINGULAR
read's failure posture (`### load / loadDiagnosed`: `load` collapses "no loader
has this item" and "every loader failed" into one `null`) and said nothing
about the plural reads'. `list` / `listNames` have two distinct outcomes and
the page distinguished neither:
- degrade — a loader that cannot be read is reported once and skipped, the read
resolves over the remaining loaders (`MetadataManager.readListUncached`,
`listNames`); `listDiagnosed` carries the `degraded`/`errors` verdict and
`listNames` has no diagnosed counterpart at all;
- refuse — `AmbiguousMetadataStemError` propagates out of both plural reads
(ADR-0112 envelope, `AMBIGUOUS_METADATA_STEM`, status 500, every colliding
path named).
Addition only: the singular passage is unchanged and the two postures now sit
side by side. `listDiagnosed?` is added to the page's interface listing because
the new prose names it.
Claude-Session: https://claude.ai/code/session_01Vbw3RPgdtqesx4azk9SbW8
Co-authored-by: Claude <noreply@anthropic.com>
The plural reads' failure posture. Both read a **set** through the same
138
+
registered loaders, and — unlike the singular reads above, which collapse every
139
+
fault into one `null` — they answer two different kinds of fault differently.
140
+
141
+
| condition | outcome |
142
+
|:---|:---|
143
+
| A loader cannot be read — a storage outage, an unreachable `sys_metadata`, any other throw |**Degrade** — that loader is reported once and skipped; the read resolves with what the reachable loaders hold |
144
+
| One metadata name is derived from more than one file — `twin.json` beside `twin.yaml` in one type directory |**Refuse** — `AmbiguousMetadataStemError` propagates out of both reads |
145
+
146
+
**Degrade** is the older of the two postures and the one nothing announces to
147
+
the caller: `list` and `listNames` still resolve, the caller still gets an
148
+
array, nothing 500s, and the set is quietly short. `listDiagnosed` is what
149
+
tells a short set apart from a complete one — it returns the same items plus
150
+
`degraded` and `errors`, and `degraded` is true when at least one loader could
151
+
not be read while the set was assembled. It says the set is **known-partial**,
152
+
never that it is empty and never that it is wrong: a reason to withhold a claim
153
+
of *completeness*, never a reason to withhold the items.
154
+
155
+
`listNames` has **no diagnosed counterpart**. A short name set is not
156
+
distinguishable by its caller at all — the lost loader is reported at `error`
157
+
in the server log and nowhere else.
158
+
159
+
**Refuse** is an authoring error rather than an outage, so it is deliberately
160
+
not absorbed by the degrade seam above. The filesystem loader derives a
161
+
metadata name by stripping the extension from a flat file's basename, so two
162
+
files under one type directory sharing a stem produce one name that is listed
163
+
twice while only one of them is reachable under that name. Instead of picking a
164
+
winner by extension precedence, the loader throws, and both plural reads
165
+
re-raise it. The error carries the ADR-0112 envelope — code
166
+
`AMBIGUOUS_METADATA_STEM`, status `500` (the request is well formed and no
167
+
caller can fix it by sending something else; only deleting or renaming a file
168
+
does), plus the metadata `type`, the `stem`, and **every** colliding path,
169
+
sorted — never just the precedence winner. Catch it with
170
+
`isAmbiguousMetadataStemError` from `@objectstack/metadata` wherever you need
171
+
to tell it apart from an outage.
172
+
173
+
<Callouttype="info">
174
+
Only stems the loader would actually resolve collide: the comparison is
175
+
case-sensitive, it covers just the extensions whose serializers are registered
176
+
(`.js` is not in the default set), and a nested file sharing a flat file's
177
+
basename is not a collision.
178
+
</Callout>
179
+
134
180
### register / unregister
135
181
136
182
`register` saves (creates or replaces) the full definition for a `(type, name)`.
0 commit comments