|
1 | 1 | # ADR-0076: objectql is the data engine — relocate metadata management (protocol) out of it; enforce the boundary; defer the engine repo-split |
2 | 2 |
|
3 | | -**Status**: Proposed (2026-06-28, rev. 9) — D1–D12 below. D9 step-1 (interface segmentation) shipped in #2429; OQ#7 resolved (keep `metadata-protocol` name). rev.9 adds **D12 (honest capabilities** — discovery must not report stub/fallback services as real; the analytics fallback + dev stubs are marked honestly, not deleted) and corrects the D10 analytics note (deliberate fallback + `replaceService`, not a collision). — v12 assessment. Verified 2026-07-16: D1 (metadata-protocol extraction + back-compat re-export), D2 (core-boundary ratchet test), D9-step1 (segmented protocol interfaces) confirmed in code; D3 capability/profile contract unbuilt; D12 framework side landed in #3028 (standardized `__serviceInfo` marker — OQ#11 — honored by BOTH discovery builders; `svcAvailable` no longer hardcodes `available`; analytics fallback reports `degraded`, `/realtime` no longer advertised) — the console-side consumer update ("trust only `handlerReady:true`") remains for the cross-repo window; D7/D10/D11-decomposition deferred as designed (OQ#9/OQ#10 resolved below, #3037). |
| 3 | +**Status**: Accepted — D1/D2/D4/D5/D6/D8/D9 implemented; D10/D11/D12 partially landed; D3 unbuilt; D7 deliberately deferred (proposed 2026-06-28, rev. 9 · calibrated 2026-08-05 by #5063). This ADR has been binding for some time — `AGENTS.md`, `packages/runtime/src/domains/*` (D11's own output), `packages/objectql`'s core boundary and ADR-0121 all cite it as a settled decision — while the header still read `Proposed`; per Prime Directive #13 an accepted decision binds until superseded, so the header is corrected here and, following #4919's calibration of ADR-0078, **per decision** rather than by a single flip. Verified against source (not against the rev.9 narrative), 2026-08-05: |
| 4 | + |
| 5 | +- **D1 — implemented, with OQ#2 unexecuted.** `packages/metadata-protocol/` owns `protocol.ts`, `sys-metadata-repository.ts` and `metadata-diagnostics.ts`; `packages/objectql` depends on it one-way (`packages/objectql/package.json`, `src/plugin.ts` imports `assembleMetadataProtocol`). **But `SysMetadataEngine` never moved to `@objectstack/metadata-core`** — it is still declared in `packages/metadata-protocol/src/sys-metadata-repository.ts` and `packages/metadata-core/src/` has no occurrence of the name. OQ#2 is therefore *unexecuted*, not resolved; the D1 bullet below states the intent, not the state. |
| 6 | +- **D2 — implemented.** `packages/objectql/src/core-boundary.ratchet.test.ts` walks the `core.ts` import closure and forbids `@objectstack/metadata-protocol` plus the local `plugin` / `kernel-factory` modules. |
| 7 | +- **D3 — unbuilt. The one decision here with no implementation at all.** No `profile: 'trusted' | 'internal'` exists in `packages/objectql/src`, `packages/core/src` or `packages/spec/src/kernel`; nothing derives required capabilities from object declarations; boot is **not** fail-closed — `packages/core/src/kernel.ts` only *warns* ("System started with degraded capabilities. Missing core services: …"). The `requiredCapabilities` / `provides` keys that do exist belong to the unrelated plugin-conformance schema `packages/spec/src/kernel/plugin-capability.zod.ts`, not to this decision. (Zero-hit counter-checked against live neighbours in the same search surface: `registerMiddleware`, `isServiceServeable`, `__serviceInfo` all match.) |
| 8 | +- **D4/D5/D6/D8 — ratifications, all still true.** `@objectstack/formula` remains an `objectql` dependency used by `engine.ts` / `hook-wrappers.ts` / `validation/rule-validator.ts` (D4). `@objectstack/spec` carries only `zod` as a runtime dependency, and `examples/embed-objectql/` boots `@objectstack/objectql/core` against an ordinary `ObjectSchema.create` object — the same definition shape a full backend ships (D5, and Phasing P4). `engine.ts`'s `registerMiddleware` is the attachment point `plugin-security` and `plugin-sharing` actually use (D6), and the engine still hard-codes no governance (D8) — the D2 ratchet is what keeps it that way. |
| 9 | +- **D9 — implemented, past step-1, at its own rev.7 end-state.** `packages/spec/src/api/protocol.zod.ts` declares ten per-domain contracts (`DataProtocol`, `MetadataProtocol`, `AnalyticsProtocol`, `AutomationProtocol`, `PackageProtocol`, `ViewProtocol`, `PermissionProtocol`, `RealtimeProtocol`, `NotificationProtocol`, `I18nProtocol`), and **no `ObjectStackProtocol` union type is declared or exported anywhere in the repo** — the transitional composed alias is *dissolved*, not merely deprecated. Consumers are narrowing accordingly: `packages/rest/src/rest-server.ts` types its dependency as `RestProtocol = DataProtocol & MetadataProtocol`. |
| 10 | +- **D10 — partially implemented.** Landed: the feed domain and then the analytics fallback left the facade (analytics now has exactly one implementation, in `service-analytics`), and OQ#7 resolved to keep the package name. Outstanding: the central facade class this decision rules out **still exists** — `packages/metadata-protocol/src/protocol.ts` declares `class ObjectStackProtocolImplementation implements DataProtocol, MetadataProtocol, PackageProtocol` — so the `DataProtocol` implementation has not moved to the engine-adjacent/transport layer and **OQ#6 remains open**. |
| 11 | +- **D11 — substantially implemented; the rest-server half is untouched.** The dispatcher decomposed exactly as OQ#9's verdict describes: every domain body lives in `packages/runtime/src/domains/*`, routing goes through `packages/runtime/src/domain-handler-registry.ts`'s `DomainHandlerRegistry`, and `http-dispatcher.ts` is down to ~1.7k LOC from the ~3.8k recorded below. Multi-adapter is validated (OQ#10) by `packages/qa/http-conformance`. **Not** decomposed: the *second* central route generator this decision names — `packages/rest/src/rest-server.ts` — is now ~7.7k LOC, i.e. larger than the ~5.1k figure below, not smaller. |
| 12 | +- **D12 — framework side implemented; console side cross-repo and unverified from here.** `packages/spec/src/api/discovery.zod.ts` carries the `unavailable` / `degraded` / `stub` statuses plus `ServiceSelfInfoSchema` + `readServiceSelfInfo`; `svcAvailable` in `packages/runtime/src/http-dispatcher.ts` derives `status`/`handlerReady` from that marker for every slot (no hardcodes left); `packages/runtime/src/service-serveable.ts`'s `isServiceServeable` is the single predicate the dispatcher-owned domains, the route-mount gate and discovery all read. The consumer half ("trust only `handlerReady: true`") lives in cloud/objectui and cannot be confirmed from this repo. |
| 13 | +- **D7 — deferred as designed, and now instrumented.** `packages/objectql` is still in the monorepo. New since rev.9: `scripts/check-engine-split-ratio.mjs` and `.github/workflows/engine-split-metric.yml` compute and report the cross-package commit ratio that gates the split; it is deliberately **report-only** because the threshold itself is still OQ#5. |
| 14 | + |
| 15 | +This supersedes the 2026-07-16 verification note, which predates D9's dissolution of the union, D11's decomposition and D12's later passes. |
4 | 16 | **Deciders**: ObjectStack Protocol Architects |
5 | 17 | **Builds on**: [ADR-0005](./0005-metadata-customization-overlay.md) (sys_metadata overlay substrate), [ADR-0025](./0025-plugin-package-distribution.md) (plugin package distribution), [ADR-0033](./0033-ai-assisted-metadata-authoring.md) (open-core boundary), [ADR-0048](./0048-cross-package-metadata-collision.md) (package id is the addressing unit), [ADR-0066](./0066-unified-authorization-model.md) (secure-by-default, posture-gated bypass) |
6 | 18 | **Consumers**: **new** `@objectstack/metadata-protocol` (receives `protocol` + `sys-metadata-repository` + `metadata-diagnostics`), `@objectstack/objectql` (loses protocol → becomes a lean data engine; keeps a back-compat re-export), `@objectstack/metadata-core` (gains the `SysMetadataEngine` interface), `@objectstack/plugin-security`, `@objectstack/plugin-sharing`, `@objectstack/spec`, and out-of-tree embedders — notably `../objectbase` (its `gateway`). |
@@ -94,7 +106,7 @@ Decision — split the interface into focused contracts: |
94 | 106 | - **`DataProtocol`** — `findData/getData/createData/updateData/deleteData` (+ batch): thin wire-normalizers over the engine. |
95 | 107 | - **`MetadataProtocol`** — metadata read/write, draft/publish, locks (ADR-0010), commits (ADR-0067), package ownership (ADR-0048), `loadMetaFromDb`: the heavy control plane (the true content of `@objectstack/metadata-protocol`). |
96 | 108 | - **Optional capability protocols** — `AnalyticsProtocol` / `FeedProtocol` / `RealtimeProtocol` / `NotificationProtocol` / `ViewProtocol` / …, each owned by its existing service and independently optional/versionable. |
97 | | -- **Back-compat** — keep `ObjectStackProtocol = DataProtocol & MetadataProtocol & Partial<…>` as a composed alias so current callers/types keep working. |
| 109 | +- **Back-compat** — keep `ObjectStackProtocol = DataProtocol & MetadataProtocol & Partial<…>` as a composed alias so current callers/types keep working. *(Status 2026-08-05 (#5063): the alias is **gone**, not merely deprecated — no `ObjectStackProtocol` type is declared or exported anywhere in `packages/`, only prose references to the historical name remain. The rev.7 refinement immediately below is therefore the state, not the plan; consumers already depend on the narrow slices, e.g. `rest-server.ts`'s `RestProtocol = DataProtocol & MetadataProtocol`.)* |
98 | 110 |
|
99 | 111 | The segmentation is **spec/type-level and may start incrementally now** (define sub-interfaces; narrow consumers over time). The implementation restructure + the `@objectstack/metadata-protocol` rename are breaking and ride the **same cross-repo window as D7 / Step 2**. |
100 | 112 |
|
|
0 commit comments