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
fix(metadata-protocol,objectql): a boot that could not read `sys_metadata` says so at `error`, instead of reporting "no persisted metadata" at debug (#5897)
7
+
8
+
`loadMetaFromDb` — the boot step that hydrates `sys_metadata` overlay rows into
9
+
the SchemaRegistry — returned `{ loaded, errors, invalid }`, and no field in
10
+
that shape could express **"this hydration never read the store"**. An
11
+
unreachable database and a genuinely empty one both answered `loaded: 0`.
12
+
13
+
Its only production consumer, `ObjectQLPlugin.restoreMetadataFromDb`, therefore
14
+
had nothing to branch on: its single branch chose between two log lines, and
15
+
the "nothing came back" side was
16
+
`logger.debug('No persisted metadata found in database')`. So a kernel that
17
+
could not read a word of its persisted metadata stated at **debug** level that
18
+
there was none, and went on to report ready.
19
+
20
+
What that costs is not hypothetical — it is written into the plugin's own
21
+
Phase 2 comment. With the registry empty, `registry.getObject` answers "not
22
+
declared" where the truth is "we could not look": unknown-column query guards,
23
+
hooks and relationships silently degrade, and overlay objects get neither a
24
+
synced table nor a metadata bridge. This is ADR-0110 D3 (an outage is not a
25
+
miss) on the boot side, after the same rule landed for `DatabaseLoader`
26
+
(#5108), `listForIndex` (#5089) and the overlay reads (#5532 / #5707).
27
+
28
+
**What changed**
29
+
30
+
-`loadMetaFromDb` returns `storeUnavailable: boolean`, set on exactly the
31
+
branch that already prints `[Protocol] DB hydration skipped` — a read that
32
+
failed for a reason `isMissingTableError` does *not* call benign. A store
33
+
that has merely not been provisioned yet (first boot, before migrations)
34
+
keeps `storeUnavailable: false`, because `loaded: 0` genuinely is the truth
35
+
there (#5841).
36
+
-`restoreMetadataFromDb` reads it and logs at **`error`**, naming the
37
+
consequence (nothing was restored, the kernel keeps reporting healthy, and
38
+
which capabilities silently degrade) and the fix (check the datasource behind
39
+
`sys_metadata` — connection, credentials, table existence — then restart).
40
+
Per AGENTS.md "Degradation log levels": persisted state and runtime state
41
+
disagreeing while the system still looks healthy is the `error` class. An
42
+
empty-but-readable store keeps its quiet debug line, so first boots do not
43
+
start emitting durability errors.
44
+
45
+
**Not changed**: control flow. Boot still degrades and continues — refusing to
46
+
boot on an unreadable overlay store would turn a transient outage into an
47
+
outright one. What changes is that the degradation is now distinguishable from
48
+
health, and reported as such.
49
+
50
+
**Impact on duck-typed `ProtocolWithDbRestore` implementers**: none required.
51
+
`ObjectQLPlugin` matches the `protocol` service structurally, and the new field
52
+
is declared **optional** on its side of the contract, exactly as `invalid`
53
+
already is. A shim that predates the field keeps type-checking and is read as
54
+
"not an outage" — the only verdict it was able to express before — so its
55
+
behaviour is byte-for-byte what it was. The trade-off is deliberate and worth
56
+
naming: an optional field cannot *force* a third-party shim to start reporting
57
+
outages, so such a shim stays as silent as it is today. Requiring the field
58
+
would have made that impossible to ignore at the cost of breaking every
59
+
external implementer for a bit only one in-repo producer sets; the in-repo
60
+
producer (`ObjectStackProtocolImplementation`) declares and returns it
61
+
**required**, so the path that actually runs in every ObjectStack kernel is
0 commit comments