From 8e4edff643e4a1c46ce4c92cf5ca0dffd92c0da3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 18 Jul 2026 14:41:27 +0000 Subject: [PATCH] chore: version packages --- .../adr-0097-openapi-upstream-classify.md | 20 - .changeset/analytics-drill-raw-totals.md | 7 - .changeset/annotate-schema-only-enums.md | 16 - .../approver-type-org-membership-level.md | 44 --- .changeset/automation-schema-resolver-e2e.md | 13 - .../betterauth-adapter-system-writes.md | 27 -- .changeset/bulk-update-validation-rules.md | 6 - .changeset/bulk-write-hardening.md | 31 -- .changeset/cli-strip-arg-separator.md | 30 -- .changeset/collapse-hook-event-taxonomy.md | 13 - .changeset/date-equality-runtime-fix.md | 40 -- .changeset/date-field-equality-guardrail.md | 41 -- .changeset/dev-loop-dx-p2.md | 13 - ...cument-validation-governance-crossfield.md | 10 - ...ow-registration-schema-aware-validation.md | 26 -- .changeset/flow-trigger-observability.md | 20 - .../i18n-inline-label-default-locale.md | 24 -- .changeset/lint-hide-platform-baseline.md | 5 - .changeset/logger-esm-file-destination.md | 7 - .changeset/logger-honors-no-color.md | 15 - .changeset/mcp-validate-expression-tool.md | 28 -- .../metadata-register-notifies-watchers.md | 15 - .changeset/ownership-record-model-field.md | 27 -- .changeset/perf-timing-admin-detail.md | 29 -- .changeset/perf-timing-per-request-gating.md | 29 -- .changeset/publish-drafts-org-scope.md | 11 - .changeset/readonly-static-insert-strip.md | 49 --- .changeset/remove-dead-metadata-props-2377.md | 55 --- .../remove-form-surfaced-dead-props-2377.md | 47 --- .changeset/retire-feed-contracts.md | 53 --- .changeset/retire-feed-discovery-surface.md | 25 -- .../scaffold-default-connector-executors.md | 28 -- .../scaffold-gitignore-survives-publish.md | 13 - .changeset/scaffold-pnpm11-build-approvals.md | 35 -- .changeset/scaffold-skill-catalog-boundary.md | 5 - .changeset/seed-replay-lookup-corruption.md | 22 -- .changeset/seed-replayer-skipped.md | 19 - .changeset/server-timing-perf-spans-2408.md | 19 - .changeset/state-machine-initial-states.md | 20 - .changeset/systemfields-drop-owner-key.md | 18 - .changeset/tidy-views-guard.md | 7 - .changeset/tier4-type-soundness-warnings.md | 36 -- .changeset/trim-validation-delete-event.md | 5 - .changeset/trim-webhook-dead-triggers.md | 11 - ...iew-metadata-type-schema-runtime-shapes.md | 15 - examples/app-crm/CHANGELOG.md | 31 ++ examples/app-crm/package.json | 2 +- examples/app-showcase/CHANGELOG.md | 40 ++ examples/app-showcase/package.json | 2 +- examples/app-todo/CHANGELOG.md | 40 ++ examples/app-todo/package.json | 2 +- examples/embed-objectql/CHANGELOG.md | 29 ++ examples/embed-objectql/package.json | 2 +- packages/adapters/hono/CHANGELOG.md | 15 + packages/adapters/hono/package.json | 2 +- packages/apps/account/CHANGELOG.md | 25 ++ packages/apps/account/package.json | 2 +- packages/apps/setup/CHANGELOG.md | 25 ++ packages/apps/setup/package.json | 2 +- packages/apps/studio/CHANGELOG.md | 25 ++ packages/apps/studio/package.json | 2 +- packages/cli/CHANGELOG.md | 180 +++++++++ packages/cli/package.json | 2 +- packages/client-react/CHANGELOG.md | 29 ++ packages/client-react/package.json | 2 +- packages/client/CHANGELOG.md | 97 +++++ packages/client/package.json | 2 +- packages/cloud-connection/CHANGELOG.md | 36 ++ packages/cloud-connection/package.json | 2 +- .../connectors/connector-mcp/CHANGELOG.md | 28 ++ .../connectors/connector-mcp/package.json | 2 +- .../connectors/connector-openapi/CHANGELOG.md | 47 +++ .../connectors/connector-openapi/package.json | 2 +- .../connectors/connector-rest/CHANGELOG.md | 28 ++ .../connectors/connector-rest/package.json | 2 +- .../connectors/connector-slack/CHANGELOG.md | 28 ++ .../connectors/connector-slack/package.json | 2 +- packages/console/CHANGELOG.md | 2 + packages/console/package.json | 2 +- packages/core/CHANGELOG.md | 65 ++++ packages/core/package.json | 2 +- packages/create-objectstack/CHANGELOG.md | 75 ++++ packages/create-objectstack/package.json | 2 +- packages/formula/CHANGELOG.md | 133 +++++++ packages/formula/package.json | 2 +- packages/lint/CHANGELOG.md | 114 ++++++ packages/lint/package.json | 2 +- packages/mcp/CHANGELOG.md | 60 +++ packages/mcp/package.json | 2 +- packages/metadata-core/CHANGELOG.md | 24 ++ packages/metadata-core/package.json | 2 +- packages/metadata-fs/CHANGELOG.md | 6 + packages/metadata-fs/package.json | 2 +- packages/metadata-protocol/CHANGELOG.md | 199 ++++++++++ packages/metadata-protocol/package.json | 2 +- packages/metadata/CHANGELOG.md | 48 +++ packages/metadata/package.json | 2 +- packages/objectql/CHANGELOG.md | 164 ++++++++ packages/objectql/package.json | 2 +- packages/observability/CHANGELOG.md | 87 +++++ packages/observability/package.json | 2 +- packages/platform-objects/CHANGELOG.md | 25 ++ packages/platform-objects/package.json | 2 +- packages/plugins/driver-memory/CHANGELOG.md | 28 ++ packages/plugins/driver-memory/package.json | 2 +- packages/plugins/driver-mongodb/CHANGELOG.md | 28 ++ packages/plugins/driver-mongodb/package.json | 2 +- packages/plugins/driver-sql/CHANGELOG.md | 72 ++++ packages/plugins/driver-sql/package.json | 2 +- .../plugins/driver-sqlite-wasm/CHANGELOG.md | 31 ++ .../plugins/driver-sqlite-wasm/package.json | 2 +- packages/plugins/embedder-openai/CHANGELOG.md | 24 ++ packages/plugins/embedder-openai/package.json | 2 +- .../plugins/knowledge-memory/CHANGELOG.md | 29 ++ .../plugins/knowledge-memory/package.json | 2 +- .../plugins/knowledge-ragflow/CHANGELOG.md | 29 ++ .../plugins/knowledge-ragflow/package.json | 2 +- .../plugins/plugin-approvals/CHANGELOG.md | 75 ++++ .../plugins/plugin-approvals/package.json | 2 +- packages/plugins/plugin-audit/CHANGELOG.md | 40 ++ packages/plugins/plugin-audit/package.json | 2 +- packages/plugins/plugin-auth/CHANGELOG.md | 61 +++ packages/plugins/plugin-auth/package.json | 2 +- packages/plugins/plugin-dev/CHANGELOG.md | 47 +++ packages/plugins/plugin-dev/package.json | 2 +- packages/plugins/plugin-email/CHANGELOG.md | 33 ++ packages/plugins/plugin-email/package.json | 2 +- .../plugins/plugin-hono-server/CHANGELOG.md | 96 +++++ .../plugins/plugin-hono-server/package.json | 2 +- .../plugins/plugin-pinyin-search/CHANGELOG.md | 18 + .../plugins/plugin-pinyin-search/package.json | 2 +- packages/plugins/plugin-reports/CHANGELOG.md | 29 ++ packages/plugins/plugin-reports/package.json | 2 +- packages/plugins/plugin-security/CHANGELOG.md | 33 ++ packages/plugins/plugin-security/package.json | 2 +- packages/plugins/plugin-sharing/CHANGELOG.md | 36 ++ packages/plugins/plugin-sharing/package.json | 2 +- packages/plugins/plugin-webhooks/CHANGELOG.md | 36 ++ packages/plugins/plugin-webhooks/package.json | 2 +- packages/qa/dogfood/CHANGELOG.md | 40 ++ packages/qa/dogfood/package.json | 2 +- packages/qa/downstream-contract/CHANGELOG.md | 24 ++ packages/qa/downstream-contract/package.json | 2 +- packages/qa/http-conformance/CHANGELOG.md | 9 + packages/qa/http-conformance/package.json | 2 +- packages/rest/CHANGELOG.md | 56 +++ packages/rest/package.json | 2 +- packages/runtime/CHANGELOG.md | 142 +++++++ packages/runtime/package.json | 2 +- packages/sdui-parser/CHANGELOG.md | 2 + packages/sdui-parser/package.json | 2 +- .../services/service-analytics/CHANGELOG.md | 34 ++ .../services/service-analytics/package.json | 2 +- .../services/service-automation/CHANGELOG.md | 78 ++++ .../services/service-automation/package.json | 2 +- packages/services/service-cache/CHANGELOG.md | 32 ++ packages/services/service-cache/package.json | 2 +- .../service-cluster-redis/CHANGELOG.md | 25 ++ .../service-cluster-redis/package.json | 2 +- .../services/service-cluster/CHANGELOG.md | 28 ++ .../services/service-cluster/package.json | 2 +- .../services/service-datasource/CHANGELOG.md | 28 ++ .../services/service-datasource/package.json | 2 +- packages/services/service-i18n/CHANGELOG.md | 28 ++ packages/services/service-i18n/package.json | 2 +- packages/services/service-job/CHANGELOG.md | 29 ++ packages/services/service-job/package.json | 2 +- .../services/service-knowledge/CHANGELOG.md | 28 ++ .../services/service-knowledge/package.json | 2 +- .../services/service-messaging/CHANGELOG.md | 28 ++ .../services/service-messaging/package.json | 2 +- .../services/service-package/CHANGELOG.md | 29 ++ .../services/service-package/package.json | 2 +- packages/services/service-queue/CHANGELOG.md | 29 ++ packages/services/service-queue/package.json | 2 +- .../services/service-realtime/CHANGELOG.md | 29 ++ .../services/service-realtime/package.json | 2 +- .../services/service-settings/CHANGELOG.md | 30 ++ .../services/service-settings/package.json | 2 +- packages/services/service-sms/CHANGELOG.md | 28 ++ packages/services/service-sms/package.json | 2 +- .../services/service-storage/CHANGELOG.md | 33 ++ .../services/service-storage/package.json | 2 +- packages/spec/CHANGELOG.md | 368 ++++++++++++++++++ packages/spec/package.json | 2 +- packages/triggers/trigger-api/CHANGELOG.md | 28 ++ packages/triggers/trigger-api/package.json | 2 +- .../trigger-record-change/CHANGELOG.md | 41 ++ .../trigger-record-change/package.json | 2 +- .../triggers/trigger-schedule/CHANGELOG.md | 28 ++ .../triggers/trigger-schedule/package.json | 2 +- packages/types/CHANGELOG.md | 24 ++ packages/types/package.json | 2 +- packages/verify/CHANGELOG.md | 51 +++ packages/verify/package.json | 2 +- packages/vscode-objectstack/CHANGELOG.md | 2 + packages/vscode-objectstack/package.json | 2 +- 197 files changed, 3857 insertions(+), 1105 deletions(-) delete mode 100644 .changeset/adr-0097-openapi-upstream-classify.md delete mode 100644 .changeset/analytics-drill-raw-totals.md delete mode 100644 .changeset/annotate-schema-only-enums.md delete mode 100644 .changeset/approver-type-org-membership-level.md delete mode 100644 .changeset/automation-schema-resolver-e2e.md delete mode 100644 .changeset/betterauth-adapter-system-writes.md delete mode 100644 .changeset/bulk-update-validation-rules.md delete mode 100644 .changeset/bulk-write-hardening.md delete mode 100644 .changeset/cli-strip-arg-separator.md delete mode 100644 .changeset/collapse-hook-event-taxonomy.md delete mode 100644 .changeset/date-equality-runtime-fix.md delete mode 100644 .changeset/date-field-equality-guardrail.md delete mode 100644 .changeset/dev-loop-dx-p2.md delete mode 100644 .changeset/document-validation-governance-crossfield.md delete mode 100644 .changeset/flow-registration-schema-aware-validation.md delete mode 100644 .changeset/flow-trigger-observability.md delete mode 100644 .changeset/i18n-inline-label-default-locale.md delete mode 100644 .changeset/lint-hide-platform-baseline.md delete mode 100644 .changeset/logger-esm-file-destination.md delete mode 100644 .changeset/logger-honors-no-color.md delete mode 100644 .changeset/mcp-validate-expression-tool.md delete mode 100644 .changeset/metadata-register-notifies-watchers.md delete mode 100644 .changeset/ownership-record-model-field.md delete mode 100644 .changeset/perf-timing-admin-detail.md delete mode 100644 .changeset/perf-timing-per-request-gating.md delete mode 100644 .changeset/publish-drafts-org-scope.md delete mode 100644 .changeset/readonly-static-insert-strip.md delete mode 100644 .changeset/remove-dead-metadata-props-2377.md delete mode 100644 .changeset/remove-form-surfaced-dead-props-2377.md delete mode 100644 .changeset/retire-feed-contracts.md delete mode 100644 .changeset/retire-feed-discovery-surface.md delete mode 100644 .changeset/scaffold-default-connector-executors.md delete mode 100644 .changeset/scaffold-gitignore-survives-publish.md delete mode 100644 .changeset/scaffold-pnpm11-build-approvals.md delete mode 100644 .changeset/scaffold-skill-catalog-boundary.md delete mode 100644 .changeset/seed-replay-lookup-corruption.md delete mode 100644 .changeset/seed-replayer-skipped.md delete mode 100644 .changeset/server-timing-perf-spans-2408.md delete mode 100644 .changeset/state-machine-initial-states.md delete mode 100644 .changeset/systemfields-drop-owner-key.md delete mode 100644 .changeset/tidy-views-guard.md delete mode 100644 .changeset/tier4-type-soundness-warnings.md delete mode 100644 .changeset/trim-validation-delete-event.md delete mode 100644 .changeset/trim-webhook-dead-triggers.md delete mode 100644 .changeset/view-metadata-type-schema-runtime-shapes.md diff --git a/.changeset/adr-0097-openapi-upstream-classify.md b/.changeset/adr-0097-openapi-upstream-classify.md deleted file mode 100644 index 0c6cbb0d5..000000000 --- a/.changeset/adr-0097-openapi-upstream-classify.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -'@objectstack/connector-openapi': minor ---- - -feat(connector-openapi): degrade + retry on an unreachable remote spec URL (#3049 follow-up) - -The `openapi` provider fetches `providerConfig.spec` when it is an http(s) URL. -That fetch previously threw plain on any failure, so a momentarily-unreachable -spec endpoint aborted the whole app boot. It now classifies the fault the same -way `connector-mcp` classifies its connect path (ADR-0097): - -- **Network error** (DNS / connection refused / timeout) or a **transient HTTP - status** (`408` / `429` / `5xx`, mirroring the `retryableStatusCodes` - convention) throws `ConnectorUpstreamUnavailableError` — the materializer - degrades the instance (`state: 'degraded'` on `GET /connectors`, dispatch - fails clearly) and retries with backoff plus on every `metadata:reloaded`. -- A **wrong URL** (non-retryable `4xx`) or an **unparseable document** stays a - plain, fatal configuration fault. - -Inline and file-path (`#3016`) specs do no boot I/O and are unaffected. diff --git a/.changeset/analytics-drill-raw-totals.md b/.changeset/analytics-drill-raw-totals.md deleted file mode 100644 index e05383d44..000000000 --- a/.changeset/analytics-drill-raw-totals.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@objectstack/service-analytics": minor ---- - -Analytics drill metadata now snapshots raw grouped values for totals/subtotal rows too (#3214). The ADR-0021 D2 drill sidecar (`drillRawRows`, #2080) only covered `result.rows`, but the totals rows added in #1753 carry dimension values and go through the same label resolution — which overwrote their stored value (select option value, lookup/master_detail FK id) with the display label, leaving a subtotal drill nothing to exact-match on. - -`queryDataset` now also emits `drillRawTotals`, aligned to `result.totals` by index (`drillRawTotals[i][j]` ↔ `result.totals[i].rows[j]`), captured in the same pre-label-resolution pass. Each map is restricted to the drillable dimensions the grouping actually groups by, so the grand-total grouping (`[]`) contributes an empty map per row. Purely additive result props (same as #2080) — no spec-contract change. diff --git a/.changeset/annotate-schema-only-enums.md b/.changeset/annotate-schema-only-enums.md deleted file mode 100644 index ade2f6596..000000000 --- a/.changeset/annotate-schema-only-enums.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -"@objectstack/spec": patch ---- - -Annotate the schema-only event/subscription/connector surfaces flagged by the #3197 audit with explicit "not yet enforced / not yet implemented" notes in their doc comments and `.describe()` texts, so authoring metadata against them is no longer silently swallowed. No runtime behavior or schema shape changes — documentation only. - -Surfaces annotated (each trace re-confirmed against the current tree before annotating): - -- `GraphQLSubscriptionConfigSchema` (`api/graphql.zod.ts`) — no subscription transport exists; the GraphQL HTTP entry serves query/mutation only. -- `WebSocketMessageType` + module header (`api/websocket.zod.ts`) — no WebSocket server is mounted (#2462); the protocol is a future wire contract. -- `RealtimeEventType` (`api/realtime.zod.ts`) — zero runtime importers; the engine emits `data.record.*` names (which don't match this enum's members) and nothing emits `field.changed`. -- Connector `webhooks`/`WebhookConfigSchema`/`WebhookEventSchema` and `triggers`/`ConnectorTriggerSchema` (`integration/connector.zod.ts`) — `AutomationEngine.registerConnector` reads only `actions`; webhook events and trigger definitions parse but are never dispatched or polled. -- Automation `ConnectorTriggerSchema`/`TriggerRegistrySchema` (`automation/trigger-registry.zod.ts`) — no runtime importer; the `stream` trigger mechanism exists only here. -- `NotificationChannelSchema` (`system/notification.zod.ts`) + the mirrored `NotificationChannel` contract type — implemented delivery channels are `inbox`/`email`/`sms`; `push`/`slack`/`teams`/`webhook` dead-letter, and the enum's `in-app` does not match the registered `inbox` channel id. - -The audit's sixth row (`SubscriptionEventType`, formerly `data/subscription.zod.ts`) needed no annotation — it was already removed outright by the feed-contract retirement (#1959). diff --git a/.changeset/approver-type-org-membership-level.md b/.changeset/approver-type-org-membership-level.md deleted file mode 100644 index d4e1899b0..000000000 --- a/.changeset/approver-type-org-membership-level.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -"@objectstack/spec": minor -"@objectstack/plugin-approvals": minor -"@objectstack/lint": minor ---- - -feat(approvals): rename the `role` approver type to `org_membership_level` (#3133) - -`ApproverType.role` was the last platform surface projecting the reserved word -"role" (ADR-0090 D3). It is not covered by D3's better-auth exception: that -exception protects better-auth's own `sys_member.role` **column**, which we do -not own — `ApproverType` is our own enum, an authoring surface, and D3 mandates -that the projection of that concept is spelled `org_membership_level` and -labelled "organization membership", **never "role"**. - -The sentence licensing the leak was also false: ADR-0090 D3 claims -`sys_member.role` is "already relabelled `org_membership_level` in the platform -projection", but `org_membership_level` existed nowhere in the codebase and -ADR-0057 D7 lists that relabel under "Deferred (evidence-gated, P4)". The -projection never landed, so the word reached authors. - -The name manufactured a real, silent failure — "hotcrm class": every other -surface renamed to `position` (`sys_role`, `ShareRecipientType.role`, -`ctx.roles[]`), so `{ type: 'role', value: 'sales_manager' }` reads as the -legacy spelling of a position. It resolves against the membership tier, finds -no member row, falls back to an inert `role:sales_manager` literal, and the -request waits forever on an approver that cannot exist. - -- **spec**: `ApproverType` gains `org_membership_level`; `role` stays as a - deprecated alias for one window (a published 15.x flow keeps loading) with - `DEPRECATED_APPROVER_TYPES` + `canonicalApproverType()` as the single source - for the mapping. Removed in the next major. -- **plugin-approvals**: resolves on the canonical type and warns on the - deprecated spelling. The `type:value` fallback literal keeps the **authored** - spelling — stored `sys_approval_approver` rows and `pending_approvers` slots - from 15.x carry `role:`, and rewriting it would orphan them. -- **lint**: `approval-role-not-membership-tier` → `approval-approver-not-membership-tier` - (the rule id carried the reserved word too), plus a new - `approval-approver-type-deprecated`. The two are mutually exclusive: a bad - *value* wins, because prescribing `org_membership_level` for a position name - would be wrong advice — the fix there is `position`. - -Authoring `type: 'role'` keeps working and now says so out loud. Rewrite it as -`org_membership_level`; if the value is an org position, the fix is `position`. diff --git a/.changeset/automation-schema-resolver-e2e.md b/.changeset/automation-schema-resolver-e2e.md deleted file mode 100644 index 318427604..000000000 --- a/.changeset/automation-schema-resolver-e2e.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -"@objectstack/service-automation": patch ---- - -test(automation): end-to-end coverage for the #1928 object-schema resolver wiring - -Adds a kernel-level integration test proving `AutomationServicePlugin` bridges -the engine's object-schema resolver to the live `objectql.registry.getObject` at -`start()` (fields + types resolved from the registry), and that a flow -registered through the running kernel with a text field misused in arithmetic -emits the tier-4 advisory — while a sound condition stays quiet. Locks in the -production integration point that the engine-level unit tests (which set the -resolver by hand) could not exercise. Test-only; no behavior change. diff --git a/.changeset/betterauth-adapter-system-writes.md b/.changeset/betterauth-adapter-system-writes.md deleted file mode 100644 index d9371813c..000000000 --- a/.changeset/betterauth-adapter-system-writes.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -"@objectstack/plugin-auth": patch ---- - -fix(plugin-auth): run better-auth adapter WRITES as system context so #2948 doesn't strip readonly identity columns (#3164) - -The better-auth ObjectQL adapter wrapped the engine so its READS carried -`isSystem` (to bypass the control-plane org-scope read hook), but its WRITES -passed through with no context. The static-`readonly` UPDATE strip (#2948) runs -on any non-system update — and since the adapter carries no caller context, -`!ctx?.isSystem` was `true`, so the strip silently DROPPED better-auth's own -writes to readonly `sys_user` columns: `email` (change-email), `banned` / -`ban_reason` / `ban_expires` (admin ban). Those operations returned success but -never persisted. - -`withSystemReadContext` is renamed to `withSystemContext` (a deprecated alias is -kept for one release) and now injects `isSystem` on `insert` / `update` / -`delete` as well as reads. This is correct because these are the identity -authority's own writes — user-context writes to `managedBy: 'better-auth'` tables -are already rejected upstream by the ADR-0092 identity write guard, so the -adapter path only ever carries better-auth's internal writes. - -Found while implementing #3043 (the INSERT-side readonly strip). This is its -UPDATE-side dual: #3043 relocated the insert strip to the external ingress -precisely because internal writers (this adapter included) don't declare -`isSystem`; the pre-existing engine-level UPDATE strip has no such relocation, so -the adapter had to declare its writes system. diff --git a/.changeset/bulk-update-validation-rules.md b/.changeset/bulk-update-validation-rules.md deleted file mode 100644 index a15675d28..000000000 --- a/.changeset/bulk-update-validation-rules.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@objectstack/objectql": patch -"@objectstack/spec": patch ---- - -Enforce validation rules, `requiredWhen`, and per-option `visibleWhen` on multi-row updates (#3106). The bulk branch of `engine.update` (`options.multi` → `driver.updateMany`) previously never called `evaluateValidationRules`, so every object-level rule (`script`, `state_machine`, `format`, `cross_field`, `json_schema`, `conditional`), field-level `requiredWhen`, and per-option `visibleWhen` check was a silent no-op there. The engine now reads the row-scoped match set (the same AST the write binds, one query shared with the `readonlyWhen` bulk strip) and evaluates the payload against each matched row's prior state; any error-severity violation rejects the whole batch with `ValidationError` (annotated with the failing record id) before anything is written. Schemas needing no prior state (`format`/`json_schema`-only) are evaluated once against the payload with no fetch, and rule-free schemas are unaffected. Behavior change: bulk writes that previously slipped past declared rules now throw. Doc comments in `rule-validator.ts` and `validation.zod.ts` no longer overstate coverage and name the remaining `events: ['delete']` gap (tracked separately). diff --git a/.changeset/bulk-write-hardening.md b/.changeset/bulk-write-hardening.md deleted file mode 100644 index e32a7e46b..000000000 --- a/.changeset/bulk-write-hardening.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -"@objectstack/core": patch -"@objectstack/objectql": patch -"@objectstack/rest": patch -"@objectstack/metadata-protocol": patch ---- - -fix: harden the bulk-write path — retries, idempotency, contracts, and summary visibility (#3147–#3152) - -Six reliability fixes to the batched seed/import + `engine.insert(array)` path -introduced by the #2678 bulk-write rework: - -- **#3151** `bulkWrite` validates that `writeBatch` returns one record per input - row (a short/long/non-array return is degraded per-row, not backfilled as - phantom success); `engine.insert(array)` likewise rejects a short driver - `bulkCreate` return instead of padding afterInsert with `undefined`. -- **#3150** wraps the two remaining un-retried write points (seed - `writeRecord`/`resolveDeferredUpdates`, import's no-`createManyData` - fallback) in `withTransientRetry`; `defaultIsTransientError` short-circuits - definitive logical errors to non-transient. -- **#3148** import `resolveRef` flushes pending creates on a same-object miss so - a later row can reference an earlier same-file CREATE, and no longer - negatively caches a miss. -- **#3149** threads an `attempt` counter through `bulkWrite`; seed rechecks by - `externalId` and import by `matchFields` before re-writing, so a - commit-then-lost-response retry cannot duplicate a batch. -- **#3147** `recomputeSummaries` retries transient failures and, on exhaustion, - surfaces `SummaryRecomputeError` (`ERR_SUMMARY_RECOMPUTE`) instead of a - silent warn; seed/import recover it to a warning without re-writing. -- **#3152** autonumbers are assigned after validation, so a batch that dies in - validation consumes no sequence value (no number-range gaps). diff --git a/.changeset/cli-strip-arg-separator.md b/.changeset/cli-strip-arg-separator.md deleted file mode 100644 index b7e858905..000000000 --- a/.changeset/cli-strip-arg-separator.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -"@objectstack/cli": patch ---- - -fix(cli): tolerate the `--` separator pnpm injects when forwarding script args (#3114) - -The AGENTS.md-documented backend-debug flow `pnpm dev -- --fresh -p ` failed at -the repo root with an opaque `Unexpected arguments: -p, 44637` (exit 2 + a help dump). - -pnpm appends forwarded args to a script **verbatim, including the `--`**, and each -nested `pnpm --filter` hop preserves it, so the showcase's `objectstack dev ---seed-admin` ran as `objectstack dev --seed-admin -- --fresh -p 44637`. oclif reads -`--` as POSIX end-of-flags, so everything after it became positional: `--fresh` was -silently swallowed as the `package` arg and `-p 44637` overflowed the arg list. Every -flag the user asked for was dropped — the failure was opaque precisely because the -`--` looks inert. - -A `preparse` hook now drops `--` separators before oclif parses argv, so the -npm-style `-- ` form and the bare form behave identically, for every command -and both bins (`run.js`, `run-dev.js`). No `os` command takes passthrough args (none -sets `strict = false`, none reads raw argv), so a `--` carries no meaning here and is -always a package-manager artifact. - -Note this is not fixable via oclif's `'--': false` parser option: that keeps -flag-parsing on past the separator but re-appends the `--` into argv, so strict -commands fail with `Unexpected argument: --` instead. - -Tradeoff: a `-`-prefixed token can no longer be forced to parse as a positional -value. Every `os` positional is a config path, a metadata / datasource / package -name, or an id — none start with `-`. diff --git a/.changeset/collapse-hook-event-taxonomy.md b/.changeset/collapse-hook-event-taxonomy.md deleted file mode 100644 index bfce023b9..000000000 --- a/.changeset/collapse-hook-event-taxonomy.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -"@objectstack/spec": patch -"@objectstack/objectql": patch ---- - -Collapse the hook event taxonomy from 18 declared events to the 8 the engine actually dispatches (#3195). The removed 10 (`beforeFindOne`/`afterFindOne`, `beforeCount`/`afterCount`, `beforeAggregate`/`afterAggregate`, `beforeUpdateMany`/`afterUpdateMany`, `beforeDeleteMany`/`afterDeleteMany`) were declared in `HookEvent` but never fired — the enum mirrored the engine method table instead of domain events, so a hook subscribing to them registered fine and then silently no-op'd. - -- `findOne` now fires the same `beforeFind`/`afterFind` hooks as `find` — the read event attaches to record materialization, not the engine method, so one subscription covers every read shape (no separate `beforeFindOne`/`afterFindOne`). -- Bulk (`multi: true`) updates/deletes already fire the singular `beforeUpdate`/`beforeDelete`/`afterUpdate`/`afterDelete` events with the row-scoping predicate in `ctx.input.ast`; this is now documented, and there is no `*Many` event. -- Read authorization / row filtering is the RLS/permission-rule layer's job and field masking is field-level metadata — neither is a hook every author must re-attach. -- `engine.registerHook` now warns when a hook subscribes to an event the engine never dispatches, so enum-vs-dispatch drift can't recur silently. - -No shipped hook or authored metadata used any of the removed events; authoring one now fails loudly at parse/validate time instead of registering a dead hook. Skills and docs updated to teach the 8 events and the declarative alternatives. diff --git a/.changeset/date-equality-runtime-fix.md b/.changeset/date-equality-runtime-fix.md deleted file mode 100644 index ec79d30d1..000000000 --- a/.changeset/date-equality-runtime-fix.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -"@objectstack/formula": minor ---- - -feat(formula): `dateField == today()` now matches — AST temporal-comparison rewrite (#3183) - -**Behavior change (the fix):** a `Field.date` compared with `==`/`!=` against a -temporal function now matches on the calendar day. Previously it **silently -returned the wrong answer** — `record.due_date == today()` was always `false` -(and `!= today()` always `true`) even for a same-day record, because a -`Field.date` reads back as a `YYYY-MM-DD` **string** (ADR-0053 Phase 1) and -cel-js's equality (`overloads.js` `isEqual`) treats a string and a timestamp as -unequal without consulting any overload. - -`celEngine.evaluate` now rewrites the parsed AST: for each `==`/`!=` whose one -operand is `today()`/`daysFromNow()`/`daysAgo()`/`now()`, the **field operand** -is wrapped in `date(...)` (the stdlib coercion), then the expression is -serialized and evaluated. So `record.due_date == today()` runs as -`date(record.due_date) == today()`. - -- **Per-occurrence**, not per-field: `record.d == "2026-06-20" || record.d == today()` - keeps the string-literal comparison intact while fixing the temporal one. -- **Type-blind-safe**: `date()` degrades gracefully — an already-`Date` - (`Field.datetime`) operand passes through; a non-date string or null → - `Invalid Date` → the comparison stays `false`, exactly as before. No - field-type information is needed, and no currently-correct result is worsened. -- **Cheap**: the rewrite only reserializes when such a comparison is present - (a plain-`includes` gate skips the rest), and is memoized per source string. - -Applies to every interpreter site — read-time `Field.formula`, default values, -validation rules, hook conditions, and flow conditions — since all route through -`celEngine.evaluate`. RLS/sharing conditions are unaffected: they compile via -`cel-to-filter`, which already rejects function calls as a loud authoring error. - -**Supersedes the #3192 advisory lint.** That build-time warning -(`checkTemporalDateEquality`) flagged `dateField == today()` as a silent-miss; -with the runtime fixed it would be a false alarm, so it (and the -`temporalEqualityFields` helper it used) is removed. Authors can now write the -natural `record.due_date == today()` directly; the `date(...)` / -`daysBetween(...) == 0` / range idioms all keep working. diff --git a/.changeset/date-field-equality-guardrail.md b/.changeset/date-field-equality-guardrail.md deleted file mode 100644 index a8e7ff302..000000000 --- a/.changeset/date-field-equality-guardrail.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -"@objectstack/formula": minor ---- - -feat(formula): warn when a `date` field is compared to a temporal function with `==`/`!=` (#3183) - -A `Field.date` deserializes as a `YYYY-MM-DD` **string** (ADR-0053 Phase 1), and -cel-js's equality hard-codes `string == ` to `false` — it returns -`false` for a string left operand without ever consulting a registered overload, -and refuses cross-type object equality (`@marcbachmann/cel-js` `overloads.js` -`isEqual`). So the most natural "is it due today" predicate — - -```cel -record.due_date == today() // silently false, even when due_date IS today -record.due_date != today() // silently true for a same-day record -``` - -— compiles clean, throws nothing, and silently never matches. Same silent-miss -family as #1928; **timezone-independent** (fails identically at UTC) and -cross-cutting (formulas, validation, RLS, flow/action/sharing/hook predicates). - -cel-js gives no operator-layer hook to fix the comparison, so this adds a -**build-time advisory warning** (the established ADR-0032 guardrail strategy) -rather than a runtime behavior change. `validateExpression` reuses the shared -`ExprSchemaHint.fieldTypes` (the same per-field type map the #1928 tier-4 -soundness check already threads through `@objectstack/lint`) to flag a `==`/`!=` -between a `date` field (`record.`/`previous.`/bare) and -`today()`/`daysFromNow()`/`daysAgo()`/`now()`, with a self-correcting message -pointing at the working idioms: `date(record.d) == today()`, a range -(`>= … && <= …`), or `daysBetween(today(), record.d) == 0`. - -Warning severity — never fails the build (the write/validation path may carry a -real `Date`). Restricted to `type: 'date'` (unambiguously a string); `datetime` -is excluded to avoid false positives. Ordering operators (`>=`/`<=`/`<`/`>`) -already work — cel-js *throws* for them, tripping the engine's existing -string-hydration retry — so they are not flagged. - -A runtime fix (normalizing the peer of a temporal operand in the data layer) -remains tracked in #3183; a naive "hydrate date fields to `Date`" version would -trade this silent-miss for another (breaking `dateField == "2026-06-20"`), so it -needs its own design. diff --git a/.changeset/dev-loop-dx-p2.md b/.changeset/dev-loop-dx-p2.md deleted file mode 100644 index 081ef6eae..000000000 --- a/.changeset/dev-loop-dx-p2.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -"@objectstack/objectql": patch -"@objectstack/metadata": patch -"@objectstack/runtime": patch -"@objectstack/plugin-auth": patch -"@objectstack/cli": patch ---- - -Dev-loop DX fixes from the 15.1 third-party evaluation (P2 batch): - -- **Hot-added objects are now queryable without a restart.** Adding a `*.object.ts` under `os dev` used to recompile "green" while every query answered `no such table` (or `not registered`) until a manual restart: the artifact reload never notified the ObjectQL registry, tables were only created at boot, and seeds only loaded from the boot-time bundle. The `metadata:reloaded` payload now carries the parsed artifact; ObjectQL ingests the object definitions and re-runs the idempotent schema sync (same `skipSchemaSync` opt-out as boot), and the runtime loads seeds for first-seen objects (dev, single-tenant). `os dev` also prints `✚ new object(s): …` on recompile. -- **Dev admin credentials stay visible.** The `os dev` startup banner only showed `admin@objectos.ai / admin123` on the boot that actually seeded it; with the persistent default DB every later boot hid it, and the Console login page never knew it existed. The hint now re-arms on every dev boot for as long as the account still verifies against the default password, and `GET /api/v1/auth/config` exposes a dev-gated `devSeedAdmin` field (never present outside `NODE_ENV=development`) so the login page can show it. -- **`os doctor` reference analysis understands current metadata shapes.** Objects bound through `defineView` containers (`list`/`listViews`/`form`/`formViews` → `data.object`, subform `childObject`, lookup form fields) and app navigation (`objectName`, nested `children`, `areas`) were reported as "defined but not referenced". The collector now walks the canonical shapes (plus flow node `config.object`/`objectName`) and the orphan-view check descends into containers. diff --git a/.changeset/document-validation-governance-crossfield.md b/.changeset/document-validation-governance-crossfield.md deleted file mode 100644 index 1bcb9417b..000000000 --- a/.changeset/document-validation-governance-crossfield.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@objectstack/spec": patch ---- - -Document two validation-rule facts surfaced by the 2026-06 liveness audit (follow-up to #3106 / #3184), and clean up a stale form-schema mirror — no runtime behavior change: - -- `label` / `description` / `tags` on validation rules are governance / editor metadata (surfaced to the Studio rule editor and rule listings), not evaluated on the write path. Documented as such on `BaseValidationSchema` rather than removed — they are set by nearly every example rule and feed the `/meta/types` editor form, so they are declared on purpose, not silent no-ops. -- `cross_field` evaluates identically to `script` (same CEL predicate path); only `fields[0]` is read, to target the violation at a field. Documented the overlap on the schema, its `fields` `.describe()`, and the validation docs so authors can choose between them; the variant is kept for the field-targeting affordance and backward compatibility. -- Removed dead form-field entries (`scope`, `caseSensitive`, `url`, `handler`) and the stale `type=unique` hint from the hand-written `HAND_CRAFTED_SCHEMAS['validation']` fallback in `@objectstack/metadata-protocol` — leftovers from the removed `unique`/`async`/`custom` variants. -- Added the missing `beforeDelete` lifecycle-hook pointer to the validation docs' "not a rule type" callout, so delete-time guards aren't stranded now that validation has no `delete` event (#3184). diff --git a/.changeset/flow-registration-schema-aware-validation.md b/.changeset/flow-registration-schema-aware-validation.md deleted file mode 100644 index 935bbb557..000000000 --- a/.changeset/flow-registration-schema-aware-validation.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -"@objectstack/service-automation": minor ---- - -feat(automation): schema-aware flow-condition validation at registration (#1928) - -`registerFlow` now runs the same schema-aware condition checks as -`objectstack build` — so a flow registered dynamically (via the API / Studio, -bypassing the build lint) still gets the guardrail. When the host wires an -object-schema resolver, a flow condition that references an unknown field, -likely-typos a field name, or does arithmetic/ordering on a text/boolean field -against a number is surfaced as an **advisory warning** (logged), pointing at -the object's real schema. - -- New `AutomationEngine.setObjectSchemaResolver(resolver)` bridge (mirrors - `setFunctionResolver`); `AutomationServicePlugin` wires it to - `objectql.registry.getObject` in `start()`, before the flow pull, so - registry-sourced flows are covered too. -- **Strictly additive / zero regression**: the fatal set is unchanged (syntax, - brace-in-CEL, unknown-function still throw); everything the schema pass adds is - logged, never thrown, and the whole thing is a no-op when no resolver is wired. - Flow conditions bind fields flat, so the check runs in `flattened` scope - (flow variables stay `dyn` and are never flagged; equality is runtime-safe). - -Builds on the tier-4 type-soundness check in `@objectstack/formula` / -`@objectstack/lint` (#1928). diff --git a/.changeset/flow-trigger-observability.md b/.changeset/flow-trigger-observability.md deleted file mode 100644 index 5f4cf09e6..000000000 --- a/.changeset/flow-trigger-observability.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -'@objectstack/service-automation': minor -'@objectstack/trigger-record-change': minor -'@objectstack/lint': minor -'@objectstack/cli': minor -'@objectstack/objectql': patch -'@objectstack/runtime': patch -'@objectstack/plugin-audit': patch ---- - -Flow trigger observability — kill the four-layer silence around record-change flows that never fire (2026-07-17 third-party eval). - -A misauthored auto-launched flow (wrong `objectName`, missing `requires: ['automation','triggers']`, failing start condition) produced ZERO output at every layer: the engine's own registration/binding logs land inside the CLI's boot-quiet stdout window (which swallows debug/info/warn — only error/fatal reach stderr), and each "didn't happen" path was itself silent. Fixes: - -- **Startup banner `Flows:` section** (`os serve`/`os dev`/`os start`): flow count, bound-to-trigger count, registered trigger types, draft count — plus loud `⚠` lines for flows declared with no automation engine enabled (`requires` missing), flows whose trigger type has no registered trigger, and bound record-change flows targeting an unknown object (dead binding). Printed after stdout is restored, so it is immune to the boot-quiet window. -- **Trigger-fired run failures now log at ERROR** (stderr — always visible): the automation engine no longer drops the AutomationResult of a trigger-fired execution; condition-evaluation faults and node failures surface with the flow name. Condition-not-met skips stay at debug (high-frequency, intentional). -- **`RecordChangeTrigger` probes object existence at bind time** and warns when a flow's `objectName` matches no registered object (exact-name matching), instead of silently arming a hook that can never fire. -- **`kernel:bootstrapped` binding audit** in the automation plugin: warns per enabled-but-unbound triggered flow with the reason, and reports registered/bound/draft counts (`AutomationEngine.getTriggerBindingAudit()`, extended `getFlowRuntimeStates()` with `status`/`triggerType`/`object`). -- **`os validate` flow-wiring advisories** (`@objectstack/lint` `validateFlowTriggerReadiness`): warns when a record-triggered flow targets an object the stack does not define, and when an auto-triggered flow's status is `draft` (authored or defaulted — draft flows still fire; declare `active` or `obsolete`). -- Removed leftover boot-debug writes (`registerApp`/`AppPlugin`/`StandaloneStack`/`AuditPlugin` stderr noise) that previous debugging of this same silence had left behind. diff --git a/.changeset/i18n-inline-label-default-locale.md b/.changeset/i18n-inline-label-default-locale.md deleted file mode 100644 index 076e60d2c..000000000 --- a/.changeset/i18n-inline-label-default-locale.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -"@objectstack/cli": patch ---- - -fix(cli): treat an inline `label:` as the default-locale source in i18n coverage - -A fresh `npm create objectstack` scaffold reported 4 `i18n/missing-object` / -`i18n/missing-field` errors for its own `_note` object, even though the -template authors `label: 'Note'`, `pluralLabel: 'Notes'`, `label: 'Title'` and -`label: 'Body'` inline. The only way to silence them was to commit an `en` -bundle restating strings the metadata already carries. - -The inline `label:` *is* the default-locale text: the runtime resolver falls -back to it when a bundle has no entry (`translateObject`), and `os i18n -extract` seeds bundles from it. Coverage now honours that contract — an inline -label satisfies the default locale, and a bundle is what *other* locales need. -Keys with no source string anywhere are no longer reported as i18n gaps; a -missing label is already `required/label`'s finding. - -Non-default locales are unaffected: they still warn for every untranslated key -(`os lint` on `examples/app-todo` reports the same 79 warnings as before, with -its 39 default-locale errors gone). `os lint --include-platform` drops the -platform baseline's default-locale errors for the same reason — the platform -ships English labels inline — while keeping its non-default-locale warnings. diff --git a/.changeset/lint-hide-platform-baseline.md b/.changeset/lint-hide-platform-baseline.md deleted file mode 100644 index ebb8f8b24..000000000 --- a/.changeset/lint-hide-platform-baseline.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@objectstack/cli": patch ---- - -`os lint` no longer buries the user's own signal under the platform i18n baseline. A fresh scaffold reported 800+ `i18n/missing-metadataForm` errors — translation keys for platform built-in metadata forms (email_template, …) that the platform packages already ship at runtime. Those are now hidden by default and folded into one summary line (`platform built-ins: N i18n issue(s) hidden`); pass `--include-platform` to audit them, and read `hiddenPlatform` in `--json` output. User-authored metadata coverage is reported unchanged. diff --git a/.changeset/logger-esm-file-destination.md b/.changeset/logger-esm-file-destination.md deleted file mode 100644 index 0ae3935b2..000000000 --- a/.changeset/logger-esm-file-destination.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@objectstack/core": patch ---- - -**`createLogger({ file })` now actually writes the file under ESM.** `openFileStream` loaded `fs` with a lazy `require()` to keep the browser-safe logger entry out of the `fs` bundle graph; esbuild rewrites that to its `__require` shim in the ESM output, which throws `Dynamic require of "fs" is not supported`, and a bare `catch {}` swallowed it. Since the workspace is `type: module`, every Node ESM consumer — `os serve`, `os dev` — silently got no file logging at all, while the CJS build kept working. The builtin now loads via `process.getBuiltinModule` (opaque to bundlers, works in both module systems, with a `require` fallback for Node < 20.16), and a `file` destination that cannot be opened reports itself on stderr instead of disappearing. - -Turning the destination back on also fixed three faults that were unreachable while it never opened: `child()` opened a second stream per child and orphaned it, destroying a child logger closed the stream its parent and siblings were still writing to, and an async open failure (e.g. an unwritable path) hit an `'error'` event with no listener and took the process down. diff --git a/.changeset/logger-honors-no-color.md b/.changeset/logger-honors-no-color.md deleted file mode 100644 index 5b95d7482..000000000 --- a/.changeset/logger-honors-no-color.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -"@objectstack/core": patch ---- - -fix(core): ObjectLogger honors NO_COLOR and TTY detection before emitting ANSI colors - -The kernel/plugin logger (`ctx.logger`, wired by `os serve` / `os dev`) colorized its -`pretty`-format level tags unconditionally, so `NO_COLOR=1` runs and piped/CI output -still carried ANSI escapes (e.g. `\x1b[31m…ERROR\x1b[0m`), breaking plain-text log -scanners (see scripts/publish-smoke.sh, which had to strip ANSI before grepping). - -Per the no-color.org convention, color is now emitted only when the destination stream -(stdout, or stderr for error/fatal) is an interactive TTY **and** `NO_COLOR` is unset or -empty — any non-empty `NO_COLOR` value disables color. Interactive terminals keep the -existing colorized output. The optional file destination now always receives plain text. diff --git a/.changeset/mcp-validate-expression-tool.md b/.changeset/mcp-validate-expression-tool.md deleted file mode 100644 index 6bda9ef26..000000000 --- a/.changeset/mcp-validate-expression-tool.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -"@objectstack/mcp": minor ---- - -feat(mcp): `validate_expression` tool — validate a CEL expression against a schema before authoring (#1928) - -Adds an agent-callable MCP tool that runs the same build-time expression checks -as `objectstack build`, so an AI can validate a formula / predicate / flow -condition **while authoring** instead of shipping one that silently evaluates to -`null`. Given `{ objectName, expression, site? }` it resolves the object's real -schema (field names + types, via the principal-bound `describeObject` bridge) -and returns: - -- **errors** — bare field refs (`amount` → `record.amount`), unknown fields - (with a did-you-mean), unknown functions; -- **warnings** — text/boolean fields misused in arithmetic, date-equality - pitfalls; -- **inScope** — the fields, stdlib functions, and namespace roots available, so - the model can self-correct; -- **inferredType** for a `formula` site. - -`site` (`formula` | `validation` | `flow_condition` | `template`, default -`formula`) maps to the validator's role + scope — `flow_condition` binds fields -bare, the rest bind `record.`. Read-only, gated by the `data:read` OAuth -scope, and fail-closed on `sys_*` objects like the other schema tools. This is -the authoring-time surface the guardrail series (#1928) always pointed at; -`@objectstack/mcp` gains a `@objectstack/formula` dependency (acyclic; formula is -a leaf). diff --git a/.changeset/metadata-register-notifies-watchers.md b/.changeset/metadata-register-notifies-watchers.md deleted file mode 100644 index f77d1ad86..000000000 --- a/.changeset/metadata-register-notifies-watchers.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -"@objectstack/spec": patch -"@objectstack/metadata": patch -"@objectstack/objectql": patch ---- - -**`MetadataManager.register()` / `unregister()` now announce to `subscribe()` watchers.** Both updated the registry, persisted to writable loaders and published to realtime, but never fired the watch callbacks — so `subscribe()` looked like it covered every write while silently missing all of them. Only the `saveMetaItem` path (via the repository watch stream) and the filesystem watcher ever reached a subscriber. Runtime consumers that cache metadata — notably ObjectQL's SchemaRegistry bridge, the component that decides what is queryable — went stale on every other write until the process restarted. - -Announcing is now the **default**, so a new call site is correct without knowing this contract exists. This is a contract fix rather than a bug fix: the one live behavior change is that runtime datasource writes (`datasource-admin`) now reach the HMR SSE stream, which subscribes to every registered type. `unregisterPackage()` / `bulkUnregister()` also announce their deletes now — correct, but latent, since neither has a production caller today. - -Bulk ingest opts out explicitly with the new `MetadataWriteOptions` (`{ notify: false }`) — boot-time filesystem priming, artifact ingest, and ObjectQL's registry bridge, each of which either runs before consumers cache anything or announces the whole batch once (as the artifact reload path does via `metadata:reloaded`). The bridge in particular MUST stay silent: it copies objects out of the SchemaRegistry, and announcing would feed them back through a handler that re-registers under `_packageId ?? 'metadata-service'`, overwriting the true package provenance of every object whose body carries no `_packageId`. - -Additive only — `register(type, name, data)` and `unregister(type, name)` keep working unchanged. - -Fixes #3112. diff --git a/.changeset/ownership-record-model-field.md b/.changeset/ownership-record-model-field.md deleted file mode 100644 index 1fab1f596..000000000 --- a/.changeset/ownership-record-model-field.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -"@objectstack/spec": minor -"@objectstack/cli": patch ---- - -fix(spec): declare `ownership` as a first-class ObjectSchema field (#3175) - -The object-level record-ownership model — `ownership: 'user' | 'org' | 'none'`, -which drives the registry's `owner_id` auto-provisioning (`applySystemFields`) — -was read by the engine via `(schema as any).ownership` while `ObjectSchema.create()` -**rejected** it as an unknown top-level key (ADR-0032 / #1535). So a tested engine -opt-out (`ownership: 'org' | 'none'` on catalog / junction tables) could not be -set through the sanctioned authoring path, and the same `ownership` word was read -elsewhere as the unrelated package-contribution kind (`own` / `extend`). - -- **spec**: `ObjectSchema` now declares `ownership: z.enum(['user','org','none']).optional()`. - Authoring the record-ownership opt-out validates cleanly; the registry reads it - off the typed schema (no `as any`). A retired `ownership: 'own'` / `'extend'` - value fails with guidance pointing at the record-ownership model and noting that - `own`/`extend` is the contribution kind (`registerObject`), not an object-schema value. -- **cli**: the `object` scaffold no longer emits the now-invalid `ownership: 'own'` - (owner injection is the default), and `objectstack info` labels the record model - with the correct `user` default. - -No runtime behavior change: `applySystemFields` and its `owner_id` injection logic -are unchanged — this makes the property the engine already honors legally authorable -and consistently typed. diff --git a/.changeset/perf-timing-admin-detail.md b/.changeset/perf-timing-admin-detail.md deleted file mode 100644 index c5822ad5d..000000000 --- a/.changeset/perf-timing-admin-detail.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -"@objectstack/observability": minor -"@objectstack/plugin-hono-server": minor -"@objectstack/driver-sql": minor ---- - -feat(observability): admin-only richer per-request timing detail via `X-OS-Debug-Timing: json` (#2408) - -Completes the optional "richer JSON" diagnostic from #2408. In addition to the -basic `Server-Timing` header, an admin/service caller can now request a -per-query breakdown — the slowest SQL statements and a query count — by sending -`X-OS-Debug-Timing: json`. The detail is returned in a separate -`X-OS-Debug-Timing-Detail` response header (compact JSON) and is **admin-only, -even under global mode**: an ordinary caller never sees SQL shapes. - -- **observability**: `PerfTiming` gains opt-in per-event detail capture - (`enableDetail` / `recordDetail` / `details`) plus the ambient - `recordServerTimingDetail`. The disclosure gate gains a `privileged` level - (set by `allowPerfDisclosure`, read via `isPerfDisclosurePrivileged`) so the - richer detail can be gated independently of the basic header. -- **driver-sql**: when detail capture is on, the query listener additionally - records each query's **parametrized** statement (knex's `q.sql`, `?` - placeholders) — never the bindings, so no literal row value ever enters the - collector. Zero overhead when detail is off. -- **plugin-hono-server**: `X-OS-Debug-Timing: json` enables detail capture; the - middleware emits `X-OS-Debug-Timing-Detail` (slowest queries, capped and - sanitized to header-safe ASCII) only when the principal is a proven admin. - -Basic and global behavior are unchanged; `json` is purely additive. diff --git a/.changeset/perf-timing-per-request-gating.md b/.changeset/perf-timing-per-request-gating.md deleted file mode 100644 index 946787a94..000000000 --- a/.changeset/perf-timing-per-request-gating.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -"@objectstack/observability": minor -"@objectstack/plugin-hono-server": minor -"@objectstack/runtime": minor ---- - -feat(observability): admin-gated per-request `Server-Timing` via `X-OS-Debug-Timing` (#2408) - -Perf-tuning mode was previously global-only (`serverTiming` option / -`OS_SERVER_TIMING`), which discloses internal phase durations — a mild -backend-fingerprinting surface — to every caller. This adds the per-request -gating path from the design so an operator can pull a single request's -`Server-Timing` breakdown on a live environment without turning the header on -for everyone. - -- **observability**: a request-scoped disclosure gate (`runWithPerfDisclosure`, - `allowPerfDisclosure`, `isPerfDisclosureAllowed`, `PerfDisclosureGate`) kept - separate from the pure `PerfTiming` collector and pinned to its own - `Symbol.for` store so the middleware and dispatcher share it across module - copies. -- **plugin-hono-server**: the Server-Timing middleware is registered by default - (unless `serverTiming: false`). It runs the collector when timing is global - **or** the request sends `X-OS-Debug-Timing: 1`, and emits the header only - when the gate is open. `OS_PERF_TIMING=1` now also enables global mode. -- **runtime**: after resolving the execution context, the dispatcher opens the - gate for admin/service/system principals, so ordinary callers never receive - the header even if they send the debug header. - -Existing global-mode behavior is unchanged. diff --git a/.changeset/publish-drafts-org-scope.md b/.changeset/publish-drafts-org-scope.md deleted file mode 100644 index be88095c7..000000000 --- a/.changeset/publish-drafts-org-scope.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@objectstack/metadata-protocol": patch ---- - -Publish/discard package drafts in the draft's own org scope, fixing `no_draft` after saving a draft via Studio. - -Studio "Save Draft" (`PUT /meta/:type/:name?mode=draft`) never threads the session's `activeOrganizationId`, so the draft row is written env-wide (`organization_id = NULL`). "Publish" (`POST /packages/:id/publish-drafts`) resolves the active org and passed it to `promoteDraft`, which looked the draft up with a strict `organization_id = ` equality — so it 404'd (`[no_draft] No pending draft exists …`) on the env-wide row it could never match, even though `listDrafts` had already surfaced that draft to the publish CTA (PR #1852's `$or`). `discardPackageDrafts` had the same latent gap. - -`listDrafts` now projects each draft's own `organizationId`, and `publishPackageDrafts` / `discardPackageDrafts` promote / delete each draft in that scope (env-wide stays env-wide, per-org stays per-org). Seed-body capture and the ADR-0067 revert-plan pre-state read are scoped the same way. - -Fixes #3115. diff --git a/.changeset/readonly-static-insert-strip.md b/.changeset/readonly-static-insert-strip.md deleted file mode 100644 index fdd40f79e..000000000 --- a/.changeset/readonly-static-insert-strip.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -"@objectstack/metadata-protocol": patch -"@objectstack/spec": patch ---- - -fix(metadata-protocol): strip static `readonly` on INSERT at the data-write ingress (#3043) - -#2948/#3003 made static `readonly: true` fields server-enforced on UPDATE (a -non-system PATCH forging `approval_status: 'approved'` is silently stripped in -the engine), but INSERT was exempt. For approval/status/verdict columns that -exemption was the *shorter* attack: instead of the #3003 draft-then-PATCH move, a -non-system caller could `POST` a record already `approval_status: 'approved'` in -one step — and the UPDATE-only strip never reached it. - -The strip now also runs on INSERT, but at the **external data-write ingress** -(`DataProtocol.createData` / `createManyData` / `batchData` / `cloneData`) rather -than in the engine. That seam is the single point every external programmatic -create funnels through — the REST CRUD route, the GraphQL/MCP dispatcher -(`bridge.create` → `callData` → `createData`), and bulk import — while **trusted -internal writers** (better-auth's adapter, the metadata repository, the seed -loader) call `engine.insert` directly and bypass it. Enforcing at the ingress -protects every caller/agent path at once without stripping the internal writers -that legitimately seed read-only columns on create (identity provisioning, -provenance stamps, event-log cursors) — the blast radius an engine-level insert -strip would have. - -- **Caller-forged only, at the ingress.** The payload here is raw caller input - (the security middleware stamps `owner_id` / `organization_id` later, inside - `engine.insert`), so only keys the caller actually sent are dropped; server - stamps are added afterwards and are unaffected. -- **Re-derives the default.** A stripped field falls back to its declared - `defaultValue` in the engine (a forged `approval_status` becomes `draft`, not - NULL). -- **System-context exempt.** `isSystem` writes still seed read-only columns. -- **Silent** (HTTP 2xx), per-row on batch/import. `readonlyWhen` stays - INSERT-exempt (a conditional lock needs a prior record). -- **Author-defined business objects only.** Platform objects (`managedBy` set, - or the `sys_` namespace) carry their own field-write governance that a silent - strip must not pre-empt — e.g. ADR-0086 REJECTS (403) a forged - `managed_by:'package'` on `sys_permission_set`, and #3004 rejects a forged - `owner_id`; several of those columns are `readonly`, so stripping them here - would swallow the payload the guard is meant to reject. The #3043 threat is app - approval/status fields, never `sys_` — the same boundary `applySystemFields` - uses for ownership. - -Behavior change: a non-system create through the data API (REST / GraphQL / MCP / -import) can no longer seed a `readonly` column from the payload. Flows that -legitimately write read-only columns at creation must run with a system context -(`isSystem`), the same requirement the UPDATE strip already imposes. diff --git a/.changeset/remove-dead-metadata-props-2377.md b/.changeset/remove-dead-metadata-props-2377.md deleted file mode 100644 index 24fb4240c..000000000 --- a/.changeset/remove-dead-metadata-props-2377.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -"@objectstack/spec": minor ---- - -feat(spec)!: remove dead author-facing metadata properties (#2377, ADR-0049 enforce-or-remove) - -Breaking spec-surface removal, versioned as `minor` per the launch-window changeset -policy (a `major` would promote the whole fixed-group monorepo; breaking cleanups ride -the minor line, as with #2402 → 11.1.0). - -Removes a batch of spec properties that parsed but had **no runtime consumer** — -authoring them was a false affordance (especially dangerous for AI-authored -metadata). Verified dead against the liveness ledger (`packages/spec/liveness/*.json`) -and a repo-wide grep of readers. This is the follow-up slice to #2402. - -## Removed (each was `dead` + no reader anywhere) - -- **field** (`field.zod.ts`): `vectorConfig` (+ `VectorConfigSchema` + types), - `fileAttachmentConfig` (+ `FileAttachmentConfigSchema` + types), `dependencies`. - Vector fields keep the live flat `dimensions` prop; file/image fields keep the - live flat `multiple`/`accept`/`maxSize` siblings. -- **object** (`object.zod.ts`): `versioning` (+ `VersioningConfigSchema`), - `softDelete` (+ `SoftDeleteConfigSchema`), `search` (+ `SearchConfigSchema`), - `recordName`, `keyPrefix`. Each is now a **rejecting tombstone** in - `UNKNOWN_KEY_GUIDANCE` carrying the upgrade prescription. -- **action** (`action.zod.ts`): `timeout` (server uses `body.timeoutMs`; no - action-level timeout is enforced). -- **agent** (`agent.zod.ts`): `planning.strategy`, `planning.allowReplan` - (only `planning.maxIterations` is read by the runtime). -- **dataset** (`dataset.zod.ts`): `measures.certified` (declared-but-unenforced - governance flag — never compiled into the Cube). - -Liveness ledgers, the ledger README table, and `api-surface.json` are updated; -the removed sub-schema keys are dropped from `json-schema.manifest.json`. - -## Migration - -- **field/agent/dataset/action props**: authoring them is now silently stripped - (they never did anything). Remove them. Vector → set flat `dimensions`; - file/image → set flat `multiple`/`accept`/`maxSize`. -- **object props**: `ObjectSchema.create()` now throws a located error naming the - replacement — `versioning`/`softDelete` → hard deletes + `Field.trackHistory` / - `lifecycle`; `search` → `searchableFields`; `recordName` → an `autonumber` - `Field` designated as `nameField`; `keyPrefix` → remove (never had an effect). - -## Deliberately NOT removed (dead, but entangled — a scoped follow-up) - -`field.index`/`columnName`/`referenceFilters` and object -`tags`/`active`/`isSystem`/`abstract`/`enable.searchable`/`enable.trash`/`enable.mru` -and `agent.tenantId` are surfaced in the Studio metadata-authoring forms -(`*.form.ts`) — removing them cascades into i18n bundle regeneration, so they are -deferred. `action.type:'form'` has a dedicated build-time lint (`lint-view-refs.ts`) -and a first-party showcase usage, so it needs a UX decision. `field.columnName` -additionally has an ADR-0062 D7 lint. These stay `dead` + `authorWarn` in the -ledgers. diff --git a/.changeset/remove-form-surfaced-dead-props-2377.md b/.changeset/remove-form-surfaced-dead-props-2377.md deleted file mode 100644 index 45e85bb38..000000000 --- a/.changeset/remove-form-surfaced-dead-props-2377.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -"@objectstack/spec": minor ---- - -feat(spec)!: remove form-surfaced dead metadata props + correct 3 misclassified-live entries (#2377, ADR-0049) - -The next enforce-or-remove slice of #2377. Versioned `minor` per the launch-window -policy (the fixed group makes a `major` promote the whole monorepo). - -## Removed (dead, no runtime reader — verified in both framework and objectui) - -- **field**: `columnName`, `index`, `referenceFilters`. This empties the field - dead-prop set. `columnName` also removed its now-moot **ADR-0062 D7** lint - (`validate-expressions.ts`), the dead `StorageNameMapping.resolveColumnName` / - `buildColumnMap` / `buildReverseColumnMap` helpers, and closes ADR-0062 R10 — - external physical-column mapping is `external.columnMap` only. -- **object**: `tags`, `active`, `abstract` — now rejecting tombstones in - `UNKNOWN_KEY_GUIDANCE`. -- **agent**: `tenantId`. - -The removed props are dropped from the authoring forms (`field/object/agent.form.ts`) -and the regenerated metadata-forms i18n bundles. - -## Corrected to `live` (the ledger was wrong — readers existed) - -- **object `isSystem`** — `plugin-sharing` `effectiveSharingModel` defaults a - no-`sharingModel` `isSystem` object to public; also read by the security-posture - lint. KEPT. -- **object `enable.searchable`** — `metadata-protocol` global search (`searchAll`) - uses `enable.searchable === false` as an opt-out. KEPT. -- **action `type:'form'`** — objectui `ActionRunner.executeForm` routes it to the - FormView at `/forms/:target`; a build-time lint validates the target. KEPT. - -## Deliberately deferred - -`object.enable.trash` / `enable.mru` — dead, but inert `default(true)` flags set by -~35 `sys-*.object.ts` files; removing them is high-churn / low-value. Left `dead` -(authorWarn-skipped). - -## Migration - -- field/agent props: authoring them was already a no-op; they now strip silently. - `columnName` → the physical column is always the field key (rename the field, or - use `external.columnMap` for external objects); `index` → declare it in object - `indexes[]`; `referenceFilters` → `lookupFilters`. -- object `tags`/`active`/`abstract`: `ObjectSchema.create()` now throws a located - error naming the removal. None gated anything at runtime — remove them. diff --git a/.changeset/retire-feed-contracts.md b/.changeset/retire-feed-contracts.md deleted file mode 100644 index 91021af2e..000000000 --- a/.changeset/retire-feed-contracts.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -"@objectstack/spec": minor -"@objectstack/metadata-protocol": minor -"@objectstack/client": minor -"@objectstack/objectql": patch ---- - -**Breaking (npm type surface): retire the vestigial feed contracts + protocol surface (ADR-0052 §5 follow-up, #1959).** - -The `service-feed` runtime was deleted in #1955; `sys_comment` / `sys_activity` -are the canonical record-collaboration/timeline backend. This removes the dead -type surface that still pointed at the deleted runtime — every removed method was -already unreachable (the feed REST route was never mounted → 404; the protocol -implementation was never wired with a feed service, so `requireFeedService()` -could only throw). No behavior changes. - -No authorable metadata key is removed (the `feeds:` object capability flag and -the `RecordActivity` UI component config are unchanged), so `PROTOCOL_MAJOR` -stays 15 and this ships as `minor` rather than a protocol major. - -FROM → TO migration for every removed export: - -- `@objectstack/spec/contracts` — `IFeedService`, `CreateFeedItemInput`, - `UpdateFeedItemInput`, `ListFeedOptions`, `FeedListResult` → **removed, no - replacement**. Comments/activity are plain records: write `sys_comment` / read - `sys_activity` via the data engine or the REST data API. -- `@objectstack/spec/api` — `FeedApiContracts`, `FeedApiErrorCode`, - `FeedProtocol`, and all feed request/response schemas + types (`GetFeed*`, - `CreateFeedItem*`, `UpdateFeedItem*`, `DeleteFeedItem*`, `AddReaction*`, - `RemoveReaction*`, `PinFeedItem*`, `UnpinFeedItem*`, `StarFeedItem*`, - `UnstarFeedItem*`, `SearchFeed*`, `GetChangelog*`, `ChangelogEntry`, - `SubscribeRequest/Response`, `FeedUnsubscribeRequest`, `UnsubscribeResponse`, - `FeedPathParams`, `FeedItemPathParams`, `FeedListFilterType`) → **removed**. Use - the data API against `sys_comment` / `sys_activity` (`/api/v1/data/sys_comment/…`); - reactions and threaded replies are fields on `sys_comment`. -- `@objectstack/spec/data` — `FeedItemSchema`/`FeedItem`, `FeedActorSchema`/`FeedActor`, - `MentionSchema`/`Mention`, `ReactionSchema`/`Reaction`, - `FieldChangeEntrySchema`/`FieldChangeEntry`, `FeedVisibility`, - `RecordSubscriptionSchema`/`RecordSubscription`, `SubscriptionEventType`, and the - `data`-namespace `NotificationChannel` → **removed**. `FeedItemType` and - `FeedFilterMode` are **kept** (live UI activity-timeline config). For notification - channels use `NotificationChannelSchema` from `@objectstack/spec/system`. -- `@objectstack/client` — `client.feed.*` (`list` / `create` / `update` / `delete` / - `addReaction` / `removeReaction` / `pin` / `unpin` / `star` / `unstar` / `search` / - `getChangelog` / `subscribe` / `unsubscribe`) and the re-exported feed response - types → **removed**. One-line fix: use `client.data.*` on `sys_comment` / - `sys_activity`, e.g. `client.data.create('sys_comment', { object, record_id, body })` - and `client.data.find('sys_activity', { filters: [['record_id', '=', id]] })`. -- `@objectstack/metadata-protocol` — `ObjectStackProtocolImplementation` no longer - implements the 14 feed methods; its constructor - `(engine, getServicesRegistry?, getFeedService?, environmentId?)` becomes - `(engine, getServicesRegistry?, environmentId?)`. One-line fix: delete the third - argument. diff --git a/.changeset/retire-feed-discovery-surface.md b/.changeset/retire-feed-discovery-surface.md deleted file mode 100644 index bdad54d6f..000000000 --- a/.changeset/retire-feed-discovery-surface.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -"@objectstack/spec": minor -"@objectstack/metadata-protocol": patch -"@objectstack/client": patch ---- - -**Breaking (discovery response shape): retire the residual feed capability surface (#3180, follow-up to #1959 / ADR-0052 §5).** - -The feed backend was retired long ago; #1959 removed the feed contracts + SDK. This -removes the last discovery/dispatcher references to it, and fixes a real bug where the -`comments` capability was permanently `false`. - -- `@objectstack/spec` — `WellKnownCapabilitiesSchema.feed` and `ApiRoutesSchema.feed` - (`routes.feed`) are **removed**, and the `/api/v1/feed` entry is dropped from - `DEFAULT_DISPATCHER_ROUTES`. FROM → TO: clients reading `discovery.capabilities.feed` - or `discovery.routes.feed` → use `discovery.capabilities.comments`; comments/activity - are served by the generic data API on `sys_comment` / `sys_activity` - (`/api/v1/data/sys_comment/…`). -- `@objectstack/metadata-protocol` — `getDiscovery()` no longer emits the always-`false` - `feed` service/capability. **Bug fix:** the `comments` capability previously keyed off - the deleted `'feed'` service (so it was permanently `false` after #1955); it now tracks - the presence of the `sys_comment` object (provided by the always-on audit slate), so - `declared === enforced`. -- `@objectstack/client` — the internal `feed: '/api/v1/feed'` route constant is removed - (it only existed to satisfy the now-removed `ApiRoutes.feed` type; no client code used it). diff --git a/.changeset/scaffold-default-connector-executors.md b/.changeset/scaffold-default-connector-executors.md deleted file mode 100644 index ca3707fd4..000000000 --- a/.changeset/scaffold-default-connector-executors.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -"create-objectstack": minor ---- - -feat(create-objectstack): the blank scaffold ships the three generic connector executors by default - -`npm create objectstack` now generates an `objectstack.config.ts` that wires the -`rest`, `openapi`, and `mcp` connector executor plugins (ADR-0022/0023/0024 + -ADR-0097) into `plugins:`, alongside `requires: ['automation']`. This closes the -last authoring gap in the ADR-0097 promise that integrations are expressible -**and executable** as pure metadata: an author (human or AI) can now add a -declarative `connectors:` entry naming `provider: 'rest' | 'openapi' | 'mcp'` -and have it materialize into a live, dispatchable connector at boot — with no -host-code edit. - -- `plugins:` — `new ConnectorRestPlugin()`, `new ConnectorOpenApiPlugin()`, - `new ConnectorMcpPlugin()` (zero-arg = contribute the provider factory only). -- `requires: ['automation']` — the automation service performs the - materialization and owns the registry the executors register into. It is also - a hard dependency of the connector plugins, so a scaffold that lists them in - `plugins:` without it fails boot; automation ships transitively via - `@objectstack/cli`. -- deps — `@objectstack/connector-rest`, `@objectstack/connector-openapi`, - `@objectstack/connector-mcp`. -- Security (#3055): declarative `mcp` stdio transports stay denied by default — - opt in per host with `new ConnectorMcpPlugin({ declarativeStdio: ['node'] })`. - -Brand connectors (Slack, …) remain marketplace/opt-in. diff --git a/.changeset/scaffold-gitignore-survives-publish.md b/.changeset/scaffold-gitignore-survives-publish.md deleted file mode 100644 index 67fb4c2b0..000000000 --- a/.changeset/scaffold-gitignore-survives-publish.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -"create-objectstack": patch ---- - -Scaffolded projects ship with a `.gitignore` again — `npx create-objectstack` produced none, leaving `node_modules/` and `.env` un-ignored for every new user. - -`npm pack` / `pnpm pack` strip `.gitignore` from a tarball unconditionally, at every depth. The blank template committed one at `src/templates/blank/.gitignore` and the build faithfully copied it to `dist/templates/blank/.gitignore`, but `files: ["dist"]` publishing dropped it on the way to the registry — so the file was present in the repo, present in every local build, and absent from all 11 files of a real scaffold. Verified against the published 15.1.1 tarball, which ships `dist/templates/blank/.dockerignore` and no `.gitignore`. - -The template is now committed as `_gitignore` (a name npm does not strip) and restored to `.gitignore` when the template is copied, via a `TEMPLATE_FILE_ALIASES` map in the new `template-copy.ts`. Only `.gitignore` is aliased: the strip list is `.gitignore` and `.npmrc`, not "every dotfile" — `.dockerignore` packs fine and stays literal. - -The restored ignore rules also cover `.env` / `.env.*`, which they never did. The template README has users write `OS_AUTH_SECRET` and `OS_SECRET_KEY` into a `.env`, and `docker-compose.yml` calls that file "never committed" — but only the prose said so, and `.dockerignore` was the only file that listed it. - -A packing ratchet in `template-consistency.test.ts` guards both halves: it packs the real package, scaffolds from the extracted tarball with the real copy logic, and asserts every template file lands under its intended name. Source-level assertions cannot see this class of bug — the file only vanishes at publish. diff --git a/.changeset/scaffold-pnpm11-build-approvals.md b/.changeset/scaffold-pnpm11-build-approvals.md deleted file mode 100644 index 5472aa39a..000000000 --- a/.changeset/scaffold-pnpm11-build-approvals.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -"create-objectstack": patch ---- - -fix(create-objectstack): the blank scaffold declares pnpm build approvals, so a fresh `pnpm install` no longer exits 1 on pnpm 11 - -pnpm 11 turned an unapproved dependency build script from a warning into a hard -error. The blank template declared no build approvals, so the very first command -a new user runs failed on any current pnpm: - -``` -npx create-objectstack myapp && cd myapp && pnpm install -# [ERR_PNPM_IGNORED_BUILDS] Ignored build scripts: better-sqlite3@12.11.1, esbuild@0.28.1 -# exit 1 -``` - -The scaffold now ships a `pnpm-workspace.yaml` approving the two packages it -actually depends on building — `better-sqlite3` (the native sqlite driver behind -`@objectstack/driver-sql`) and `esbuild` (compiles `objectstack.config.ts`). - -Both approval keys are present because pnpm reads them by version, and neither -alone covers the supported range: - -- `allowBuilds` (a package → boolean map) — the only key pnpm 11 honors, and - understood back to pnpm 10.31. `onlyBuiltDependencies` alone still errors. -- `onlyBuiltDependencies` (a list) — pnpm 10.0–10.30, which ignore `allowBuilds`. - -npm and yarn ignore the file, so the npm install path is unaffected. Both -packages ship prebuilt binaries, so this was an install-time hard stop rather -than a runtime defect — the project ran fine once installed. - -This is the #3091 failure class (in-repo settings masking what users resolve) -and was caught by the publish smoke gate added in #3100, which installs the -release candidate the way a user does — on whatever pnpm corepack hands a fresh -machine. diff --git a/.changeset/scaffold-skill-catalog-boundary.md b/.changeset/scaffold-skill-catalog-boundary.md deleted file mode 100644 index 5d4168b7d..000000000 --- a/.changeset/scaffold-skill-catalog-boundary.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"create-objectstack": patch ---- - -Stop leaking repo-internal skills into scaffolded projects. The scaffolder (and the docs) advertised `npx skills add objectstack-ai/framework --all`, and the skills CLI's `--all` implies `--skill '*'` — which includes even `metadata.internal` skills — so repo-internal tooling like `.claude/skills/dogfood-verification` landed in every new project's `.agents/skills/`. All install commands are now scoped to the published catalog via the `/skills` subpath (`npx skills add objectstack-ai/framework/skills --all`), the internal skill is additionally marked `metadata.internal: true` to hide it from interactive discovery, and a template-consistency ratchet plus a scaffold-e2e assertion keep the boundary from regressing. diff --git a/.changeset/seed-replay-lookup-corruption.md b/.changeset/seed-replay-lookup-corruption.md deleted file mode 100644 index 230f31fd6..000000000 --- a/.changeset/seed-replay-lookup-corruption.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -"@objectstack/metadata-protocol": patch -"@objectstack/runtime": patch ---- - -fix(seed): replaying seeds no longer corrupts lookup natural keys on the upsert update path - -Every dev-server restart replayed package seeds in upsert mode, and any record whose -lookup/master_detail was authored as a natural key could have that reference overwritten -with NULL on the update path (`NOT NULL constraint failed` on required columns; silent -link loss on nullable ones). Four fixes: - -- An unresolved reference now leaves the column untouched (deferred to pass 2) or drops - the record loudly — it is never written as NULL over an existing row. -- DB-side reference resolution probes the target dataset's declared `externalId` (e.g. - `email`) before falling back to `name` and `id`, matching how in-memory resolution - already keyed records. -- A rejected update (e.g. a `state_machine` rule vetoing the replay) no longer severs - natural-key resolution for downstream child datasets. -- Replays are idempotent: an upsert/update whose declared fields already match the - existing row is skipped instead of rewritten (no more `updated_at` churn or lifecycle - re-validation on every boot). diff --git a/.changeset/seed-replayer-skipped.md b/.changeset/seed-replayer-skipped.md deleted file mode 100644 index 2e583096d..000000000 --- a/.changeset/seed-replayer-skipped.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -"@objectstack/runtime": patch ---- - -feat(runtime): seed-replayer reports `skipped` so hosts can stamp seed-once on progress - -The `seed-replayer` kernel service returned `{ inserted, updated, errors }` but -not `skipped`. A cloud host therefore could not tell an **all-skip replay** -(the env's seed data is already present — a no-op) apart from the -zero-summary early-returns that never ran the loader (no organization, no -metadata service, no datasets). Both looked like `inserted = updated = 0`, so -the host could not safely stamp its seed-once record for the all-skip case and -re-ran the full remote replay on every cold boot. - -Add `skipped: result.summary.totalSkipped` to the replayer's return; the -early-returns report `skipped: 0`. This lets a host (cloud#853's -`decideSeedStamp`) stamp on progress — including an all-skip replay — while -still declining to stamp a genuine no-loader zero-summary. Additive and -backward compatible; existing consumers ignore the new field. diff --git a/.changeset/server-timing-perf-spans-2408.md b/.changeset/server-timing-perf-spans-2408.md deleted file mode 100644 index a9f86aaf0..000000000 --- a/.changeset/server-timing-perf-spans-2408.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -"@objectstack/observability": patch -"@objectstack/driver-sql": patch -"@objectstack/runtime": patch -"@objectstack/plugin-hono-server": patch ---- - -feat(observability): decompose `Server-Timing` into auth / db / hooks / serialize spans (perf-tuning mode) - -The opt-in `Server-Timing` header now breaks a request's server time into the phases that actually explain it, so an operator can open DevTools → Network → Timing and see where the time went without standing up an external tracing backend: - -- **`db`** — total SQL time with a **query count**. The SQL driver wires knex's `query` / `query-response` events (keyed by `__knexQueryUid`) and folds each query into one aggregate member (`db;dur=210;desc="6 queries"`) — the query count is the number most useful for spotting N sequential round-trips. Timing is attributed to the originating request via `AsyncLocalStorage`, so it is correct under concurrency and never cross-attributes. SQL text is never emitted, only durations and a count. -- **`auth`** — identity / session resolution in the dispatcher, the prime suspect for unexplained data-API overhead. -- **`hooks`** — total business-hook execution time with a hook count, fed through the engine's existing `HookMetricsRecorder` seam (wired from the runtime, so `@objectstack/objectql`'s lean `core` tier stays observability-free). -- **`serialize`** — response JSON encoding in the HTTP adapter. - -Adds `countServerTiming(name, dur, unit)` (and `PerfTiming.count`) to fold high-frequency phases into a single aggregate member instead of flooding the header. Every phase is a no-op when perf-tuning is off (`serverTiming: true` / `OS_SERVER_TIMING=true`), so there is zero measurable overhead on the normal path. - -Closes #2408. diff --git a/.changeset/state-machine-initial-states.md b/.changeset/state-machine-initial-states.md deleted file mode 100644 index 4556cf1ce..000000000 --- a/.changeset/state-machine-initial-states.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -"@objectstack/spec": minor -"@objectstack/objectql": minor ---- - -feat(validation): `state_machine.initialStates` enforces the FSM entry point on INSERT (#3165) - -A `state_machine` rule's `transitions` only governs UPDATE — on INSERT the rule -was a no-op, and a `select` field permits ANY declared option as the initial -value. So a record could be born mid-flow (created already `approved`), skipping -the whole state machine. This was the gap #3043's mitigation idea assumed didn't -exist (declared ≠ enforced, ADR-0049). - -`state_machine` rules gain an optional `initialStates: string[]` — the states a -record may be CREATED in. When set, an insert whose (defaulted) state-field value -is outside the list is rejected server-side with `code: 'invalid_initial_state'`. -Omit it to keep the legacy behavior (no initial-state check on insert). A missing -/ empty value is left to required-validation; `transitions` (UPDATE) is -unaffected. Enforced at the same `evaluateValidationRules(..., 'insert')` seam the -engine already runs after field defaults. diff --git a/.changeset/systemfields-drop-owner-key.md b/.changeset/systemfields-drop-owner-key.md deleted file mode 100644 index 7901cc8f9..000000000 --- a/.changeset/systemfields-drop-owner-key.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -"@objectstack/spec": minor ---- - -fix(spec): drop the dead `systemFields.owner` key (#3175 follow-up) - -`ObjectSchema.systemFields` exposed an `owner?: boolean` opt-out key that nothing -read — the registry (`applySystemFields`) only consumes `systemFields.tenant` and -`systemFields.audit`, and `owner_id` provisioning is governed by the object-level -`ownership` property (`'user' | 'org' | 'none'`, made first-class in #3185). The -key was declared but wired to nothing. - -Removed it so the schema only advertises the two opt-outs it actually honors -(`tenant`, `audit`). Backward-compatible at runtime: the key was ignored before and -is stripped now (both no-ops). A TypeScript author who set `systemFields.owner` -will now see an excess-property error — the fix is to delete the key (it never did -anything) or use `ownership: 'org' | 'none'` to skip `owner_id`. Also corrected the -stale `objectql/security` doc that called `audit` "reserved" (it is active). diff --git a/.changeset/tidy-views-guard.md b/.changeset/tidy-views-guard.md deleted file mode 100644 index 29236abdd..000000000 --- a/.changeset/tidy-views-guard.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@objectstack/spec": patch -"@objectstack/lint": patch -"@objectstack/cli": patch ---- - -Reject view containers that define no views. A flat list-view object (`{ name, label, type, columns, ... }`) parses to an empty `ViewSchema` container because Zod strips unknown keys — zero views register and the Console silently renders nothing. `defineView()` now throws on a zero-view container, and `os validate` gains a `view-container-shape` check (`validateViewContainers` in `@objectstack/lint`) that reports flat or empty `views: []` entries pre-parse with a wrap-it fix hint. diff --git a/.changeset/tier4-type-soundness-warnings.md b/.changeset/tier4-type-soundness-warnings.md deleted file mode 100644 index 628827e21..000000000 --- a/.changeset/tier4-type-soundness-warnings.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -"@objectstack/formula": minor -"@objectstack/lint": minor ---- - -feat(formula,lint): advisory type-soundness warnings for formula/predicate expressions (#1928 tier 4) - -Closes the last open guardrail from #1928. A `Field.formula` or record-scoped -predicate that uses a **text or boolean field with an arithmetic (`+ - * / %`) -or ordering (`< > <= >=`) operator against a number** faults the runtime -overload and silently evaluates to `null` (e.g. `record.title * 2`, -`record.is_active + 1`). The build now surfaces this as a **non-blocking -warning** with the offending field and a corrective message. - -Honours the ADR-0032 design law — the checker only flags what the runtime -would also fail: - -- Number / currency / percent / date / datetime fields are declared `dyn`, so - the cases the runtime rescues never warn — `record.amount / 100` (the #1930 - `registerOperator` fix), `record.due == today()` and numeric-string / ISO-date - values (the string-hydration retry), and numeric-coded `select` option values. -- Equality (`==` / `!=`) is excluded: a heterogeneous equality is runtime-safe - (evaluates to `false`), never a fault. - -New `firstTypeMismatch(source, fieldCelTypes, scope)` export in -`@objectstack/formula` (and an optional `fieldTypes` hint on -`validateExpression`); `@objectstack/lint`'s `validateStackExpressions` threads -each object's field types into every checked site: - -- **record-scoped** sites (`record.`) — formula fields, validation rules, - action / hook / sharing predicates; -- **flattened** flow / automation conditions (bare `field`) — where flow - variables stay `dyn` and are never flagged, and equality stays runtime-safe. - -Warnings are advisory in `objectstack build` / `validate` (fatal only under -`--strict`), matching the tier-3 channel. diff --git a/.changeset/trim-validation-delete-event.md b/.changeset/trim-validation-delete-event.md deleted file mode 100644 index 67dca51bc..000000000 --- a/.changeset/trim-validation-delete-event.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@objectstack/spec": patch ---- - -Remove the dead `'delete'` member from the validation-rule `events` enum (#3184). The rule evaluator only runs on the insert/update write path — `engine.delete` never invokes it — so a rule declaring `events: ['delete']` was a silent no-op (flagged in #3106 and `docs/audits/2026-06-validationschema-property-liveness.md`). The enum now admits only `insert`/`update`; guard deletions with a `beforeDelete` lifecycle hook instead. No shipped metadata declares `events: ['delete']`; any off-spec metadata that did now fails loudly at `os validate` / registration rather than parsing and doing nothing. Also narrows the two hand-written mirrors (`rule-validator.ts` `BaseRule`, `metadata-protocol` JSON-schema form helper — whose stale `type` enum listing removed `unique`/`async`/`custom` variants is corrected in the same pass), updates the doc comments, the published data skill, and the hand-written validation doc. diff --git a/.changeset/trim-webhook-dead-triggers.md b/.changeset/trim-webhook-dead-triggers.md deleted file mode 100644 index 4c898be4c..000000000 --- a/.changeset/trim-webhook-dead-triggers.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@objectstack/spec": patch -"@objectstack/plugin-webhooks": patch ---- - -Trim the dead `undelete` and `api` webhook triggers (#3196). `WebhookTriggerType` declared five triggers but only three ever fired: - -- `undelete` had no event source — the engine has no soft-delete/restore capability (`delete` is a hard delete; no `deleted_at` convention, no restore operation, and `data.record.undeleted` is never emitted). The `undeleted` case in the auto-enqueuer's action mapper was dead code awaiting a producer that doesn't exist. -- `api` ("manually triggered") had no fire path — the only webhook HTTP surface re-queues already-failed deliveries; nothing originates a manual fire. - -Both are removed from the enum (contract-first, matching #3184/#3195): authoring a webhook on a removed trigger now fails loudly at `os validate` / registration instead of registering a webhook that silently never fires. No shipped webhook metadata used either. The auto-enqueuer now also warns when a persisted `sys_webhook` row carries a trigger it can't map to an emitted record event (a drift-guard, so a dead trigger can't silently no-op again). Reintroduce `undelete` only alongside a real restore subsystem, and `api` only alongside a real manual-fire endpoint. Updated the `sys_webhook` trigger options, field help (all locales), docs, and reference; added rejection tests. diff --git a/.changeset/view-metadata-type-schema-runtime-shapes.md b/.changeset/view-metadata-type-schema-runtime-shapes.md deleted file mode 100644 index ac5117881..000000000 --- a/.changeset/view-metadata-type-schema-runtime-shapes.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -"@objectstack/spec": patch ---- - -**The `view` metadata type-schema now validates all three runtime `view` shapes instead of stripping two of them to `{}`.** `metadata-type-schemas.ts` mapped `view` to the aggregate container `ViewSchema` (`{ list, form, listViews, formViews }`, every slot optional). Zod strips unknown keys, so the two non-container shapes a `view` body actually carries at runtime — a standalone **ViewItem record** (`{ name, object, viewKind, config }`) and a **console personalization overlay** (raw view config + identity inherited by `normalizeViewMetadata`, #2555) — both strip-parsed to `{}`. That made the `422` check in `saveMetaItem` and read-time `computeMetadataDiagnostics` a **no-op** for those shapes: a broken `config` (e.g. a kanban missing `groupByField`) saved with a false `200` and badged valid, and the view create-seed test validated against nothing. - -`view` now maps to a new `ViewMetadataSchema` — a union over the three shapes, each validated genuinely: - -1. **defineView container** — non-empty (`ViewSchema` refined to require at least one of `list`/`form`/`listViews`/`formViews`; an empty container is rejected, mirroring `defineView`). -2. **ViewItem record** — `ViewItemSchema`; the nested `config` is validated against ListView/FormView. -3. **Flattened personalization overlay** — inline ListView/FormView config plus optional identity fields. Structural guards pin `config`/`list`/`form`/`listViews`/`formViews` to `undefined` so a malformed record or container can never be rescued through this lenient branch with its real payload silently stripped. - -All members strip-parse (no `.strict()`), so auxiliary Studio round-trip keys (`isPinned`, `sortOrder`, …) still ride along without a false `422`, and `saveMetaItem` keeps persisting the body verbatim. `z.toJSONSchema()` emits the schema as an `anyOf` of the four members, which `/api/v1/meta/types/view` serves to Studio's SchemaForm. - -Fixes #3095. diff --git a/examples/app-crm/CHANGELOG.md b/examples/app-crm/CHANGELOG.md index a4abb372a..8cb5da393 100644 --- a/examples/app-crm/CHANGELOG.md +++ b/examples/app-crm/CHANGELOG.md @@ -1,5 +1,36 @@ # @objectstack/example-crm +## 4.0.90 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [a3823b2] +- Updated dependencies [fdc244e] +- Updated dependencies [5e3301d] +- Updated dependencies [2ea08ee] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [2049b6a] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [515f11a] +- Updated dependencies [4174a07] +- Updated dependencies [ce468c8] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/runtime@15.2.0 + ## 4.0.89 ### Patch Changes diff --git a/examples/app-crm/package.json b/examples/app-crm/package.json index 9097ec6a0..131609c9e 100644 --- a/examples/app-crm/package.json +++ b/examples/app-crm/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/example-crm", - "version": "4.0.89", + "version": "4.0.90", "description": "Minimal CRM example — a smoke-test workspace that exercises the metadata loading pipeline (objects → views → app → dashboard → hook → flow → seed). For a full-featured enterprise CRM see https://github.com/objectstack-ai/hotcrm.", "license": "Apache-2.0", "private": true, diff --git a/examples/app-showcase/CHANGELOG.md b/examples/app-showcase/CHANGELOG.md index 291fc0a6c..7315e431c 100644 --- a/examples/app-showcase/CHANGELOG.md +++ b/examples/app-showcase/CHANGELOG.md @@ -1,5 +1,45 @@ # @objectstack/example-showcase +## 0.3.12 + +### Patch Changes + +- Updated dependencies [41e703b] +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [a3823b2] +- Updated dependencies [fdc244e] +- Updated dependencies [5e3301d] +- Updated dependencies [2ea08ee] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [efbcfe1] +- Updated dependencies [2049b6a] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [515f11a] +- Updated dependencies [4174a07] +- Updated dependencies [ce468c8] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/connector-openapi@15.2.0 + - @objectstack/spec@15.2.0 + - @objectstack/runtime@15.2.0 + - @objectstack/driver-sql@15.2.0 + - @objectstack/cloud-connection@15.2.0 + - @objectstack/connector-mcp@15.2.0 + - @objectstack/connector-rest@15.2.0 + - @objectstack/connector-slack@15.2.0 + - @objectstack/service-datasource@15.2.0 + ## 0.3.11 ### Patch Changes diff --git a/examples/app-showcase/package.json b/examples/app-showcase/package.json index fba1e6e6b..4a99be56e 100644 --- a/examples/app-showcase/package.json +++ b/examples/app-showcase/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/example-showcase", - "version": "0.3.11", + "version": "0.3.12", "description": "Kitchen-sink showcase workspace — exercises every metadata type, every view type, every chart type, and the major end-to-end capability chains (security, automation, analytics). Built for demonstration, debugging, and coverage-driven verification.", "license": "Apache-2.0", "private": true, diff --git a/examples/app-todo/CHANGELOG.md b/examples/app-todo/CHANGELOG.md index 5cb1024d7..1b3e14425 100644 --- a/examples/app-todo/CHANGELOG.md +++ b/examples/app-todo/CHANGELOG.md @@ -1,5 +1,45 @@ # @objectstack/example-todo +## 4.0.90 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [fdc244e] +- Updated dependencies [5e3301d] +- Updated dependencies [2ea08ee] +- Updated dependencies [230358c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [2049b6a] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [515f11a] +- Updated dependencies [4174a07] +- Updated dependencies [ce468c8] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/objectql@15.2.0 + - @objectstack/metadata@15.2.0 + - @objectstack/runtime@15.2.0 + - @objectstack/mcp@15.2.0 + - @objectstack/client@15.2.0 + - @objectstack/driver-sqlite-wasm@15.2.0 + - @objectstack/knowledge-memory@15.2.0 + - @objectstack/service-knowledge@15.2.0 + ## 4.0.89 ### Patch Changes diff --git a/examples/app-todo/package.json b/examples/app-todo/package.json index ad1d85fdb..79fcb7fba 100644 --- a/examples/app-todo/package.json +++ b/examples/app-todo/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/example-todo", - "version": "4.0.89", + "version": "4.0.90", "description": "Example Todo App using ObjectStack Protocol", "license": "Apache-2.0", "private": true, diff --git a/examples/embed-objectql/CHANGELOG.md b/examples/embed-objectql/CHANGELOG.md index 7d49610a7..10442e10a 100644 --- a/examples/embed-objectql/CHANGELOG.md +++ b/examples/embed-objectql/CHANGELOG.md @@ -1,5 +1,34 @@ # @objectstack/example-embed-objectql +## 0.0.30 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [fdc244e] +- Updated dependencies [5e3301d] +- Updated dependencies [2ea08ee] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/objectql@15.2.0 + - @objectstack/driver-memory@15.2.0 + ## 0.0.29 ### Patch Changes diff --git a/examples/embed-objectql/package.json b/examples/embed-objectql/package.json index 28450981d..c5bb38846 100644 --- a/examples/embed-objectql/package.json +++ b/examples/embed-objectql/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/example-embed-objectql", - "version": "0.0.29", + "version": "0.0.30", "private": true, "description": "Embed the ObjectQL engine as a plain library via @objectstack/objectql/core — no kernel, no plugins, no metadata protocol (ADR-0076).", "type": "module", diff --git a/packages/adapters/hono/CHANGELOG.md b/packages/adapters/hono/CHANGELOG.md index eb51cc9ba..e83f42ab6 100644 --- a/packages/adapters/hono/CHANGELOG.md +++ b/packages/adapters/hono/CHANGELOG.md @@ -1,5 +1,20 @@ # @objectstack/hono +## 15.2.0 + +### Patch Changes + +- Updated dependencies [fdc244e] +- Updated dependencies [2ea08ee] +- Updated dependencies [efbcfe1] +- Updated dependencies [2049b6a] +- Updated dependencies [515f11a] +- Updated dependencies [4174a07] +- Updated dependencies [ce468c8] + - @objectstack/runtime@15.2.0 + - @objectstack/plugin-hono-server@15.2.0 + - @objectstack/types@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/adapters/hono/package.json b/packages/adapters/hono/package.json index 018b9b206..e61591fab 100644 --- a/packages/adapters/hono/package.json +++ b/packages/adapters/hono/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/hono", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/apps/account/CHANGELOG.md b/packages/apps/account/CHANGELOG.md index c50c05a17..2164114aa 100644 --- a/packages/apps/account/CHANGELOG.md +++ b/packages/apps/account/CHANGELOG.md @@ -1,5 +1,30 @@ # @objectstack/account +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/platform-objects@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/apps/account/package.json b/packages/apps/account/package.json index d1dee90ea..b39ee3254 100644 --- a/packages/apps/account/package.json +++ b/packages/apps/account/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/account", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "ObjectStack Account — the end-user account/self-service console app, packaged as its own ObjectStack app package (ADR-0048: one app per package).", "main": "dist/index.js", diff --git a/packages/apps/setup/CHANGELOG.md b/packages/apps/setup/CHANGELOG.md index af8a82e5f..1452b948d 100644 --- a/packages/apps/setup/CHANGELOG.md +++ b/packages/apps/setup/CHANGELOG.md @@ -1,5 +1,30 @@ # @objectstack/setup +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/platform-objects@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/apps/setup/package.json b/packages/apps/setup/package.json index ed69a4d47..56ca292f3 100644 --- a/packages/apps/setup/package.json +++ b/packages/apps/setup/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/setup", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "ObjectStack Setup — the platform administration app, packaged as its own ObjectStack app package (ADR-0048: one app per package).", "main": "dist/index.js", diff --git a/packages/apps/studio/CHANGELOG.md b/packages/apps/studio/CHANGELOG.md index 835885226..7dd44e636 100644 --- a/packages/apps/studio/CHANGELOG.md +++ b/packages/apps/studio/CHANGELOG.md @@ -1,5 +1,30 @@ # @objectstack/studio +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/platform-objects@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/apps/studio/package.json b/packages/apps/studio/package.json index a68667a64..001aa6e45 100644 --- a/packages/apps/studio/package.json +++ b/packages/apps/studio/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/studio", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "ObjectStack Studio — the metadata builder app, packaged as its own ObjectStack app package (ADR-0048: one app per package).", "main": "dist/index.js", diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 8736b9517..5bac98f5f 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,185 @@ # @objectstack/cli +## 15.2.0 + +### Minor Changes + +- 2ea08ee: Flow trigger observability — kill the four-layer silence around record-change flows that never fire (2026-07-17 third-party eval). + + A misauthored auto-launched flow (wrong `objectName`, missing `requires: ['automation','triggers']`, failing start condition) produced ZERO output at every layer: the engine's own registration/binding logs land inside the CLI's boot-quiet stdout window (which swallows debug/info/warn — only error/fatal reach stderr), and each "didn't happen" path was itself silent. Fixes: + + - **Startup banner `Flows:` section** (`os serve`/`os dev`/`os start`): flow count, bound-to-trigger count, registered trigger types, draft count — plus loud `⚠` lines for flows declared with no automation engine enabled (`requires` missing), flows whose trigger type has no registered trigger, and bound record-change flows targeting an unknown object (dead binding). Printed after stdout is restored, so it is immune to the boot-quiet window. + - **Trigger-fired run failures now log at ERROR** (stderr — always visible): the automation engine no longer drops the AutomationResult of a trigger-fired execution; condition-evaluation faults and node failures surface with the flow name. Condition-not-met skips stay at debug (high-frequency, intentional). + - **`RecordChangeTrigger` probes object existence at bind time** and warns when a flow's `objectName` matches no registered object (exact-name matching), instead of silently arming a hook that can never fire. + - **`kernel:bootstrapped` binding audit** in the automation plugin: warns per enabled-but-unbound triggered flow with the reason, and reports registered/bound/draft counts (`AutomationEngine.getTriggerBindingAudit()`, extended `getFlowRuntimeStates()` with `status`/`triggerType`/`object`). + - **`os validate` flow-wiring advisories** (`@objectstack/lint` `validateFlowTriggerReadiness`): warns when a record-triggered flow targets an object the stack does not define, and when an auto-triggered flow's status is `draft` (authored or defaulted — draft flows still fire; declare `active` or `obsolete`). + - Removed leftover boot-debug writes (`registerApp`/`AppPlugin`/`StandaloneStack`/`AuditPlugin` stderr noise) that previous debugging of this same silence had left behind. + +### Patch Changes + +- fb107b8: fix(cli): tolerate the `--` separator pnpm injects when forwarding script args (#3114) + + The AGENTS.md-documented backend-debug flow `pnpm dev -- --fresh -p ` failed at + the repo root with an opaque `Unexpected arguments: -p, 44637` (exit 2 + a help dump). + + pnpm appends forwarded args to a script **verbatim, including the `--`**, and each + nested `pnpm --filter` hop preserves it, so the showcase's `objectstack dev +--seed-admin` ran as `objectstack dev --seed-admin -- --fresh -p 44637`. oclif reads + `--` as POSIX end-of-flags, so everything after it became positional: `--fresh` was + silently swallowed as the `package` arg and `-p 44637` overflowed the arg list. Every + flag the user asked for was dropped — the failure was opaque precisely because the + `--` looks inert. + + A `preparse` hook now drops `--` separators before oclif parses argv, so the + npm-style `-- ` form and the bare form behave identically, for every command + and both bins (`run.js`, `run-dev.js`). No `os` command takes passthrough args (none + sets `strict = false`, none reads raw argv), so a `--` carries no meaning here and is + always a package-manager artifact. + + Note this is not fixable via oclif's `'--': false` parser option: that keeps + flag-parsing on past the separator but re-appends the `--` into argv, so strict + commands fail with `Unexpected argument: --` instead. + + Tradeoff: a `-`-prefixed token can no longer be forced to parse as a positional + value. Every `os` positional is a config path, a metadata / datasource / package + name, or an id — none start with `-`. + +- fdc244e: Dev-loop DX fixes from the 15.1 third-party evaluation (P2 batch): + + - **Hot-added objects are now queryable without a restart.** Adding a `*.object.ts` under `os dev` used to recompile "green" while every query answered `no such table` (or `not registered`) until a manual restart: the artifact reload never notified the ObjectQL registry, tables were only created at boot, and seeds only loaded from the boot-time bundle. The `metadata:reloaded` payload now carries the parsed artifact; ObjectQL ingests the object definitions and re-runs the idempotent schema sync (same `skipSchemaSync` opt-out as boot), and the runtime loads seeds for first-seen objects (dev, single-tenant). `os dev` also prints `✚ new object(s): …` on recompile. + - **Dev admin credentials stay visible.** The `os dev` startup banner only showed `admin@objectos.ai / admin123` on the boot that actually seeded it; with the persistent default DB every later boot hid it, and the Console login page never knew it existed. The hint now re-arms on every dev boot for as long as the account still verifies against the default password, and `GET /api/v1/auth/config` exposes a dev-gated `devSeedAdmin` field (never present outside `NODE_ENV=development`) so the login page can show it. + - **`os doctor` reference analysis understands current metadata shapes.** Objects bound through `defineView` containers (`list`/`listViews`/`form`/`formViews` → `data.object`, subform `childObject`, lookup form fields) and app navigation (`objectName`, nested `children`, `areas`) were reported as "defined but not referenced". The collector now walks the canonical shapes (plus flow node `config.object`/`objectName`) and the orphan-view check descends into containers. + +- f58db35: fix(cli): treat an inline `label:` as the default-locale source in i18n coverage + + A fresh `npm create objectstack` scaffold reported 4 `i18n/missing-object` / + `i18n/missing-field` errors for its own `_note` object, even though the + template authors `label: 'Note'`, `pluralLabel: 'Notes'`, `label: 'Title'` and + `label: 'Body'` inline. The only way to silence them was to commit an `en` + bundle restating strings the metadata already carries. + + The inline `label:` _is_ the default-locale text: the runtime resolver falls + back to it when a bundle has no entry (`translateObject`), and `os i18n +extract` seeds bundles from it. Coverage now honours that contract — an inline + label satisfies the default locale, and a bundle is what _other_ locales need. + Keys with no source string anywhere are no longer reported as i18n gaps; a + missing label is already `required/label`'s finding. + + Non-default locales are unaffected: they still warn for every untranslated key + (`os lint` on `examples/app-todo` reports the same 79 warnings as before, with + its 39 default-locale errors gone). `os lint --include-platform` drops the + platform baseline's default-locale errors for the same reason — the platform + ships English labels inline — while keeping its non-default-locale warnings. + +- 878c1ed: `os lint` no longer buries the user's own signal under the platform i18n baseline. A fresh scaffold reported 800+ `i18n/missing-metadataForm` errors — translation keys for platform built-in metadata forms (email_template, …) that the platform packages already ship at runtime. Those are now hidden by default and folded into one summary line (`platform built-ins: N i18n issue(s) hidden`); pass `--include-platform` to audit them, and read `hiddenPlatform` in `--json` output. User-authored metadata coverage is reported unchanged. +- fefcd54: fix(spec): declare `ownership` as a first-class ObjectSchema field (#3175) + + The object-level record-ownership model — `ownership: 'user' | 'org' | 'none'`, + which drives the registry's `owner_id` auto-provisioning (`applySystemFields`) — + was read by the engine via `(schema as any).ownership` while `ObjectSchema.create()` + **rejected** it as an unknown top-level key (ADR-0032 / #1535). So a tested engine + opt-out (`ownership: 'org' | 'none'` on catalog / junction tables) could not be + set through the sanctioned authoring path, and the same `ownership` word was read + elsewhere as the unrelated package-contribution kind (`own` / `extend`). + + - **spec**: `ObjectSchema` now declares `ownership: z.enum(['user','org','none']).optional()`. + Authoring the record-ownership opt-out validates cleanly; the registry reads it + off the typed schema (no `as any`). A retired `ownership: 'own'` / `'extend'` + value fails with guidance pointing at the record-ownership model and noting that + `own`/`extend` is the contribution kind (`registerObject`), not an object-schema value. + - **cli**: the `object` scaffold no longer emits the now-invalid `ownership: 'own'` + (owner injection is the default), and `objectstack info` labels the record model + with the correct `user` default. + + No runtime behavior change: `applySystemFields` and its `owner_id` injection logic + are unchanged — this makes the property the engine already honors legally authorable + and consistently typed. + +- 8923843: Reject view containers that define no views. A flat list-view object (`{ name, label, type, columns, ... }`) parses to an empty `ViewSchema` container because Zod strips unknown keys — zero views register and the Console silently renders nothing. `defineView()` now throws on a zero-view container, and `os validate` gains a `view-container-shape` check (`validateViewContainers` in `@objectstack/lint`) that reports flat or empty `views: []` entries pre-parse with a wrap-it fix hint. +- Updated dependencies [a9459e6] +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [02eafa5] +- Updated dependencies [deb7e7e] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [6b51346] +- Updated dependencies [80273c8] +- Updated dependencies [fdc244e] +- Updated dependencies [5e3301d] +- Updated dependencies [780b4b5] +- Updated dependencies [2ea08ee] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [230358c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [efbcfe1] +- Updated dependencies [2049b6a] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [515f11a] +- Updated dependencies [4174a07] +- Updated dependencies [ce468c8] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [ea32ec7] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/service-analytics@15.2.0 + - @objectstack/spec@15.2.0 + - @objectstack/plugin-approvals@15.2.0 + - @objectstack/lint@15.2.0 + - @objectstack/service-automation@15.2.0 + - @objectstack/plugin-auth@15.2.0 + - @objectstack/objectql@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/rest@15.2.0 + - @objectstack/formula@15.2.0 + - @objectstack/metadata@15.2.0 + - @objectstack/runtime@15.2.0 + - @objectstack/trigger-record-change@15.2.0 + - @objectstack/plugin-audit@15.2.0 + - @objectstack/mcp@15.2.0 + - @objectstack/observability@15.2.0 + - @objectstack/plugin-hono-server@15.2.0 + - @objectstack/driver-sql@15.2.0 + - @objectstack/client@15.2.0 + - @objectstack/plugin-webhooks@15.2.0 + - @objectstack/verify@15.2.0 + - @objectstack/account@15.2.0 + - @objectstack/setup@15.2.0 + - @objectstack/cloud-connection@15.2.0 + - @objectstack/platform-objects@15.2.0 + - @objectstack/driver-memory@15.2.0 + - @objectstack/driver-mongodb@15.2.0 + - @objectstack/driver-sqlite-wasm@15.2.0 + - @objectstack/plugin-email@15.2.0 + - @objectstack/plugin-reports@15.2.0 + - @objectstack/plugin-security@15.2.0 + - @objectstack/plugin-sharing@15.2.0 + - @objectstack/service-cache@15.2.0 + - @objectstack/service-datasource@15.2.0 + - @objectstack/service-job@15.2.0 + - @objectstack/service-messaging@15.2.0 + - @objectstack/service-package@15.2.0 + - @objectstack/service-queue@15.2.0 + - @objectstack/service-realtime@15.2.0 + - @objectstack/service-settings@15.2.0 + - @objectstack/service-sms@15.2.0 + - @objectstack/service-storage@15.2.0 + - @objectstack/trigger-api@15.2.0 + - @objectstack/trigger-schedule@15.2.0 + - @objectstack/types@15.2.0 + - @objectstack/plugin-pinyin-search@15.2.0 + - @objectstack/console@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index f4bd244f7..78377407c 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/cli", - "version": "15.1.1", + "version": "15.2.0", "description": "Command Line Interface for ObjectStack Protocol", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/client-react/CHANGELOG.md b/packages/client-react/CHANGELOG.md index 5cea754e1..c07dad26e 100644 --- a/packages/client-react/CHANGELOG.md +++ b/packages/client-react/CHANGELOG.md @@ -1,5 +1,34 @@ # @objectstack/client-react +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/client@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/client-react/package.json b/packages/client-react/package.json index 5bdfdcd8f..cf94e3c13 100644 --- a/packages/client-react/package.json +++ b/packages/client-react/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/client-react", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "React hooks for ObjectStack Client SDK", "main": "dist/index.js", diff --git a/packages/client/CHANGELOG.md b/packages/client/CHANGELOG.md index b8ae9fb62..12a9acba6 100644 --- a/packages/client/CHANGELOG.md +++ b/packages/client/CHANGELOG.md @@ -1,5 +1,102 @@ # @objectstack/client +## 15.2.0 + +### Minor Changes + +- 668dd17: **Breaking (npm type surface): retire the vestigial feed contracts + protocol surface (ADR-0052 §5 follow-up, #1959).** + + The `service-feed` runtime was deleted in #1955; `sys_comment` / `sys_activity` + are the canonical record-collaboration/timeline backend. This removes the dead + type surface that still pointed at the deleted runtime — every removed method was + already unreachable (the feed REST route was never mounted → 404; the protocol + implementation was never wired with a feed service, so `requireFeedService()` + could only throw). No behavior changes. + + No authorable metadata key is removed (the `feeds:` object capability flag and + the `RecordActivity` UI component config are unchanged), so `PROTOCOL_MAJOR` + stays 15 and this ships as `minor` rather than a protocol major. + + FROM → TO migration for every removed export: + + - `@objectstack/spec/contracts` — `IFeedService`, `CreateFeedItemInput`, + `UpdateFeedItemInput`, `ListFeedOptions`, `FeedListResult` → **removed, no + replacement**. Comments/activity are plain records: write `sys_comment` / read + `sys_activity` via the data engine or the REST data API. + - `@objectstack/spec/api` — `FeedApiContracts`, `FeedApiErrorCode`, + `FeedProtocol`, and all feed request/response schemas + types (`GetFeed*`, + `CreateFeedItem*`, `UpdateFeedItem*`, `DeleteFeedItem*`, `AddReaction*`, + `RemoveReaction*`, `PinFeedItem*`, `UnpinFeedItem*`, `StarFeedItem*`, + `UnstarFeedItem*`, `SearchFeed*`, `GetChangelog*`, `ChangelogEntry`, + `SubscribeRequest/Response`, `FeedUnsubscribeRequest`, `UnsubscribeResponse`, + `FeedPathParams`, `FeedItemPathParams`, `FeedListFilterType`) → **removed**. Use + the data API against `sys_comment` / `sys_activity` (`/api/v1/data/sys_comment/…`); + reactions and threaded replies are fields on `sys_comment`. + - `@objectstack/spec/data` — `FeedItemSchema`/`FeedItem`, `FeedActorSchema`/`FeedActor`, + `MentionSchema`/`Mention`, `ReactionSchema`/`Reaction`, + `FieldChangeEntrySchema`/`FieldChangeEntry`, `FeedVisibility`, + `RecordSubscriptionSchema`/`RecordSubscription`, `SubscriptionEventType`, and the + `data`-namespace `NotificationChannel` → **removed**. `FeedItemType` and + `FeedFilterMode` are **kept** (live UI activity-timeline config). For notification + channels use `NotificationChannelSchema` from `@objectstack/spec/system`. + - `@objectstack/client` — `client.feed.*` (`list` / `create` / `update` / `delete` / + `addReaction` / `removeReaction` / `pin` / `unpin` / `star` / `unstar` / `search` / + `getChangelog` / `subscribe` / `unsubscribe`) and the re-exported feed response + types → **removed**. One-line fix: use `client.data.*` on `sys_comment` / + `sys_activity`, e.g. `client.data.create('sys_comment', { object, record_id, body })` + and `client.data.find('sys_activity', { filters: [['record_id', '=', id]] })`. + - `@objectstack/metadata-protocol` — `ObjectStackProtocolImplementation` no longer + implements the 14 feed methods; its constructor + `(engine, getServicesRegistry?, getFeedService?, environmentId?)` becomes + `(engine, getServicesRegistry?, environmentId?)`. One-line fix: delete the third + argument. + +### Patch Changes + +- 8abf133: **Breaking (discovery response shape): retire the residual feed capability surface (#3180, follow-up to #1959 / ADR-0052 §5).** + + The feed backend was retired long ago; #1959 removed the feed contracts + SDK. This + removes the last discovery/dispatcher references to it, and fixes a real bug where the + `comments` capability was permanently `false`. + + - `@objectstack/spec` — `WellKnownCapabilitiesSchema.feed` and `ApiRoutesSchema.feed` + (`routes.feed`) are **removed**, and the `/api/v1/feed` entry is dropped from + `DEFAULT_DISPATCHER_ROUTES`. FROM → TO: clients reading `discovery.capabilities.feed` + or `discovery.routes.feed` → use `discovery.capabilities.comments`; comments/activity + are served by the generic data API on `sys_comment` / `sys_activity` + (`/api/v1/data/sys_comment/…`). + - `@objectstack/metadata-protocol` — `getDiscovery()` no longer emits the always-`false` + `feed` service/capability. **Bug fix:** the `comments` capability previously keyed off + the deleted `'feed'` service (so it was permanently `false` after #1955); it now tracks + the presence of the `sys_comment` object (provided by the always-on audit slate), so + `declared === enforced`. + - `@objectstack/client` — the internal `feed: '/api/v1/feed'` route constant is removed + (it only existed to satisfy the now-removed `ApiRoutes.feed` type; no client code used it). + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/client/package.json b/packages/client/package.json index 611b21129..30e807fc4 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/client", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Official Client SDK for ObjectStack Protocol", "main": "dist/index.js", diff --git a/packages/cloud-connection/CHANGELOG.md b/packages/cloud-connection/CHANGELOG.md index 424a21552..b386c3440 100644 --- a/packages/cloud-connection/CHANGELOG.md +++ b/packages/cloud-connection/CHANGELOG.md @@ -1,5 +1,41 @@ # @objectstack/cloud-connection +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [fdc244e] +- Updated dependencies [5e3301d] +- Updated dependencies [2ea08ee] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [2049b6a] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [515f11a] +- Updated dependencies [4174a07] +- Updated dependencies [ce468c8] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/runtime@15.2.0 + - @objectstack/types@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/cloud-connection/package.json b/packages/cloud-connection/package.json index 936ff7d66..9152b1624 100644 --- a/packages/cloud-connection/package.json +++ b/packages/cloud-connection/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/cloud-connection", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Runtime-side client for an ObjectStack cloud control plane — marketplace browse proxy, install-local, device-code binding, org catalog and installed views, and the /api/v1/runtime/config discovery endpoint. Open mechanism (ADR-0008): the hub service, plan policy, and entitlements stay server-side.", "type": "module", diff --git a/packages/connectors/connector-mcp/CHANGELOG.md b/packages/connectors/connector-mcp/CHANGELOG.md index 681bd9531..cda954cdc 100644 --- a/packages/connectors/connector-mcp/CHANGELOG.md +++ b/packages/connectors/connector-mcp/CHANGELOG.md @@ -1,5 +1,33 @@ # @objectstack/connector-mcp +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/connectors/connector-mcp/package.json b/packages/connectors/connector-mcp/package.json index 3c8209e74..d01351773 100644 --- a/packages/connectors/connector-mcp/package.json +++ b/packages/connectors/connector-mcp/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/connector-mcp", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Model Context Protocol (MCP) connector for ObjectStack — a generic adapter that turns any MCP server's tools into a connector's actions on the automation engine's connector registry (ADR-0024).", "main": "dist/index.js", diff --git a/packages/connectors/connector-openapi/CHANGELOG.md b/packages/connectors/connector-openapi/CHANGELOG.md index cc13b5afa..65527b743 100644 --- a/packages/connectors/connector-openapi/CHANGELOG.md +++ b/packages/connectors/connector-openapi/CHANGELOG.md @@ -1,5 +1,52 @@ # @objectstack/connector-openapi +## 15.2.0 + +### Minor Changes + +- 41e703b: feat(connector-openapi): degrade + retry on an unreachable remote spec URL (#3049 follow-up) + + The `openapi` provider fetches `providerConfig.spec` when it is an http(s) URL. + That fetch previously threw plain on any failure, so a momentarily-unreachable + spec endpoint aborted the whole app boot. It now classifies the fault the same + way `connector-mcp` classifies its connect path (ADR-0097): + + - **Network error** (DNS / connection refused / timeout) or a **transient HTTP + status** (`408` / `429` / `5xx`, mirroring the `retryableStatusCodes` + convention) throws `ConnectorUpstreamUnavailableError` — the materializer + degrades the instance (`state: 'degraded'` on `GET /connectors`, dispatch + fails clearly) and retries with backoff plus on every `metadata:reloaded`. + - A **wrong URL** (non-retryable `4xx`) or an **unparseable document** stays a + plain, fatal configuration fault. + + Inline and file-path (`#3016`) specs do no boot I/O and are unaffected. + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/connectors/connector-openapi/package.json b/packages/connectors/connector-openapi/package.json index 81a8e829e..fc6641b21 100644 --- a/packages/connectors/connector-openapi/package.json +++ b/packages/connectors/connector-openapi/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/connector-openapi", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "OpenAPI 3.x connector generator for ObjectStack — turns a declarative OpenAPI document into connector actions on the automation engine's registry, with a self-contained static-auth HTTP transport (ADR-0023).", "main": "dist/index.js", diff --git a/packages/connectors/connector-rest/CHANGELOG.md b/packages/connectors/connector-rest/CHANGELOG.md index 76363d279..ba24ecc8b 100644 --- a/packages/connectors/connector-rest/CHANGELOG.md +++ b/packages/connectors/connector-rest/CHANGELOG.md @@ -1,5 +1,33 @@ # @objectstack/connector-rest +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/connectors/connector-rest/package.json b/packages/connectors/connector-rest/package.json index 5b6f21ac1..04793164f 100644 --- a/packages/connectors/connector-rest/package.json +++ b/packages/connectors/connector-rest/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/connector-rest", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Generic REST connector for ObjectStack — the reference concrete connector that registers a `request` action on the automation engine's connector registry (ADR-0018 §Addendum).", "main": "dist/index.js", diff --git a/packages/connectors/connector-slack/CHANGELOG.md b/packages/connectors/connector-slack/CHANGELOG.md index 697666be0..fc8b7f331 100644 --- a/packages/connectors/connector-slack/CHANGELOG.md +++ b/packages/connectors/connector-slack/CHANGELOG.md @@ -1,5 +1,33 @@ # @objectstack/connector-slack +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/connectors/connector-slack/package.json b/packages/connectors/connector-slack/package.json index a96f269a7..67a7b0122 100644 --- a/packages/connectors/connector-slack/package.json +++ b/packages/connectors/connector-slack/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/connector-slack", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Slack Web API connector for ObjectStack — registers `chat.postMessage` / `chat.update` / `call` actions on the automation engine's connector registry (ADR-0018 §Addendum, ADR-0022).", "main": "dist/index.js", diff --git a/packages/console/CHANGELOG.md b/packages/console/CHANGELOG.md index 2de3314c5..65f704771 100644 --- a/packages/console/CHANGELOG.md +++ b/packages/console/CHANGELOG.md @@ -1,5 +1,7 @@ # @objectstack/console +## 15.2.0 + ## 15.1.1 ## 15.1.0 diff --git a/packages/console/package.json b/packages/console/package.json index 7b7b05599..ef102b9a6 100644 --- a/packages/console/package.json +++ b/packages/console/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/console", - "version": "15.1.1", + "version": "15.2.0", "description": "Prebuilt Console SPA pinned to this @objectstack/framework release. Source of truth: @object-ui/console (https://github.com/objectstack-ai/objectui).", "license": "Apache-2.0", "homepage": "https://github.com/objectstack-ai/framework/tree/main/packages/console", diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index 919fecedc..daceef961 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -1,5 +1,70 @@ # @objectstack/core +## 15.2.0 + +### Patch Changes + +- e057f42: fix: harden the bulk-write path — retries, idempotency, contracts, and summary visibility (#3147–#3152) + + Six reliability fixes to the batched seed/import + `engine.insert(array)` path + introduced by the #2678 bulk-write rework: + + - **#3151** `bulkWrite` validates that `writeBatch` returns one record per input + row (a short/long/non-array return is degraded per-row, not backfilled as + phantom success); `engine.insert(array)` likewise rejects a short driver + `bulkCreate` return instead of padding afterInsert with `undefined`. + - **#3150** wraps the two remaining un-retried write points (seed + `writeRecord`/`resolveDeferredUpdates`, import's no-`createManyData` + fallback) in `withTransientRetry`; `defaultIsTransientError` short-circuits + definitive logical errors to non-transient. + - **#3148** import `resolveRef` flushes pending creates on a same-object miss so + a later row can reference an earlier same-file CREATE, and no longer + negatively caches a miss. + - **#3149** threads an `attempt` counter through `bulkWrite`; seed rechecks by + `externalId` and import by `matchFields` before re-writing, so a + commit-then-lost-response retry cannot duplicate a batch. + - **#3147** `recomputeSummaries` retries transient failures and, on exhaustion, + surfaces `SummaryRecomputeError` (`ERR_SUMMARY_RECOMPUTE`) instead of a + silent warn; seed/import recover it to a warning without re-writing. + - **#3152** autonumbers are assigned after validation, so a batch that dies in + validation consumes no sequence value (no number-range gaps). + +- 5f05de2: **`createLogger({ file })` now actually writes the file under ESM.** `openFileStream` loaded `fs` with a lazy `require()` to keep the browser-safe logger entry out of the `fs` bundle graph; esbuild rewrites that to its `__require` shim in the ESM output, which throws `Dynamic require of "fs" is not supported`, and a bare `catch {}` swallowed it. Since the workspace is `type: module`, every Node ESM consumer — `os serve`, `os dev` — silently got no file logging at all, while the CJS build kept working. The builtin now loads via `process.getBuiltinModule` (opaque to bundlers, works in both module systems, with a `require` fallback for Node < 20.16), and a `file` destination that cannot be opened reports itself on stderr instead of disappearing. + + Turning the destination back on also fixed three faults that were unreachable while it never opened: `child()` opened a second stream per child and orphaned it, destroying a child logger closed the stream its parent and siblings were still writing to, and an async open failure (e.g. an unwritable path) hit an `'error'` event with no listener and took the process down. + +- 021ba4c: fix(core): ObjectLogger honors NO_COLOR and TTY detection before emitting ANSI colors + + The kernel/plugin logger (`ctx.logger`, wired by `os serve` / `os dev`) colorized its + `pretty`-format level tags unconditionally, so `NO_COLOR=1` runs and piped/CI output + still carried ANSI escapes (e.g. `\x1b[31m…ERROR\x1b[0m`), breaking plain-text log + scanners (see scripts/publish-smoke.sh, which had to strip ANSI before grepping). + + Per the no-color.org convention, color is now emitted only when the destination stream + (stdout, or stderr for error/fatal) is an interactive TTY **and** `NO_COLOR` is unset or + empty — any non-empty `NO_COLOR` value disables color. Interactive terminals keep the + existing colorized output. The optional file destination now always receives plain text. + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/core/package.json b/packages/core/package.json index 090c37b0a..3fbdd5ae6 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/core", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Microkernel Core for ObjectStack", "type": "module", diff --git a/packages/create-objectstack/CHANGELOG.md b/packages/create-objectstack/CHANGELOG.md index f2f630bf9..1b6ba426e 100644 --- a/packages/create-objectstack/CHANGELOG.md +++ b/packages/create-objectstack/CHANGELOG.md @@ -1,5 +1,80 @@ # create-objectstack +## 15.2.0 + +### Minor Changes + +- 3f218e4: feat(create-objectstack): the blank scaffold ships the three generic connector executors by default + + `npm create objectstack` now generates an `objectstack.config.ts` that wires the + `rest`, `openapi`, and `mcp` connector executor plugins (ADR-0022/0023/0024 + + ADR-0097) into `plugins:`, alongside `requires: ['automation']`. This closes the + last authoring gap in the ADR-0097 promise that integrations are expressible + **and executable** as pure metadata: an author (human or AI) can now add a + declarative `connectors:` entry naming `provider: 'rest' | 'openapi' | 'mcp'` + and have it materialize into a live, dispatchable connector at boot — with no + host-code edit. + + - `plugins:` — `new ConnectorRestPlugin()`, `new ConnectorOpenApiPlugin()`, + `new ConnectorMcpPlugin()` (zero-arg = contribute the provider factory only). + - `requires: ['automation']` — the automation service performs the + materialization and owns the registry the executors register into. It is also + a hard dependency of the connector plugins, so a scaffold that lists them in + `plugins:` without it fails boot; automation ships transitively via + `@objectstack/cli`. + - deps — `@objectstack/connector-rest`, `@objectstack/connector-openapi`, + `@objectstack/connector-mcp`. + - Security (#3055): declarative `mcp` stdio transports stay denied by default — + opt in per host with `new ConnectorMcpPlugin({ declarativeStdio: ['node'] })`. + + Brand connectors (Slack, …) remain marketplace/opt-in. + +### Patch Changes + +- 3b6ef8a: Scaffolded projects ship with a `.gitignore` again — `npx create-objectstack` produced none, leaving `node_modules/` and `.env` un-ignored for every new user. + + `npm pack` / `pnpm pack` strip `.gitignore` from a tarball unconditionally, at every depth. The blank template committed one at `src/templates/blank/.gitignore` and the build faithfully copied it to `dist/templates/blank/.gitignore`, but `files: ["dist"]` publishing dropped it on the way to the registry — so the file was present in the repo, present in every local build, and absent from all 11 files of a real scaffold. Verified against the published 15.1.1 tarball, which ships `dist/templates/blank/.dockerignore` and no `.gitignore`. + + The template is now committed as `_gitignore` (a name npm does not strip) and restored to `.gitignore` when the template is copied, via a `TEMPLATE_FILE_ALIASES` map in the new `template-copy.ts`. Only `.gitignore` is aliased: the strip list is `.gitignore` and `.npmrc`, not "every dotfile" — `.dockerignore` packs fine and stays literal. + + The restored ignore rules also cover `.env` / `.env.*`, which they never did. The template README has users write `OS_AUTH_SECRET` and `OS_SECRET_KEY` into a `.env`, and `docker-compose.yml` calls that file "never committed" — but only the prose said so, and `.dockerignore` was the only file that listed it. + + A packing ratchet in `template-consistency.test.ts` guards both halves: it packs the real package, scaffolds from the extracted tarball with the real copy logic, and asserts every template file lands under its intended name. Source-level assertions cannot see this class of bug — the file only vanishes at publish. + +- 3a8ce9d: fix(create-objectstack): the blank scaffold declares pnpm build approvals, so a fresh `pnpm install` no longer exits 1 on pnpm 11 + + pnpm 11 turned an unapproved dependency build script from a warning into a hard + error. The blank template declared no build approvals, so the very first command + a new user runs failed on any current pnpm: + + ``` + npx create-objectstack myapp && cd myapp && pnpm install + # [ERR_PNPM_IGNORED_BUILDS] Ignored build scripts: better-sqlite3@12.11.1, esbuild@0.28.1 + # exit 1 + ``` + + The scaffold now ships a `pnpm-workspace.yaml` approving the two packages it + actually depends on building — `better-sqlite3` (the native sqlite driver behind + `@objectstack/driver-sql`) and `esbuild` (compiles `objectstack.config.ts`). + + Both approval keys are present because pnpm reads them by version, and neither + alone covers the supported range: + + - `allowBuilds` (a package → boolean map) — the only key pnpm 11 honors, and + understood back to pnpm 10.31. `onlyBuiltDependencies` alone still errors. + - `onlyBuiltDependencies` (a list) — pnpm 10.0–10.30, which ignore `allowBuilds`. + + npm and yarn ignore the file, so the npm install path is unaffected. Both + packages ship prebuilt binaries, so this was an install-time hard stop rather + than a runtime defect — the project ran fine once installed. + + This is the #3091 failure class (in-repo settings masking what users resolve) + and was caught by the publish smoke gate added in #3100, which installs the + release candidate the way a user does — on whatever pnpm corepack hands a fresh + machine. + +- 809214f: Stop leaking repo-internal skills into scaffolded projects. The scaffolder (and the docs) advertised `npx skills add objectstack-ai/framework --all`, and the skills CLI's `--all` implies `--skill '*'` — which includes even `metadata.internal` skills — so repo-internal tooling like `.claude/skills/dogfood-verification` landed in every new project's `.agents/skills/`. All install commands are now scoped to the published catalog via the `/skills` subpath (`npx skills add objectstack-ai/framework/skills --all`), the internal skill is additionally marked `metadata.internal: true` to hide it from interactive discovery, and a template-consistency ratchet plus a scaffold-e2e assertion keep the boundary from regressing. + ## 15.1.1 ## 15.1.0 diff --git a/packages/create-objectstack/package.json b/packages/create-objectstack/package.json index 795a1f5c0..245fd0722 100644 --- a/packages/create-objectstack/package.json +++ b/packages/create-objectstack/package.json @@ -1,6 +1,6 @@ { "name": "create-objectstack", - "version": "15.1.1", + "version": "15.2.0", "description": "Create a new ObjectStack project — npx create-objectstack", "bin": { "create-objectstack": "./bin/create-objectstack.js" diff --git a/packages/formula/CHANGELOG.md b/packages/formula/CHANGELOG.md index 4d43af207..c777a0d02 100644 --- a/packages/formula/CHANGELOG.md +++ b/packages/formula/CHANGELOG.md @@ -1,5 +1,138 @@ # @objectstack/formula +## 15.2.0 + +### Minor Changes + +- 6b51346: feat(formula): `dateField == today()` now matches — AST temporal-comparison rewrite (#3183) + + **Behavior change (the fix):** a `Field.date` compared with `==`/`!=` against a + temporal function now matches on the calendar day. Previously it **silently + returned the wrong answer** — `record.due_date == today()` was always `false` + (and `!= today()` always `true`) even for a same-day record, because a + `Field.date` reads back as a `YYYY-MM-DD` **string** (ADR-0053 Phase 1) and + cel-js's equality (`overloads.js` `isEqual`) treats a string and a timestamp as + unequal without consulting any overload. + + `celEngine.evaluate` now rewrites the parsed AST: for each `==`/`!=` whose one + operand is `today()`/`daysFromNow()`/`daysAgo()`/`now()`, the **field operand** + is wrapped in `date(...)` (the stdlib coercion), then the expression is + serialized and evaluated. So `record.due_date == today()` runs as + `date(record.due_date) == today()`. + + - **Per-occurrence**, not per-field: `record.d == "2026-06-20" || record.d == today()` + keeps the string-literal comparison intact while fixing the temporal one. + - **Type-blind-safe**: `date()` degrades gracefully — an already-`Date` + (`Field.datetime`) operand passes through; a non-date string or null → + `Invalid Date` → the comparison stays `false`, exactly as before. No + field-type information is needed, and no currently-correct result is worsened. + - **Cheap**: the rewrite only reserializes when such a comparison is present + (a plain-`includes` gate skips the rest), and is memoized per source string. + + Applies to every interpreter site — read-time `Field.formula`, default values, + validation rules, hook conditions, and flow conditions — since all route through + `celEngine.evaluate`. RLS/sharing conditions are unaffected: they compile via + `cel-to-filter`, which already rejects function calls as a loud authoring error. + + **Supersedes the #3192 advisory lint.** That build-time warning + (`checkTemporalDateEquality`) flagged `dateField == today()` as a silent-miss; + with the runtime fixed it would be a false alarm, so it (and the + `temporalEqualityFields` helper it used) is removed. Authors can now write the + natural `record.due_date == today()` directly; the `date(...)` / + `daysBetween(...) == 0` / range idioms all keep working. + +- 80273c8: feat(formula): warn when a `date` field is compared to a temporal function with `==`/`!=` (#3183) + + A `Field.date` deserializes as a `YYYY-MM-DD` **string** (ADR-0053 Phase 1), and + cel-js's equality hard-codes `string == ` to `false` — it returns + `false` for a string left operand without ever consulting a registered overload, + and refuses cross-type object equality (`@marcbachmann/cel-js` `overloads.js` + `isEqual`). So the most natural "is it due today" predicate — + + ```cel + record.due_date == today() // silently false, even when due_date IS today + record.due_date != today() // silently true for a same-day record + ``` + + — compiles clean, throws nothing, and silently never matches. Same silent-miss + family as #1928; **timezone-independent** (fails identically at UTC) and + cross-cutting (formulas, validation, RLS, flow/action/sharing/hook predicates). + + cel-js gives no operator-layer hook to fix the comparison, so this adds a + **build-time advisory warning** (the established ADR-0032 guardrail strategy) + rather than a runtime behavior change. `validateExpression` reuses the shared + `ExprSchemaHint.fieldTypes` (the same per-field type map the #1928 tier-4 + soundness check already threads through `@objectstack/lint`) to flag a `==`/`!=` + between a `date` field (`record.`/`previous.`/bare) and + `today()`/`daysFromNow()`/`daysAgo()`/`now()`, with a self-correcting message + pointing at the working idioms: `date(record.d) == today()`, a range + (`>= … && <= …`), or `daysBetween(today(), record.d) == 0`. + + Warning severity — never fails the build (the write/validation path may carry a + real `Date`). Restricted to `type: 'date'` (unambiguously a string); `datetime` + is excluded to avoid false positives. Ordering operators (`>=`/`<=`/`<`/`>`) + already work — cel-js _throws_ for them, tripping the engine's existing + string-hydration retry — so they are not flagged. + + A runtime fix (normalizing the peer of a temporal operand in the data layer) + remains tracked in #3183; a naive "hydrate date fields to `Date`" version would + trade this silent-miss for another (breaking `dateField == "2026-06-20"`), so it + needs its own design. + +- ea32ec7: feat(formula,lint): advisory type-soundness warnings for formula/predicate expressions (#1928 tier 4) + + Closes the last open guardrail from #1928. A `Field.formula` or record-scoped + predicate that uses a **text or boolean field with an arithmetic (`+ - * / %`) + or ordering (`< > <= >=`) operator against a number** faults the runtime + overload and silently evaluates to `null` (e.g. `record.title * 2`, + `record.is_active + 1`). The build now surfaces this as a **non-blocking + warning** with the offending field and a corrective message. + + Honours the ADR-0032 design law — the checker only flags what the runtime + would also fail: + + - Number / currency / percent / date / datetime fields are declared `dyn`, so + the cases the runtime rescues never warn — `record.amount / 100` (the #1930 + `registerOperator` fix), `record.due == today()` and numeric-string / ISO-date + values (the string-hydration retry), and numeric-coded `select` option values. + - Equality (`==` / `!=`) is excluded: a heterogeneous equality is runtime-safe + (evaluates to `false`), never a fault. + + New `firstTypeMismatch(source, fieldCelTypes, scope)` export in + `@objectstack/formula` (and an optional `fieldTypes` hint on + `validateExpression`); `@objectstack/lint`'s `validateStackExpressions` threads + each object's field types into every checked site: + + - **record-scoped** sites (`record.`) — formula fields, validation rules, + action / hook / sharing predicates; + - **flattened** flow / automation conditions (bare `field`) — where flow + variables stay `dyn` and are never flagged, and equality stays runtime-safe. + + Warnings are advisory in `objectstack build` / `validate` (fatal only under + `--strict`), matching the tier-3 channel. + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/formula/package.json b/packages/formula/package.json index 2a3ea8e69..e7236a2e4 100644 --- a/packages/formula/package.json +++ b/packages/formula/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/formula", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "ObjectStack canonical expression engine — CEL (cel-js) + ObjectStack stdlib + dialect registry", "main": "dist/index.js", diff --git a/packages/lint/CHANGELOG.md b/packages/lint/CHANGELOG.md index a38c1d0be..c8218366c 100644 --- a/packages/lint/CHANGELOG.md +++ b/packages/lint/CHANGELOG.md @@ -1,5 +1,119 @@ # @objectstack/lint +## 15.2.0 + +### Minor Changes + +- 3a18b60: feat(approvals): rename the `role` approver type to `org_membership_level` (#3133) + + `ApproverType.role` was the last platform surface projecting the reserved word + "role" (ADR-0090 D3). It is not covered by D3's better-auth exception: that + exception protects better-auth's own `sys_member.role` **column**, which we do + not own — `ApproverType` is our own enum, an authoring surface, and D3 mandates + that the projection of that concept is spelled `org_membership_level` and + labelled "organization membership", **never "role"**. + + The sentence licensing the leak was also false: ADR-0090 D3 claims + `sys_member.role` is "already relabelled `org_membership_level` in the platform + projection", but `org_membership_level` existed nowhere in the codebase and + ADR-0057 D7 lists that relabel under "Deferred (evidence-gated, P4)". The + projection never landed, so the word reached authors. + + The name manufactured a real, silent failure — "hotcrm class": every other + surface renamed to `position` (`sys_role`, `ShareRecipientType.role`, + `ctx.roles[]`), so `{ type: 'role', value: 'sales_manager' }` reads as the + legacy spelling of a position. It resolves against the membership tier, finds + no member row, falls back to an inert `role:sales_manager` literal, and the + request waits forever on an approver that cannot exist. + + - **spec**: `ApproverType` gains `org_membership_level`; `role` stays as a + deprecated alias for one window (a published 15.x flow keeps loading) with + `DEPRECATED_APPROVER_TYPES` + `canonicalApproverType()` as the single source + for the mapping. Removed in the next major. + - **plugin-approvals**: resolves on the canonical type and warns on the + deprecated spelling. The `type:value` fallback literal keeps the **authored** + spelling — stored `sys_approval_approver` rows and `pending_approvers` slots + from 15.x carry `role:`, and rewriting it would orphan them. + - **lint**: `approval-role-not-membership-tier` → `approval-approver-not-membership-tier` + (the rule id carried the reserved word too), plus a new + `approval-approver-type-deprecated`. The two are mutually exclusive: a bad + _value_ wins, because prescribing `org_membership_level` for a position name + would be wrong advice — the fix there is `position`. + + Authoring `type: 'role'` keeps working and now says so out loud. Rewrite it as + `org_membership_level`; if the value is an org position, the fix is `position`. + +- 2ea08ee: Flow trigger observability — kill the four-layer silence around record-change flows that never fire (2026-07-17 third-party eval). + + A misauthored auto-launched flow (wrong `objectName`, missing `requires: ['automation','triggers']`, failing start condition) produced ZERO output at every layer: the engine's own registration/binding logs land inside the CLI's boot-quiet stdout window (which swallows debug/info/warn — only error/fatal reach stderr), and each "didn't happen" path was itself silent. Fixes: + + - **Startup banner `Flows:` section** (`os serve`/`os dev`/`os start`): flow count, bound-to-trigger count, registered trigger types, draft count — plus loud `⚠` lines for flows declared with no automation engine enabled (`requires` missing), flows whose trigger type has no registered trigger, and bound record-change flows targeting an unknown object (dead binding). Printed after stdout is restored, so it is immune to the boot-quiet window. + - **Trigger-fired run failures now log at ERROR** (stderr — always visible): the automation engine no longer drops the AutomationResult of a trigger-fired execution; condition-evaluation faults and node failures surface with the flow name. Condition-not-met skips stay at debug (high-frequency, intentional). + - **`RecordChangeTrigger` probes object existence at bind time** and warns when a flow's `objectName` matches no registered object (exact-name matching), instead of silently arming a hook that can never fire. + - **`kernel:bootstrapped` binding audit** in the automation plugin: warns per enabled-but-unbound triggered flow with the reason, and reports registered/bound/draft counts (`AutomationEngine.getTriggerBindingAudit()`, extended `getFlowRuntimeStates()` with `status`/`triggerType`/`object`). + - **`os validate` flow-wiring advisories** (`@objectstack/lint` `validateFlowTriggerReadiness`): warns when a record-triggered flow targets an object the stack does not define, and when an auto-triggered flow's status is `draft` (authored or defaulted — draft flows still fire; declare `active` or `obsolete`). + - Removed leftover boot-debug writes (`registerApp`/`AppPlugin`/`StandaloneStack`/`AuditPlugin` stderr noise) that previous debugging of this same silence had left behind. + +- ea32ec7: feat(formula,lint): advisory type-soundness warnings for formula/predicate expressions (#1928 tier 4) + + Closes the last open guardrail from #1928. A `Field.formula` or record-scoped + predicate that uses a **text or boolean field with an arithmetic (`+ - * / %`) + or ordering (`< > <= >=`) operator against a number** faults the runtime + overload and silently evaluates to `null` (e.g. `record.title * 2`, + `record.is_active + 1`). The build now surfaces this as a **non-blocking + warning** with the offending field and a corrective message. + + Honours the ADR-0032 design law — the checker only flags what the runtime + would also fail: + + - Number / currency / percent / date / datetime fields are declared `dyn`, so + the cases the runtime rescues never warn — `record.amount / 100` (the #1930 + `registerOperator` fix), `record.due == today()` and numeric-string / ISO-date + values (the string-hydration retry), and numeric-coded `select` option values. + - Equality (`==` / `!=`) is excluded: a heterogeneous equality is runtime-safe + (evaluates to `false`), never a fault. + + New `firstTypeMismatch(source, fieldCelTypes, scope)` export in + `@objectstack/formula` (and an optional `fieldTypes` hint on + `validateExpression`); `@objectstack/lint`'s `validateStackExpressions` threads + each object's field types into every checked site: + + - **record-scoped** sites (`record.`) — formula fields, validation rules, + action / hook / sharing predicates; + - **flattened** flow / automation conditions (bare `field`) — where flow + variables stay `dyn` and are never flagged, and equality stays runtime-safe. + + Warnings are advisory in `objectstack build` / `validate` (fatal only under + `--strict`), matching the tier-3 channel. + +### Patch Changes + +- 8923843: Reject view containers that define no views. A flat list-view object (`{ name, label, type, columns, ... }`) parses to an empty `ViewSchema` container because Zod strips unknown keys — zero views register and the Console silently renders nothing. `defineView()` now throws on a zero-view container, and `os validate` gains a `view-container-shape` check (`validateViewContainers` in `@objectstack/lint`) that reports flat or empty `views: []` entries pre-parse with a wrap-it fix hint. +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [a3823b2] +- Updated dependencies [6b51346] +- Updated dependencies [80273c8] +- Updated dependencies [5e3301d] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [ea32ec7] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/formula@15.2.0 + - @objectstack/sdui-parser@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/lint/package.json b/packages/lint/package.json index e266bd98a..4fed17f55 100644 --- a/packages/lint/package.json +++ b/packages/lint/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/lint", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Static, build-time validation for an ObjectStack metadata graph — dashboard widget bindings, CEL/predicate expressions, and more. Pure (stack) => Issue[] functions shared by the CLI's `os validate` and any other consumer (e.g. AI authoring). Depends on @objectstack/spec; never on a runtime.", "type": "module", diff --git a/packages/mcp/CHANGELOG.md b/packages/mcp/CHANGELOG.md index 40fcf8f0c..4a9cc9a6c 100644 --- a/packages/mcp/CHANGELOG.md +++ b/packages/mcp/CHANGELOG.md @@ -1,5 +1,65 @@ # @objectstack/plugin-mcp-server +## 15.2.0 + +### Minor Changes + +- 230358c: feat(mcp): `validate_expression` tool — validate a CEL expression against a schema before authoring (#1928) + + Adds an agent-callable MCP tool that runs the same build-time expression checks + as `objectstack build`, so an AI can validate a formula / predicate / flow + condition **while authoring** instead of shipping one that silently evaluates to + `null`. Given `{ objectName, expression, site? }` it resolves the object's real + schema (field names + types, via the principal-bound `describeObject` bridge) + and returns: + + - **errors** — bare field refs (`amount` → `record.amount`), unknown fields + (with a did-you-mean), unknown functions; + - **warnings** — text/boolean fields misused in arithmetic, date-equality + pitfalls; + - **inScope** — the fields, stdlib functions, and namespace roots available, so + the model can self-correct; + - **inferredType** for a `formula` site. + + `site` (`formula` | `validation` | `flow_condition` | `template`, default + `formula`) maps to the validator's role + scope — `flow_condition` binds fields + bare, the rest bind `record.`. Read-only, gated by the `data:read` OAuth + scope, and fail-closed on `sys_*` objects like the other schema tools. This is + the authoring-time surface the guardrail series (#1928) always pointed at; + `@objectstack/mcp` gains a `@objectstack/formula` dependency (acyclic; formula is + a leaf). + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [6b51346] +- Updated dependencies [80273c8] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [ea32ec7] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/formula@15.2.0 + - @objectstack/types@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/mcp/package.json b/packages/mcp/package.json index 287f82337..caa681e13 100644 --- a/packages/mcp/package.json +++ b/packages/mcp/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/mcp", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "ObjectStack as an MCP server — exposes your app's objects (and AI tools) over the Model Context Protocol (stdio + Streamable HTTP)", "type": "module", diff --git a/packages/metadata-core/CHANGELOG.md b/packages/metadata-core/CHANGELOG.md index 3a0868d9e..c18435eeb 100644 --- a/packages/metadata-core/CHANGELOG.md +++ b/packages/metadata-core/CHANGELOG.md @@ -1,5 +1,29 @@ # @objectstack/metadata-core +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/metadata-core/package.json b/packages/metadata-core/package.json index 6032264e8..7f7c74609 100644 --- a/packages/metadata-core/package.json +++ b/packages/metadata-core/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/metadata-core", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Metadata Repository contracts: types, canonicalization, errors, interface (ADR-0008).", "type": "module", diff --git a/packages/metadata-fs/CHANGELOG.md b/packages/metadata-fs/CHANGELOG.md index 4125d795b..2a05a704d 100644 --- a/packages/metadata-fs/CHANGELOG.md +++ b/packages/metadata-fs/CHANGELOG.md @@ -1,5 +1,11 @@ # @objectstack/metadata-fs +## 15.2.0 + +### Patch Changes + +- @objectstack/metadata-core@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/metadata-fs/package.json b/packages/metadata-fs/package.json index 4d2e86734..3cbec0d3e 100644 --- a/packages/metadata-fs/package.json +++ b/packages/metadata-fs/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/metadata-fs", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "FileSystemRepository: Node-only Repository implementation backed by JSON files and a JSONL change log (ADR-0008).", "type": "module", diff --git a/packages/metadata-protocol/CHANGELOG.md b/packages/metadata-protocol/CHANGELOG.md index e0c0353b4..b3a31475e 100644 --- a/packages/metadata-protocol/CHANGELOG.md +++ b/packages/metadata-protocol/CHANGELOG.md @@ -1,5 +1,204 @@ # @objectstack/metadata-protocol +## 15.2.0 + +### Minor Changes + +- 668dd17: **Breaking (npm type surface): retire the vestigial feed contracts + protocol surface (ADR-0052 §5 follow-up, #1959).** + + The `service-feed` runtime was deleted in #1955; `sys_comment` / `sys_activity` + are the canonical record-collaboration/timeline backend. This removes the dead + type surface that still pointed at the deleted runtime — every removed method was + already unreachable (the feed REST route was never mounted → 404; the protocol + implementation was never wired with a feed service, so `requireFeedService()` + could only throw). No behavior changes. + + No authorable metadata key is removed (the `feeds:` object capability flag and + the `RecordActivity` UI component config are unchanged), so `PROTOCOL_MAJOR` + stays 15 and this ships as `minor` rather than a protocol major. + + FROM → TO migration for every removed export: + + - `@objectstack/spec/contracts` — `IFeedService`, `CreateFeedItemInput`, + `UpdateFeedItemInput`, `ListFeedOptions`, `FeedListResult` → **removed, no + replacement**. Comments/activity are plain records: write `sys_comment` / read + `sys_activity` via the data engine or the REST data API. + - `@objectstack/spec/api` — `FeedApiContracts`, `FeedApiErrorCode`, + `FeedProtocol`, and all feed request/response schemas + types (`GetFeed*`, + `CreateFeedItem*`, `UpdateFeedItem*`, `DeleteFeedItem*`, `AddReaction*`, + `RemoveReaction*`, `PinFeedItem*`, `UnpinFeedItem*`, `StarFeedItem*`, + `UnstarFeedItem*`, `SearchFeed*`, `GetChangelog*`, `ChangelogEntry`, + `SubscribeRequest/Response`, `FeedUnsubscribeRequest`, `UnsubscribeResponse`, + `FeedPathParams`, `FeedItemPathParams`, `FeedListFilterType`) → **removed**. Use + the data API against `sys_comment` / `sys_activity` (`/api/v1/data/sys_comment/…`); + reactions and threaded replies are fields on `sys_comment`. + - `@objectstack/spec/data` — `FeedItemSchema`/`FeedItem`, `FeedActorSchema`/`FeedActor`, + `MentionSchema`/`Mention`, `ReactionSchema`/`Reaction`, + `FieldChangeEntrySchema`/`FieldChangeEntry`, `FeedVisibility`, + `RecordSubscriptionSchema`/`RecordSubscription`, `SubscriptionEventType`, and the + `data`-namespace `NotificationChannel` → **removed**. `FeedItemType` and + `FeedFilterMode` are **kept** (live UI activity-timeline config). For notification + channels use `NotificationChannelSchema` from `@objectstack/spec/system`. + - `@objectstack/client` — `client.feed.*` (`list` / `create` / `update` / `delete` / + `addReaction` / `removeReaction` / `pin` / `unpin` / `star` / `unstar` / `search` / + `getChangelog` / `subscribe` / `unsubscribe`) and the re-exported feed response + types → **removed**. One-line fix: use `client.data.*` on `sys_comment` / + `sys_activity`, e.g. `client.data.create('sys_comment', { object, record_id, body })` + and `client.data.find('sys_activity', { filters: [['record_id', '=', id]] })`. + - `@objectstack/metadata-protocol` — `ObjectStackProtocolImplementation` no longer + implements the 14 feed methods; its constructor + `(engine, getServicesRegistry?, getFeedService?, environmentId?)` becomes + `(engine, getServicesRegistry?, environmentId?)`. One-line fix: delete the third + argument. + +### Patch Changes + +- e057f42: fix: harden the bulk-write path — retries, idempotency, contracts, and summary visibility (#3147–#3152) + + Six reliability fixes to the batched seed/import + `engine.insert(array)` path + introduced by the #2678 bulk-write rework: + + - **#3151** `bulkWrite` validates that `writeBatch` returns one record per input + row (a short/long/non-array return is degraded per-row, not backfilled as + phantom success); `engine.insert(array)` likewise rejects a short driver + `bulkCreate` return instead of padding afterInsert with `undefined`. + - **#3150** wraps the two remaining un-retried write points (seed + `writeRecord`/`resolveDeferredUpdates`, import's no-`createManyData` + fallback) in `withTransientRetry`; `defaultIsTransientError` short-circuits + definitive logical errors to non-transient. + - **#3148** import `resolveRef` flushes pending creates on a same-object miss so + a later row can reference an earlier same-file CREATE, and no longer + negatively caches a miss. + - **#3149** threads an `attempt` counter through `bulkWrite`; seed rechecks by + `externalId` and import by `matchFields` before re-writing, so a + commit-then-lost-response retry cannot duplicate a batch. + - **#3147** `recomputeSummaries` retries transient failures and, on exhaustion, + surfaces `SummaryRecomputeError` (`ERR_SUMMARY_RECOMPUTE`) instead of a + silent warn; seed/import recover it to a warning without re-writing. + - **#3152** autonumbers are assigned after validation, so a batch that dies in + validation consumes no sequence value (no number-range gaps). + +- b8a21ad: Publish/discard package drafts in the draft's own org scope, fixing `no_draft` after saving a draft via Studio. + + Studio "Save Draft" (`PUT /meta/:type/:name?mode=draft`) never threads the session's `activeOrganizationId`, so the draft row is written env-wide (`organization_id = NULL`). "Publish" (`POST /packages/:id/publish-drafts`) resolves the active org and passed it to `promoteDraft`, which looked the draft up with a strict `organization_id = ` equality — so it 404'd (`[no_draft] No pending draft exists …`) on the env-wide row it could never match, even though `listDrafts` had already surfaced that draft to the publish CTA (PR #1852's `$or`). `discardPackageDrafts` had the same latent gap. + + `listDrafts` now projects each draft's own `organizationId`, and `publishPackageDrafts` / `discardPackageDrafts` promote / delete each draft in that scope (env-wide stays env-wide, per-org stays per-org). Seed-body capture and the ADR-0067 revert-plan pre-state read are scoped the same way. + + Fixes #3115. + +- beaf2de: fix(metadata-protocol): strip static `readonly` on INSERT at the data-write ingress (#3043) + + #2948/#3003 made static `readonly: true` fields server-enforced on UPDATE (a + non-system PATCH forging `approval_status: 'approved'` is silently stripped in + the engine), but INSERT was exempt. For approval/status/verdict columns that + exemption was the _shorter_ attack: instead of the #3003 draft-then-PATCH move, a + non-system caller could `POST` a record already `approval_status: 'approved'` in + one step — and the UPDATE-only strip never reached it. + + The strip now also runs on INSERT, but at the **external data-write ingress** + (`DataProtocol.createData` / `createManyData` / `batchData` / `cloneData`) rather + than in the engine. That seam is the single point every external programmatic + create funnels through — the REST CRUD route, the GraphQL/MCP dispatcher + (`bridge.create` → `callData` → `createData`), and bulk import — while **trusted + internal writers** (better-auth's adapter, the metadata repository, the seed + loader) call `engine.insert` directly and bypass it. Enforcing at the ingress + protects every caller/agent path at once without stripping the internal writers + that legitimately seed read-only columns on create (identity provisioning, + provenance stamps, event-log cursors) — the blast radius an engine-level insert + strip would have. + + - **Caller-forged only, at the ingress.** The payload here is raw caller input + (the security middleware stamps `owner_id` / `organization_id` later, inside + `engine.insert`), so only keys the caller actually sent are dropped; server + stamps are added afterwards and are unaffected. + - **Re-derives the default.** A stripped field falls back to its declared + `defaultValue` in the engine (a forged `approval_status` becomes `draft`, not + NULL). + - **System-context exempt.** `isSystem` writes still seed read-only columns. + - **Silent** (HTTP 2xx), per-row on batch/import. `readonlyWhen` stays + INSERT-exempt (a conditional lock needs a prior record). + - **Author-defined business objects only.** Platform objects (`managedBy` set, + or the `sys_` namespace) carry their own field-write governance that a silent + strip must not pre-empt — e.g. ADR-0086 REJECTS (403) a forged + `managed_by:'package'` on `sys_permission_set`, and #3004 rejects a forged + `owner_id`; several of those columns are `readonly`, so stripping them here + would swallow the payload the guard is meant to reject. The #3043 threat is app + approval/status fields, never `sys_` — the same boundary `applySystemFields` + uses for ownership. + + Behavior change: a non-system create through the data API (REST / GraphQL / MCP / + import) can no longer seed a `readonly` column from the payload. Flows that + legitimately write read-only columns at creation must run with a system context + (`isSystem`), the same requirement the UPDATE strip already imposes. + +- 8abf133: **Breaking (discovery response shape): retire the residual feed capability surface (#3180, follow-up to #1959 / ADR-0052 §5).** + + The feed backend was retired long ago; #1959 removed the feed contracts + SDK. This + removes the last discovery/dispatcher references to it, and fixes a real bug where the + `comments` capability was permanently `false`. + + - `@objectstack/spec` — `WellKnownCapabilitiesSchema.feed` and `ApiRoutesSchema.feed` + (`routes.feed`) are **removed**, and the `/api/v1/feed` entry is dropped from + `DEFAULT_DISPATCHER_ROUTES`. FROM → TO: clients reading `discovery.capabilities.feed` + or `discovery.routes.feed` → use `discovery.capabilities.comments`; comments/activity + are served by the generic data API on `sys_comment` / `sys_activity` + (`/api/v1/data/sys_comment/…`). + - `@objectstack/metadata-protocol` — `getDiscovery()` no longer emits the always-`false` + `feed` service/capability. **Bug fix:** the `comments` capability previously keyed off + the deleted `'feed'` service (so it was permanently `false` after #1955); it now tracks + the presence of the `sys_comment` object (provided by the always-on audit slate), so + `declared === enforced`. + - `@objectstack/client` — the internal `feed: '/api/v1/feed'` route constant is removed + (it only existed to satisfy the now-removed `ApiRoutes.feed` type; no client code used it). + +- 515f11a: fix(seed): replaying seeds no longer corrupts lookup natural keys on the upsert update path + + Every dev-server restart replayed package seeds in upsert mode, and any record whose + lookup/master_detail was authored as a natural key could have that reference overwritten + with NULL on the update path (`NOT NULL constraint failed` on required columns; silent + link loss on nullable ones). Four fixes: + + - An unresolved reference now leaves the column untouched (deferred to pass 2) or drops + the record loudly — it is never written as NULL over an existing row. + - DB-side reference resolution probes the target dataset's declared `externalId` (e.g. + `email`) before falling back to `name` and `id`, matching how in-memory resolution + already keyed records. + - A rejected update (e.g. a `state_machine` rule vetoing the replay) no longer severs + natural-key resolution for downstream child datasets. + - Replays are idempotent: an upsert/update whose declared fields already match the + existing row is skipped instead of rewritten (no more `updated_at` churn or lifecycle + re-validation on every boot). + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [6b51346] +- Updated dependencies [80273c8] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [ea32ec7] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/formula@15.2.0 + - @objectstack/metadata-core@15.2.0 + - @objectstack/types@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/metadata-protocol/package.json b/packages/metadata-protocol/package.json index 793e85268..5260df211 100644 --- a/packages/metadata-protocol/package.json +++ b/packages/metadata-protocol/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/metadata-protocol", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "ObjectStack metadata management protocol: sys_metadata CRUD, draft/publish, locks, package ownership, diagnostics (ADR-0076).", "type": "module", diff --git a/packages/metadata/CHANGELOG.md b/packages/metadata/CHANGELOG.md index eea85fe56..26a848f50 100644 --- a/packages/metadata/CHANGELOG.md +++ b/packages/metadata/CHANGELOG.md @@ -1,5 +1,53 @@ # @objectstack/metadata +## 15.2.0 + +### Patch Changes + +- fdc244e: Dev-loop DX fixes from the 15.1 third-party evaluation (P2 batch): + + - **Hot-added objects are now queryable without a restart.** Adding a `*.object.ts` under `os dev` used to recompile "green" while every query answered `no such table` (or `not registered`) until a manual restart: the artifact reload never notified the ObjectQL registry, tables were only created at boot, and seeds only loaded from the boot-time bundle. The `metadata:reloaded` payload now carries the parsed artifact; ObjectQL ingests the object definitions and re-runs the idempotent schema sync (same `skipSchemaSync` opt-out as boot), and the runtime loads seeds for first-seen objects (dev, single-tenant). `os dev` also prints `✚ new object(s): …` on recompile. + - **Dev admin credentials stay visible.** The `os dev` startup banner only showed `admin@objectos.ai / admin123` on the boot that actually seeded it; with the persistent default DB every later boot hid it, and the Console login page never knew it existed. The hint now re-arms on every dev boot for as long as the account still verifies against the default password, and `GET /api/v1/auth/config` exposes a dev-gated `devSeedAdmin` field (never present outside `NODE_ENV=development`) so the login page can show it. + - **`os doctor` reference analysis understands current metadata shapes.** Objects bound through `defineView` containers (`list`/`listViews`/`form`/`formViews` → `data.object`, subform `childObject`, lookup form fields) and app navigation (`objectName`, nested `children`, `areas`) were reported as "defined but not referenced". The collector now walks the canonical shapes (plus flow node `config.object`/`objectName`) and the orphan-view check descends into containers. + +- d2723e2: **`MetadataManager.register()` / `unregister()` now announce to `subscribe()` watchers.** Both updated the registry, persisted to writable loaders and published to realtime, but never fired the watch callbacks — so `subscribe()` looked like it covered every write while silently missing all of them. Only the `saveMetaItem` path (via the repository watch stream) and the filesystem watcher ever reached a subscriber. Runtime consumers that cache metadata — notably ObjectQL's SchemaRegistry bridge, the component that decides what is queryable — went stale on every other write until the process restarted. + + Announcing is now the **default**, so a new call site is correct without knowing this contract exists. This is a contract fix rather than a bug fix: the one live behavior change is that runtime datasource writes (`datasource-admin`) now reach the HMR SSE stream, which subscribes to every registered type. `unregisterPackage()` / `bulkUnregister()` also announce their deletes now — correct, but latent, since neither has a production caller today. + + Bulk ingest opts out explicitly with the new `MetadataWriteOptions` (`{ notify: false }`) — boot-time filesystem priming, artifact ingest, and ObjectQL's registry bridge, each of which either runs before consumers cache anything or announces the whole batch once (as the artifact reload path does via `metadata:reloaded`). The bridge in particular MUST stay silent: it copies objects out of the SchemaRegistry, and announcing would feed them back through a handler that re-registers under `_packageId ?? 'metadata-service'`, overwriting the true package provenance of every object whose body carries no `_packageId`. + + Additive only — `register(type, name, data)` and `unregister(type, name)` keep working unchanged. + + Fixes #3112. + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/metadata-core@15.2.0 + - @objectstack/platform-objects@15.2.0 + - @objectstack/types@15.2.0 + - @objectstack/metadata-fs@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/metadata/package.json b/packages/metadata/package.json index bbc4b5cca..767b18380 100644 --- a/packages/metadata/package.json +++ b/packages/metadata/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/metadata", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Metadata loading, saving, and persistence for ObjectStack", "type": "module", diff --git a/packages/objectql/CHANGELOG.md b/packages/objectql/CHANGELOG.md index e37de8c58..87d9628e6 100644 --- a/packages/objectql/CHANGELOG.md +++ b/packages/objectql/CHANGELOG.md @@ -1,5 +1,169 @@ # @objectstack/objectql +## 15.2.0 + +### Minor Changes + +- 04ecd4e: feat(validation): `state_machine.initialStates` enforces the FSM entry point on INSERT (#3165) + + A `state_machine` rule's `transitions` only governs UPDATE — on INSERT the rule + was a no-op, and a `select` field permits ANY declared option as the initial + value. So a record could be born mid-flow (created already `approved`), skipping + the whole state machine. This was the gap #3043's mitigation idea assumed didn't + exist (declared ≠ enforced, ADR-0049). + + `state_machine` rules gain an optional `initialStates: string[]` — the states a + record may be CREATED in. When set, an insert whose (defaulted) state-field value + is outside the list is rejected server-side with `code: 'invalid_initial_state'`. + Omit it to keep the legacy behavior (no initial-state check on insert). A missing + / empty value is left to required-validation; `transitions` (UPDATE) is + unaffected. Enforced at the same `evaluateValidationRules(..., 'insert')` seam the + engine already runs after field defaults. + +### Patch Changes + +- a8aa34c: Enforce validation rules, `requiredWhen`, and per-option `visibleWhen` on multi-row updates (#3106). The bulk branch of `engine.update` (`options.multi` → `driver.updateMany`) previously never called `evaluateValidationRules`, so every object-level rule (`script`, `state_machine`, `format`, `cross_field`, `json_schema`, `conditional`), field-level `requiredWhen`, and per-option `visibleWhen` check was a silent no-op there. The engine now reads the row-scoped match set (the same AST the write binds, one query shared with the `readonlyWhen` bulk strip) and evaluates the payload against each matched row's prior state; any error-severity violation rejects the whole batch with `ValidationError` (annotated with the failing record id) before anything is written. Schemas needing no prior state (`format`/`json_schema`-only) are evaluated once against the payload with no fetch, and rule-free schemas are unaffected. Behavior change: bulk writes that previously slipped past declared rules now throw. Doc comments in `rule-validator.ts` and `validation.zod.ts` no longer overstate coverage and name the remaining `events: ['delete']` gap (tracked separately). +- e057f42: fix: harden the bulk-write path — retries, idempotency, contracts, and summary visibility (#3147–#3152) + + Six reliability fixes to the batched seed/import + `engine.insert(array)` path + introduced by the #2678 bulk-write rework: + + - **#3151** `bulkWrite` validates that `writeBatch` returns one record per input + row (a short/long/non-array return is degraded per-row, not backfilled as + phantom success); `engine.insert(array)` likewise rejects a short driver + `bulkCreate` return instead of padding afterInsert with `undefined`. + - **#3150** wraps the two remaining un-retried write points (seed + `writeRecord`/`resolveDeferredUpdates`, import's no-`createManyData` + fallback) in `withTransientRetry`; `defaultIsTransientError` short-circuits + definitive logical errors to non-transient. + - **#3148** import `resolveRef` flushes pending creates on a same-object miss so + a later row can reference an earlier same-file CREATE, and no longer + negatively caches a miss. + - **#3149** threads an `attempt` counter through `bulkWrite`; seed rechecks by + `externalId` and import by `matchFields` before re-writing, so a + commit-then-lost-response retry cannot duplicate a batch. + - **#3147** `recomputeSummaries` retries transient failures and, on exhaustion, + surfaces `SummaryRecomputeError` (`ERR_SUMMARY_RECOMPUTE`) instead of a + silent warn; seed/import recover it to a warning without re-writing. + - **#3152** autonumbers are assigned after validation, so a batch that dies in + validation consumes no sequence value (no number-range gaps). + +- a3823b2: Collapse the hook event taxonomy from 18 declared events to the 8 the engine actually dispatches (#3195). The removed 10 (`beforeFindOne`/`afterFindOne`, `beforeCount`/`afterCount`, `beforeAggregate`/`afterAggregate`, `beforeUpdateMany`/`afterUpdateMany`, `beforeDeleteMany`/`afterDeleteMany`) were declared in `HookEvent` but never fired — the enum mirrored the engine method table instead of domain events, so a hook subscribing to them registered fine and then silently no-op'd. + + - `findOne` now fires the same `beforeFind`/`afterFind` hooks as `find` — the read event attaches to record materialization, not the engine method, so one subscription covers every read shape (no separate `beforeFindOne`/`afterFindOne`). + - Bulk (`multi: true`) updates/deletes already fire the singular `beforeUpdate`/`beforeDelete`/`afterUpdate`/`afterDelete` events with the row-scoping predicate in `ctx.input.ast`; this is now documented, and there is no `*Many` event. + - Read authorization / row filtering is the RLS/permission-rule layer's job and field masking is field-level metadata — neither is a hook every author must re-attach. + - `engine.registerHook` now warns when a hook subscribes to an event the engine never dispatches, so enum-vs-dispatch drift can't recur silently. + + No shipped hook or authored metadata used any of the removed events; authoring one now fails loudly at parse/validate time instead of registering a dead hook. Skills and docs updated to teach the 8 events and the declarative alternatives. + +- fdc244e: Dev-loop DX fixes from the 15.1 third-party evaluation (P2 batch): + + - **Hot-added objects are now queryable without a restart.** Adding a `*.object.ts` under `os dev` used to recompile "green" while every query answered `no such table` (or `not registered`) until a manual restart: the artifact reload never notified the ObjectQL registry, tables were only created at boot, and seeds only loaded from the boot-time bundle. The `metadata:reloaded` payload now carries the parsed artifact; ObjectQL ingests the object definitions and re-runs the idempotent schema sync (same `skipSchemaSync` opt-out as boot), and the runtime loads seeds for first-seen objects (dev, single-tenant). `os dev` also prints `✚ new object(s): …` on recompile. + - **Dev admin credentials stay visible.** The `os dev` startup banner only showed `admin@objectos.ai / admin123` on the boot that actually seeded it; with the persistent default DB every later boot hid it, and the Console login page never knew it existed. The hint now re-arms on every dev boot for as long as the account still verifies against the default password, and `GET /api/v1/auth/config` exposes a dev-gated `devSeedAdmin` field (never present outside `NODE_ENV=development`) so the login page can show it. + - **`os doctor` reference analysis understands current metadata shapes.** Objects bound through `defineView` containers (`list`/`listViews`/`form`/`formViews` → `data.object`, subform `childObject`, lookup form fields) and app navigation (`objectName`, nested `children`, `areas`) were reported as "defined but not referenced". The collector now walks the canonical shapes (plus flow node `config.object`/`objectName`) and the orphan-view check descends into containers. + +- 2ea08ee: Flow trigger observability — kill the four-layer silence around record-change flows that never fire (2026-07-17 third-party eval). + + A misauthored auto-launched flow (wrong `objectName`, missing `requires: ['automation','triggers']`, failing start condition) produced ZERO output at every layer: the engine's own registration/binding logs land inside the CLI's boot-quiet stdout window (which swallows debug/info/warn — only error/fatal reach stderr), and each "didn't happen" path was itself silent. Fixes: + + - **Startup banner `Flows:` section** (`os serve`/`os dev`/`os start`): flow count, bound-to-trigger count, registered trigger types, draft count — plus loud `⚠` lines for flows declared with no automation engine enabled (`requires` missing), flows whose trigger type has no registered trigger, and bound record-change flows targeting an unknown object (dead binding). Printed after stdout is restored, so it is immune to the boot-quiet window. + - **Trigger-fired run failures now log at ERROR** (stderr — always visible): the automation engine no longer drops the AutomationResult of a trigger-fired execution; condition-evaluation faults and node failures surface with the flow name. Condition-not-met skips stay at debug (high-frequency, intentional). + - **`RecordChangeTrigger` probes object existence at bind time** and warns when a flow's `objectName` matches no registered object (exact-name matching), instead of silently arming a hook that can never fire. + - **`kernel:bootstrapped` binding audit** in the automation plugin: warns per enabled-but-unbound triggered flow with the reason, and reports registered/bound/draft counts (`AutomationEngine.getTriggerBindingAudit()`, extended `getFlowRuntimeStates()` with `status`/`triggerType`/`object`). + - **`os validate` flow-wiring advisories** (`@objectstack/lint` `validateFlowTriggerReadiness`): warns when a record-triggered flow targets an object the stack does not define, and when an auto-triggered flow's status is `draft` (authored or defaulted — draft flows still fire; declare `active` or `obsolete`). + - Removed leftover boot-debug writes (`registerApp`/`AppPlugin`/`StandaloneStack`/`AuditPlugin` stderr noise) that previous debugging of this same silence had left behind. + +- d2723e2: **`MetadataManager.register()` / `unregister()` now announce to `subscribe()` watchers.** Both updated the registry, persisted to writable loaders and published to realtime, but never fired the watch callbacks — so `subscribe()` looked like it covered every write while silently missing all of them. Only the `saveMetaItem` path (via the repository watch stream) and the filesystem watcher ever reached a subscriber. Runtime consumers that cache metadata — notably ObjectQL's SchemaRegistry bridge, the component that decides what is queryable — went stale on every other write until the process restarted. + + Announcing is now the **default**, so a new call site is correct without knowing this contract exists. This is a contract fix rather than a bug fix: the one live behavior change is that runtime datasource writes (`datasource-admin`) now reach the HMR SSE stream, which subscribes to every registered type. `unregisterPackage()` / `bulkUnregister()` also announce their deletes now — correct, but latent, since neither has a production caller today. + + Bulk ingest opts out explicitly with the new `MetadataWriteOptions` (`{ notify: false }`) — boot-time filesystem priming, artifact ingest, and ObjectQL's registry bridge, each of which either runs before consumers cache anything or announces the whole batch once (as the artifact reload path does via `metadata:reloaded`). The bridge in particular MUST stay silent: it copies objects out of the SchemaRegistry, and announcing would feed them back through a handler that re-registers under `_packageId ?? 'metadata-service'`, overwriting the true package provenance of every object whose body carries no `_packageId`. + + Additive only — `register(type, name, data)` and `unregister(type, name)` keep working unchanged. + + Fixes #3112. + +- 668dd17: **Breaking (npm type surface): retire the vestigial feed contracts + protocol surface (ADR-0052 §5 follow-up, #1959).** + + The `service-feed` runtime was deleted in #1955; `sys_comment` / `sys_activity` + are the canonical record-collaboration/timeline backend. This removes the dead + type surface that still pointed at the deleted runtime — every removed method was + already unreachable (the feed REST route was never mounted → 404; the protocol + implementation was never wired with a feed service, so `requireFeedService()` + could only throw). No behavior changes. + + No authorable metadata key is removed (the `feeds:` object capability flag and + the `RecordActivity` UI component config are unchanged), so `PROTOCOL_MAJOR` + stays 15 and this ships as `minor` rather than a protocol major. + + FROM → TO migration for every removed export: + + - `@objectstack/spec/contracts` — `IFeedService`, `CreateFeedItemInput`, + `UpdateFeedItemInput`, `ListFeedOptions`, `FeedListResult` → **removed, no + replacement**. Comments/activity are plain records: write `sys_comment` / read + `sys_activity` via the data engine or the REST data API. + - `@objectstack/spec/api` — `FeedApiContracts`, `FeedApiErrorCode`, + `FeedProtocol`, and all feed request/response schemas + types (`GetFeed*`, + `CreateFeedItem*`, `UpdateFeedItem*`, `DeleteFeedItem*`, `AddReaction*`, + `RemoveReaction*`, `PinFeedItem*`, `UnpinFeedItem*`, `StarFeedItem*`, + `UnstarFeedItem*`, `SearchFeed*`, `GetChangelog*`, `ChangelogEntry`, + `SubscribeRequest/Response`, `FeedUnsubscribeRequest`, `UnsubscribeResponse`, + `FeedPathParams`, `FeedItemPathParams`, `FeedListFilterType`) → **removed**. Use + the data API against `sys_comment` / `sys_activity` (`/api/v1/data/sys_comment/…`); + reactions and threaded replies are fields on `sys_comment`. + - `@objectstack/spec/data` — `FeedItemSchema`/`FeedItem`, `FeedActorSchema`/`FeedActor`, + `MentionSchema`/`Mention`, `ReactionSchema`/`Reaction`, + `FieldChangeEntrySchema`/`FieldChangeEntry`, `FeedVisibility`, + `RecordSubscriptionSchema`/`RecordSubscription`, `SubscriptionEventType`, and the + `data`-namespace `NotificationChannel` → **removed**. `FeedItemType` and + `FeedFilterMode` are **kept** (live UI activity-timeline config). For notification + channels use `NotificationChannelSchema` from `@objectstack/spec/system`. + - `@objectstack/client` — `client.feed.*` (`list` / `create` / `update` / `delete` / + `addReaction` / `removeReaction` / `pin` / `unpin` / `star` / `unstar` / `search` / + `getChangelog` / `subscribe` / `unsubscribe`) and the re-exported feed response + types → **removed**. One-line fix: use `client.data.*` on `sys_comment` / + `sys_activity`, e.g. `client.data.create('sys_comment', { object, record_id, body })` + and `client.data.find('sys_activity', { filters: [['record_id', '=', id]] })`. + - `@objectstack/metadata-protocol` — `ObjectStackProtocolImplementation` no longer + implements the 14 feed methods; its constructor + `(engine, getServicesRegistry?, getFeedService?, environmentId?)` becomes + `(engine, getServicesRegistry?, environmentId?)`. One-line fix: delete the third + argument. + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [6b51346] +- Updated dependencies [80273c8] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [b8a21ad] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [515f11a] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [ea32ec7] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/metadata-protocol@15.2.0 + - @objectstack/formula@15.2.0 + - @objectstack/metadata-core@15.2.0 + - @objectstack/types@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/objectql/package.json b/packages/objectql/package.json index a97abd272..38fe56cb4 100644 --- a/packages/objectql/package.json +++ b/packages/objectql/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/objectql", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Isomorphic ObjectQL Engine for ObjectStack", "main": "dist/index.js", diff --git a/packages/observability/CHANGELOG.md b/packages/observability/CHANGELOG.md index 6e199e617..38ca9f2cd 100644 --- a/packages/observability/CHANGELOG.md +++ b/packages/observability/CHANGELOG.md @@ -1,5 +1,92 @@ # @objectstack/observability +## 15.2.0 + +### Minor Changes + +- efbcfe1: feat(observability): admin-only richer per-request timing detail via `X-OS-Debug-Timing: json` (#2408) + + Completes the optional "richer JSON" diagnostic from #2408. In addition to the + basic `Server-Timing` header, an admin/service caller can now request a + per-query breakdown — the slowest SQL statements and a query count — by sending + `X-OS-Debug-Timing: json`. The detail is returned in a separate + `X-OS-Debug-Timing-Detail` response header (compact JSON) and is **admin-only, + even under global mode**: an ordinary caller never sees SQL shapes. + + - **observability**: `PerfTiming` gains opt-in per-event detail capture + (`enableDetail` / `recordDetail` / `details`) plus the ambient + `recordServerTimingDetail`. The disclosure gate gains a `privileged` level + (set by `allowPerfDisclosure`, read via `isPerfDisclosurePrivileged`) so the + richer detail can be gated independently of the basic header. + - **driver-sql**: when detail capture is on, the query listener additionally + records each query's **parametrized** statement (knex's `q.sql`, `?` + placeholders) — never the bindings, so no literal row value ever enters the + collector. Zero overhead when detail is off. + - **plugin-hono-server**: `X-OS-Debug-Timing: json` enables detail capture; the + middleware emits `X-OS-Debug-Timing-Detail` (slowest queries, capped and + sanitized to header-safe ASCII) only when the principal is a proven admin. + + Basic and global behavior are unchanged; `json` is purely additive. + +- 2049b6a: feat(observability): admin-gated per-request `Server-Timing` via `X-OS-Debug-Timing` (#2408) + + Perf-tuning mode was previously global-only (`serverTiming` option / + `OS_SERVER_TIMING`), which discloses internal phase durations — a mild + backend-fingerprinting surface — to every caller. This adds the per-request + gating path from the design so an operator can pull a single request's + `Server-Timing` breakdown on a live environment without turning the header on + for everyone. + + - **observability**: a request-scoped disclosure gate (`runWithPerfDisclosure`, + `allowPerfDisclosure`, `isPerfDisclosureAllowed`, `PerfDisclosureGate`) kept + separate from the pure `PerfTiming` collector and pinned to its own + `Symbol.for` store so the middleware and dispatcher share it across module + copies. + - **plugin-hono-server**: the Server-Timing middleware is registered by default + (unless `serverTiming: false`). It runs the collector when timing is global + **or** the request sends `X-OS-Debug-Timing: 1`, and emits the header only + when the gate is open. `OS_PERF_TIMING=1` now also enables global mode. + - **runtime**: after resolving the execution context, the dispatcher opens the + gate for admin/service/system principals, so ordinary callers never receive + the header even if they send the debug header. + + Existing global-mode behavior is unchanged. + +### Patch Changes + +- ce468c8: feat(observability): decompose `Server-Timing` into auth / db / hooks / serialize spans (perf-tuning mode) + + The opt-in `Server-Timing` header now breaks a request's server time into the phases that actually explain it, so an operator can open DevTools → Network → Timing and see where the time went without standing up an external tracing backend: + + - **`db`** — total SQL time with a **query count**. The SQL driver wires knex's `query` / `query-response` events (keyed by `__knexQueryUid`) and folds each query into one aggregate member (`db;dur=210;desc="6 queries"`) — the query count is the number most useful for spotting N sequential round-trips. Timing is attributed to the originating request via `AsyncLocalStorage`, so it is correct under concurrency and never cross-attributes. SQL text is never emitted, only durations and a count. + - **`auth`** — identity / session resolution in the dispatcher, the prime suspect for unexplained data-API overhead. + - **`hooks`** — total business-hook execution time with a hook count, fed through the engine's existing `HookMetricsRecorder` seam (wired from the runtime, so `@objectstack/objectql`'s lean `core` tier stays observability-free). + - **`serialize`** — response JSON encoding in the HTTP adapter. + + Adds `countServerTiming(name, dur, unit)` (and `PerfTiming.count`) to fold high-frequency phases into a single aggregate member instead of flooding the header. Every phase is a no-op when perf-tuning is off (`serverTiming: true` / `OS_SERVER_TIMING=true`), so there is zero measurable overhead on the normal path. + + Closes #2408. + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/observability/package.json b/packages/observability/package.json index 587be9089..bee00878f 100644 --- a/packages/observability/package.json +++ b/packages/observability/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/observability", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Observability contracts and exporters for ObjectStack — MetricsRegistry, ErrorReporter, Logger plus noop/console/OTLP-HTTP exporters. Deployment-target neutral; runtime and services depend on this so the same instrumentation works on Cloudflare Workers, Node, and self-hosted Kubernetes.", "type": "module", diff --git a/packages/platform-objects/CHANGELOG.md b/packages/platform-objects/CHANGELOG.md index d0b9b61f7..352946433 100644 --- a/packages/platform-objects/CHANGELOG.md +++ b/packages/platform-objects/CHANGELOG.md @@ -1,5 +1,30 @@ # @objectstack/platform-objects +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/metadata-core@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/platform-objects/package.json b/packages/platform-objects/package.json index 4fa32a183..72c5ab4c6 100644 --- a/packages/platform-objects/package.json +++ b/packages/platform-objects/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/platform-objects", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Core platform object schemas for ObjectStack — identity, security, audit, tenant, and metadata objects", "main": "dist/index.js", diff --git a/packages/plugins/driver-memory/CHANGELOG.md b/packages/plugins/driver-memory/CHANGELOG.md index 08a0f24ba..a6d31cdaf 100644 --- a/packages/plugins/driver-memory/CHANGELOG.md +++ b/packages/plugins/driver-memory/CHANGELOG.md @@ -1,5 +1,33 @@ # @objectstack/driver-memory +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/plugins/driver-memory/package.json b/packages/plugins/driver-memory/package.json index 0bea70672..b36b5a41f 100644 --- a/packages/plugins/driver-memory/package.json +++ b/packages/plugins/driver-memory/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/driver-memory", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "In-Memory Driver for ObjectStack (Reference Implementation)", "main": "dist/index.js", diff --git a/packages/plugins/driver-mongodb/CHANGELOG.md b/packages/plugins/driver-mongodb/CHANGELOG.md index 09e68aef7..2e167f0be 100644 --- a/packages/plugins/driver-mongodb/CHANGELOG.md +++ b/packages/plugins/driver-mongodb/CHANGELOG.md @@ -1,5 +1,33 @@ # @objectstack/driver-mongodb +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/plugins/driver-mongodb/package.json b/packages/plugins/driver-mongodb/package.json index 08cc44981..a7c790fa1 100644 --- a/packages/plugins/driver-mongodb/package.json +++ b/packages/plugins/driver-mongodb/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/driver-mongodb", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "MongoDB Driver for ObjectStack - Native document database driver via official mongodb client", "main": "dist/index.js", diff --git a/packages/plugins/driver-sql/CHANGELOG.md b/packages/plugins/driver-sql/CHANGELOG.md index 5dd597ed2..77d1dee38 100644 --- a/packages/plugins/driver-sql/CHANGELOG.md +++ b/packages/plugins/driver-sql/CHANGELOG.md @@ -1,5 +1,77 @@ # @objectstack/driver-sql +## 15.2.0 + +### Minor Changes + +- efbcfe1: feat(observability): admin-only richer per-request timing detail via `X-OS-Debug-Timing: json` (#2408) + + Completes the optional "richer JSON" diagnostic from #2408. In addition to the + basic `Server-Timing` header, an admin/service caller can now request a + per-query breakdown — the slowest SQL statements and a query count — by sending + `X-OS-Debug-Timing: json`. The detail is returned in a separate + `X-OS-Debug-Timing-Detail` response header (compact JSON) and is **admin-only, + even under global mode**: an ordinary caller never sees SQL shapes. + + - **observability**: `PerfTiming` gains opt-in per-event detail capture + (`enableDetail` / `recordDetail` / `details`) plus the ambient + `recordServerTimingDetail`. The disclosure gate gains a `privileged` level + (set by `allowPerfDisclosure`, read via `isPerfDisclosurePrivileged`) so the + richer detail can be gated independently of the basic header. + - **driver-sql**: when detail capture is on, the query listener additionally + records each query's **parametrized** statement (knex's `q.sql`, `?` + placeholders) — never the bindings, so no literal row value ever enters the + collector. Zero overhead when detail is off. + - **plugin-hono-server**: `X-OS-Debug-Timing: json` enables detail capture; the + middleware emits `X-OS-Debug-Timing-Detail` (slowest queries, capped and + sanitized to header-safe ASCII) only when the principal is a proven admin. + + Basic and global behavior are unchanged; `json` is purely additive. + +### Patch Changes + +- ce468c8: feat(observability): decompose `Server-Timing` into auth / db / hooks / serialize spans (perf-tuning mode) + + The opt-in `Server-Timing` header now breaks a request's server time into the phases that actually explain it, so an operator can open DevTools → Network → Timing and see where the time went without standing up an external tracing backend: + + - **`db`** — total SQL time with a **query count**. The SQL driver wires knex's `query` / `query-response` events (keyed by `__knexQueryUid`) and folds each query into one aggregate member (`db;dur=210;desc="6 queries"`) — the query count is the number most useful for spotting N sequential round-trips. Timing is attributed to the originating request via `AsyncLocalStorage`, so it is correct under concurrency and never cross-attributes. SQL text is never emitted, only durations and a count. + - **`auth`** — identity / session resolution in the dispatcher, the prime suspect for unexplained data-API overhead. + - **`hooks`** — total business-hook execution time with a hook count, fed through the engine's existing `HookMetricsRecorder` seam (wired from the runtime, so `@objectstack/objectql`'s lean `core` tier stays observability-free). + - **`serialize`** — response JSON encoding in the HTTP adapter. + + Adds `countServerTiming(name, dur, unit)` (and `PerfTiming.count`) to fold high-frequency phases into a single aggregate member instead of flooding the header. Every phase is a no-op when perf-tuning is off (`serverTiming: true` / `OS_SERVER_TIMING=true`), so there is zero measurable overhead on the normal path. + + Closes #2408. + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [efbcfe1] +- Updated dependencies [2049b6a] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [ce468c8] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/observability@15.2.0 + - @objectstack/types@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/plugins/driver-sql/package.json b/packages/plugins/driver-sql/package.json index 1c9a603a8..65dbd023a 100644 --- a/packages/plugins/driver-sql/package.json +++ b/packages/plugins/driver-sql/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/driver-sql", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "SQL Driver for ObjectStack - Supports PostgreSQL, MySQL, SQLite via Knex", "main": "dist/index.js", diff --git a/packages/plugins/driver-sqlite-wasm/CHANGELOG.md b/packages/plugins/driver-sqlite-wasm/CHANGELOG.md index 595c54803..f3a9eb919 100644 --- a/packages/plugins/driver-sqlite-wasm/CHANGELOG.md +++ b/packages/plugins/driver-sqlite-wasm/CHANGELOG.md @@ -1,5 +1,36 @@ # @objectstack/driver-sqlite-wasm +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [efbcfe1] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [ce468c8] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/driver-sql@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/plugins/driver-sqlite-wasm/package.json b/packages/plugins/driver-sqlite-wasm/package.json index 3f9114624..6a1194533 100644 --- a/packages/plugins/driver-sqlite-wasm/package.json +++ b/packages/plugins/driver-sqlite-wasm/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/driver-sqlite-wasm", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "WASM SQLite Driver for ObjectStack — runs in browser/WebContainer (StackBlitz) without native bindings", "keywords": [ diff --git a/packages/plugins/embedder-openai/CHANGELOG.md b/packages/plugins/embedder-openai/CHANGELOG.md index cdc103da1..5cea2a4df 100644 --- a/packages/plugins/embedder-openai/CHANGELOG.md +++ b/packages/plugins/embedder-openai/CHANGELOG.md @@ -1,5 +1,29 @@ # @objectstack/embedder-openai +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/plugins/embedder-openai/package.json b/packages/plugins/embedder-openai/package.json index 4a0f52779..f5f502db3 100644 --- a/packages/plugins/embedder-openai/package.json +++ b/packages/plugins/embedder-openai/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/embedder-openai", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "OpenAI-compatible embedder for ObjectStack — works against OpenAI, 阿里通义 DashScope, 智谱 BigModel, 硅基流动 SiliconFlow, 火山引擎 Doubao, MiniMax, Ollama, and any drop-in OpenAI-shape endpoint.", "main": "dist/index.js", diff --git a/packages/plugins/knowledge-memory/CHANGELOG.md b/packages/plugins/knowledge-memory/CHANGELOG.md index 43d9940c9..b606248b2 100644 --- a/packages/plugins/knowledge-memory/CHANGELOG.md +++ b/packages/plugins/knowledge-memory/CHANGELOG.md @@ -1,5 +1,34 @@ # @objectstack/knowledge-memory +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/service-knowledge@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/plugins/knowledge-memory/package.json b/packages/plugins/knowledge-memory/package.json index 7bae9b8f3..10613b3e0 100644 --- a/packages/plugins/knowledge-memory/package.json +++ b/packages/plugins/knowledge-memory/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/knowledge-memory", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "In-memory knowledge adapter for ObjectStack (dev / test reference implementation).", "main": "dist/index.js", diff --git a/packages/plugins/knowledge-ragflow/CHANGELOG.md b/packages/plugins/knowledge-ragflow/CHANGELOG.md index 5b0849064..da92873a2 100644 --- a/packages/plugins/knowledge-ragflow/CHANGELOG.md +++ b/packages/plugins/knowledge-ragflow/CHANGELOG.md @@ -1,5 +1,34 @@ # @objectstack/knowledge-ragflow +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/service-knowledge@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/plugins/knowledge-ragflow/package.json b/packages/plugins/knowledge-ragflow/package.json index 8c48e3a31..1d4b692b2 100644 --- a/packages/plugins/knowledge-ragflow/package.json +++ b/packages/plugins/knowledge-ragflow/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/knowledge-ragflow", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "RAGFlow knowledge adapter for ObjectStack — production-grade RAG via the Apache 2.0 RAGFlow REST API.", "main": "dist/index.js", diff --git a/packages/plugins/plugin-approvals/CHANGELOG.md b/packages/plugins/plugin-approvals/CHANGELOG.md index 175d0f87b..bd3fb23b4 100644 --- a/packages/plugins/plugin-approvals/CHANGELOG.md +++ b/packages/plugins/plugin-approvals/CHANGELOG.md @@ -1,5 +1,80 @@ # @objectstack/plugin-approvals +## 15.2.0 + +### Minor Changes + +- 3a18b60: feat(approvals): rename the `role` approver type to `org_membership_level` (#3133) + + `ApproverType.role` was the last platform surface projecting the reserved word + "role" (ADR-0090 D3). It is not covered by D3's better-auth exception: that + exception protects better-auth's own `sys_member.role` **column**, which we do + not own — `ApproverType` is our own enum, an authoring surface, and D3 mandates + that the projection of that concept is spelled `org_membership_level` and + labelled "organization membership", **never "role"**. + + The sentence licensing the leak was also false: ADR-0090 D3 claims + `sys_member.role` is "already relabelled `org_membership_level` in the platform + projection", but `org_membership_level` existed nowhere in the codebase and + ADR-0057 D7 lists that relabel under "Deferred (evidence-gated, P4)". The + projection never landed, so the word reached authors. + + The name manufactured a real, silent failure — "hotcrm class": every other + surface renamed to `position` (`sys_role`, `ShareRecipientType.role`, + `ctx.roles[]`), so `{ type: 'role', value: 'sales_manager' }` reads as the + legacy spelling of a position. It resolves against the membership tier, finds + no member row, falls back to an inert `role:sales_manager` literal, and the + request waits forever on an approver that cannot exist. + + - **spec**: `ApproverType` gains `org_membership_level`; `role` stays as a + deprecated alias for one window (a published 15.x flow keeps loading) with + `DEPRECATED_APPROVER_TYPES` + `canonicalApproverType()` as the single source + for the mapping. Removed in the next major. + - **plugin-approvals**: resolves on the canonical type and warns on the + deprecated spelling. The `type:value` fallback literal keeps the **authored** + spelling — stored `sys_approval_approver` rows and `pending_approvers` slots + from 15.x carry `role:`, and rewriting it would orphan them. + - **lint**: `approval-role-not-membership-tier` → `approval-approver-not-membership-tier` + (the rule id carried the reserved word too), plus a new + `approval-approver-type-deprecated`. The two are mutually exclusive: a bad + _value_ wins, because prescribing `org_membership_level` for a position name + would be wrong advice — the fix there is `position`. + + Authoring `type: 'role'` keeps working and now says so out loud. Rewrite it as + `org_membership_level`; if the value is an org position, the fix is `position`. + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [6b51346] +- Updated dependencies [80273c8] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [ea32ec7] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/formula@15.2.0 + - @objectstack/metadata-core@15.2.0 + - @objectstack/platform-objects@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/plugins/plugin-approvals/package.json b/packages/plugins/plugin-approvals/package.json index a16b0fb73..44a99f8ef 100644 --- a/packages/plugins/plugin-approvals/package.json +++ b/packages/plugins/plugin-approvals/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/plugin-approvals", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Multi-step approval engine for ObjectStack — sys_approval_process + sys_approval_request + sys_approval_action + IApprovalService.", "main": "dist/index.js", diff --git a/packages/plugins/plugin-audit/CHANGELOG.md b/packages/plugins/plugin-audit/CHANGELOG.md index d81cd2cca..eb680e62d 100644 --- a/packages/plugins/plugin-audit/CHANGELOG.md +++ b/packages/plugins/plugin-audit/CHANGELOG.md @@ -1,5 +1,45 @@ # @objectstack/plugin-audit +## 15.2.0 + +### Patch Changes + +- 2ea08ee: Flow trigger observability — kill the four-layer silence around record-change flows that never fire (2026-07-17 third-party eval). + + A misauthored auto-launched flow (wrong `objectName`, missing `requires: ['automation','triggers']`, failing start condition) produced ZERO output at every layer: the engine's own registration/binding logs land inside the CLI's boot-quiet stdout window (which swallows debug/info/warn — only error/fatal reach stderr), and each "didn't happen" path was itself silent. Fixes: + + - **Startup banner `Flows:` section** (`os serve`/`os dev`/`os start`): flow count, bound-to-trigger count, registered trigger types, draft count — plus loud `⚠` lines for flows declared with no automation engine enabled (`requires` missing), flows whose trigger type has no registered trigger, and bound record-change flows targeting an unknown object (dead binding). Printed after stdout is restored, so it is immune to the boot-quiet window. + - **Trigger-fired run failures now log at ERROR** (stderr — always visible): the automation engine no longer drops the AutomationResult of a trigger-fired execution; condition-evaluation faults and node failures surface with the flow name. Condition-not-met skips stay at debug (high-frequency, intentional). + - **`RecordChangeTrigger` probes object existence at bind time** and warns when a flow's `objectName` matches no registered object (exact-name matching), instead of silently arming a hook that can never fire. + - **`kernel:bootstrapped` binding audit** in the automation plugin: warns per enabled-but-unbound triggered flow with the reason, and reports registered/bound/draft counts (`AutomationEngine.getTriggerBindingAudit()`, extended `getFlowRuntimeStates()` with `status`/`triggerType`/`object`). + - **`os validate` flow-wiring advisories** (`@objectstack/lint` `validateFlowTriggerReadiness`): warns when a record-triggered flow targets an object the stack does not define, and when an auto-triggered flow's status is `draft` (authored or defaulted — draft flows still fire; declare `active` or `obsolete`). + - Removed leftover boot-debug writes (`registerApp`/`AppPlugin`/`StandaloneStack`/`AuditPlugin` stderr noise) that previous debugging of this same silence had left behind. + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/platform-objects@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/plugins/plugin-audit/package.json b/packages/plugins/plugin-audit/package.json index 8fd3467b9..ffc293652 100644 --- a/packages/plugins/plugin-audit/package.json +++ b/packages/plugins/plugin-audit/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/plugin-audit", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Audit Plugin for ObjectStack — System audit log object and audit trail", "main": "dist/index.js", diff --git a/packages/plugins/plugin-auth/CHANGELOG.md b/packages/plugins/plugin-auth/CHANGELOG.md index 512310c0e..78b998d4e 100644 --- a/packages/plugins/plugin-auth/CHANGELOG.md +++ b/packages/plugins/plugin-auth/CHANGELOG.md @@ -1,5 +1,66 @@ # Changelog +## 15.2.0 + +### Patch Changes + +- deb7e7e: fix(plugin-auth): run better-auth adapter WRITES as system context so #2948 doesn't strip readonly identity columns (#3164) + + The better-auth ObjectQL adapter wrapped the engine so its READS carried + `isSystem` (to bypass the control-plane org-scope read hook), but its WRITES + passed through with no context. The static-`readonly` UPDATE strip (#2948) runs + on any non-system update — and since the adapter carries no caller context, + `!ctx?.isSystem` was `true`, so the strip silently DROPPED better-auth's own + writes to readonly `sys_user` columns: `email` (change-email), `banned` / + `ban_reason` / `ban_expires` (admin ban). Those operations returned success but + never persisted. + + `withSystemReadContext` is renamed to `withSystemContext` (a deprecated alias is + kept for one release) and now injects `isSystem` on `insert` / `update` / + `delete` as well as reads. This is correct because these are the identity + authority's own writes — user-context writes to `managedBy: 'better-auth'` tables + are already rejected upstream by the ADR-0092 identity write guard, so the + adapter path only ever carries better-auth's internal writes. + + Found while implementing #3043 (the INSERT-side readonly strip). This is its + UPDATE-side dual: #3043 relocated the insert strip to the external ingress + precisely because internal writers (this adapter included) don't declare + `isSystem`; the pre-existing engine-level UPDATE strip has no such relocation, so + the adapter had to declare its writes system. + +- fdc244e: Dev-loop DX fixes from the 15.1 third-party evaluation (P2 batch): + + - **Hot-added objects are now queryable without a restart.** Adding a `*.object.ts` under `os dev` used to recompile "green" while every query answered `no such table` (or `not registered`) until a manual restart: the artifact reload never notified the ObjectQL registry, tables were only created at boot, and seeds only loaded from the boot-time bundle. The `metadata:reloaded` payload now carries the parsed artifact; ObjectQL ingests the object definitions and re-runs the idempotent schema sync (same `skipSchemaSync` opt-out as boot), and the runtime loads seeds for first-seen objects (dev, single-tenant). `os dev` also prints `✚ new object(s): …` on recompile. + - **Dev admin credentials stay visible.** The `os dev` startup banner only showed `admin@objectos.ai / admin123` on the boot that actually seeded it; with the persistent default DB every later boot hid it, and the Console login page never knew it existed. The hint now re-arms on every dev boot for as long as the account still verifies against the default password, and `GET /api/v1/auth/config` exposes a dev-gated `devSeedAdmin` field (never present outside `NODE_ENV=development`) so the login page can show it. + - **`os doctor` reference analysis understands current metadata shapes.** Objects bound through `defineView` containers (`list`/`listViews`/`form`/`formViews` → `data.object`, subform `childObject`, lookup form fields) and app navigation (`objectName`, nested `children`, `areas`) were reported as "defined but not referenced". The collector now walks the canonical shapes (plus flow node `config.object`/`objectName`) and the orphan-view check descends into containers. + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/rest@15.2.0 + - @objectstack/platform-objects@15.2.0 + - @objectstack/types@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/plugins/plugin-auth/package.json b/packages/plugins/plugin-auth/package.json index 0b5f5e41e..75b74c4ef 100644 --- a/packages/plugins/plugin-auth/package.json +++ b/packages/plugins/plugin-auth/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/plugin-auth", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Authentication & Identity Plugin for ObjectStack", "main": "dist/index.js", diff --git a/packages/plugins/plugin-dev/CHANGELOG.md b/packages/plugins/plugin-dev/CHANGELOG.md index 7518e766d..842b1f00a 100644 --- a/packages/plugins/plugin-dev/CHANGELOG.md +++ b/packages/plugins/plugin-dev/CHANGELOG.md @@ -1,5 +1,52 @@ # @objectstack/plugin-dev +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [deb7e7e] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [fdc244e] +- Updated dependencies [5e3301d] +- Updated dependencies [2ea08ee] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [efbcfe1] +- Updated dependencies [2049b6a] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [515f11a] +- Updated dependencies [4174a07] +- Updated dependencies [ce468c8] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/plugin-auth@15.2.0 + - @objectstack/objectql@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/rest@15.2.0 + - @objectstack/runtime@15.2.0 + - @objectstack/plugin-hono-server@15.2.0 + - @objectstack/account@15.2.0 + - @objectstack/setup@15.2.0 + - @objectstack/driver-memory@15.2.0 + - @objectstack/plugin-security@15.2.0 + - @objectstack/service-i18n@15.2.0 + - @objectstack/types@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/plugins/plugin-dev/package.json b/packages/plugins/plugin-dev/package.json index f2e8de407..353d5c412 100644 --- a/packages/plugins/plugin-dev/package.json +++ b/packages/plugins/plugin-dev/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/plugin-dev", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Development Mode Plugin for ObjectStack — auto-enables all services with in-memory implementations", "main": "dist/index.js", diff --git a/packages/plugins/plugin-email/CHANGELOG.md b/packages/plugins/plugin-email/CHANGELOG.md index 870b32c09..26a476868 100644 --- a/packages/plugins/plugin-email/CHANGELOG.md +++ b/packages/plugins/plugin-email/CHANGELOG.md @@ -1,5 +1,38 @@ # @objectstack/plugin-email +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [6b51346] +- Updated dependencies [80273c8] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [ea32ec7] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/formula@15.2.0 + - @objectstack/platform-objects@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/plugins/plugin-email/package.json b/packages/plugins/plugin-email/package.json index 7b390bc8e..a95525bd5 100644 --- a/packages/plugins/plugin-email/package.json +++ b/packages/plugins/plugin-email/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/plugin-email", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Email service plugin for ObjectStack — IEmailService + transport-pluggable outbound delivery with sys_email persistence.", "main": "dist/index.js", diff --git a/packages/plugins/plugin-hono-server/CHANGELOG.md b/packages/plugins/plugin-hono-server/CHANGELOG.md index bf5b9adec..de86eb9ff 100644 --- a/packages/plugins/plugin-hono-server/CHANGELOG.md +++ b/packages/plugins/plugin-hono-server/CHANGELOG.md @@ -1,5 +1,101 @@ # @objectstack/plugin-hono-server +## 15.2.0 + +### Minor Changes + +- efbcfe1: feat(observability): admin-only richer per-request timing detail via `X-OS-Debug-Timing: json` (#2408) + + Completes the optional "richer JSON" diagnostic from #2408. In addition to the + basic `Server-Timing` header, an admin/service caller can now request a + per-query breakdown — the slowest SQL statements and a query count — by sending + `X-OS-Debug-Timing: json`. The detail is returned in a separate + `X-OS-Debug-Timing-Detail` response header (compact JSON) and is **admin-only, + even under global mode**: an ordinary caller never sees SQL shapes. + + - **observability**: `PerfTiming` gains opt-in per-event detail capture + (`enableDetail` / `recordDetail` / `details`) plus the ambient + `recordServerTimingDetail`. The disclosure gate gains a `privileged` level + (set by `allowPerfDisclosure`, read via `isPerfDisclosurePrivileged`) so the + richer detail can be gated independently of the basic header. + - **driver-sql**: when detail capture is on, the query listener additionally + records each query's **parametrized** statement (knex's `q.sql`, `?` + placeholders) — never the bindings, so no literal row value ever enters the + collector. Zero overhead when detail is off. + - **plugin-hono-server**: `X-OS-Debug-Timing: json` enables detail capture; the + middleware emits `X-OS-Debug-Timing-Detail` (slowest queries, capped and + sanitized to header-safe ASCII) only when the principal is a proven admin. + + Basic and global behavior are unchanged; `json` is purely additive. + +- 2049b6a: feat(observability): admin-gated per-request `Server-Timing` via `X-OS-Debug-Timing` (#2408) + + Perf-tuning mode was previously global-only (`serverTiming` option / + `OS_SERVER_TIMING`), which discloses internal phase durations — a mild + backend-fingerprinting surface — to every caller. This adds the per-request + gating path from the design so an operator can pull a single request's + `Server-Timing` breakdown on a live environment without turning the header on + for everyone. + + - **observability**: a request-scoped disclosure gate (`runWithPerfDisclosure`, + `allowPerfDisclosure`, `isPerfDisclosureAllowed`, `PerfDisclosureGate`) kept + separate from the pure `PerfTiming` collector and pinned to its own + `Symbol.for` store so the middleware and dispatcher share it across module + copies. + - **plugin-hono-server**: the Server-Timing middleware is registered by default + (unless `serverTiming: false`). It runs the collector when timing is global + **or** the request sends `X-OS-Debug-Timing: 1`, and emits the header only + when the gate is open. `OS_PERF_TIMING=1` now also enables global mode. + - **runtime**: after resolving the execution context, the dispatcher opens the + gate for admin/service/system principals, so ordinary callers never receive + the header even if they send the debug header. + + Existing global-mode behavior is unchanged. + +### Patch Changes + +- ce468c8: feat(observability): decompose `Server-Timing` into auth / db / hooks / serialize spans (perf-tuning mode) + + The opt-in `Server-Timing` header now breaks a request's server time into the phases that actually explain it, so an operator can open DevTools → Network → Timing and see where the time went without standing up an external tracing backend: + + - **`db`** — total SQL time with a **query count**. The SQL driver wires knex's `query` / `query-response` events (keyed by `__knexQueryUid`) and folds each query into one aggregate member (`db;dur=210;desc="6 queries"`) — the query count is the number most useful for spotting N sequential round-trips. Timing is attributed to the originating request via `AsyncLocalStorage`, so it is correct under concurrency and never cross-attributes. SQL text is never emitted, only durations and a count. + - **`auth`** — identity / session resolution in the dispatcher, the prime suspect for unexplained data-API overhead. + - **`hooks`** — total business-hook execution time with a hook count, fed through the engine's existing `HookMetricsRecorder` seam (wired from the runtime, so `@objectstack/objectql`'s lean `core` tier stays observability-free). + - **`serialize`** — response JSON encoding in the HTTP adapter. + + Adds `countServerTiming(name, dur, unit)` (and `PerfTiming.count`) to fold high-frequency phases into a single aggregate member instead of flooding the header. Every phase is a no-op when perf-tuning is off (`serverTiming: true` / `OS_SERVER_TIMING=true`), so there is zero measurable overhead on the normal path. + + Closes #2408. + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [efbcfe1] +- Updated dependencies [2049b6a] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [ce468c8] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/observability@15.2.0 + - @objectstack/types@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/plugins/plugin-hono-server/package.json b/packages/plugins/plugin-hono-server/package.json index f00dbcbb8..7406e3f69 100644 --- a/packages/plugins/plugin-hono-server/package.json +++ b/packages/plugins/plugin-hono-server/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/plugin-hono-server", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Standard Hono Server Adapter for ObjectStack Runtime", "main": "dist/index.js", diff --git a/packages/plugins/plugin-pinyin-search/CHANGELOG.md b/packages/plugins/plugin-pinyin-search/CHANGELOG.md index ceb7d22fa..c34eb19d4 100644 --- a/packages/plugins/plugin-pinyin-search/CHANGELOG.md +++ b/packages/plugins/plugin-pinyin-search/CHANGELOG.md @@ -1,5 +1,23 @@ # @objectstack/plugin-pinyin-search +## 15.2.0 + +### Patch Changes + +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [fdc244e] +- Updated dependencies [2ea08ee] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [668dd17] +- Updated dependencies [04ecd4e] + - @objectstack/objectql@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/types@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/plugins/plugin-pinyin-search/package.json b/packages/plugins/plugin-pinyin-search/package.json index abcc26ce4..418f491bc 100644 --- a/packages/plugins/plugin-pinyin-search/package.json +++ b/packages/plugins/plugin-pinyin-search/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/plugin-pinyin-search", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Pinyin search recall for ObjectStack — populates the hidden `__search` companion column (full pinyin + initials of the display/name field) so `$search` hits CJK names typed as pinyin. Locale-gated via OS_SEARCH_PINYIN_ENABLED (#2486).", "main": "dist/index.js", diff --git a/packages/plugins/plugin-reports/CHANGELOG.md b/packages/plugins/plugin-reports/CHANGELOG.md index d6294a3b9..645b6ee59 100644 --- a/packages/plugins/plugin-reports/CHANGELOG.md +++ b/packages/plugins/plugin-reports/CHANGELOG.md @@ -1,5 +1,34 @@ # @objectstack/plugin-reports +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/platform-objects@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/plugins/plugin-reports/package.json b/packages/plugins/plugin-reports/package.json index 33c99eeec..1d6d5a383 100644 --- a/packages/plugins/plugin-reports/package.json +++ b/packages/plugins/plugin-reports/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/plugin-reports", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Saved reports + scheduled email digests for ObjectStack — sys_saved_report + sys_report_schedule + IReportService.", "main": "dist/index.js", diff --git a/packages/plugins/plugin-security/CHANGELOG.md b/packages/plugins/plugin-security/CHANGELOG.md index 962f20507..782a59ac8 100644 --- a/packages/plugins/plugin-security/CHANGELOG.md +++ b/packages/plugins/plugin-security/CHANGELOG.md @@ -1,5 +1,38 @@ # @objectstack/plugin-security +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [6b51346] +- Updated dependencies [80273c8] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [ea32ec7] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/formula@15.2.0 + - @objectstack/platform-objects@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/plugins/plugin-security/package.json b/packages/plugins/plugin-security/package.json index fe02c5091..5296f6fb5 100644 --- a/packages/plugins/plugin-security/package.json +++ b/packages/plugins/plugin-security/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/plugin-security", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Security Plugin for ObjectStack — RBAC, RLS, and Field-Level Security Runtime", "main": "dist/index.js", diff --git a/packages/plugins/plugin-sharing/CHANGELOG.md b/packages/plugins/plugin-sharing/CHANGELOG.md index 73ffc162d..a99544b00 100644 --- a/packages/plugins/plugin-sharing/CHANGELOG.md +++ b/packages/plugins/plugin-sharing/CHANGELOG.md @@ -1,5 +1,41 @@ # @objectstack/plugin-sharing +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [6b51346] +- Updated dependencies [80273c8] +- Updated dependencies [fdc244e] +- Updated dependencies [5e3301d] +- Updated dependencies [2ea08ee] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [ea32ec7] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/objectql@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/formula@15.2.0 + - @objectstack/platform-objects@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/plugins/plugin-sharing/package.json b/packages/plugins/plugin-sharing/package.json index 18db7193c..27d5faf31 100644 --- a/packages/plugins/plugin-sharing/package.json +++ b/packages/plugins/plugin-sharing/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/plugin-sharing", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Record-level sharing for ObjectStack — sys_record_share + middleware that enforces sharingModel + ISharingService.", "main": "dist/index.js", diff --git a/packages/plugins/plugin-webhooks/CHANGELOG.md b/packages/plugins/plugin-webhooks/CHANGELOG.md index 9d6857b33..16c315092 100644 --- a/packages/plugins/plugin-webhooks/CHANGELOG.md +++ b/packages/plugins/plugin-webhooks/CHANGELOG.md @@ -1,5 +1,41 @@ # @objectstack/plugin-webhooks +## 15.2.0 + +### Patch Changes + +- 4b6fde8: Trim the dead `undelete` and `api` webhook triggers (#3196). `WebhookTriggerType` declared five triggers but only three ever fired: + + - `undelete` had no event source — the engine has no soft-delete/restore capability (`delete` is a hard delete; no `deleted_at` convention, no restore operation, and `data.record.undeleted` is never emitted). The `undeleted` case in the auto-enqueuer's action mapper was dead code awaiting a producer that doesn't exist. + - `api` ("manually triggered") had no fire path — the only webhook HTTP surface re-queues already-failed deliveries; nothing originates a manual fire. + + Both are removed from the enum (contract-first, matching #3184/#3195): authoring a webhook on a removed trigger now fails loudly at `os validate` / registration instead of registering a webhook that silently never fires. No shipped webhook metadata used either. The auto-enqueuer now also warns when a persisted `sys_webhook` row carries a trigger it can't map to an emitted record event (a drift-guard, so a dead trigger can't silently no-op again). Reintroduce `undelete` only alongside a real restore subsystem, and `api` only alongside a real manual-fire endpoint. Updated the `sys_webhook` trigger options, field help (all locales), docs, and reference; added rejection tests. + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/service-messaging@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/plugins/plugin-webhooks/package.json b/packages/plugins/plugin-webhooks/package.json index 50ca71add..3c368d8ea 100644 --- a/packages/plugins/plugin-webhooks/package.json +++ b/packages/plugins/plugin-webhooks/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/plugin-webhooks", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Persistent, cluster-aware webhook dispatcher. Durable outbox + per-partition cluster.lock for exactly-once-ish delivery across nodes. See content/docs/concepts/webhook-delivery.mdx.", "type": "module", diff --git a/packages/qa/dogfood/CHANGELOG.md b/packages/qa/dogfood/CHANGELOG.md index 0fc120659..083bef255 100644 --- a/packages/qa/dogfood/CHANGELOG.md +++ b/packages/qa/dogfood/CHANGELOG.md @@ -1,5 +1,45 @@ # @objectstack/dogfood +## 0.0.38 + +### Patch Changes + +- Updated dependencies [41e703b] +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [deb7e7e] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [fdc244e] +- Updated dependencies [5e3301d] +- Updated dependencies [2ea08ee] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/connector-openapi@15.2.0 + - @objectstack/spec@15.2.0 + - @objectstack/plugin-auth@15.2.0 + - @objectstack/objectql@15.2.0 + - @objectstack/plugin-audit@15.2.0 + - @objectstack/example-showcase@0.3.12 + - @objectstack/verify@15.2.0 + - @objectstack/example-crm@4.0.90 + - @objectstack/connector-mcp@15.2.0 + - @objectstack/connector-rest@15.2.0 + - @objectstack/plugin-security@15.2.0 + - @objectstack/service-storage@15.2.0 + ## 0.0.37 ### Patch Changes diff --git a/packages/qa/dogfood/package.json b/packages/qa/dogfood/package.json index 3a565cdc8..d5baaf232 100644 --- a/packages/qa/dogfood/package.json +++ b/packages/qa/dogfood/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/dogfood", - "version": "0.0.37", + "version": "0.0.38", "private": true, "license": "Apache-2.0", "description": "Dogfood regression gate — hand-written golden tests that boot real example apps through @objectstack/verify's in-process HTTP stack, pinning historical runtime regressions (#2018 timezone bucketing, #1994 cross-owner RLS, #2004 field fidelity) that static checks miss.", diff --git a/packages/qa/downstream-contract/CHANGELOG.md b/packages/qa/downstream-contract/CHANGELOG.md index 4131a65d9..9e6caca9c 100644 --- a/packages/qa/downstream-contract/CHANGELOG.md +++ b/packages/qa/downstream-contract/CHANGELOG.md @@ -1,5 +1,29 @@ # @objectstack/downstream-contract +## 0.0.36 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + ## 0.0.35 ### Patch Changes diff --git a/packages/qa/downstream-contract/package.json b/packages/qa/downstream-contract/package.json index 369735b93..5ec4d1404 100644 --- a/packages/qa/downstream-contract/package.json +++ b/packages/qa/downstream-contract/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/downstream-contract", - "version": "0.0.35", + "version": "0.0.36", "description": "Frozen third-party consumer fixture — a backward-compatibility gate for @objectstack/spec. Authored the way an external project on a published release authors metadata; if a spec change breaks it, that change is breaking (#2035).", "license": "Apache-2.0", "private": true, diff --git a/packages/qa/http-conformance/CHANGELOG.md b/packages/qa/http-conformance/CHANGELOG.md index 87f20efdf..865ae32ba 100644 --- a/packages/qa/http-conformance/CHANGELOG.md +++ b/packages/qa/http-conformance/CHANGELOG.md @@ -1,5 +1,14 @@ # @objectstack/http-conformance +## 0.0.4 + +### Patch Changes + +- Updated dependencies [e057f42] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] + - @objectstack/core@15.2.0 + ## 0.0.3 ### Patch Changes diff --git a/packages/qa/http-conformance/package.json b/packages/qa/http-conformance/package.json index 8b38ebfa6..4bec23a72 100644 --- a/packages/qa/http-conformance/package.json +++ b/packages/qa/http-conformance/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/http-conformance", - "version": "0.0.3", + "version": "0.0.4", "private": true, "license": "Apache-2.0", "description": "HTTP transport-port conformance gate (ADR-0076 D11/OQ#10, #2462) — a zero-dependency node:http reference implementation of IHttpServer plus a cross-adapter suite that boots the dispatcher bridge and REST generator on it AND on plugin-hono-server, pinning that the port stays free of framework-isms. Not published; validation instrument, not a product server.", diff --git a/packages/rest/CHANGELOG.md b/packages/rest/CHANGELOG.md index 5f6f62083..8c5b532d2 100644 --- a/packages/rest/CHANGELOG.md +++ b/packages/rest/CHANGELOG.md @@ -1,5 +1,61 @@ # @objectstack/rest +## 15.2.0 + +### Patch Changes + +- e057f42: fix: harden the bulk-write path — retries, idempotency, contracts, and summary visibility (#3147–#3152) + + Six reliability fixes to the batched seed/import + `engine.insert(array)` path + introduced by the #2678 bulk-write rework: + + - **#3151** `bulkWrite` validates that `writeBatch` returns one record per input + row (a short/long/non-array return is degraded per-row, not backfilled as + phantom success); `engine.insert(array)` likewise rejects a short driver + `bulkCreate` return instead of padding afterInsert with `undefined`. + - **#3150** wraps the two remaining un-retried write points (seed + `writeRecord`/`resolveDeferredUpdates`, import's no-`createManyData` + fallback) in `withTransientRetry`; `defaultIsTransientError` short-circuits + definitive logical errors to non-transient. + - **#3148** import `resolveRef` flushes pending creates on a same-object miss so + a later row can reference an earlier same-file CREATE, and no longer + negatively caches a miss. + - **#3149** threads an `attempt` counter through `bulkWrite`; seed rechecks by + `externalId` and import by `matchFields` before re-writing, so a + commit-then-lost-response retry cannot duplicate a batch. + - **#3147** `recomputeSummaries` retries transient failures and, on exhaustion, + surfaces `SummaryRecomputeError` (`ERR_SUMMARY_RECOMPUTE`) instead of a + silent warn; seed/import recover it to a warning without re-writing. + - **#3152** autonumbers are assigned after validation, so a batch that dies in + validation consumes no sequence value (no number-range gaps). + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/platform-objects@15.2.0 + - @objectstack/service-package@15.2.0 + - @objectstack/types@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/rest/package.json b/packages/rest/package.json index 198d14a67..878ccaa7d 100644 --- a/packages/rest/package.json +++ b/packages/rest/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/rest", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "ObjectStack REST API Server - automatic REST endpoint generation from protocol", "type": "module", diff --git a/packages/runtime/CHANGELOG.md b/packages/runtime/CHANGELOG.md index b8758efa5..638a429c8 100644 --- a/packages/runtime/CHANGELOG.md +++ b/packages/runtime/CHANGELOG.md @@ -1,5 +1,147 @@ # @objectstack/runtime +## 15.2.0 + +### Minor Changes + +- 2049b6a: feat(observability): admin-gated per-request `Server-Timing` via `X-OS-Debug-Timing` (#2408) + + Perf-tuning mode was previously global-only (`serverTiming` option / + `OS_SERVER_TIMING`), which discloses internal phase durations — a mild + backend-fingerprinting surface — to every caller. This adds the per-request + gating path from the design so an operator can pull a single request's + `Server-Timing` breakdown on a live environment without turning the header on + for everyone. + + - **observability**: a request-scoped disclosure gate (`runWithPerfDisclosure`, + `allowPerfDisclosure`, `isPerfDisclosureAllowed`, `PerfDisclosureGate`) kept + separate from the pure `PerfTiming` collector and pinned to its own + `Symbol.for` store so the middleware and dispatcher share it across module + copies. + - **plugin-hono-server**: the Server-Timing middleware is registered by default + (unless `serverTiming: false`). It runs the collector when timing is global + **or** the request sends `X-OS-Debug-Timing: 1`, and emits the header only + when the gate is open. `OS_PERF_TIMING=1` now also enables global mode. + - **runtime**: after resolving the execution context, the dispatcher opens the + gate for admin/service/system principals, so ordinary callers never receive + the header even if they send the debug header. + + Existing global-mode behavior is unchanged. + +### Patch Changes + +- fdc244e: Dev-loop DX fixes from the 15.1 third-party evaluation (P2 batch): + + - **Hot-added objects are now queryable without a restart.** Adding a `*.object.ts` under `os dev` used to recompile "green" while every query answered `no such table` (or `not registered`) until a manual restart: the artifact reload never notified the ObjectQL registry, tables were only created at boot, and seeds only loaded from the boot-time bundle. The `metadata:reloaded` payload now carries the parsed artifact; ObjectQL ingests the object definitions and re-runs the idempotent schema sync (same `skipSchemaSync` opt-out as boot), and the runtime loads seeds for first-seen objects (dev, single-tenant). `os dev` also prints `✚ new object(s): …` on recompile. + - **Dev admin credentials stay visible.** The `os dev` startup banner only showed `admin@objectos.ai / admin123` on the boot that actually seeded it; with the persistent default DB every later boot hid it, and the Console login page never knew it existed. The hint now re-arms on every dev boot for as long as the account still verifies against the default password, and `GET /api/v1/auth/config` exposes a dev-gated `devSeedAdmin` field (never present outside `NODE_ENV=development`) so the login page can show it. + - **`os doctor` reference analysis understands current metadata shapes.** Objects bound through `defineView` containers (`list`/`listViews`/`form`/`formViews` → `data.object`, subform `childObject`, lookup form fields) and app navigation (`objectName`, nested `children`, `areas`) were reported as "defined but not referenced". The collector now walks the canonical shapes (plus flow node `config.object`/`objectName`) and the orphan-view check descends into containers. + +- 2ea08ee: Flow trigger observability — kill the four-layer silence around record-change flows that never fire (2026-07-17 third-party eval). + + A misauthored auto-launched flow (wrong `objectName`, missing `requires: ['automation','triggers']`, failing start condition) produced ZERO output at every layer: the engine's own registration/binding logs land inside the CLI's boot-quiet stdout window (which swallows debug/info/warn — only error/fatal reach stderr), and each "didn't happen" path was itself silent. Fixes: + + - **Startup banner `Flows:` section** (`os serve`/`os dev`/`os start`): flow count, bound-to-trigger count, registered trigger types, draft count — plus loud `⚠` lines for flows declared with no automation engine enabled (`requires` missing), flows whose trigger type has no registered trigger, and bound record-change flows targeting an unknown object (dead binding). Printed after stdout is restored, so it is immune to the boot-quiet window. + - **Trigger-fired run failures now log at ERROR** (stderr — always visible): the automation engine no longer drops the AutomationResult of a trigger-fired execution; condition-evaluation faults and node failures surface with the flow name. Condition-not-met skips stay at debug (high-frequency, intentional). + - **`RecordChangeTrigger` probes object existence at bind time** and warns when a flow's `objectName` matches no registered object (exact-name matching), instead of silently arming a hook that can never fire. + - **`kernel:bootstrapped` binding audit** in the automation plugin: warns per enabled-but-unbound triggered flow with the reason, and reports registered/bound/draft counts (`AutomationEngine.getTriggerBindingAudit()`, extended `getFlowRuntimeStates()` with `status`/`triggerType`/`object`). + - **`os validate` flow-wiring advisories** (`@objectstack/lint` `validateFlowTriggerReadiness`): warns when a record-triggered flow targets an object the stack does not define, and when an auto-triggered flow's status is `draft` (authored or defaulted — draft flows still fire; declare `active` or `obsolete`). + - Removed leftover boot-debug writes (`registerApp`/`AppPlugin`/`StandaloneStack`/`AuditPlugin` stderr noise) that previous debugging of this same silence had left behind. + +- 515f11a: fix(seed): replaying seeds no longer corrupts lookup natural keys on the upsert update path + + Every dev-server restart replayed package seeds in upsert mode, and any record whose + lookup/master_detail was authored as a natural key could have that reference overwritten + with NULL on the update path (`NOT NULL constraint failed` on required columns; silent + link loss on nullable ones). Four fixes: + + - An unresolved reference now leaves the column untouched (deferred to pass 2) or drops + the record loudly — it is never written as NULL over an existing row. + - DB-side reference resolution probes the target dataset's declared `externalId` (e.g. + `email`) before falling back to `name` and `id`, matching how in-memory resolution + already keyed records. + - A rejected update (e.g. a `state_machine` rule vetoing the replay) no longer severs + natural-key resolution for downstream child datasets. + - Replays are idempotent: an upsert/update whose declared fields already match the + existing row is skipped instead of rewritten (no more `updated_at` churn or lifecycle + re-validation on every boot). + +- 4174a07: feat(runtime): seed-replayer reports `skipped` so hosts can stamp seed-once on progress + + The `seed-replayer` kernel service returned `{ inserted, updated, errors }` but + not `skipped`. A cloud host therefore could not tell an **all-skip replay** + (the env's seed data is already present — a no-op) apart from the + zero-summary early-returns that never ran the loader (no organization, no + metadata service, no datasets). Both looked like `inserted = updated = 0`, so + the host could not safely stamp its seed-once record for the all-skip case and + re-ran the full remote replay on every cold boot. + + Add `skipped: result.summary.totalSkipped` to the replayer's return; the + early-returns report `skipped: 0`. This lets a host (cloud#853's + `decideSeedStamp`) stamp on progress — including an all-skip replay — while + still declining to stamp a genuine no-loader zero-summary. Additive and + backward compatible; existing consumers ignore the new field. + +- ce468c8: feat(observability): decompose `Server-Timing` into auth / db / hooks / serialize spans (perf-tuning mode) + + The opt-in `Server-Timing` header now breaks a request's server time into the phases that actually explain it, so an operator can open DevTools → Network → Timing and see where the time went without standing up an external tracing backend: + + - **`db`** — total SQL time with a **query count**. The SQL driver wires knex's `query` / `query-response` events (keyed by `__knexQueryUid`) and folds each query into one aggregate member (`db;dur=210;desc="6 queries"`) — the query count is the number most useful for spotting N sequential round-trips. Timing is attributed to the originating request via `AsyncLocalStorage`, so it is correct under concurrency and never cross-attributes. SQL text is never emitted, only durations and a count. + - **`auth`** — identity / session resolution in the dispatcher, the prime suspect for unexplained data-API overhead. + - **`hooks`** — total business-hook execution time with a hook count, fed through the engine's existing `HookMetricsRecorder` seam (wired from the runtime, so `@objectstack/objectql`'s lean `core` tier stays observability-free). + - **`serialize`** — response JSON encoding in the HTTP adapter. + + Adds `countServerTiming(name, dur, unit)` (and `PerfTiming.count`) to fold high-frequency phases into a single aggregate member instead of flooding the header. Every phase is a no-op when perf-tuning is off (`serverTiming: true` / `OS_SERVER_TIMING=true`), so there is zero measurable overhead on the normal path. + + Closes #2408. + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [deb7e7e] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [6b51346] +- Updated dependencies [80273c8] +- Updated dependencies [fdc244e] +- Updated dependencies [5e3301d] +- Updated dependencies [2ea08ee] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [efbcfe1] +- Updated dependencies [2049b6a] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [ce468c8] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [ea32ec7] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/plugin-auth@15.2.0 + - @objectstack/objectql@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/rest@15.2.0 + - @objectstack/formula@15.2.0 + - @objectstack/metadata@15.2.0 + - @objectstack/observability@15.2.0 + - @objectstack/driver-sql@15.2.0 + - @objectstack/metadata-core@15.2.0 + - @objectstack/driver-memory@15.2.0 + - @objectstack/driver-sqlite-wasm@15.2.0 + - @objectstack/plugin-security@15.2.0 + - @objectstack/service-cluster@15.2.0 + - @objectstack/service-datasource@15.2.0 + - @objectstack/service-i18n@15.2.0 + - @objectstack/types@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/runtime/package.json b/packages/runtime/package.json index 5db5da222..30af48936 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/runtime", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "ObjectStack Core Runtime & Query Engine", "type": "module", diff --git a/packages/sdui-parser/CHANGELOG.md b/packages/sdui-parser/CHANGELOG.md index 2910f03c2..cf4194bae 100644 --- a/packages/sdui-parser/CHANGELOG.md +++ b/packages/sdui-parser/CHANGELOG.md @@ -1,5 +1,7 @@ # @objectstack/sdui-parser +## 15.2.0 + ## 15.1.1 ## 15.1.0 diff --git a/packages/sdui-parser/package.json b/packages/sdui-parser/package.json index 9a09d7ea9..eb9e3b6ae 100644 --- a/packages/sdui-parser/package.json +++ b/packages/sdui-parser/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/sdui-parser", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "ObjectStack constrained JSX-source → SDUI SchemaNode tree compiler (parse, never execute). Isomorphic, zero React. ADR-0080.", "main": "dist/index.js", diff --git a/packages/services/service-analytics/CHANGELOG.md b/packages/services/service-analytics/CHANGELOG.md index 63f87fc1f..fc36af671 100644 --- a/packages/services/service-analytics/CHANGELOG.md +++ b/packages/services/service-analytics/CHANGELOG.md @@ -1,5 +1,39 @@ # Changelog — @objectstack/service-analytics +## 15.2.0 + +### Minor Changes + +- a9459e6: Analytics drill metadata now snapshots raw grouped values for totals/subtotal rows too (#3214). The ADR-0021 D2 drill sidecar (`drillRawRows`, #2080) only covered `result.rows`, but the totals rows added in #1753 carry dimension values and go through the same label resolution — which overwrote their stored value (select option value, lookup/master_detail FK id) with the display label, leaving a subtotal drill nothing to exact-match on. + + `queryDataset` now also emits `drillRawTotals`, aligned to `result.totals` by index (`drillRawTotals[i][j]` ↔ `result.totals[i].rows[j]`), captured in the same pre-label-resolution pass. Each map is restricted to the drillable dimensions the grouping actually groups by, so the grand-total grouping (`[]`) contributes an empty map per row. Purely additive result props (same as #2080) — no spec-contract change. + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/services/service-analytics/package.json b/packages/services/service-analytics/package.json index 829ad7ed8..47d3d4d6d 100644 --- a/packages/services/service-analytics/package.json +++ b/packages/services/service-analytics/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/service-analytics", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Analytics Service for ObjectStack — implements IAnalyticsService with multi-driver strategy pattern (NativeSQL, ObjectQL, InMemory)", "type": "module", diff --git a/packages/services/service-automation/CHANGELOG.md b/packages/services/service-automation/CHANGELOG.md index 1f628944d..d8ca20fd4 100644 --- a/packages/services/service-automation/CHANGELOG.md +++ b/packages/services/service-automation/CHANGELOG.md @@ -1,5 +1,83 @@ # @objectstack/service-automation +## 15.2.0 + +### Minor Changes + +- 780b4b5: feat(automation): schema-aware flow-condition validation at registration (#1928) + + `registerFlow` now runs the same schema-aware condition checks as + `objectstack build` — so a flow registered dynamically (via the API / Studio, + bypassing the build lint) still gets the guardrail. When the host wires an + object-schema resolver, a flow condition that references an unknown field, + likely-typos a field name, or does arithmetic/ordering on a text/boolean field + against a number is surfaced as an **advisory warning** (logged), pointing at + the object's real schema. + + - New `AutomationEngine.setObjectSchemaResolver(resolver)` bridge (mirrors + `setFunctionResolver`); `AutomationServicePlugin` wires it to + `objectql.registry.getObject` in `start()`, before the flow pull, so + registry-sourced flows are covered too. + - **Strictly additive / zero regression**: the fatal set is unchanged (syntax, + brace-in-CEL, unknown-function still throw); everything the schema pass adds is + logged, never thrown, and the whole thing is a no-op when no resolver is wired. + Flow conditions bind fields flat, so the check runs in `flattened` scope + (flow variables stay `dyn` and are never flagged; equality is runtime-safe). + + Builds on the tier-4 type-soundness check in `@objectstack/formula` / + `@objectstack/lint` (#1928). + +- 2ea08ee: Flow trigger observability — kill the four-layer silence around record-change flows that never fire (2026-07-17 third-party eval). + + A misauthored auto-launched flow (wrong `objectName`, missing `requires: ['automation','triggers']`, failing start condition) produced ZERO output at every layer: the engine's own registration/binding logs land inside the CLI's boot-quiet stdout window (which swallows debug/info/warn — only error/fatal reach stderr), and each "didn't happen" path was itself silent. Fixes: + + - **Startup banner `Flows:` section** (`os serve`/`os dev`/`os start`): flow count, bound-to-trigger count, registered trigger types, draft count — plus loud `⚠` lines for flows declared with no automation engine enabled (`requires` missing), flows whose trigger type has no registered trigger, and bound record-change flows targeting an unknown object (dead binding). Printed after stdout is restored, so it is immune to the boot-quiet window. + - **Trigger-fired run failures now log at ERROR** (stderr — always visible): the automation engine no longer drops the AutomationResult of a trigger-fired execution; condition-evaluation faults and node failures surface with the flow name. Condition-not-met skips stay at debug (high-frequency, intentional). + - **`RecordChangeTrigger` probes object existence at bind time** and warns when a flow's `objectName` matches no registered object (exact-name matching), instead of silently arming a hook that can never fire. + - **`kernel:bootstrapped` binding audit** in the automation plugin: warns per enabled-but-unbound triggered flow with the reason, and reports registered/bound/draft counts (`AutomationEngine.getTriggerBindingAudit()`, extended `getFlowRuntimeStates()` with `status`/`triggerType`/`object`). + - **`os validate` flow-wiring advisories** (`@objectstack/lint` `validateFlowTriggerReadiness`): warns when a record-triggered flow targets an object the stack does not define, and when an auto-triggered flow's status is `draft` (authored or defaulted — draft flows still fire; declare `active` or `obsolete`). + - Removed leftover boot-debug writes (`registerApp`/`AppPlugin`/`StandaloneStack`/`AuditPlugin` stderr noise) that previous debugging of this same silence had left behind. + +### Patch Changes + +- 02eafa5: test(automation): end-to-end coverage for the #1928 object-schema resolver wiring + + Adds a kernel-level integration test proving `AutomationServicePlugin` bridges + the engine's object-schema resolver to the live `objectql.registry.getObject` at + `start()` (fields + types resolved from the registry), and that a flow + registered through the running kernel with a text field misused in arithmetic + emits the tier-4 advisory — while a sound condition stays quiet. Locks in the + production integration point that the engine-level unit tests (which set the + resolver by hand) could not exercise. Test-only; no behavior change. + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [6b51346] +- Updated dependencies [80273c8] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [ea32ec7] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/formula@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/services/service-automation/package.json b/packages/services/service-automation/package.json index b3137144f..3aa5646a1 100644 --- a/packages/services/service-automation/package.json +++ b/packages/services/service-automation/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/service-automation", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Automation Service for ObjectStack — implements IAutomationService with plugin-based DAG flow execution engine", "type": "module", diff --git a/packages/services/service-cache/CHANGELOG.md b/packages/services/service-cache/CHANGELOG.md index 61baaf03e..b9b242c39 100644 --- a/packages/services/service-cache/CHANGELOG.md +++ b/packages/services/service-cache/CHANGELOG.md @@ -1,5 +1,37 @@ # @objectstack/service-cache +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [efbcfe1] +- Updated dependencies [2049b6a] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [ce468c8] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/observability@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/services/service-cache/package.json b/packages/services/service-cache/package.json index 7500aa04e..d18e305f0 100644 --- a/packages/services/service-cache/package.json +++ b/packages/services/service-cache/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/service-cache", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Cache Service for ObjectStack — implements ICacheService with in-memory and Redis adapters", "type": "module", diff --git a/packages/services/service-cluster-redis/CHANGELOG.md b/packages/services/service-cluster-redis/CHANGELOG.md index 8065a4063..766548837 100644 --- a/packages/services/service-cluster-redis/CHANGELOG.md +++ b/packages/services/service-cluster-redis/CHANGELOG.md @@ -1,5 +1,30 @@ # @objectstack/service-cluster-redis +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/service-cluster@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/services/service-cluster-redis/package.json b/packages/services/service-cluster-redis/package.json index 45551ff9a..809017afa 100644 --- a/packages/services/service-cluster-redis/package.json +++ b/packages/services/service-cluster-redis/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/service-cluster-redis", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Redis cluster driver for ObjectStack — implements IPubSub/ILock/IKV/ICounter against Redis using ioredis.", "type": "module", diff --git a/packages/services/service-cluster/CHANGELOG.md b/packages/services/service-cluster/CHANGELOG.md index bf1465ec2..e9f17eb8f 100644 --- a/packages/services/service-cluster/CHANGELOG.md +++ b/packages/services/service-cluster/CHANGELOG.md @@ -1,5 +1,33 @@ # @objectstack/service-cluster +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/services/service-cluster/package.json b/packages/services/service-cluster/package.json index 338d6adef..6b8dd1764 100644 --- a/packages/services/service-cluster/package.json +++ b/packages/services/service-cluster/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/service-cluster", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Cluster Service for ObjectStack — pluggable PubSub/Lock/KV/Counter primitives. Memory driver included; postgres/redis drivers ship separately.", "type": "module", diff --git a/packages/services/service-datasource/CHANGELOG.md b/packages/services/service-datasource/CHANGELOG.md index e6ec90008..ef3beb8e2 100644 --- a/packages/services/service-datasource/CHANGELOG.md +++ b/packages/services/service-datasource/CHANGELOG.md @@ -1,5 +1,33 @@ # @objectstack/service-external-datasource +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/services/service-datasource/package.json b/packages/services/service-datasource/package.json index 2ba847fc2..2f79cdbc4 100644 --- a/packages/services/service-datasource/package.json +++ b/packages/services/service-datasource/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/service-datasource", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "The datasource service (ADR-0015): external-table federation (introspect/draft/import/validate) + runtime UI datasource lifecycle (list/test/create/update/remove + REST routes). Open-source mechanism; the tier line falls on which ICryptoProvider / driver factory a host injects.", "type": "module", diff --git a/packages/services/service-i18n/CHANGELOG.md b/packages/services/service-i18n/CHANGELOG.md index 49133dc21..a5f8b250c 100644 --- a/packages/services/service-i18n/CHANGELOG.md +++ b/packages/services/service-i18n/CHANGELOG.md @@ -1,5 +1,33 @@ # @objectstack/service-i18n +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/services/service-i18n/package.json b/packages/services/service-i18n/package.json index 00a44cf1f..989ac9bed 100644 --- a/packages/services/service-i18n/package.json +++ b/packages/services/service-i18n/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/service-i18n", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "I18n Service for ObjectStack — implements II18nService with file-based locale loading", "type": "module", diff --git a/packages/services/service-job/CHANGELOG.md b/packages/services/service-job/CHANGELOG.md index d9b2004e6..43806d545 100644 --- a/packages/services/service-job/CHANGELOG.md +++ b/packages/services/service-job/CHANGELOG.md @@ -1,5 +1,34 @@ # @objectstack/service-job +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/platform-objects@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/services/service-job/package.json b/packages/services/service-job/package.json index 0e0e855e2..f83281917 100644 --- a/packages/services/service-job/package.json +++ b/packages/services/service-job/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/service-job", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Job Service for ObjectStack — implements IJobService with setInterval and cron scheduling", "type": "module", diff --git a/packages/services/service-knowledge/CHANGELOG.md b/packages/services/service-knowledge/CHANGELOG.md index fc378329e..cab907b12 100644 --- a/packages/services/service-knowledge/CHANGELOG.md +++ b/packages/services/service-knowledge/CHANGELOG.md @@ -1,5 +1,33 @@ # @objectstack/service-knowledge +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/services/service-knowledge/package.json b/packages/services/service-knowledge/package.json index 76d448edc..cae35a535 100644 --- a/packages/services/service-knowledge/package.json +++ b/packages/services/service-knowledge/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/service-knowledge", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Knowledge Service for ObjectStack — orchestrator implementing IKnowledgeService over pluggable IKnowledgeAdapter backends (RAGFlow, LlamaIndex, Dify, in-memory).", "type": "module", diff --git a/packages/services/service-messaging/CHANGELOG.md b/packages/services/service-messaging/CHANGELOG.md index ffcf31e25..d5239914f 100644 --- a/packages/services/service-messaging/CHANGELOG.md +++ b/packages/services/service-messaging/CHANGELOG.md @@ -1,5 +1,33 @@ # @objectstack/service-messaging +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/services/service-messaging/package.json b/packages/services/service-messaging/package.json index c3a26e354..4e1e32619 100644 --- a/packages/services/service-messaging/package.json +++ b/packages/services/service-messaging/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/service-messaging", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Messaging Service for ObjectStack — outbound notification dispatch (ADR-0012). Ships the MessagingChannel registry, emit() fan-out, and the always-on inbox channel; other channels (email/webhook/push/IM) plug in.", "type": "module", diff --git a/packages/services/service-package/CHANGELOG.md b/packages/services/service-package/CHANGELOG.md index afc7937a0..7f307c3ef 100644 --- a/packages/services/service-package/CHANGELOG.md +++ b/packages/services/service-package/CHANGELOG.md @@ -1,5 +1,34 @@ # @objectstack/service-package +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/metadata-core@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/services/service-package/package.json b/packages/services/service-package/package.json index fdcf76d8f..3bffa1750 100644 --- a/packages/services/service-package/package.json +++ b/packages/services/service-package/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/service-package", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Package management service for ObjectStack — publish, install, and manage packages", "type": "module", diff --git a/packages/services/service-queue/CHANGELOG.md b/packages/services/service-queue/CHANGELOG.md index 20a3f123b..ebe7aed53 100644 --- a/packages/services/service-queue/CHANGELOG.md +++ b/packages/services/service-queue/CHANGELOG.md @@ -1,5 +1,34 @@ # @objectstack/service-queue +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/platform-objects@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/services/service-queue/package.json b/packages/services/service-queue/package.json index c4c55aa29..042102c64 100644 --- a/packages/services/service-queue/package.json +++ b/packages/services/service-queue/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/service-queue", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Queue Service for ObjectStack — implements IQueueService with in-memory and durable DB-backed (sys_job_queue) adapters", "type": "module", diff --git a/packages/services/service-realtime/CHANGELOG.md b/packages/services/service-realtime/CHANGELOG.md index 7b716f1a4..f835ea9ef 100644 --- a/packages/services/service-realtime/CHANGELOG.md +++ b/packages/services/service-realtime/CHANGELOG.md @@ -1,5 +1,34 @@ # @objectstack/service-realtime +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/platform-objects@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/services/service-realtime/package.json b/packages/services/service-realtime/package.json index fe91c3f43..4b320a720 100644 --- a/packages/services/service-realtime/package.json +++ b/packages/services/service-realtime/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/service-realtime", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Realtime Service for ObjectStack — implements IRealtimeService with WebSocket and in-memory pub/sub", "type": "module", diff --git a/packages/services/service-settings/CHANGELOG.md b/packages/services/service-settings/CHANGELOG.md index f5d5f92a7..df57aa747 100644 --- a/packages/services/service-settings/CHANGELOG.md +++ b/packages/services/service-settings/CHANGELOG.md @@ -1,5 +1,35 @@ # @objectstack/service-settings +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/platform-objects@15.2.0 + - @objectstack/types@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/services/service-settings/package.json b/packages/services/service-settings/package.json index fe84bf072..e8d3cde37 100644 --- a/packages/services/service-settings/package.json +++ b/packages/services/service-settings/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/service-settings", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Settings service for ObjectStack — manifest registry + K/V resolver (OS_* env > Tenant > User > Default) + REST routes. See ADR-0007.", "type": "module", diff --git a/packages/services/service-sms/CHANGELOG.md b/packages/services/service-sms/CHANGELOG.md index 7778a464a..cbf18855f 100644 --- a/packages/services/service-sms/CHANGELOG.md +++ b/packages/services/service-sms/CHANGELOG.md @@ -1,5 +1,33 @@ # @objectstack/service-sms +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/services/service-sms/package.json b/packages/services/service-sms/package.json index ed0c5e306..ae2afc067 100644 --- a/packages/services/service-sms/package.json +++ b/packages/services/service-sms/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/service-sms", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "SMS service for ObjectStack — ISmsService + transport-pluggable outbound delivery (Aliyun / Twilio / log).", "main": "dist/index.js", diff --git a/packages/services/service-storage/CHANGELOG.md b/packages/services/service-storage/CHANGELOG.md index 612cac3f2..b51e68c25 100644 --- a/packages/services/service-storage/CHANGELOG.md +++ b/packages/services/service-storage/CHANGELOG.md @@ -1,5 +1,38 @@ # @objectstack/service-storage +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [efbcfe1] +- Updated dependencies [2049b6a] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [ce468c8] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/observability@15.2.0 + - @objectstack/platform-objects@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/services/service-storage/package.json b/packages/services/service-storage/package.json index 0de39a619..12027b66c 100644 --- a/packages/services/service-storage/package.json +++ b/packages/services/service-storage/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/service-storage", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Storage Service for ObjectStack — implements IStorageService with local filesystem and S3 adapter skeleton", "type": "module", diff --git a/packages/spec/CHANGELOG.md b/packages/spec/CHANGELOG.md index 5a61b6ec4..906dbed61 100644 --- a/packages/spec/CHANGELOG.md +++ b/packages/spec/CHANGELOG.md @@ -1,5 +1,373 @@ # @objectstack/spec +## 15.2.0 + +### Minor Changes + +- 3a18b60: feat(approvals): rename the `role` approver type to `org_membership_level` (#3133) + + `ApproverType.role` was the last platform surface projecting the reserved word + "role" (ADR-0090 D3). It is not covered by D3's better-auth exception: that + exception protects better-auth's own `sys_member.role` **column**, which we do + not own — `ApproverType` is our own enum, an authoring surface, and D3 mandates + that the projection of that concept is spelled `org_membership_level` and + labelled "organization membership", **never "role"**. + + The sentence licensing the leak was also false: ADR-0090 D3 claims + `sys_member.role` is "already relabelled `org_membership_level` in the platform + projection", but `org_membership_level` existed nowhere in the codebase and + ADR-0057 D7 lists that relabel under "Deferred (evidence-gated, P4)". The + projection never landed, so the word reached authors. + + The name manufactured a real, silent failure — "hotcrm class": every other + surface renamed to `position` (`sys_role`, `ShareRecipientType.role`, + `ctx.roles[]`), so `{ type: 'role', value: 'sales_manager' }` reads as the + legacy spelling of a position. It resolves against the membership tier, finds + no member row, falls back to an inert `role:sales_manager` literal, and the + request waits forever on an approver that cannot exist. + + - **spec**: `ApproverType` gains `org_membership_level`; `role` stays as a + deprecated alias for one window (a published 15.x flow keeps loading) with + `DEPRECATED_APPROVER_TYPES` + `canonicalApproverType()` as the single source + for the mapping. Removed in the next major. + - **plugin-approvals**: resolves on the canonical type and warns on the + deprecated spelling. The `type:value` fallback literal keeps the **authored** + spelling — stored `sys_approval_approver` rows and `pending_approvers` slots + from 15.x carry `role:`, and rewriting it would orphan them. + - **lint**: `approval-role-not-membership-tier` → `approval-approver-not-membership-tier` + (the rule id carried the reserved word too), plus a new + `approval-approver-type-deprecated`. The two are mutually exclusive: a bad + _value_ wins, because prescribing `org_membership_level` for a position name + would be wrong advice — the fix there is `position`. + + Authoring `type: 'role'` keeps working and now says so out loud. Rewrite it as + `org_membership_level`; if the value is an org position, the fix is `position`. + +- fefcd54: fix(spec): declare `ownership` as a first-class ObjectSchema field (#3175) + + The object-level record-ownership model — `ownership: 'user' | 'org' | 'none'`, + which drives the registry's `owner_id` auto-provisioning (`applySystemFields`) — + was read by the engine via `(schema as any).ownership` while `ObjectSchema.create()` + **rejected** it as an unknown top-level key (ADR-0032 / #1535). So a tested engine + opt-out (`ownership: 'org' | 'none'` on catalog / junction tables) could not be + set through the sanctioned authoring path, and the same `ownership` word was read + elsewhere as the unrelated package-contribution kind (`own` / `extend`). + + - **spec**: `ObjectSchema` now declares `ownership: z.enum(['user','org','none']).optional()`. + Authoring the record-ownership opt-out validates cleanly; the registry reads it + off the typed schema (no `as any`). A retired `ownership: 'own'` / `'extend'` + value fails with guidance pointing at the record-ownership model and noting that + `own`/`extend` is the contribution kind (`registerObject`), not an object-schema value. + - **cli**: the `object` scaffold no longer emits the now-invalid `ownership: 'own'` + (owner injection is the default), and `objectstack info` labels the record model + with the correct `user` default. + + No runtime behavior change: `applySystemFields` and its `owner_id` injection logic + are unchanged — this makes the property the engine already honors legally authorable + and consistently typed. + +- b659111: feat(spec)!: remove dead author-facing metadata properties (#2377, ADR-0049 enforce-or-remove) + + Breaking spec-surface removal, versioned as `minor` per the launch-window changeset + policy (a `major` would promote the whole fixed-group monorepo; breaking cleanups ride + the minor line, as with #2402 → 11.1.0). + + Removes a batch of spec properties that parsed but had **no runtime consumer** — + authoring them was a false affordance (especially dangerous for AI-authored + metadata). Verified dead against the liveness ledger (`packages/spec/liveness/*.json`) + and a repo-wide grep of readers. This is the follow-up slice to #2402. + + ## Removed (each was `dead` + no reader anywhere) + + - **field** (`field.zod.ts`): `vectorConfig` (+ `VectorConfigSchema` + types), + `fileAttachmentConfig` (+ `FileAttachmentConfigSchema` + types), `dependencies`. + Vector fields keep the live flat `dimensions` prop; file/image fields keep the + live flat `multiple`/`accept`/`maxSize` siblings. + - **object** (`object.zod.ts`): `versioning` (+ `VersioningConfigSchema`), + `softDelete` (+ `SoftDeleteConfigSchema`), `search` (+ `SearchConfigSchema`), + `recordName`, `keyPrefix`. Each is now a **rejecting tombstone** in + `UNKNOWN_KEY_GUIDANCE` carrying the upgrade prescription. + - **action** (`action.zod.ts`): `timeout` (server uses `body.timeoutMs`; no + action-level timeout is enforced). + - **agent** (`agent.zod.ts`): `planning.strategy`, `planning.allowReplan` + (only `planning.maxIterations` is read by the runtime). + - **dataset** (`dataset.zod.ts`): `measures.certified` (declared-but-unenforced + governance flag — never compiled into the Cube). + + Liveness ledgers, the ledger README table, and `api-surface.json` are updated; + the removed sub-schema keys are dropped from `json-schema.manifest.json`. + + ## Migration + + - **field/agent/dataset/action props**: authoring them is now silently stripped + (they never did anything). Remove them. Vector → set flat `dimensions`; + file/image → set flat `multiple`/`accept`/`maxSize`. + - **object props**: `ObjectSchema.create()` now throws a located error naming the + replacement — `versioning`/`softDelete` → hard deletes + `Field.trackHistory` / + `lifecycle`; `search` → `searchableFields`; `recordName` → an `autonumber` + `Field` designated as `nameField`; `keyPrefix` → remove (never had an effect). + + ## Deliberately NOT removed (dead, but entangled — a scoped follow-up) + + `field.index`/`columnName`/`referenceFilters` and object + `tags`/`active`/`isSystem`/`abstract`/`enable.searchable`/`enable.trash`/`enable.mru` + and `agent.tenantId` are surfaced in the Studio metadata-authoring forms + (`*.form.ts`) — removing them cascades into i18n bundle regeneration, so they are + deferred. `action.type:'form'` has a dedicated build-time lint (`lint-view-refs.ts`) + and a first-party showcase usage, so it needs a UX decision. `field.columnName` + additionally has an ADR-0062 D7 lint. These stay `dead` + `authorWarn` in the + ledgers. + +- 5754a23: feat(spec)!: remove form-surfaced dead metadata props + correct 3 misclassified-live entries (#2377, ADR-0049) + + The next enforce-or-remove slice of #2377. Versioned `minor` per the launch-window + policy (the fixed group makes a `major` promote the whole monorepo). + + ## Removed (dead, no runtime reader — verified in both framework and objectui) + + - **field**: `columnName`, `index`, `referenceFilters`. This empties the field + dead-prop set. `columnName` also removed its now-moot **ADR-0062 D7** lint + (`validate-expressions.ts`), the dead `StorageNameMapping.resolveColumnName` / + `buildColumnMap` / `buildReverseColumnMap` helpers, and closes ADR-0062 R10 — + external physical-column mapping is `external.columnMap` only. + - **object**: `tags`, `active`, `abstract` — now rejecting tombstones in + `UNKNOWN_KEY_GUIDANCE`. + - **agent**: `tenantId`. + + The removed props are dropped from the authoring forms (`field/object/agent.form.ts`) + and the regenerated metadata-forms i18n bundles. + + ## Corrected to `live` (the ledger was wrong — readers existed) + + - **object `isSystem`** — `plugin-sharing` `effectiveSharingModel` defaults a + no-`sharingModel` `isSystem` object to public; also read by the security-posture + lint. KEPT. + - **object `enable.searchable`** — `metadata-protocol` global search (`searchAll`) + uses `enable.searchable === false` as an opt-out. KEPT. + - **action `type:'form'`** — objectui `ActionRunner.executeForm` routes it to the + FormView at `/forms/:target`; a build-time lint validates the target. KEPT. + + ## Deliberately deferred + + `object.enable.trash` / `enable.mru` — dead, but inert `default(true)` flags set by + ~35 `sys-*.object.ts` files; removing them is high-churn / low-value. Left `dead` + (authorWarn-skipped). + + ## Migration + + - field/agent props: authoring them was already a no-op; they now strip silently. + `columnName` → the physical column is always the field key (rename the field, or + use `external.columnMap` for external objects); `index` → declare it in object + `indexes[]`; `referenceFilters` → `lookupFilters`. + - object `tags`/`active`/`abstract`: `ObjectSchema.create()` now throws a located + error naming the removal. None gated anything at runtime — remove them. + +- 668dd17: **Breaking (npm type surface): retire the vestigial feed contracts + protocol surface (ADR-0052 §5 follow-up, #1959).** + + The `service-feed` runtime was deleted in #1955; `sys_comment` / `sys_activity` + are the canonical record-collaboration/timeline backend. This removes the dead + type surface that still pointed at the deleted runtime — every removed method was + already unreachable (the feed REST route was never mounted → 404; the protocol + implementation was never wired with a feed service, so `requireFeedService()` + could only throw). No behavior changes. + + No authorable metadata key is removed (the `feeds:` object capability flag and + the `RecordActivity` UI component config are unchanged), so `PROTOCOL_MAJOR` + stays 15 and this ships as `minor` rather than a protocol major. + + FROM → TO migration for every removed export: + + - `@objectstack/spec/contracts` — `IFeedService`, `CreateFeedItemInput`, + `UpdateFeedItemInput`, `ListFeedOptions`, `FeedListResult` → **removed, no + replacement**. Comments/activity are plain records: write `sys_comment` / read + `sys_activity` via the data engine or the REST data API. + - `@objectstack/spec/api` — `FeedApiContracts`, `FeedApiErrorCode`, + `FeedProtocol`, and all feed request/response schemas + types (`GetFeed*`, + `CreateFeedItem*`, `UpdateFeedItem*`, `DeleteFeedItem*`, `AddReaction*`, + `RemoveReaction*`, `PinFeedItem*`, `UnpinFeedItem*`, `StarFeedItem*`, + `UnstarFeedItem*`, `SearchFeed*`, `GetChangelog*`, `ChangelogEntry`, + `SubscribeRequest/Response`, `FeedUnsubscribeRequest`, `UnsubscribeResponse`, + `FeedPathParams`, `FeedItemPathParams`, `FeedListFilterType`) → **removed**. Use + the data API against `sys_comment` / `sys_activity` (`/api/v1/data/sys_comment/…`); + reactions and threaded replies are fields on `sys_comment`. + - `@objectstack/spec/data` — `FeedItemSchema`/`FeedItem`, `FeedActorSchema`/`FeedActor`, + `MentionSchema`/`Mention`, `ReactionSchema`/`Reaction`, + `FieldChangeEntrySchema`/`FieldChangeEntry`, `FeedVisibility`, + `RecordSubscriptionSchema`/`RecordSubscription`, `SubscriptionEventType`, and the + `data`-namespace `NotificationChannel` → **removed**. `FeedItemType` and + `FeedFilterMode` are **kept** (live UI activity-timeline config). For notification + channels use `NotificationChannelSchema` from `@objectstack/spec/system`. + - `@objectstack/client` — `client.feed.*` (`list` / `create` / `update` / `delete` / + `addReaction` / `removeReaction` / `pin` / `unpin` / `star` / `unstar` / `search` / + `getChangelog` / `subscribe` / `unsubscribe`) and the re-exported feed response + types → **removed**. One-line fix: use `client.data.*` on `sys_comment` / + `sys_activity`, e.g. `client.data.create('sys_comment', { object, record_id, body })` + and `client.data.find('sys_activity', { filters: [['record_id', '=', id]] })`. + - `@objectstack/metadata-protocol` — `ObjectStackProtocolImplementation` no longer + implements the 14 feed methods; its constructor + `(engine, getServicesRegistry?, getFeedService?, environmentId?)` becomes + `(engine, getServicesRegistry?, environmentId?)`. One-line fix: delete the third + argument. + +- 8abf133: **Breaking (discovery response shape): retire the residual feed capability surface (#3180, follow-up to #1959 / ADR-0052 §5).** + + The feed backend was retired long ago; #1959 removed the feed contracts + SDK. This + removes the last discovery/dispatcher references to it, and fixes a real bug where the + `comments` capability was permanently `false`. + + - `@objectstack/spec` — `WellKnownCapabilitiesSchema.feed` and `ApiRoutesSchema.feed` + (`routes.feed`) are **removed**, and the `/api/v1/feed` entry is dropped from + `DEFAULT_DISPATCHER_ROUTES`. FROM → TO: clients reading `discovery.capabilities.feed` + or `discovery.routes.feed` → use `discovery.capabilities.comments`; comments/activity + are served by the generic data API on `sys_comment` / `sys_activity` + (`/api/v1/data/sys_comment/…`). + - `@objectstack/metadata-protocol` — `getDiscovery()` no longer emits the always-`false` + `feed` service/capability. **Bug fix:** the `comments` capability previously keyed off + the deleted `'feed'` service (so it was permanently `false` after #1955); it now tracks + the presence of the `sys_comment` object (provided by the always-on audit slate), so + `declared === enforced`. + - `@objectstack/client` — the internal `feed: '/api/v1/feed'` route constant is removed + (it only existed to satisfy the now-removed `ApiRoutes.feed` type; no client code used it). + +- 04ecd4e: feat(validation): `state_machine.initialStates` enforces the FSM entry point on INSERT (#3165) + + A `state_machine` rule's `transitions` only governs UPDATE — on INSERT the rule + was a no-op, and a `select` field permits ANY declared option as the initial + value. So a record could be born mid-flow (created already `approved`), skipping + the whole state machine. This was the gap #3043's mitigation idea assumed didn't + exist (declared ≠ enforced, ADR-0049). + + `state_machine` rules gain an optional `initialStates: string[]` — the states a + record may be CREATED in. When set, an insert whose (defaulted) state-field value + is outside the list is rejected server-side with `code: 'invalid_initial_state'`. + Omit it to keep the legacy behavior (no initial-state check on insert). A missing + / empty value is left to required-validation; `transitions` (UPDATE) is + unaffected. Enforced at the same `evaluateValidationRules(..., 'insert')` seam the + engine already runs after field defaults. + +- 16cebeb: fix(spec): drop the dead `systemFields.owner` key (#3175 follow-up) + + `ObjectSchema.systemFields` exposed an `owner?: boolean` opt-out key that nothing + read — the registry (`applySystemFields`) only consumes `systemFields.tenant` and + `systemFields.audit`, and `owner_id` provisioning is governed by the object-level + `ownership` property (`'user' | 'org' | 'none'`, made first-class in #3185). The + key was declared but wired to nothing. + + Removed it so the schema only advertises the two opt-outs it actually honors + (`tenant`, `audit`). Backward-compatible at runtime: the key was ignored before and + is stripped now (both no-ops). A TypeScript author who set `systemFields.owner` + will now see an excess-property error — the fix is to delete the key (it never did + anything) or use `ownership: 'org' | 'none'` to skip `owner_id`. Also corrected the + stale `objectql/security` doc that called `audit` "reserved" (it is active). + +### Patch Changes + +- 3ad3dd5: Annotate the schema-only event/subscription/connector surfaces flagged by the #3197 audit with explicit "not yet enforced / not yet implemented" notes in their doc comments and `.describe()` texts, so authoring metadata against them is no longer silently swallowed. No runtime behavior or schema shape changes — documentation only. + + Surfaces annotated (each trace re-confirmed against the current tree before annotating): + + - `GraphQLSubscriptionConfigSchema` (`api/graphql.zod.ts`) — no subscription transport exists; the GraphQL HTTP entry serves query/mutation only. + - `WebSocketMessageType` + module header (`api/websocket.zod.ts`) — no WebSocket server is mounted (#2462); the protocol is a future wire contract. + - `RealtimeEventType` (`api/realtime.zod.ts`) — zero runtime importers; the engine emits `data.record.*` names (which don't match this enum's members) and nothing emits `field.changed`. + - Connector `webhooks`/`WebhookConfigSchema`/`WebhookEventSchema` and `triggers`/`ConnectorTriggerSchema` (`integration/connector.zod.ts`) — `AutomationEngine.registerConnector` reads only `actions`; webhook events and trigger definitions parse but are never dispatched or polled. + - Automation `ConnectorTriggerSchema`/`TriggerRegistrySchema` (`automation/trigger-registry.zod.ts`) — no runtime importer; the `stream` trigger mechanism exists only here. + - `NotificationChannelSchema` (`system/notification.zod.ts`) + the mirrored `NotificationChannel` contract type — implemented delivery channels are `inbox`/`email`/`sms`; `push`/`slack`/`teams`/`webhook` dead-letter, and the enum's `in-app` does not match the registered `inbox` channel id. + + The audit's sixth row (`SubscriptionEventType`, formerly `data/subscription.zod.ts`) needed no annotation — it was already removed outright by the feed-contract retirement (#1959). + +- a8aa34c: Enforce validation rules, `requiredWhen`, and per-option `visibleWhen` on multi-row updates (#3106). The bulk branch of `engine.update` (`options.multi` → `driver.updateMany`) previously never called `evaluateValidationRules`, so every object-level rule (`script`, `state_machine`, `format`, `cross_field`, `json_schema`, `conditional`), field-level `requiredWhen`, and per-option `visibleWhen` check was a silent no-op there. The engine now reads the row-scoped match set (the same AST the write binds, one query shared with the `readonlyWhen` bulk strip) and evaluates the payload against each matched row's prior state; any error-severity violation rejects the whole batch with `ValidationError` (annotated with the failing record id) before anything is written. Schemas needing no prior state (`format`/`json_schema`-only) are evaluated once against the payload with no fetch, and rule-free schemas are unaffected. Behavior change: bulk writes that previously slipped past declared rules now throw. Doc comments in `rule-validator.ts` and `validation.zod.ts` no longer overstate coverage and name the remaining `events: ['delete']` gap (tracked separately). +- a3823b2: Collapse the hook event taxonomy from 18 declared events to the 8 the engine actually dispatches (#3195). The removed 10 (`beforeFindOne`/`afterFindOne`, `beforeCount`/`afterCount`, `beforeAggregate`/`afterAggregate`, `beforeUpdateMany`/`afterUpdateMany`, `beforeDeleteMany`/`afterDeleteMany`) were declared in `HookEvent` but never fired — the enum mirrored the engine method table instead of domain events, so a hook subscribing to them registered fine and then silently no-op'd. + + - `findOne` now fires the same `beforeFind`/`afterFind` hooks as `find` — the read event attaches to record materialization, not the engine method, so one subscription covers every read shape (no separate `beforeFindOne`/`afterFindOne`). + - Bulk (`multi: true`) updates/deletes already fire the singular `beforeUpdate`/`beforeDelete`/`afterUpdate`/`afterDelete` events with the row-scoping predicate in `ctx.input.ast`; this is now documented, and there is no `*Many` event. + - Read authorization / row filtering is the RLS/permission-rule layer's job and field masking is field-level metadata — neither is a hook every author must re-attach. + - `engine.registerHook` now warns when a hook subscribes to an event the engine never dispatches, so enum-vs-dispatch drift can't recur silently. + + No shipped hook or authored metadata used any of the removed events; authoring one now fails loudly at parse/validate time instead of registering a dead hook. Skills and docs updated to teach the 8 events and the declarative alternatives. + +- 5e3301d: Document two validation-rule facts surfaced by the 2026-06 liveness audit (follow-up to #3106 / #3184), and clean up a stale form-schema mirror — no runtime behavior change: + + - `label` / `description` / `tags` on validation rules are governance / editor metadata (surfaced to the Studio rule editor and rule listings), not evaluated on the write path. Documented as such on `BaseValidationSchema` rather than removed — they are set by nearly every example rule and feed the `/meta/types` editor form, so they are declared on purpose, not silent no-ops. + - `cross_field` evaluates identically to `script` (same CEL predicate path); only `fields[0]` is read, to target the violation at a field. Documented the overlap on the schema, its `fields` `.describe()`, and the validation docs so authors can choose between them; the variant is kept for the field-targeting affordance and backward compatibility. + - Removed dead form-field entries (`scope`, `caseSensitive`, `url`, `handler`) and the stale `type=unique` hint from the hand-written `HAND_CRAFTED_SCHEMAS['validation']` fallback in `@objectstack/metadata-protocol` — leftovers from the removed `unique`/`async`/`custom` variants. + - Added the missing `beforeDelete` lifecycle-hook pointer to the validation docs' "not a rule type" callout, so delete-time guards aren't stranded now that validation has no `delete` event (#3184). + +- d2723e2: **`MetadataManager.register()` / `unregister()` now announce to `subscribe()` watchers.** Both updated the registry, persisted to writable loaders and published to realtime, but never fired the watch callbacks — so `subscribe()` looked like it covered every write while silently missing all of them. Only the `saveMetaItem` path (via the repository watch stream) and the filesystem watcher ever reached a subscriber. Runtime consumers that cache metadata — notably ObjectQL's SchemaRegistry bridge, the component that decides what is queryable — went stale on every other write until the process restarted. + + Announcing is now the **default**, so a new call site is correct without knowing this contract exists. This is a contract fix rather than a bug fix: the one live behavior change is that runtime datasource writes (`datasource-admin`) now reach the HMR SSE stream, which subscribes to every registered type. `unregisterPackage()` / `bulkUnregister()` also announce their deletes now — correct, but latent, since neither has a production caller today. + + Bulk ingest opts out explicitly with the new `MetadataWriteOptions` (`{ notify: false }`) — boot-time filesystem priming, artifact ingest, and ObjectQL's registry bridge, each of which either runs before consumers cache anything or announces the whole batch once (as the artifact reload path does via `metadata:reloaded`). The bridge in particular MUST stay silent: it copies objects out of the SchemaRegistry, and announcing would feed them back through a handler that re-registers under `_packageId ?? 'metadata-service'`, overwriting the true package provenance of every object whose body carries no `_packageId`. + + Additive only — `register(type, name, data)` and `unregister(type, name)` keep working unchanged. + + Fixes #3112. + +- beaf2de: fix(metadata-protocol): strip static `readonly` on INSERT at the data-write ingress (#3043) + + #2948/#3003 made static `readonly: true` fields server-enforced on UPDATE (a + non-system PATCH forging `approval_status: 'approved'` is silently stripped in + the engine), but INSERT was exempt. For approval/status/verdict columns that + exemption was the _shorter_ attack: instead of the #3003 draft-then-PATCH move, a + non-system caller could `POST` a record already `approval_status: 'approved'` in + one step — and the UPDATE-only strip never reached it. + + The strip now also runs on INSERT, but at the **external data-write ingress** + (`DataProtocol.createData` / `createManyData` / `batchData` / `cloneData`) rather + than in the engine. That seam is the single point every external programmatic + create funnels through — the REST CRUD route, the GraphQL/MCP dispatcher + (`bridge.create` → `callData` → `createData`), and bulk import — while **trusted + internal writers** (better-auth's adapter, the metadata repository, the seed + loader) call `engine.insert` directly and bypass it. Enforcing at the ingress + protects every caller/agent path at once without stripping the internal writers + that legitimately seed read-only columns on create (identity provisioning, + provenance stamps, event-log cursors) — the blast radius an engine-level insert + strip would have. + + - **Caller-forged only, at the ingress.** The payload here is raw caller input + (the security middleware stamps `owner_id` / `organization_id` later, inside + `engine.insert`), so only keys the caller actually sent are dropped; server + stamps are added afterwards and are unaffected. + - **Re-derives the default.** A stripped field falls back to its declared + `defaultValue` in the engine (a forged `approval_status` becomes `draft`, not + NULL). + - **System-context exempt.** `isSystem` writes still seed read-only columns. + - **Silent** (HTTP 2xx), per-row on batch/import. `readonlyWhen` stays + INSERT-exempt (a conditional lock needs a prior record). + - **Author-defined business objects only.** Platform objects (`managedBy` set, + or the `sys_` namespace) carry their own field-write governance that a silent + strip must not pre-empt — e.g. ADR-0086 REJECTS (403) a forged + `managed_by:'package'` on `sys_permission_set`, and #3004 rejects a forged + `owner_id`; several of those columns are `readonly`, so stripping them here + would swallow the payload the guard is meant to reject. The #3043 threat is app + approval/status fields, never `sys_` — the same boundary `applySystemFields` + uses for ownership. + + Behavior change: a non-system create through the data API (REST / GraphQL / MCP / + import) can no longer seed a `readonly` column from the payload. Flows that + legitimately write read-only columns at creation must run with a system context + (`isSystem`), the same requirement the UPDATE strip already imposes. + +- 8923843: Reject view containers that define no views. A flat list-view object (`{ name, label, type, columns, ... }`) parses to an empty `ViewSchema` container because Zod strips unknown keys — zero views register and the Console silently renders nothing. `defineView()` now throws on a zero-view container, and `os validate` gains a `view-container-shape` check (`validateViewContainers` in `@objectstack/lint`) that reports flat or empty `views: []` entries pre-parse with a wrap-it fix hint. +- f16b492: Remove the dead `'delete'` member from the validation-rule `events` enum (#3184). The rule evaluator only runs on the insert/update write path — `engine.delete` never invokes it — so a rule declaring `events: ['delete']` was a silent no-op (flagged in #3106 and `docs/audits/2026-06-validationschema-property-liveness.md`). The enum now admits only `insert`/`update`; guard deletions with a `beforeDelete` lifecycle hook instead. No shipped metadata declares `events: ['delete']`; any off-spec metadata that did now fails loudly at `os validate` / registration rather than parsing and doing nothing. Also narrows the two hand-written mirrors (`rule-validator.ts` `BaseRule`, `metadata-protocol` JSON-schema form helper — whose stale `type` enum listing removed `unique`/`async`/`custom` variants is corrected in the same pass), updates the doc comments, the published data skill, and the hand-written validation doc. +- 4b6fde8: Trim the dead `undelete` and `api` webhook triggers (#3196). `WebhookTriggerType` declared five triggers but only three ever fired: + + - `undelete` had no event source — the engine has no soft-delete/restore capability (`delete` is a hard delete; no `deleted_at` convention, no restore operation, and `data.record.undeleted` is never emitted). The `undeleted` case in the auto-enqueuer's action mapper was dead code awaiting a producer that doesn't exist. + - `api` ("manually triggered") had no fire path — the only webhook HTTP surface re-queues already-failed deliveries; nothing originates a manual fire. + + Both are removed from the enum (contract-first, matching #3184/#3195): authoring a webhook on a removed trigger now fails loudly at `os validate` / registration instead of registering a webhook that silently never fires. No shipped webhook metadata used either. The auto-enqueuer now also warns when a persisted `sys_webhook` row carries a trigger it can't map to an emitted record event (a drift-guard, so a dead trigger can't silently no-op again). Reintroduce `undelete` only alongside a real restore subsystem, and `api` only alongside a real manual-fire endpoint. Updated the `sys_webhook` trigger options, field help (all locales), docs, and reference; added rejection tests. + +- fc5a3a2: **The `view` metadata type-schema now validates all three runtime `view` shapes instead of stripping two of them to `{}`.** `metadata-type-schemas.ts` mapped `view` to the aggregate container `ViewSchema` (`{ list, form, listViews, formViews }`, every slot optional). Zod strips unknown keys, so the two non-container shapes a `view` body actually carries at runtime — a standalone **ViewItem record** (`{ name, object, viewKind, config }`) and a **console personalization overlay** (raw view config + identity inherited by `normalizeViewMetadata`, #2555) — both strip-parsed to `{}`. That made the `422` check in `saveMetaItem` and read-time `computeMetadataDiagnostics` a **no-op** for those shapes: a broken `config` (e.g. a kanban missing `groupByField`) saved with a false `200` and badged valid, and the view create-seed test validated against nothing. + + `view` now maps to a new `ViewMetadataSchema` — a union over the three shapes, each validated genuinely: + + 1. **defineView container** — non-empty (`ViewSchema` refined to require at least one of `list`/`form`/`listViews`/`formViews`; an empty container is rejected, mirroring `defineView`). + 2. **ViewItem record** — `ViewItemSchema`; the nested `config` is validated against ListView/FormView. + 3. **Flattened personalization overlay** — inline ListView/FormView config plus optional identity fields. Structural guards pin `config`/`list`/`form`/`listViews`/`formViews` to `undefined` so a malformed record or container can never be rescued through this lenient branch with its real payload silently stripped. + + All members strip-parse (no `.strict()`), so auxiliary Studio round-trip keys (`isPinned`, `sortOrder`, …) still ride along without a false `422`, and `saveMetaItem` keeps persisting the body verbatim. `z.toJSONSchema()` emits the schema as an `anyOf` of the four members, which `/api/v1/meta/types/view` serves to Studio's SchemaForm. + + Fixes #3095. + ## 15.1.1 ## 15.1.0 diff --git a/packages/spec/package.json b/packages/spec/package.json index a6c5ed2ba..85a434a77 100644 --- a/packages/spec/package.json +++ b/packages/spec/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/spec", - "version": "15.1.1", + "version": "15.2.0", "description": "ObjectStack Protocol & Specification - TypeScript Interfaces, JSON Schemas, and Convention Configurations", "license": "Apache-2.0", "main": "dist/index.js", diff --git a/packages/triggers/trigger-api/CHANGELOG.md b/packages/triggers/trigger-api/CHANGELOG.md index 7e9464a04..1e3d96961 100644 --- a/packages/triggers/trigger-api/CHANGELOG.md +++ b/packages/triggers/trigger-api/CHANGELOG.md @@ -1,5 +1,33 @@ # @objectstack/trigger-api +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/triggers/trigger-api/package.json b/packages/triggers/trigger-api/package.json index 8b96960e2..91d22d1ab 100644 --- a/packages/triggers/trigger-api/package.json +++ b/packages/triggers/trigger-api/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/trigger-api", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Inbound HTTP/webhook flow trigger for ObjectStack — per-flow HMAC-verified endpoints with queue-backed ingestion (ADR-0041)", "main": "dist/index.js", diff --git a/packages/triggers/trigger-record-change/CHANGELOG.md b/packages/triggers/trigger-record-change/CHANGELOG.md index 334362680..e49da659c 100644 --- a/packages/triggers/trigger-record-change/CHANGELOG.md +++ b/packages/triggers/trigger-record-change/CHANGELOG.md @@ -1,5 +1,46 @@ # @objectstack/plugin-trigger-record-change +## 15.2.0 + +### Minor Changes + +- 2ea08ee: Flow trigger observability — kill the four-layer silence around record-change flows that never fire (2026-07-17 third-party eval). + + A misauthored auto-launched flow (wrong `objectName`, missing `requires: ['automation','triggers']`, failing start condition) produced ZERO output at every layer: the engine's own registration/binding logs land inside the CLI's boot-quiet stdout window (which swallows debug/info/warn — only error/fatal reach stderr), and each "didn't happen" path was itself silent. Fixes: + + - **Startup banner `Flows:` section** (`os serve`/`os dev`/`os start`): flow count, bound-to-trigger count, registered trigger types, draft count — plus loud `⚠` lines for flows declared with no automation engine enabled (`requires` missing), flows whose trigger type has no registered trigger, and bound record-change flows targeting an unknown object (dead binding). Printed after stdout is restored, so it is immune to the boot-quiet window. + - **Trigger-fired run failures now log at ERROR** (stderr — always visible): the automation engine no longer drops the AutomationResult of a trigger-fired execution; condition-evaluation faults and node failures surface with the flow name. Condition-not-met skips stay at debug (high-frequency, intentional). + - **`RecordChangeTrigger` probes object existence at bind time** and warns when a flow's `objectName` matches no registered object (exact-name matching), instead of silently arming a hook that can never fire. + - **`kernel:bootstrapped` binding audit** in the automation plugin: warns per enabled-but-unbound triggered flow with the reason, and reports registered/bound/draft counts (`AutomationEngine.getTriggerBindingAudit()`, extended `getFlowRuntimeStates()` with `status`/`triggerType`/`object`). + - **`os validate` flow-wiring advisories** (`@objectstack/lint` `validateFlowTriggerReadiness`): warns when a record-triggered flow targets an object the stack does not define, and when an auto-triggered flow's status is `draft` (authored or defaulted — draft flows still fire; declare `active` or `obsolete`). + - Removed leftover boot-debug writes (`registerApp`/`AppPlugin`/`StandaloneStack`/`AuditPlugin` stderr noise) that previous debugging of this same silence had left behind. + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/triggers/trigger-record-change/package.json b/packages/triggers/trigger-record-change/package.json index ec9433abf..28a2a4b42 100644 --- a/packages/triggers/trigger-record-change/package.json +++ b/packages/triggers/trigger-record-change/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/trigger-record-change", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Record-change flow trigger for ObjectStack — auto-launches flows on object insert/update/delete via ObjectQL lifecycle hooks (ADR-0018)", "main": "dist/index.js", diff --git a/packages/triggers/trigger-schedule/CHANGELOG.md b/packages/triggers/trigger-schedule/CHANGELOG.md index a67ef158b..328abe8c6 100644 --- a/packages/triggers/trigger-schedule/CHANGELOG.md +++ b/packages/triggers/trigger-schedule/CHANGELOG.md @@ -1,5 +1,33 @@ # @objectstack/plugin-trigger-schedule +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + - @objectstack/core@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/triggers/trigger-schedule/package.json b/packages/triggers/trigger-schedule/package.json index af50e2571..34d900c2a 100644 --- a/packages/triggers/trigger-schedule/package.json +++ b/packages/triggers/trigger-schedule/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/trigger-schedule", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Schedule flow trigger for ObjectStack — auto-launches flows on a cron/interval/once schedule via the IJobService (ADR-0018)", "main": "dist/index.js", diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md index 138da4918..683461b3c 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -1,5 +1,29 @@ # @objectstack/types +## 15.2.0 + +### Patch Changes + +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [a8aa34c] +- Updated dependencies [a3823b2] +- Updated dependencies [5e3301d] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/spec@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/types/package.json b/packages/types/package.json index 64610e365..e8429668f 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/types", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Shared interfaces describing the ObjectStack Runtime environment", "main": "dist/index.js", diff --git a/packages/verify/CHANGELOG.md b/packages/verify/CHANGELOG.md index 640468b20..bf6a5574e 100644 --- a/packages/verify/CHANGELOG.md +++ b/packages/verify/CHANGELOG.md @@ -1,5 +1,56 @@ # @objectstack/verify +## 15.2.0 + +### Patch Changes + +- Updated dependencies [a9459e6] +- Updated dependencies [3ad3dd5] +- Updated dependencies [3a18b60] +- Updated dependencies [02eafa5] +- Updated dependencies [deb7e7e] +- Updated dependencies [a8aa34c] +- Updated dependencies [e057f42] +- Updated dependencies [a3823b2] +- Updated dependencies [fdc244e] +- Updated dependencies [5e3301d] +- Updated dependencies [780b4b5] +- Updated dependencies [2ea08ee] +- Updated dependencies [5f05de2] +- Updated dependencies [021ba4c] +- Updated dependencies [d2723e2] +- Updated dependencies [fefcd54] +- Updated dependencies [efbcfe1] +- Updated dependencies [2049b6a] +- Updated dependencies [beaf2de] +- Updated dependencies [b659111] +- Updated dependencies [5754a23] +- Updated dependencies [668dd17] +- Updated dependencies [8abf133] +- Updated dependencies [515f11a] +- Updated dependencies [4174a07] +- Updated dependencies [ce468c8] +- Updated dependencies [04ecd4e] +- Updated dependencies [16cebeb] +- Updated dependencies [8923843] +- Updated dependencies [f16b492] +- Updated dependencies [4b6fde8] +- Updated dependencies [fc5a3a2] + - @objectstack/service-analytics@15.2.0 + - @objectstack/spec@15.2.0 + - @objectstack/service-automation@15.2.0 + - @objectstack/plugin-auth@15.2.0 + - @objectstack/objectql@15.2.0 + - @objectstack/core@15.2.0 + - @objectstack/rest@15.2.0 + - @objectstack/runtime@15.2.0 + - @objectstack/plugin-hono-server@15.2.0 + - @objectstack/driver-sqlite-wasm@15.2.0 + - @objectstack/plugin-security@15.2.0 + - @objectstack/plugin-sharing@15.2.0 + - @objectstack/service-datasource@15.2.0 + - @objectstack/service-settings@15.2.0 + ## 15.1.1 ### Patch Changes diff --git a/packages/verify/package.json b/packages/verify/package.json index 1fd963301..47408ec3c 100644 --- a/packages/verify/package.json +++ b/packages/verify/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/verify", - "version": "15.1.1", + "version": "15.2.0", "license": "Apache-2.0", "description": "Boot any ObjectStack app in-process and verify it through the real HTTP stack — auto-derived CRUD round-trip fidelity plus the cross-owner RLS invariant. Catches runtime regressions that static checks miss.", "type": "module", diff --git a/packages/vscode-objectstack/CHANGELOG.md b/packages/vscode-objectstack/CHANGELOG.md index 99ab416cc..4c04b2773 100644 --- a/packages/vscode-objectstack/CHANGELOG.md +++ b/packages/vscode-objectstack/CHANGELOG.md @@ -1,5 +1,7 @@ # objectstack-vscode +## 15.2.0 + ## 15.1.1 ## 15.1.0 diff --git a/packages/vscode-objectstack/package.json b/packages/vscode-objectstack/package.json index 7e8795200..88cb55923 100644 --- a/packages/vscode-objectstack/package.json +++ b/packages/vscode-objectstack/package.json @@ -2,7 +2,7 @@ "name": "objectstack-vscode", "displayName": "ObjectStack", "description": "ObjectStack Protocol — Autocomplete, validation, and inline diagnostics for .object.ts, .view.ts, and objectstack.config.ts files", - "version": "15.1.1", + "version": "15.2.0", "publisher": "objectstack", "license": "Apache-2.0", "repository": {