diff --git a/.changeset/pre.json b/.changeset/pre.json index 5e49118ff1..61279cc9c1 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -123,6 +123,7 @@ "adr-0078-phase3-webhook-triggers", "adr-0078-phase4-runtime-warns", "adr-0078-status-calibration", + "adr-0087-stock-reconciliation-backfill", "adr-0104-advertise-open-gates", "adr-0104-attestation-adr-note", "adr-0104-d1-media-strict-per-deployment", @@ -188,6 +189,7 @@ "adr0104-attest-after-boot-writes", "adr0104-lax-deviation-marker", "adr0120-isolated-install-gate-and-truth-sweep", + "after-hook-in-transaction-semantics", "agent-code-is-the-record", "agent-knowledge-alias-and-experimental-markers", "agents-md-worktree-staleness", @@ -281,6 +283,7 @@ "approval-attachment-descriptors", "approval-dead-run-ordering-invariant", "approval-dead-run-record-lock", + "approval-decision-one-dialog", "approval-decision-survives-restart", "approval-empty-position-admin-override", "approval-lock-schedule-run-provenance", @@ -299,6 +302,7 @@ "approvals-payload-labels", "approvals-reports-exec-context-annotations", "approvals-stranded-request-inspection", + "approvals-unknown-query-param", "approver-live-record-3447", "approver-value-sources-and-dead-slot-warning", "apps-mdx-retired-version-mobile-navigation", @@ -321,6 +325,7 @@ "audit-tracked-change-summary-locale-and-lookup", "auth-admin-audit-hook-bypass-claim-corrected", "auth-catchall-yields-unowned-paths", + "auth-config-stop-advertising-reserved-features", "auth-contains-literal-substring", "auth-database-hooks-middleware-claim-corrected", "auth-invalid-membership-policy-outcome", @@ -344,8 +349,10 @@ "authz-ledger-flow-runas", "auto-org-admin-revoke-delete-signature", "automation-client-resume-screen-flow", + "automation-descriptor-query-refusal", "automation-resume-authority-gate", "automation-runs-query-param-refusal", + "automation-toggle-unknown-flow-404", "autonumber-builder-readonly", "autonumber-counter-readback-shared", "autonumber-default-format-contract", @@ -356,8 +363,11 @@ "autonumber-sequence-resync-on-collision", "banner-dsn-connection-display", "bare-path-parent-prefix-inside-link", + "baseline-additive-on-ui-plane", + "baseline-composes-with-platform", "batch-create-readonly-ingress", "batch-dropped-fields-observability", + "batch-not-attempted-tail-reporting", "batch-row-error-codes-registered", "batch-row-result-schema-shape", "batch-upsert-existence-fork", @@ -393,6 +403,7 @@ "capabilities-registry-provenance-seam", "capability-metadata-kind-registry-entry", "cel-classify-error-by-code", + "cel-default-temporal-storage-shape", "cel-overload-retry-operand-scope", "cel-overload-retry-structured-code", "cel-parse-fault-kind", @@ -475,6 +486,7 @@ "console-1bb77aa24514", "console-2cb8d78e24ad", "console-4a4829d0ef39", + "console-6314e87f2d49", "console-785b8a5d432c", "console-7d9734d5e321", "console-7dfbeb704e1e", @@ -540,6 +552,7 @@ "datasource-health-check-retired", "datasource-mapping-is-routing", "datasource-memory-pool-loud-reject", + "datasource-pool-turso-mongo-timeouts-reject", "datasource-read-replicas-removed", "datasource-retry-policy-retired", "datasource-routes-catch-service-throws", @@ -559,6 +572,7 @@ "decision-outputs-surface-3447", "declarative-cron-job-schedule-envelope", "declarative-endpoints-docs-skill-catchup", + "declare-public-picker", "declare-publish-meta-item-response", "declared-unique-index-not-legacy", "default-agent-value-lint", @@ -571,8 +585,10 @@ "degraded-register-cause", "degraded-suspended-run-load-log-cause-meta", "delegable-scope-read-surface", + "delete-cascade-one-unit-of-work", "delete-fallback-success-shape", "delete-many-id-predicate", + "delete-meta-item-rewrap-carries-code", "delete-restricted-user-copy", "delivery-payload-severity-closed-union", "department-approver-env-wide-business-unit", @@ -586,6 +602,7 @@ "dev-plugin-security-stubs-and-prod-guard", "dev-prereqs-stale-dist-gate", "dev-watcher-restart-honesty", + "diagnostics-clean-baseline", "direct-mount-follows-apipath", "discovery-cache-queue-job-no-route", "discovery-data-slot-computed", @@ -604,6 +621,7 @@ "dispatcher-fallback-absence-warn", "dispatcher-handler-ready-gate", "dispatcher-per-request-kernel", + "dispatcher-permission-denied-details-allowlist", "dispatcher-plugin-error-code-doc-drift", "dispatcher-returned-error-leak", "dispatcher-validation-error-fields", @@ -646,6 +664,8 @@ "dogfood-shared-boot", "dogfood-typecheck-wired", "domain-error-passthrough", + "dotted-fields-prose-corrected", + "dotted-projection-refused", "driver-capabilities-inert-bits-removed", "driver-conformance-gate", "driver-conformance-zero-discovery", @@ -693,6 +713,7 @@ "email-persistence-insert-id-contract", "email-provider-smtp", "email-template-materializer-bridge", + "embedded-action-crossref-validation", "embedded-host-unsealed-node-type-vocabulary-warns", "empty-capability-answers-501", "empty-env-disabled-package-seed", @@ -740,6 +761,7 @@ "execution-context-auth-gate-declared", "execution-context-single-assembler", "executor-contract-surface-e1", + "expand-nested-fields-join-key", "explain-context-single-authz-aggregation", "export-axis-opt-in", "export-empty-result-header", @@ -848,6 +870,7 @@ "group-union-driver-scope", "groupby-alias-multi-face", "grouping-notify-describe-align", + "groups-fold-reaches-stored-rows", "guard-refusal-chokepoint", "handwritten-errmap-fix-before-history", "has-is-not-a-null-guard-lint", @@ -954,6 +977,7 @@ "job-placeholder-migrates-to-db-adapter", "job-queue-completed-retention", "job-retry-timeout-3494", + "job-run-degraded-status", "job-runtime-create-closed", "json-schema-rule-format-enforced", "json-schema-rule-unknown-format-gate", @@ -984,8 +1008,10 @@ "lifecycle-rotation-dialect-caveat", "lifecycle-unguarded-reap-batching", "light-berries-tickle", + "like-wire-lowering", "limit-zero-presence-sql-doors", "lint-action-dedup-composite-key", + "lint-cbp-without-relation", "lint-expressions-security-alias-reads", "lint-fieldless-object-skip", "lint-flag-record-change-trap", @@ -1010,6 +1036,7 @@ "lint-visibility-bare-identifier-gate", "lint-visibility-predicate-syntax-gate", "list-column-prefix-summary-object", + "list-runs-status-filter", "list-single-flight", "listcommits-outage-503", "liveness-evidence-path-resolution", @@ -1022,6 +1049,7 @@ "liveness-readme-table-gated", "liveness-register-orphan-proofs", "liveness-stale-evidence-fails-ci", + "liveness-state-counts-generated", "liveness-ten-preview-claims", "liveness-verified-at-clock", "liveness-widget-drill-and-container-coverage", @@ -1033,6 +1061,7 @@ "login-json-refuses-non-interactive", "lost-audit-row-is-an-error", "loud-pausing-resume-authority", + "lower-callables-functions-passthrough", "lucky-buttons-shave", "lucky-moons-smoke", "lucky-pandas-repeat", @@ -1055,6 +1084,7 @@ "mcp-metadata-outage-vs-miss", "measure-emits-what-it-declares", "member-default-explicit-allow", + "member-default-personal-inbox-read", "member-default-wildcard-prose-and-vacuous-d7-denials", "member-default-wildcard-published-prose", "membership-grade-not-capability-channel", @@ -1082,6 +1112,7 @@ "metadata-event-contract", "metadata-event-dual-source-kernel-side", "metadata-facade-object-write-read-split", + "metadata-facade-roundtrip-ruling", "metadata-form-zod-reconciliation", "metadata-fs-watch-write-registration", "metadata-get-diagnosed-outage-vs-miss", @@ -1105,20 +1136,27 @@ "migrate-plan-lists-datetime-convergence", "migrate-search-companion-parity", "migration-journal-boot-recovery", + "migration-registry-per-entry-files", "milestone-summary-lookup-titles", "missing-table-column-of-relation", "mixed-wrapper-refusal", "modal-actions-are-client-only", "modifyall-records-owner-less-declaration", "mongodb-boolean-identity-reduction", + "mongodb-contains-case-sensitive", + "mongodb-filter-shape-refusals", + "mongodb-native-date-granularity", "mongodb-single-tenant-boot-guard", + "mongodb-structured-groupby-and-count-distinct", "name-shaped-log-splice-sweep", "naming-drift-recheck", "nav-access-lint", + "nav-declared-empty-group-dropped", "nav-expanded-alias-cross-variant", "nav-item-input-type", "nav-runaction-declared-contract", "nested-plugin-collection-registration", + "nested-plugin-view-container-expansion", "next-event-seq-read-failure-loud", "node-and-shutdown-timeout-guards-cleared", "notification-action-embed-config-retired", @@ -1173,6 +1211,7 @@ "org-overlay-registry-gate", "org-scoped-cold-boot-audit", "org-scoped-write-refused", + "os-test-glob-lazy-walk", "osv-batch-2026-07-dep-bumps", "osv-batch-2026-08-fixable-bumps", "osv-exemption-conventions", @@ -1186,6 +1225,7 @@ "package-routes-repeated-version-query-param", "packages-authz-gate", "packages-envelope-suite-comment", + "packages-lifecycle-readonly-gate", "page-component-zero-reader-keys-removed", "page-field-and-chart-binding-lint", "page-header-i18n-3589", @@ -1197,6 +1237,8 @@ "patch-path-id-wins-over-body-id", "per-package-typecheck-coverage", "permission-backfill-row-state-columns", + "permission-denied-error-single-declaration", + "permission-denied-user-copy", "permission-set-projection-d5r-jsdoc", "pin-control-flow-designer-forms", "platform-always-on-capabilities", @@ -1245,6 +1287,7 @@ "public-book-grant", "public-form-empty-declaration-refusal", "public-form-schema-declared-fields-only", + "public-lookup-canonical-reference", "publish-draft-drain-discriminate", "publish-drafts-endpoint-gate", "publish-drafts-partial-unhide", @@ -1253,6 +1296,7 @@ "published-pm-dispatch-skill", "published-pm-dispatch-three-axis-decision-frame", "purge-webhook-delivery-i18n-and-bundle-ownership-guards", + "qa-assertion-field-path-body-root", "qa-contains-non-evaluable-fails-loud", "qa-protocol-category-title", "qa-testing-liveness-enforce", @@ -1306,6 +1350,7 @@ "reference-id-embedded-record", "reference-integrity-object-and-action-names", "reference-integrity-wiring-guard", + "references-empty-category-meta", "refuse-bulk-file-field-write", "refuse-out-of-contract-filter-input", "refused-capability-declaration-hole", @@ -1331,6 +1376,7 @@ "remove-unenforced-plugin-loading-config", "report-caller-envelope-forwarding", "report-chart-dataset-describe", + "report-delete-enumeration-oracle", "report-order-liveness-live", "report-ordering-and-time-axis-default", "report-schedule-owner-gate", @@ -1344,6 +1390,8 @@ "rest-env-resolution-kernel-resolver-seam", "rest-exec-ctx-principal-kind", "rest-expected-4xx-not-logged-as-unhandled", + "rest-hook-refusal-status-passthrough", + "rest-list-explicit-filter-unknown-field", "rest-list-implicit-filter-and-merge", "rest-list-malformed-filter-rejected", "rest-list-search-groupby-aggregations-rejected", @@ -1365,6 +1413,7 @@ "retire-data-engine-batch", "retire-default-dispatcher-routes", "retire-degraded-analytics-shim", + "retire-delete-by-id-before-hook-repoint", "retire-delete-fetch-previous-builtin", "retire-dev-analytics-stub", "retire-dev-service-marker", @@ -1373,6 +1422,7 @@ "retire-inert-driver-plugin-options", "retire-managed-by-system-bucket", "retire-plugin-runtime-family", + "retire-public-picker-sort-read", "retire-runtime-capabilities-doc-page", "retire-sharing-execution-context", "retire-the-dev-stub-table", @@ -1392,17 +1442,20 @@ "rls-predicate-authoring-gate", "rls-predicate-over-budget", "rls-priority-removed", + "rls-using-tsdoc-grammar-rewrite", "root-reference-index-generated", "route-audit-tranche-3-service-mounts", "route-envelope-four-more-modules", "route-envelope-guard-dispatcher-domains", "route-ledger-audit-guard", + "route-ledger-live-mount-parity", "route-ledger-response-schema", "row-write-widener-composition", "rpc-alias-precedence-one-fold", "rule-compilability-publish-gate", "rule-id-barrel-export-gap", "run-summary-uncountable-effects", + "run-trigger-attribution", "runas-system-stamping", "runner-setters-first-wins", "runtime-action-execution-module", @@ -1445,9 +1498,11 @@ "sdui-component-props-enforce-or-remove", "sdui-component-props-gate", "search-auto-excluded-types-disjointness-pin", + "search-capability-serveability-predicate", "searchable-fields-formula-refused", "searchable-fields-stale-declaration", "searchable-fields-stored-hint", + "security-denial-end-user-copy", "security-get-readable-fields", "security-props-liveness-recheck", "security-service-contract", @@ -1486,6 +1541,7 @@ "settings-declared-step-grid-enforced", "settings-declared-value-window-enforced", "settings-error-details-declared-slot", + "settings-redact-encrypted-rest-read", "settings-select-options-enforced", "settings-visible-fail-closed", "settings-visible-grammar-declared", @@ -1531,6 +1587,7 @@ "skill-formula-condition-abort-scope", "skill-hook-condition-aborts", "skill-instructions-as-mcp-prompts", + "skill-permissions-docblock-truth", "skill-trigger-condition-value-shaped-by-operator", "skills-definehook-examples", "slot-contract-ledger-beyond-the-enum", @@ -1560,9 +1617,11 @@ "spec-type-alias-parsed-convention", "spec-vitest-testtimeout", "specifier-value-domain", + "split-controlled-by-parent-deny-legs", "spotty-lions-flash", "sql-distinct-bare-filter-condition", "sql-driver-boolean-identity", + "sql-driver-cross-field-comparison", "sql-driver-dialect-connect-timeout", "sql-driver-not-null-safe", "sql-driver-null-safe-negative-operators", @@ -1606,6 +1665,7 @@ "strictness-ledger-remeasure", "strip-read-decorations-on-save", "studio-strict", + "submitbehavior-jsdoc-mode-aware-default", "subscribe-metadata-event-subject", "summary-count-zero-on-parent-insert", "summary-index-registry-revision", @@ -1622,9 +1682,11 @@ "sys-view-definition-default-open", "system-data-import-opt-in", "system-field-name-injected-columns", + "system-overview-tile-label-query-agreement", "systemfields-owner-guidance-org-skips-owner-id", "tame-donkeys-repeat", "tame-jars-shake", + "tame-moons-shave", "template-manifest-optional-manifest-id", "template-manifest-scaffold-namespace", "temporal-conformance-driver-axis", @@ -1761,9 +1823,11 @@ "view-strict-final", "view-subblock-strictness-batch18", "view-union-and-container-issue-diagnostics", + "view-union-branch-focus", "view-union-identity-precondition", "views-translation-key-runtime-identity", "visibility-alias-deprecated-retired", + "visibility-predicate-family-runtime-publish", "visibility-predicate-over-budget", "wait-loose-config-graduation", "wait-node-log-cause-meta", diff --git a/examples/app-crm/CHANGELOG.md b/examples/app-crm/CHANGELOG.md index 5d8eff2f9c..0f06238f12 100644 --- a/examples/app-crm/CHANGELOG.md +++ b/examples/app-crm/CHANGELOG.md @@ -1,5 +1,44 @@ # @objectstack/example-crm +## 4.0.92-rc.6 + +### Patch Changes + +- Updated dependencies [5823d59] +- Updated dependencies [76d74ec] +- Updated dependencies [86f7a20] +- Updated dependencies [c546c89] +- Updated dependencies [22df871] +- Updated dependencies [9c82146] +- Updated dependencies [744b8f5] +- Updated dependencies [2c1988c] +- Updated dependencies [211abdb] +- Updated dependencies [b3de0dd] +- Updated dependencies [35b36f2] +- Updated dependencies [f505689] +- Updated dependencies [08363a0] +- Updated dependencies [d063a96] +- Updated dependencies [cf7c694] +- Updated dependencies [603cab8] +- Updated dependencies [9051802] +- Updated dependencies [f293d45] +- Updated dependencies [f067930] +- Updated dependencies [61ea810] +- Updated dependencies [91eddca] +- Updated dependencies [b61afc1] +- Updated dependencies [97b6658] +- Updated dependencies [814db6d] +- Updated dependencies [8dd98bf] +- Updated dependencies [8a9c079] +- Updated dependencies [cc3555e] +- Updated dependencies [69ac82c] +- Updated dependencies [c6a4eeb] +- Updated dependencies [e124711] +- Updated dependencies [1059965] +- Updated dependencies [c9b809f] + - @objectstack/spec@17.0.0-rc.7 + - @objectstack/runtime@17.0.0-rc.7 + ## 4.0.92-rc.5 ### Patch Changes diff --git a/examples/app-crm/package.json b/examples/app-crm/package.json index 2e38f8153f..34b01beed0 100644 --- a/examples/app-crm/package.json +++ b/examples/app-crm/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/example-crm", - "version": "4.0.92-rc.5", + "version": "4.0.92-rc.6", "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 e0255e63c5..2eabcc80a4 100644 --- a/examples/app-showcase/CHANGELOG.md +++ b/examples/app-showcase/CHANGELOG.md @@ -1,5 +1,52 @@ # @objectstack/example-showcase +## 0.3.14-rc.6 + +### Patch Changes + +- Updated dependencies [5823d59] +- Updated dependencies [76d74ec] +- Updated dependencies [86f7a20] +- Updated dependencies [c546c89] +- Updated dependencies [22df871] +- Updated dependencies [9c82146] +- Updated dependencies [744b8f5] +- Updated dependencies [2c1988c] +- Updated dependencies [211abdb] +- Updated dependencies [b3de0dd] +- Updated dependencies [35b36f2] +- Updated dependencies [f505689] +- Updated dependencies [08363a0] +- Updated dependencies [d063a96] +- Updated dependencies [cf7c694] +- Updated dependencies [603cab8] +- Updated dependencies [9051802] +- Updated dependencies [f293d45] +- Updated dependencies [f067930] +- Updated dependencies [61ea810] +- Updated dependencies [91eddca] +- Updated dependencies [b61afc1] +- Updated dependencies [97b6658] +- Updated dependencies [814db6d] +- Updated dependencies [8dd98bf] +- Updated dependencies [8a9c079] +- Updated dependencies [cc3555e] +- Updated dependencies [69ac82c] +- Updated dependencies [c6a4eeb] +- Updated dependencies [e124711] +- Updated dependencies [f1544e2] +- Updated dependencies [1059965] +- Updated dependencies [c9b809f] + - @objectstack/spec@17.0.0-rc.7 + - @objectstack/runtime@17.0.0-rc.7 + - @objectstack/service-datasource@17.0.0-rc.7 + - @objectstack/driver-sql@17.0.0-rc.7 + - @objectstack/cloud-connection@17.0.0-rc.7 + - @objectstack/connector-mcp@17.0.0-rc.7 + - @objectstack/connector-openapi@17.0.0-rc.7 + - @objectstack/connector-rest@17.0.0-rc.7 + - @objectstack/connector-slack@17.0.0-rc.7 + ## 0.3.14-rc.5 ### Patch Changes diff --git a/examples/app-showcase/package.json b/examples/app-showcase/package.json index aef1ecaf52..5d4c9a7261 100644 --- a/examples/app-showcase/package.json +++ b/examples/app-showcase/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/example-showcase", - "version": "0.3.14-rc.5", + "version": "0.3.14-rc.6", "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 09a8e9ce3e..4abe063c85 100644 --- a/examples/app-todo/CHANGELOG.md +++ b/examples/app-todo/CHANGELOG.md @@ -1,5 +1,57 @@ # @objectstack/example-todo +## 4.0.92-rc.6 + +### Patch Changes + +- Updated dependencies [5823d59] +- Updated dependencies [76d74ec] +- Updated dependencies [86f7a20] +- Updated dependencies [c546c89] +- Updated dependencies [22df871] +- Updated dependencies [9c82146] +- Updated dependencies [744b8f5] +- Updated dependencies [db31402] +- Updated dependencies [2c1988c] +- Updated dependencies [211abdb] +- Updated dependencies [8e17759] +- Updated dependencies [b3de0dd] +- Updated dependencies [35b36f2] +- Updated dependencies [f505689] +- Updated dependencies [08363a0] +- Updated dependencies [245d1dc] +- Updated dependencies [d063a96] +- Updated dependencies [cf7c694] +- Updated dependencies [603cab8] +- Updated dependencies [9051802] +- Updated dependencies [f293d45] +- Updated dependencies [f067930] +- Updated dependencies [edbf873] +- Updated dependencies [61ea810] +- Updated dependencies [91eddca] +- Updated dependencies [b61afc1] +- Updated dependencies [97b6658] +- Updated dependencies [814db6d] +- Updated dependencies [8dd98bf] +- Updated dependencies [8a9c079] +- Updated dependencies [cc3555e] +- Updated dependencies [69ac82c] +- Updated dependencies [c6a4eeb] +- Updated dependencies [e124711] +- Updated dependencies [f1544e2] +- Updated dependencies [1059965] +- Updated dependencies [52d1a7d] +- Updated dependencies [c9b809f] + - @objectstack/spec@17.0.0-rc.7 + - @objectstack/objectql@17.0.0-rc.7 + - @objectstack/runtime@17.0.0-rc.7 + - @objectstack/client@17.0.0-rc.7 + - @objectstack/driver-sqlite-wasm@17.0.0-rc.7 + - @objectstack/metadata@17.0.0-rc.7 + - @objectstack/mcp@17.0.0-rc.7 + - @objectstack/knowledge-memory@17.0.0-rc.7 + - @objectstack/service-knowledge@17.0.0-rc.7 + ## 4.0.92-rc.5 ### Patch Changes diff --git a/examples/app-todo/package.json b/examples/app-todo/package.json index 763228d75c..0aeeae6a3e 100644 --- a/examples/app-todo/package.json +++ b/examples/app-todo/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/example-todo", - "version": "4.0.92-rc.5", + "version": "4.0.92-rc.6", "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 80eeb2f318..0780dea8d2 100644 --- a/examples/embed-objectql/CHANGELOG.md +++ b/examples/embed-objectql/CHANGELOG.md @@ -1,5 +1,45 @@ # @objectstack/example-embed-objectql +## 0.0.32-rc.6 + +### Patch Changes + +- Updated dependencies [5823d59] +- Updated dependencies [76d74ec] +- Updated dependencies [86f7a20] +- Updated dependencies [9c82146] +- Updated dependencies [744b8f5] +- Updated dependencies [db31402] +- Updated dependencies [2c1988c] +- Updated dependencies [211abdb] +- Updated dependencies [8e17759] +- Updated dependencies [b3de0dd] +- Updated dependencies [f505689] +- Updated dependencies [08363a0] +- Updated dependencies [245d1dc] +- Updated dependencies [d063a96] +- Updated dependencies [cf7c694] +- Updated dependencies [603cab8] +- Updated dependencies [9051802] +- Updated dependencies [f293d45] +- Updated dependencies [f067930] +- Updated dependencies [edbf873] +- Updated dependencies [61ea810] +- Updated dependencies [b61afc1] +- Updated dependencies [97b6658] +- Updated dependencies [814db6d] +- Updated dependencies [8dd98bf] +- Updated dependencies [8a9c079] +- Updated dependencies [cc3555e] +- Updated dependencies [69ac82c] +- Updated dependencies [c6a4eeb] +- Updated dependencies [e124711] +- Updated dependencies [1059965] +- Updated dependencies [c9b809f] + - @objectstack/spec@17.0.0-rc.7 + - @objectstack/objectql@17.0.0-rc.7 + - @objectstack/driver-memory@17.0.0-rc.7 + ## 0.0.32-rc.5 ### Patch Changes diff --git a/examples/embed-objectql/package.json b/examples/embed-objectql/package.json index 08a1fb65fe..e751a0c49a 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.32-rc.5", + "version": "0.0.32-rc.6", "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 ab79de28b1..694ac9c036 100644 --- a/packages/adapters/hono/CHANGELOG.md +++ b/packages/adapters/hono/CHANGELOG.md @@ -1,5 +1,23 @@ # @objectstack/hono +## 17.0.0-rc.7 + +### Patch Changes + +- Updated dependencies [c546c89] +- Updated dependencies [22df871] +- Updated dependencies [51fb081] +- Updated dependencies [9c82146] +- Updated dependencies [b3de0dd] +- Updated dependencies [35b36f2] +- Updated dependencies [cf7c694] +- Updated dependencies [61ea810] +- Updated dependencies [91eddca] +- Updated dependencies [cc3555e] + - @objectstack/runtime@17.0.0-rc.7 + - @objectstack/plugin-hono-server@17.0.0-rc.7 + - @objectstack/types@17.0.0-rc.7 + ## 17.0.0-rc.6 ### Patch Changes diff --git a/packages/adapters/hono/package.json b/packages/adapters/hono/package.json index 7d0a0961a9..ca6983aad4 100644 --- a/packages/adapters/hono/package.json +++ b/packages/adapters/hono/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/hono", - "version": "17.0.0-rc.6", + "version": "17.0.0-rc.7", "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 bbcb5d9d0f..36da5e83d3 100644 --- a/packages/apps/account/CHANGELOG.md +++ b/packages/apps/account/CHANGELOG.md @@ -1,5 +1,40 @@ # @objectstack/account +## 17.0.0-rc.7 + +### Patch Changes + +- Updated dependencies [5823d59] +- Updated dependencies [76d74ec] +- Updated dependencies [86f7a20] +- Updated dependencies [9c82146] +- Updated dependencies [744b8f5] +- Updated dependencies [2c1988c] +- Updated dependencies [211abdb] +- Updated dependencies [f505689] +- Updated dependencies [08363a0] +- Updated dependencies [d063a96] +- Updated dependencies [cf7c694] +- Updated dependencies [603cab8] +- Updated dependencies [9051802] +- Updated dependencies [f293d45] +- Updated dependencies [f067930] +- Updated dependencies [61ea810] +- Updated dependencies [b61afc1] +- Updated dependencies [97b6658] +- Updated dependencies [814db6d] +- Updated dependencies [8dd98bf] +- Updated dependencies [8a9c079] +- Updated dependencies [cc3555e] +- Updated dependencies [69ac82c] +- Updated dependencies [c6a4eeb] +- Updated dependencies [e124711] +- Updated dependencies [1059965] +- Updated dependencies [8c20f75] +- Updated dependencies [c9b809f] + - @objectstack/spec@17.0.0-rc.7 + - @objectstack/platform-objects@17.0.0-rc.7 + ## 17.0.0-rc.6 ### Patch Changes diff --git a/packages/apps/account/package.json b/packages/apps/account/package.json index 74c83de8b3..54607ad28e 100644 --- a/packages/apps/account/package.json +++ b/packages/apps/account/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/account", - "version": "17.0.0-rc.6", + "version": "17.0.0-rc.7", "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 f9cc349cae..5541930bc3 100644 --- a/packages/apps/setup/CHANGELOG.md +++ b/packages/apps/setup/CHANGELOG.md @@ -1,5 +1,40 @@ # @objectstack/setup +## 17.0.0-rc.7 + +### Patch Changes + +- Updated dependencies [5823d59] +- Updated dependencies [76d74ec] +- Updated dependencies [86f7a20] +- Updated dependencies [9c82146] +- Updated dependencies [744b8f5] +- Updated dependencies [2c1988c] +- Updated dependencies [211abdb] +- Updated dependencies [f505689] +- Updated dependencies [08363a0] +- Updated dependencies [d063a96] +- Updated dependencies [cf7c694] +- Updated dependencies [603cab8] +- Updated dependencies [9051802] +- Updated dependencies [f293d45] +- Updated dependencies [f067930] +- Updated dependencies [61ea810] +- Updated dependencies [b61afc1] +- Updated dependencies [97b6658] +- Updated dependencies [814db6d] +- Updated dependencies [8dd98bf] +- Updated dependencies [8a9c079] +- Updated dependencies [cc3555e] +- Updated dependencies [69ac82c] +- Updated dependencies [c6a4eeb] +- Updated dependencies [e124711] +- Updated dependencies [1059965] +- Updated dependencies [8c20f75] +- Updated dependencies [c9b809f] + - @objectstack/spec@17.0.0-rc.7 + - @objectstack/platform-objects@17.0.0-rc.7 + ## 17.0.0-rc.6 ### Patch Changes diff --git a/packages/apps/setup/package.json b/packages/apps/setup/package.json index 82593ba476..970f6a4b41 100644 --- a/packages/apps/setup/package.json +++ b/packages/apps/setup/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/setup", - "version": "17.0.0-rc.6", + "version": "17.0.0-rc.7", "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 331c900edc..92b9b3cff5 100644 --- a/packages/apps/studio/CHANGELOG.md +++ b/packages/apps/studio/CHANGELOG.md @@ -1,5 +1,40 @@ # @objectstack/studio +## 17.0.0-rc.7 + +### Patch Changes + +- Updated dependencies [5823d59] +- Updated dependencies [76d74ec] +- Updated dependencies [86f7a20] +- Updated dependencies [9c82146] +- Updated dependencies [744b8f5] +- Updated dependencies [2c1988c] +- Updated dependencies [211abdb] +- Updated dependencies [f505689] +- Updated dependencies [08363a0] +- Updated dependencies [d063a96] +- Updated dependencies [cf7c694] +- Updated dependencies [603cab8] +- Updated dependencies [9051802] +- Updated dependencies [f293d45] +- Updated dependencies [f067930] +- Updated dependencies [61ea810] +- Updated dependencies [b61afc1] +- Updated dependencies [97b6658] +- Updated dependencies [814db6d] +- Updated dependencies [8dd98bf] +- Updated dependencies [8a9c079] +- Updated dependencies [cc3555e] +- Updated dependencies [69ac82c] +- Updated dependencies [c6a4eeb] +- Updated dependencies [e124711] +- Updated dependencies [1059965] +- Updated dependencies [8c20f75] +- Updated dependencies [c9b809f] + - @objectstack/spec@17.0.0-rc.7 + - @objectstack/platform-objects@17.0.0-rc.7 + ## 17.0.0-rc.6 ### Patch Changes diff --git a/packages/apps/studio/package.json b/packages/apps/studio/package.json index 90be6f2db2..d57de01ce5 100644 --- a/packages/apps/studio/package.json +++ b/packages/apps/studio/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/studio", - "version": "17.0.0-rc.6", + "version": "17.0.0-rc.7", "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 7cd9fae1e7..1d660eed4c 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,213 @@ # @objectstack/cli +## 17.0.0-rc.7 + +### Patch Changes + +- bf4ebe2: fix(cli): stop `lowerCallables` deleting the `functions` entries it does not recognise (#7318) + + The map branch of the top-level `functions` lowering REBUILT the map instead of + editing it: `out` admitted an entry only in the three shapes it knew — a bare + callable, `{ handler: callable }`, or a plain string ref — and everything else + was dropped. No error, no warning, no key. Two distinct failures came out of + that one line. + + **A built artifact could not be lowered again.** The already-lowered declaration + `{ handler: 'syncBilling', effect: 'writes' }` — the shape this very step emits + for a declared writer, and the one `FlowFunctionLoweredDeclarationSchema` was + added to accept in #4976 — matched none of the recognised shapes. A second pass + therefore deleted the key outright, silently un-declaring the writer the first + pass had gone out of its way to keep. Lowering is now idempotent: lower a + lowered stack and the `functions` key set and the declared entries are + unchanged, in both the map and the array spelling. + + **A malformed entry was destroyed rather than reported.** The headless husk + `{ effect: 'writes' }` — a declaration for a function that is not there, which + is exactly what a plain `JSON.stringify(stack)` leaves where a declared writer + was (#6293) — reached the lowering and left it as `functions: {}`. The stack + then parsed GREEN, so `objectstack build` wrote an artifact missing the function + instead of refusing, and the evidence had been deleted before the parse could + name it. + + Unrecognised entries now ride through under their own key, untouched, and + `FlowFunctionEntrySchema` decides. The husk is refused where the build actually + checks — `invalid_union` on `functions`, with the offending key nameable in the + branch tree, which `formatZodErrors` (#5341) prints in the terminal. + + Nothing changes for a stack that was building correctly: bare callables, declared + callables, pre-existing string refs and the array form all lower exactly as + before. A stack that was silently shipping a `functions` map missing an entry now + fails its build, naming `functions` — which is the point. + +- 072ab7f: fix(cli): `os test` walks the tree lazily and prunes, instead of listing the whole repository first (#7363) + + `os test` documents `**` in `resolveGlob`'s own header, and a `**` pattern was the + one thing it could not survive. Run from a repository root: + + ``` + $ node packages/cli/bin/run.js test '**/*.test.json' + FATAL ERROR: Ineffective mark-compacts near heap limit — JavaScript heap out of memory + ``` + + Exit 134, after ~7 minutes of GC thrash, before a single suite loaded. + + **Why.** `resolveGlob` split the pattern at the first wildcard to get a static base + directory, so a leading `**` left the base at `.` — and then called + `fs.readdirSync(baseDir, { recursive: true })`, which **materialises every path + under the base as one array before any filtering runs**. The filter that would have + thrown almost all of them away never got to run. + + The array was worse than "one entry per file", too. `readdirSync(…, { recursive: +true })` _follows symlinked directories_, and a pnpm `node_modules` is a symlink + graph in which every package links to its dependencies' real directories — so the + set of walkable paths is combinatorial in dependency depth, not linear in file + count. That is how a tree `find` reports as ~97k real entries exhausted an 8 GB heap. + + **Now.** The walk is lazy and segment-directed: it reads one directory at a time and + descends only into directories that can still satisfy the rest of the pattern, so + nothing is ever accumulated in order to be discarded. It does not follow symlinked + directories, which removes the combinatorial blow-up along with any cycle risk. + + Same command, same repository, after: **completes in 3 seconds**, having found the + three `*.test.json` files that are actually in the tree. + + **A wildcard no longer descends into `node_modules`, `.git`, `dist` or `build`.** + These are the same defect at a smaller scale: with no ignore list, a suite vendored + in `node_modules` — or a stale copy of your own suite left in `dist` — was a match + `os test` would load and **run against a live server**. A wildcard is a search of + your sources, and none of those four holds one. The prune applies only to + directories a _wildcard_ reached: a pattern that spells the name out + (`packages/*/dist/*.test.json`) still walks it, because naming a directory is asking + for it and a list of defaults must not overrule the argument you typed. + + Three smaller corrections that fell out of the rewrite: + + - **No second `statSync` pass.** The old code stat'ed every surviving match to + confirm it was a file; `Dirent` already answers that during the walk. Symlinks are + the only entries that still cost a syscall, and they are still counted as matches + exactly as before. + - **Only `*` and `**`are wildcards now.** The old translation escaped dots and +nothing else, so every other regex metacharacter in a filename reached the`RegExp`as an operator:`a+b.test.json`did not match itself, and`a?.json`meant "optional`a`" and matched `.json`. + - **Absolute patterns resolve absolutely.** A leading `/` was folded through + `path.join` as an ordinary segment, so `/tmp/x/*.test.json` was resolved against + the current working directory and silently matched nothing. + + Matching is otherwise unchanged: the default `qa/*.test.json` resolves as it always + did, `**` still matches zero segments as well as many, and a pattern with no wildcard + is still a direct file path. Results are now sorted, so suites run in the same order + on every filesystem. + +- Updated dependencies [5823d59] +- Updated dependencies [76d74ec] +- Updated dependencies [7abdd74] +- Updated dependencies [59768f7] +- Updated dependencies [86f7a20] +- Updated dependencies [c546c89] +- Updated dependencies [22df871] +- Updated dependencies [51fb081] +- Updated dependencies [9c82146] +- Updated dependencies [744b8f5] +- Updated dependencies [db31402] +- Updated dependencies [3c416a1] +- Updated dependencies [2c1988c] +- Updated dependencies [211abdb] +- Updated dependencies [8e17759] +- Updated dependencies [2c28df9] +- Updated dependencies [b3de0dd] +- Updated dependencies [35b36f2] +- Updated dependencies [f505689] +- Updated dependencies [8201000] +- Updated dependencies [08363a0] +- Updated dependencies [245d1dc] +- Updated dependencies [769511c] +- Updated dependencies [05ac83d] +- Updated dependencies [d063a96] +- Updated dependencies [90336e6] +- Updated dependencies [cf7c694] +- Updated dependencies [603cab8] +- Updated dependencies [3987a48] +- Updated dependencies [9051802] +- Updated dependencies [f293d45] +- Updated dependencies [7e9e555] +- Updated dependencies [f7a60d9] +- Updated dependencies [d17a222] +- Updated dependencies [f067930] +- Updated dependencies [7bc02f4] +- Updated dependencies [edbf873] +- Updated dependencies [61ea810] +- Updated dependencies [91eddca] +- Updated dependencies [b61afc1] +- Updated dependencies [3ac243a] +- Updated dependencies [97b6658] +- Updated dependencies [814db6d] +- Updated dependencies [af5918b] +- Updated dependencies [d6f3f2f] +- Updated dependencies [7f1d4d0] +- Updated dependencies [8dd98bf] +- Updated dependencies [b03b0e1] +- Updated dependencies [8a9c079] +- Updated dependencies [cc3555e] +- Updated dependencies [57292a8] +- Updated dependencies [69ac82c] +- Updated dependencies [c6a4eeb] +- Updated dependencies [23bc6e1] +- Updated dependencies [e124711] +- Updated dependencies [e51acd6] +- Updated dependencies [f1544e2] +- Updated dependencies [1059965] +- Updated dependencies [8c20f75] +- Updated dependencies [52d1a7d] +- Updated dependencies [c9b809f] +- Updated dependencies [333769d] + - @objectstack/spec@17.0.0-rc.7 + - @objectstack/objectql@17.0.0-rc.7 + - @objectstack/plugin-approvals@17.0.0-rc.7 + - @objectstack/rest@17.0.0-rc.7 + - @objectstack/plugin-auth@17.0.0-rc.7 + - @objectstack/runtime@17.0.0-rc.7 + - @objectstack/plugin-hono-server@17.0.0-rc.7 + - @objectstack/plugin-security@17.0.0-rc.7 + - @objectstack/metadata-protocol@17.0.0-rc.7 + - @objectstack/console@17.0.0-rc.7 + - @objectstack/service-datasource@17.0.0-rc.7 + - @objectstack/service-job@17.0.0-rc.7 + - @objectstack/service-automation@17.0.0-rc.7 + - @objectstack/driver-sql@17.0.0-rc.7 + - @objectstack/driver-memory@17.0.0-rc.7 + - @objectstack/formula@17.0.0-rc.7 + - @objectstack/client@17.0.0-rc.7 + - @objectstack/lint@17.0.0-rc.7 + - @objectstack/driver-mongodb@17.0.0-rc.7 + - @objectstack/service-settings@17.0.0-rc.7 + - @objectstack/driver-sqlite-wasm@17.0.0-rc.7 + - @objectstack/platform-objects@17.0.0-rc.7 + - @objectstack/metadata@17.0.0-rc.7 + - @objectstack/account@17.0.0-rc.7 + - @objectstack/setup@17.0.0-rc.7 + - @objectstack/cloud-connection@17.0.0-rc.7 + - @objectstack/core@17.0.0-rc.7 + - @objectstack/mcp@17.0.0-rc.7 + - @objectstack/observability@17.0.0-rc.7 + - @objectstack/plugin-audit@17.0.0-rc.7 + - @objectstack/plugin-email@17.0.0-rc.7 + - @objectstack/plugin-reports@17.0.0-rc.7 + - @objectstack/plugin-sharing@17.0.0-rc.7 + - @objectstack/plugin-webhooks@17.0.0-rc.7 + - @objectstack/service-analytics@17.0.0-rc.7 + - @objectstack/service-cache@17.0.0-rc.7 + - @objectstack/service-messaging@17.0.0-rc.7 + - @objectstack/service-package@17.0.0-rc.7 + - @objectstack/service-queue@17.0.0-rc.7 + - @objectstack/service-realtime@17.0.0-rc.7 + - @objectstack/service-sms@17.0.0-rc.7 + - @objectstack/service-storage@17.0.0-rc.7 + - @objectstack/trigger-api@17.0.0-rc.7 + - @objectstack/trigger-record-change@17.0.0-rc.7 + - @objectstack/trigger-schedule@17.0.0-rc.7 + - @objectstack/types@17.0.0-rc.7 + - @objectstack/verify@17.0.0-rc.7 + - @objectstack/plugin-pinyin-search@17.0.0-rc.7 + ## 17.0.0-rc.6 ### Major Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index 95a2c1c9e9..eef0c039bb 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/cli", - "version": "17.0.0-rc.6", + "version": "17.0.0-rc.7", "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 7a08400d41..64396894b2 100644 --- a/packages/client-react/CHANGELOG.md +++ b/packages/client-react/CHANGELOG.md @@ -1,5 +1,40 @@ # @objectstack/client-react +## 17.0.0-rc.7 + +### Patch Changes + +- Updated dependencies [5823d59] +- Updated dependencies [76d74ec] +- Updated dependencies [86f7a20] +- Updated dependencies [9c82146] +- Updated dependencies [744b8f5] +- Updated dependencies [2c1988c] +- Updated dependencies [211abdb] +- Updated dependencies [f505689] +- Updated dependencies [08363a0] +- Updated dependencies [d063a96] +- Updated dependencies [cf7c694] +- Updated dependencies [603cab8] +- Updated dependencies [9051802] +- Updated dependencies [f293d45] +- Updated dependencies [f067930] +- Updated dependencies [61ea810] +- Updated dependencies [b61afc1] +- Updated dependencies [97b6658] +- Updated dependencies [814db6d] +- Updated dependencies [8dd98bf] +- Updated dependencies [8a9c079] +- Updated dependencies [cc3555e] +- Updated dependencies [69ac82c] +- Updated dependencies [c6a4eeb] +- Updated dependencies [e124711] +- Updated dependencies [1059965] +- Updated dependencies [c9b809f] + - @objectstack/spec@17.0.0-rc.7 + - @objectstack/client@17.0.0-rc.7 + - @objectstack/core@17.0.0-rc.7 + ## 17.0.0-rc.6 ### Patch Changes diff --git a/packages/client-react/package.json b/packages/client-react/package.json index e2b6a1d410..f6a1d7e392 100644 --- a/packages/client-react/package.json +++ b/packages/client-react/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/client-react", - "version": "17.0.0-rc.6", + "version": "17.0.0-rc.7", "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 98ef578695..3e837ce8de 100644 --- a/packages/client/CHANGELOG.md +++ b/packages/client/CHANGELOG.md @@ -1,5 +1,219 @@ # @objectstack/client +## 17.0.0-rc.7 + +### Minor Changes + +- cf7c694: fix(spec,runtime,service-automation): `GET /automation/:name/runs?status=` filters the runs instead of being dropped (#7359) + + `ListRunsRequestSchema` has always declared a `status` filter on + `GET /api/automation/:name/runs` — `z.enum([...the eight ExecutionStatus +members]).optional()`, described as "Filter by execution status". Nothing read + it. It had no slot on `IAutomationService.listRuns`, whose options were + `{ limit?, cursor? }`, and the runtime handler never built it into the object it + forwarded, so the parameter was dropped at the HTTP boundary and the caller was + answered **200 with every run of the flow**, capped by `limit`. + + That is worse than an error, because the answer looks like the one that was + asked for: a monitoring caller paging `?status=failed` reads the first 20 runs + of any status and concludes those are the failures. Exposure was raw HTTP, + generated clients, and anything authored against the OpenAPI surface — the typed + SDK could not send the parameter at all, which is why nothing had tripped over + it. #7300 fixed this route's two _coerced_ parameters and deliberately preserved + the ignore-the-key behaviour rather than decide between honouring and retiring + the third; this change takes the enforce route (ADR-0049), so the declared + surface is now true. + + **The filter is honoured across both stores.** `AutomationEngine.listRuns` + serves the Runs view by merging an in-memory ring buffer with the durable run + history it reads back from the store. The narrowing is applied to the merged + result, so both halves are covered: filtering only the buffer would answer "no + failures" for a flow whose failures are all in durable history — i.e. after any + restart, which is exactly when someone asks — and filtering only the durable + rows would hide the live ones. Applying it after the merge also means each run + is matched on its **resolved** status: the buffer holds more than one entry per + run id (a run that pauses appends `paused`, then its terminal entry), and + narrowing before the collapse would have let a stale `paused` entry outlive the + terminal one, so every approval/screen/wait run that had since completed would + report itself as still paused. + + The durable arm's window is unchanged: `listHistory(flowName, limit)` has no + status slot, so the filter is applied to the rows that come back rather than + pushed down, and a status filter can therefore return fewer than `limit` matches + while older ones exist. That is this merge's pre-existing shape — durable rows + were already capped at `limit` before the sort-and-slice — and closing it is a + store-contract change. What it never does is return a run of another status. + + **An undeclared status is now refused, not silently widened.** Once the filter + is honoured, a value outside the set has no safe reading: `?status=faild` cannot + mean "no filter", and serving the empty list is no better, because "no runs are + `faild`" and "no runs failed" read identically to a caller who cannot see their + own typo. The check goes through the shared `query-param` module this route + already consumes with `/notifications`, as a new `parseEnumParam` gate, and + refuses in the house shape — `400` `VALIDATION_FAILED` (ADR-0112) with a + `details.fields[]` entry carrying ADR-0114's existing `invalid_option` + ("not a member of the field's declared options"); a value that was never a + single string at all — a repeated `?status=a&status=b`, a structured + `?status[$ne]=x` — gets `invalid_type`, the same mapping the module's string + gate already makes. No new error vocabulary. The accepted members are read from + the spec's own `ExecutionStatus` enum, the one `ListRunsRequestSchema` is built + from, so the wire's declared set and the boundary's accepted set cannot drift. + + **The typed client can now send it.** `client.automation.listRuns(flow, { +status })` — both the `automation.listRuns` alias and `automation.runs.list` — + takes the filter as an optional `ExecutionStatus`, additively. It could not send + the parameter at all before, which is the reason nothing had tripped over the + server-side gap; leaving it out would have made the enforced filter reachable + only from raw HTTP, and the Runs view that wants it goes through this client. + + **Nothing that had a defensible answer changes.** An absent `status` still + returns every run, exactly as before. So does the empty spelling `?status=` — + unlike `?read=` on the notifications inbox, which used to serve the wrong _half_ + of the result, `?status=` already served precisely what "no filter" means, and + it is what an "All statuses" `` submits. `limit` and `cursor` are + untouched, including out-of-range values, which remain the service's business. + +- 61ea810: fix(runtime): refuse to disable or delete a read-only package on the `/packages` lifecycle routes (#7560) + + `PATCH /packages//disable` and `DELETE /packages/` answered **200** on a + platform package, and the `DELETE` really removed it from the running process's + registry listing. One authorized API call took platform functionality out of a + live deployment. Reproduced on two platform packages in the QA run behind #7514. + + **Blast radius, measured.** The card reported that the packages come back after a + restart — true for `DELETE` (they are code-loaded, so nothing is permanently + destroyed), but **not** for `disable`: `setPackageDisabled` persists the choice + to `/package-state/.json`, which `SchemaRegistry` replays at boot. + A disabled platform package stayed disabled across restarts. + + **Two axes, not one.** #7033 / PR #7083 gave the whole `/packages` domain caller + authorization (`manage_metadata` on writes, the ADR-0106 D4 set on reads, an + anonymous floor) — _who may call the route_. This is the second, missing check + on the same routes: _what the route may do once the caller is allowed_. An + authorized admin — and `isSystem` — is now refused, because read-only is a + property of the **package**, not of the caller. The caller gate is unchanged; + tightening it would not have fixed this and would have broken legitimate admins. + + **No new vocabulary.** The refusal is ADR-0070's existing one, reused: `422` / + `WRITABLE_PACKAGE_REQUIRED`, the code `saveMetaItem` already throws when asked to + author _into_ a read-only package. The predicate behind it moved out of + `ObjectStackProtocolImplementation`'s private method into + `@objectstack/metadata-protocol`'s exported `isWritablePackage(engine, id)` and + is now **referenced** by both callers — a second hand-kept copy of "which + packages are read-only" is exactly the drift that let `DELETE` remove a platform + package while `saveMetaItem` was refusing to add one field to it. Both read-only + signals are covered: a booted code package (`engine.manifests`) and a + platform-delivered manifest `scope` of `system` / `cloud`. + + Packages an org owns (project-scoped bases, ADR-0048 authoring workspaces) still + disable, re-enable and delete exactly as before — pinned in both directions, on + the registry listing rather than on the status code, since the listing is where + the original defect's harm actually showed. + +- 91eddca: refactor(runtime): `PermissionDeniedError` has ONE declaration again (#7270) + + `security/resolve-execution-context.ts` re-declared `PermissionDeniedError` and + `isPermissionDeniedError` character-for-character from + `@objectstack/plugin-security`'s `errors.ts`, with a doc comment asking the next + editor to keep them "structurally identical" and **nothing enforcing it**: + + ```ts + // runtime/src/security/resolve-execution-context.ts ← the copy + export class PermissionDeniedError extends Error { + readonly code = 'PERMISSION_DENIED'; + readonly statusCode = 403; + … + ``` + + Two hand-maintained declarations of an ADR-0112 denial envelope, where both + fields are load-bearing. `statusCode` is what the dispatcher answers with, and + `code` is what a matcher keys on — edit one copy's `403` and every test in the + repo still passes while one dispatch path starts answering a denial with the + wrong status. A comment is not a constraint. + + `@objectstack/plugin-security` is the package that _throws_ these (23 call sites + across `security-plugin.ts`, `delegated-admin-gate.ts`, `predicate-guard.ts`, + `system-write-guard.ts`, `suggested-audience-bindings.ts`); the runtime only ever + _catches_ them. So the plugin owns the declaration and the runtime module now + re-exports it. `@objectstack/plugin-security` was already a plain `dependencies` + entry of `@objectstack/runtime`, so this adds no dependency — and `tsup` + externalizes workspace dependencies, so the built bundle gained an + `import "@objectstack/plugin-security"` and lost the duplicated class (ESM + 428.21 KB → 428.02 KB). + + The symbols stay exported from `security/resolve-execution-context.ts` rather + than being deleted outright, because `http-dispatcher.ts` imports + `isPermissionDeniedError` from that module path. Nothing outside the package is + affected either way: `runtime/src/security/index.ts` never re-exported either + symbol, so neither was reachable from `@objectstack/runtime`'s public barrel. + + The matcher itself is unchanged and stays **duck-typed** (`name` / `code` / + message-prefix, never `instanceof`), which is what makes the re-export safe: dual + CJS/ESM output and bundling can still hand the two sides distinct class objects, + and a denial crossing that boundary is recognized regardless. A new + `security/permission-denied-error-parity.test.ts` pins both halves — that the two + import paths reach the same declaration (the assertion that fails against the old + copy), and that an instance built from a _deliberately foreign_ class of the same + shape is still matched, so the duck-typed property is held independently of + whether the two ever collapse to one class object. + + No behaviour change: `name`, `code: 'PERMISSION_DENIED'` and `statusCode: 403` + are byte-identical to what the runtime copy produced. + +- cc3555e: Mount five ledgered-but-dead routes, and gate the class that hid them (#7526) + + Three routes shipped in the ledgers, implemented in the dispatcher, and mounted + by nobody. Two of them answered a plausible `200` rather than a 404, which is + worse: `GET /meta/types` fell into the `/meta/:type` catch-all and returned + `{"type":"types","items":[]}`, shape-identical to `/meta/zzz_not_a_type`, and + `GET /meta/:type/:name/published` fell into the compound-name route and + returned a stub identical before publish **and for a name that does not exist** + — a route that structurally could not 404. `GET /meta/objects/:name/state/:field` + was the honest one: REST's `/meta` registrations topped out at three path + segments and it needs four, so it answered Hono's `notFound`. All three now + mount, `published` 404s for a bogus name, and the compound-name arity the SDK + documents (`getPublished('lead', 'views/all_leads')`) mounts with it. + + The routes were the symptom. The route ledgers are a DECLARATION and every + guard built on them (#3563 / #3587 / #3636 / #3642) reads that union as an + OBSERVATION of what is mounted, so the whole audit chain was green on this + class by construction — `/meta/objects/:name/state/:field` counted as mounted + because it was ledgered. This adds the missing observation: a route-ledger ↔ + live-mount parity gate that boots a real server, reads the mount table off it, + and asserts both directions — every ledgered route reachably mounted, every + mounted route ledgered. It never consults a second hand-written list of what is + mounted, and it PROBES reachability through the live router rather than + checking presence in a table, because a literal route registered after a + catch-all sibling is mounted and unreachable. + + `IHttpServer` grows two optional, feature-detected members for it — + `getMountedRoutes()` (the live mount table, in registration order) and + `resolveMountedRoute(method, path)` (which registration answers a concrete + request, per the router itself) — implemented by the Hono adapter. + + The gate found three more instances of the same class on its first run: + `GET /automation/actions`, `/automation/connectors` and `/automation/_status` + were ordered ahead of the `/:name` catch-all inside `dispatch()`, with a + comment saying the order was load-bearing, while the bridge that actually + mounts `/automation` registered `/:name` and never those three. They now mount. + It also found the unledgered live mounts: the four `/api/settings` routes get a + ledger of their own, and `GET /.well-known/objectstack` and the object-less + `POST /actions//:action` get rows in the dispatcher ledger. + +- Updated dependencies [5823d59] +- Updated dependencies [76d74ec] +- Updated dependencies [59768f7] +- Updated dependencies [86f7a20] +- Updated dependencies [9c82146] +- Updated dependencies [744b8f5] +- Updated dependencies [db31402] +- Updated dependencies [2c1988c] +- Updated dependencies [211abdb] +- Updated dependencies [8e17759] +- Updated dependencies [2c28df9] +- Updated dependencies [b3de0dd] +- Updated dependencies [f505689] +- Updated dependencies [8201000] +- Updated dependencies [08363a0] +- Updated dependencies [245d1dc] +- Updated dependencies [769511c] +- Updated dependencies [d063a96] +- Updated dependencies [cf7c694] +- Updated dependencies [603cab8] +- Updated dependencies [3987a48] +- Updated dependencies [9051802] +- Updated dependencies [f293d45] +- Updated dependencies [f067930] +- Updated dependencies [7bc02f4] +- Updated dependencies [edbf873] +- Updated dependencies [61ea810] +- Updated dependencies [b61afc1] +- Updated dependencies [3ac243a] +- Updated dependencies [97b6658] +- Updated dependencies [814db6d] +- Updated dependencies [af5918b] +- Updated dependencies [d6f3f2f] +- Updated dependencies [7f1d4d0] +- Updated dependencies [8dd98bf] +- Updated dependencies [b03b0e1] +- Updated dependencies [8a9c079] +- Updated dependencies [cc3555e] +- Updated dependencies [69ac82c] +- Updated dependencies [c6a4eeb] +- Updated dependencies [e124711] +- Updated dependencies [e51acd6] +- Updated dependencies [f1544e2] +- Updated dependencies [1059965] +- Updated dependencies [52d1a7d] +- Updated dependencies [c9b809f] + - @objectstack/spec@17.0.0-rc.7 + - @objectstack/objectql@17.0.0-rc.7 + - @objectstack/rest@17.0.0-rc.7 + - @objectstack/plugin-auth@17.0.0-rc.7 + - @objectstack/plugin-security@17.0.0-rc.7 + - @objectstack/metadata-protocol@17.0.0-rc.7 + - @objectstack/service-datasource@17.0.0-rc.7 + - @objectstack/driver-sql@17.0.0-rc.7 + - @objectstack/driver-memory@17.0.0-rc.7 + - @objectstack/formula@17.0.0-rc.7 + - @objectstack/driver-sqlite-wasm@17.0.0-rc.7 + - @objectstack/metadata@17.0.0-rc.7 + - @objectstack/core@17.0.0-rc.7 + - @objectstack/metadata-core@17.0.0-rc.7 + - @objectstack/observability@17.0.0-rc.7 + - @objectstack/service-cluster@17.0.0-rc.7 + - @objectstack/service-i18n@17.0.0-rc.7 + - @objectstack/types@17.0.0-rc.7 + ## 17.0.0-rc.6 ### Major Changes diff --git a/packages/runtime/package.json b/packages/runtime/package.json index 897d11e0ee..cc8c443d22 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/runtime", - "version": "17.0.0-rc.6", + "version": "17.0.0-rc.7", "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 b4163686dc..024ce215f6 100644 --- a/packages/sdui-parser/CHANGELOG.md +++ b/packages/sdui-parser/CHANGELOG.md @@ -1,5 +1,7 @@ # @objectstack/sdui-parser +## 17.0.0-rc.7 + ## 17.0.0-rc.6 ## 17.0.0-rc.5 diff --git a/packages/sdui-parser/package.json b/packages/sdui-parser/package.json index bd0138c53a..9c4f323339 100644 --- a/packages/sdui-parser/package.json +++ b/packages/sdui-parser/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/sdui-parser", - "version": "17.0.0-rc.6", + "version": "17.0.0-rc.7", "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 da8e3647b1..4e438a4a1e 100644 --- a/packages/services/service-analytics/CHANGELOG.md +++ b/packages/services/service-analytics/CHANGELOG.md @@ -1,5 +1,40 @@ # Changelog — @objectstack/service-analytics +## 17.0.0-rc.7 + +### Patch Changes + +- Updated dependencies [5823d59] +- Updated dependencies [76d74ec] +- Updated dependencies [86f7a20] +- Updated dependencies [9c82146] +- Updated dependencies [744b8f5] +- Updated dependencies [2c1988c] +- Updated dependencies [211abdb] +- Updated dependencies [f505689] +- Updated dependencies [08363a0] +- Updated dependencies [d063a96] +- Updated dependencies [cf7c694] +- Updated dependencies [603cab8] +- Updated dependencies [9051802] +- Updated dependencies [f293d45] +- Updated dependencies [f067930] +- Updated dependencies [61ea810] +- Updated dependencies [b61afc1] +- Updated dependencies [97b6658] +- Updated dependencies [814db6d] +- Updated dependencies [8dd98bf] +- Updated dependencies [8a9c079] +- Updated dependencies [cc3555e] +- Updated dependencies [69ac82c] +- Updated dependencies [c6a4eeb] +- Updated dependencies [e124711] +- Updated dependencies [1059965] +- Updated dependencies [c9b809f] + - @objectstack/spec@17.0.0-rc.7 + - @objectstack/core@17.0.0-rc.7 + - @objectstack/types@17.0.0-rc.7 + ## 17.0.0-rc.6 ### Minor Changes @@ -199,7 +234,7 @@ vocabulary − this`), which is what stops the next aggregate added to the spec is untouched; it is simply no longer reachable through a spec-valid request. On the dataset path nothing changes: `compileDataset` refused both by name already. - + - 2bc1876: fix(service-analytics): refuse a dotted `measures` entry loudly instead of aggregating the base column (#5918) diff --git a/packages/services/service-analytics/package.json b/packages/services/service-analytics/package.json index 0f8a23dff0..9714704d4f 100644 --- a/packages/services/service-analytics/package.json +++ b/packages/services/service-analytics/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/service-analytics", - "version": "17.0.0-rc.6", + "version": "17.0.0-rc.7", "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 b9ff95e25e..897d3e6ff1 100644 --- a/packages/services/service-automation/CHANGELOG.md +++ b/packages/services/service-automation/CHANGELOG.md @@ -1,5 +1,159 @@ # @objectstack/service-automation +## 17.0.0-rc.7 + +### Minor Changes + +- 57292a8: **Automation runs now record what triggered them — and keep it across a restart (#7533).** + + Two gaps in run attribution, both measured by QA run #7516 (`trigger-type-matrix`): + + - **`trigger.recordId` is populated on `record_change` runs.** The field was declared in + `ExecutionLogSchema` and written by nothing, so the platform's most common trigger kind + produced runs that could not be correlated to the record that caused them — neither + "which record provoked this run?" nor "which runs did this record provoke?" was + answerable from the run log. The trigger block is now built at a single chokepoint + (`buildRunTrigger`) instead of being re-spelled at each of the ten places a run is + logged, which is how `recordId` came to be omitted from all ten. + - **The durable `sys_automation_run` row carries the trigger block.** The in-memory run + recorded its runtime kind; the persistence mapping dropped it, so after a process + restart a scheduled run, a webhook intake and a record change were indistinguishable + rows — the durable copy of the history was strictly less informative than the volatile + one. `sys_automation_run` gains `trigger_type`, `trigger_object` and `trigger_record_id` + as **columns** (not a JSON blob: both questions above are queries, not readings of a + single row), indexed on `(trigger_object, trigger_record_id)`. Written on terminal + history rows and on live paused rows alike. + + Rows written before this change carry no trigger columns; they keep rehydrating exactly as + they did, with an empty trigger type. Absent means "not recorded", never "no trigger". + +### Patch Changes + +- 05ac83d: Job runs that finish without doing their work are now audited as `degraded`, not `success` (#5548) + + `DbJobAdapter` decided a run's outcome solely by whether the handler threw, so a + handler that failed internally and deliberately did not throw was recorded as + `sys_job_run.status: 'success'` — the audit surface Studio's jobs view reads + reported the one thing that had definitely not happened. + + The adapters now consume the `JobRunOutcome` channel `JobHandler` gained in + #6617, using the `degraded` status vocabulary added in #7072: + + - a handler resolving `{ outcome: 'degraded', reason? }` lands + `sys_job_run.status: 'degraded'` with the reason in `error`, and mirrors onto + `sys_job.last_status` / `last_error`; + - `degraded` is not a failure: `failure_count` stays flat and nothing retries + (retry keys on a rejected promise only, unchanged); + - `IntervalJobAdapter` / `CronJobAdapter` report the same verdict through + `getExecutions()`, so the in-memory history and the persisted row agree. + + Strictly additive: a handler that resolves `undefined` — every handler written + before #6617 — is still recorded as `success`, byte for byte as before. + + The first adopter is the `wait` node's timer wake-up: a shot that fires into an + unreachable suspended-run store now reports `degraded` / `STORE_UNAVAILABLE` + while still keeping its one-shot armed and its `sys_job` row active (#5529). + +- cf7c694: fix(spec,runtime,service-automation): `GET /automation/:name/runs?status=` filters the runs instead of being dropped (#7359) + + `ListRunsRequestSchema` has always declared a `status` filter on + `GET /api/automation/:name/runs` — `z.enum([...the eight ExecutionStatus +members]).optional()`, described as "Filter by execution status". Nothing read + it. It had no slot on `IAutomationService.listRuns`, whose options were + `{ limit?, cursor? }`, and the runtime handler never built it into the object it + forwarded, so the parameter was dropped at the HTTP boundary and the caller was + answered **200 with every run of the flow**, capped by `limit`. + + That is worse than an error, because the answer looks like the one that was + asked for: a monitoring caller paging `?status=failed` reads the first 20 runs + of any status and concludes those are the failures. Exposure was raw HTTP, + generated clients, and anything authored against the OpenAPI surface — the typed + SDK could not send the parameter at all, which is why nothing had tripped over + it. #7300 fixed this route's two _coerced_ parameters and deliberately preserved + the ignore-the-key behaviour rather than decide between honouring and retiring + the third; this change takes the enforce route (ADR-0049), so the declared + surface is now true. + + **The filter is honoured across both stores.** `AutomationEngine.listRuns` + serves the Runs view by merging an in-memory ring buffer with the durable run + history it reads back from the store. The narrowing is applied to the merged + result, so both halves are covered: filtering only the buffer would answer "no + failures" for a flow whose failures are all in durable history — i.e. after any + restart, which is exactly when someone asks — and filtering only the durable + rows would hide the live ones. Applying it after the merge also means each run + is matched on its **resolved** status: the buffer holds more than one entry per + run id (a run that pauses appends `paused`, then its terminal entry), and + narrowing before the collapse would have let a stale `paused` entry outlive the + terminal one, so every approval/screen/wait run that had since completed would + report itself as still paused. + + The durable arm's window is unchanged: `listHistory(flowName, limit)` has no + status slot, so the filter is applied to the rows that come back rather than + pushed down, and a status filter can therefore return fewer than `limit` matches + while older ones exist. That is this merge's pre-existing shape — durable rows + were already capped at `limit` before the sort-and-slice — and closing it is a + store-contract change. What it never does is return a run of another status. + + **An undeclared status is now refused, not silently widened.** Once the filter + is honoured, a value outside the set has no safe reading: `?status=faild` cannot + mean "no filter", and serving the empty list is no better, because "no runs are + `faild`" and "no runs failed" read identically to a caller who cannot see their + own typo. The check goes through the shared `query-param` module this route + already consumes with `/notifications`, as a new `parseEnumParam` gate, and + refuses in the house shape — `400` `VALIDATION_FAILED` (ADR-0112) with a + `details.fields[]` entry carrying ADR-0114's existing `invalid_option` + ("not a member of the field's declared options"); a value that was never a + single string at all — a repeated `?status=a&status=b`, a structured + `?status[$ne]=x` — gets `invalid_type`, the same mapping the module's string + gate already makes. No new error vocabulary. The accepted members are read from + the spec's own `ExecutionStatus` enum, the one `ListRunsRequestSchema` is built + from, so the wire's declared set and the boundary's accepted set cannot drift. + + **The typed client can now send it.** `client.automation.listRuns(flow, { +status })` — both the `automation.listRuns` alias and `automation.runs.list` — + takes the filter as an optional `ExecutionStatus`, additively. It could not send + the parameter at all before, which is the reason nothing had tripped over the + server-side gap; leaving it out would have made the enforced filter reachable + only from raw HTTP, and the Runs view that wants it goes through this client. + + **Nothing that had a defensible answer changes.** An absent `status` still + returns every run, exactly as before. So does the empty spelling `?status=` — + unlike `?read=` on the notifications inbox, which used to serve the wrong _half_ + of the result, `?status=` already served precisely what "no filter" means, and + it is what an "All statuses" `` submits. `limit` and `cursor` are + untouched, including out-of-range values, which remain the service's business. + +- b61afc1: fix(plugin-security,spec): the `403 PERMISSION_DENIED` from the object CRUD gate stops handing a business user internal authorization vocabulary + + An operation the caller's permission sets do not grant is correctly refused with + `403 PERMISSION_DENIED`, and the transport was never the problem. What reached + the end user was: `Error.message` is the body's human-readable string on every + transport (`mapDataError`'s `body.error`, the dispatcher's `error.message`) and + Console renders it verbatim in a toast. So an operator in a fully localized app + read + + ``` + [Security] Access denied: operation 'delete' on object 'app_child_object' + is not permitted for positions [org_member, everyone] + ``` + + English-only; naming a table they have never seen; ending in `positions [...]`, + internal authorization vocabulary that reads as a contradiction to someone who + does hold rights on the record they clicked. It is not confined to obviously + unauthorized actions either — `cascadeDeleteRelations` re-authorises every + cascade CHILD independently, so an ordinary delete of a parent the app + deliberately granted can surface a 403 naming a child object the operator never + addressed. + + The error now carries two messages because it has two audiences: + + - `message` — the user's half, rendered in `ExecutionContext.locale` through the + shared operation-message catalog (`@objectstack/spec/system`, the mechanism + built for `DELETE_RESTRICTED`), overridable per deployment under + `errors.permission_denied`. It names no object, no operation and no position, + in any of the four shipped locales. + - `developerMessage` — the developer's half, the previous sentence byte for + byte. It is LOGGED at the throw site, not shipped to the client. + + That last point is where this deliberately diverges from its sibling. + `DELETE_RESTRICTED` ships its developer half over the wire because the same body + already carries the API names it mentions; the 403 body does not. REST's + `mapDataError` builds `{ error, code, object? }` for a permission denial and + never reads `error.details`, so the positions, the operation and (on a cascade) + the child object's API name reach a client through nothing but the message — + shipping a `developerMessage` there would have ADDED a disclosure rather than + removed one. `developerMessage` is therefore a sibling of `details`, never a + member of it, because `details` is the field the runtime dispatcher serialises. + + Enforcement is untouched: same 403, same `PERMISSION_DENIED`, same decision + logic, and the structured `details` payload (`operation`, `object`, `positions`, + `permissionSets`) is byte-identical to before. + +- c6a4eeb: fix(plugin-security,spec): the row-level and capability `403 PERMISSION_DENIED` refusals stop handing a business user internal authorization vocabulary + + #7414 converted one template of this family — the object CRUD grant denial. The + same defect sat on the other gates of the same middleware that an ordinary, + non-admin principal reaches on ordinary business work. `Error.message` is the + body's human-readable string on every transport (`mapDataError`'s `body.error`, + the dispatcher's `error.message`) and Console renders it verbatim in a toast, so + a salesperson editing someone else's opportunity read + + ``` + [Security] Access denied: not permitted to update this 'crm_opportunity' + record (row-level security) + ``` + + English-only, naming a table they have never seen, and ending in the name of the + mechanism that refused them rather than anything they can act on. + + Three gates now render the user's half through the shared operation-message + catalog (`@objectstack/spec/system`, the mechanism built for `DELETE_RESTRICTED` + and reused by #7414), overridable per deployment under `errors.`: + + - the row-level pre-image write denial renders `record_access_denied`; + - the row-level CHECK post-image denial renders `record_change_not_allowed`; + - the capability AND-gate (ADR-0066 D3) renders the existing `permission_denied`. + + Two new catalog keys, in all four shipped locales, and not three: the rule is one + key per SITUATION, not per gate and not per wire code. A user blocked by + row-level security can often ask the record's owner; a user whose post-image + failed a CHECK can simply change what they typed; a user whose grants do not + cover the action needs an administrator. Those are three different next steps, so + they are three different sentences. A caller missing a CRUD bit and a caller + missing a `requiredPermissions` capability, by contrast, are in ONE situation with + one remedy — the difference between them is a fact about our authorization model, + which is exactly the vocabulary that must not reach a toast — so both render + `permission_denied`. + + Each sentence names nothing: no object, no record id, no capability, no + mechanism. That was re-derived per site rather than inherited. The row-level + denial is the one gate here that COULD have named honestly, because the refused + record is the one the caller just addressed; it still does not, because the only + spellings available at the throw site are the object's API name and an opaque row + id, and reaching a label means the ladder whose last rung is the API name. + + Each refusal keeps its developer half as `developerMessage`, the previous + sentence byte for byte, LOGGED at the throw site rather than shipped — following + #7414, which measured that REST's `mapDataError` builds `{ error, code, object? }` + and never reads `error.details`, so shipping it would ADD a disclosure on the + transport that discloses less. `developerMessage` is a sibling of `details`, + never a member, because `details` is what the runtime dispatcher serialises. + + Enforcement is untouched: same 403, same `PERMISSION_DENIED`, same decision + logic, and every structured `details` payload — including `requiredPermissions`, + `missingPermissions` and `recordId` — is byte-identical to before. + +### Patch Changes + +- 76d74ec: docs(spec,objectql): declare that `after*` hooks fire inside the unit of work (#7477) + + `afterInsert` / `afterUpdate` / `afterDelete` are dispatched **before** the + enclosing transaction commits. What that guarantees has never been written + down, and the two readings differ in exactly the case that matters — so it is + now declared, on the API surface and in the docs, per the maintainer ruling on + #7477. + + **The declared meaning:** an `after*` hook means _"the write has been requested + and will happen unless this unit of work is undone"_ — not _"the write + happened"_. A later refusal inside the same unit rolls the row back after the + hook has already run. + + Three ordinary operations put a write inside such a unit: + + - a by-id `delete()` whose cascade is atomic — each **cascaded child's** + `afterDelete` fires inside the wrap the parent opened (#7413); the parent's + own `afterDelete` runs after that unit closes and is unaffected; + - `batchData` / `deleteManyData` with `atomic: true` — every member's `after*` + fires inside one transaction that aborts on the first failure (#4620); + - any caller that wrapped the write in `engine.transaction()` / + `ctx.api.transaction()`. + + **What it means for a handler.** Effects routed back through the engine + (`ctx.api`, `ctx.ql`) join the same transaction and roll back with everything + else — that is what makes an in-engine audit or projection hook correct. + Effects that leave the engine — webhooks, notifications, external index + updates, file deletion — are the handler's own responsibility to make + rollback-tolerant: idempotent and reconcilable, or handed to a worker that + re-reads the record instead of trusting the event alone. + + **No behaviour change.** Nothing about when a hook fires moved; the alternative + (deferring `after*` to commit) was considered and rejected in the same ruling, + because it would push a handler's own `ctx.api` writes outside the transaction + the write ran in. The statement lands as JSDoc on `HookEvent` and + `HookEventType` in `@objectstack/spec`, on `DISPATCHABLE_HOOK_EVENTS`, + `HookHandler` and `triggerHooks` in `@objectstack/objectql`, and as a new + section on the Hooks documentation page. The existing #7413 pin already + asserted this ordering; its comment now records the ruling instead of leaving + the question open. + +- 9c82146: fix(security): an app-declared permission baseline COMPOSES with the platform `member_default` instead of replacing it (#7555) + + A permission set marked `isDefault: true` used to become the deployment's ONLY + baseline: `SecurityPlugin`'s `fallbackPermissionSet` held a single name, and an + app's declared set went into it, so every member of that app silently lost the + platform floor. Measured on the showcase (#7555): a fresh member is served all + 10 built-in Account nav entries and 7/7 of the objects behind them answer 403, + because `showcase_member_default` names no `sys_*` object and `member_default` + was no longer in force for anyone in that app. + + That is the ADR-0090 D5 fallback cliff in its second spelling — D5 rules the + baseline additive without exception ("The fallback cliff is abolished. … + `everyone` is additive like any other position: baseline ∪ explicit, always") + and narrows `isDefault` to a package-authored _suggestion_, "never a runtime + fallback". + + The human baseline is now the list of names it always was: the declared set + **plus** the platform `member_default`, deduped. Both are pushed into the + per-request resolution, both back the post-resolution fallback and the ADR-0106 + D7 metadata-plane resolution, and both are bound to the `everyone` audience + anchor at boot so `security/explain` and the Setup UI report the default a + request actually applies. The composed list is published as a new + `security.baselinePermissionSets` service, which `/auth/me/permissions` and + `/me/apps` read so the capability and tab surface cannot disagree with the data + plane; `security.fallbackPermissionSet` is unchanged and still means "the single + name this deployment declared". + + Deliberately unchanged: + + - **Agent principals** keep exactly their ADR-0090 D10 restricted ceiling — the + composed human baseline is unreachable from `principalKind: 'agent'`. + - **`fallbackPermissionSet: null`** still disables the baseline entirely; the + composition never re-adds one. + - **`member_default`'s own grant rows**, the D5/D9 high-privilege anchor-binding + gate, and #5491's narrowing of the platform baseline to explicit-allow. + + An app that declares no `isDefault` set resolves `['member_default']` and is + byte-for-byte unaffected. + +- 744b8f5: fix(metadata-protocol,spec): a bulk write that STOPS now reports every record — `NOT_ATTEMPTED` rows instead of a truncated `results` array, and counters that reconcile (#7539) + + `POST /data/:object/batch` with no `options` (so `atomic` defaults `false`, + ADR-0119 D4) and three records — valid, failing, valid — answered: + + ``` + 200 { "total": 3, "succeeded": 1, "failed": 1, + "results": [ { idx 0: ok }, { idx 1: VALIDATION_FAILED } ] } + ``` + + Two results for three records, no entry for idx 2, and `succeeded + failed` (2) + `!= total` (3). The un-attempted record was invisible **twice over**: it + produced no `results[]` entry and was counted in neither bucket, so the only + trace of it was an arithmetic mismatch a client had to notice and interpret. + + `buildBatchDataResponse` read `total` from the REQUEST (`records.length`) while + `results` / `succeeded` / `failed` came from a loop that had stopped early. Its + two siblings under-reported identically — the same defect on `updateManyData` + and `deleteManyData`, whose per-object bulk counters lost the tail whenever a + row failed without `continueOnError`. All three now go through one shared + reconciler rather than a fourth copy of the same arithmetic. + + **What changed is the REPORT, not the semantics.** Every record now gets a row + saying what happened to it: records after the failure carry + `errors[0].code === 'NOT_ATTEMPTED'` — the same registered ADR-0112 code the + atomic arm has emitted since #4793, because "never ran" means the same thing to + a client whether the batch stopped to roll back or stopped because it was told + to. The message names the causal row index and `continueOnError`, since on this + arm the caller's next action is a flag rather than a fixed row. `results` now + always covers all `total` records, and `succeeded` / `failed` partition it, so + `succeeded + failed === total === results.length` on both arms. + + **The stop itself is unchanged, deliberately.** Without `continueOnError` the + first failure still ends the run, records written before it stay written + (nothing is rolled back on this arm), and the tail is still not attempted. + That is the declared contract, not an accident: + `BatchOptionsSchema.continueOnError` reads _"If true (and atomic=false), + continue processing remaining records after errors"_, ADR-0119 D4 scopes the + flag to exactly `atomic=false`, and D4's test plan holds non-atomic batches to + "behave exactly as before". If `atomic: false` alone continued past a failure, + `continueOnError` would be inert. Callers who want every valid row to land + should send `continueOnError: true` — unchanged, and now the only difference + between the two is whether the tail is attempted, not whether it is reported. + + **Upgrade note.** A non-atomic batch that stops now returns more `results` rows + and a larger `failed` count than before, for the same request and the same + writes. `failed` counts every row that is not a success — matching the atomic + rollback response, which has always counted never-reached rows this way. A + client that summed `succeeded + failed` and compared it to `total` to detect + truncation no longer needs to; one that treated `failed` as "rows the server + tried and could not write" should branch on `errors[0].code` instead, where + `NOT_ATTEMPTED` distinguishes "skipped" from "attempted and failed". No schema + field was added or removed. + +- 2c1988c: datasource `pool`: the last two silent drops are now loud — `turso` whole-arm, and mongodb's two timeout keys by name (#7243) + + `datasource.pool` is declared, strict and documented, and #5714 / #5931 already + made it an authoring error on the three arms that cannot honour it + (`sqlite` / `sqlite-wasm` / `memory`). #6214's ledger pass read every remaining + arm and found two faces the rejected set could not cover, both still dropped in + silence. Measured on `origin/main` before this change: + + ```text + turso + pool{min:3,max:9,idleTimeoutMillis:30000} the arm never references `spec.pool` at all + mongodb + pool{max:20,idleTimeoutMillis:30000,connectionTimeoutMillis:3000} + → driver config: url + database + maxPoolSize:20, and nothing else + ``` + + The mongodb line is the harder of the two because it is **half**-effective: `max` + took effect, so the author had real evidence their pool config worked, and the + two timeouts vanished anyway. + + Maintainer ruling 2026-08-11, both halves: + + 1. **`turso` joins `POOL_UNSUPPORTED_DRIVER_IDS` whole-arm**, with no fork by url + mode. `TursoDriverConfig` has no `min` / `max`; a `file:` / `:memory:` url runs + the same better-sqlite3 engine the set already rejects for, and a `libsql://` + url is a remote request transport with no persistent connections, capped by + `config.concurrency`. The arm carries its own explanation rather than + borrowing SQLite's, because an author on the remote transport told about + `:memory:` would be reading about somebody else's datasource. + 2. **mongodb's two unread timeout keys are rejected by name, not wired.** + `MongoClient` does expose `maxIdleTimeMS` / `connectTimeoutMS`, so this one + could have been implemented; with no measured consumer asking for it, wiring + would be behaviour-surface expansion. Rejection keeps declared = enforced and + tells the author at authoring time. It stays a one-line change on the day real + demand appears. + + The second half is a new shape for this module: a rejection scoped to individual + **keys** rather than the whole block, because `min` / `max` on `mongodb` are + honoured and must keep working. It is a data table (`POOL_UNREAD_KEYS_BY_DRIVER`) + rather than a per-arm `if`, so the next arm that half-reads the block is one line + and inherits all three doors — the Setup wizard's create/update, the boot-time + auto-connect pre-pass, and the driver factory's last door. + + Both rejections name the datasource, name the offending key(s), say the rejection + is deliberate, and give the one edit that fixes it. Neither offers an escape-hatch + env var (#5794), and the mongodb message says what SURVIVES the edit — telling a + mongo author to "remove `pool`" would delete two keys that do take effect. + + Nothing that was honoured changes: `postgres` / `mysql` still receive all four + keys, `mongodb` still maps `min` / `max` onto `minPoolSize` / `maxPoolSize`. New + API surface is `POOL_UNREAD_KEYS_BY_DRIVER` / `unreadPoolKeys` / + `unreadPoolKeysMessage`; `unsupportedPoolIssue` and `assertDatasourcePoolSupported` + keep their signatures and now cover both gates, so an injected host factory that + already calls them inherits this with no change. + + `@objectstack/spec` carries the ledger half: `liveness/datasource.json`'s four + `pool.*` rows and their block note recorded both of these as "still dropped in + silence" — the honest record #6214 left, and false the moment this lands. They now + state the new verdicts. No schema, type or runtime behaviour changes in `spec`. + +- f505689: **docs(spec): `fields` stops prescribing a dotted path no driver resolves (#7601)** + + Six in-repo surfaces offered `fields: ['owner.name']` as the supported way to read + one related column. No driver ever implemented it — measured on a real `SqlDriver`, + a dotted projection is byte-identical to no projection at all, because Knex renders + `"account"."name"` against a table that was never joined and the #3821 recovery + ladder retries `select('*')`. Since #7532 those surfaces are additionally + contradicted by a `400 INVALID_FIELD` at the ingress gate + (`assertProjectionFieldsExist`). The migration tooling was the sharpest case: both + protocol-17 upgrade prescriptions routed authors off `query.joins` and off the + retired `{ field, fields, alias }` form directly into the refused spelling. + + This aligns the declaration to the enforcement. The normative `fields` `.describe()` + now names `expand` as the sanctioned mechanism for related data — its nested + `QueryAST` both filters (`where`) and selects (`fields`) the related record's + columns — and carries the sharp edge that was pinned but never documented: **the + projection must retain the foreign-key column.** `fields: ['title']` with + `expand: 'project_id'` resolves nothing, because the relation is carried by that + key; adding `'project_id'` makes it work. Where the value is wanted on the queried + object itself, the honest remedy is to denormalise it onto that object (a stored + field, written when the source changes) — the same remedy the sort axis prescribes + (#6924). Both retirement prescriptions and the two tombstone rejection messages now + say the same thing, and the JSON Schema artifacts and reference docs regenerate from + the source. + + **No schema change.** `FieldNodeSchema` stays `z.string()`: the refusal of dotted + projections is a _semantic_ verdict, made at the ingress gate where the field map is + available to judge against — not a _shape_ check. Narrowing the type would duplicate + that gate and refuse the registry-less internal callers the ingress deliberately + tolerates. Every input that parsed before this change parses byte-identically after + it, and the type/runtime pins that assert so are kept and renamed + (`fieldNodeDottedNotNarrowed`) so they read as the non-narrowing guard they are + rather than as an endorsement of a feature that does not exist. + + Prose, prescriptions and generated artifacts only — no wire, stored-data or + validation behaviour changes. + +- 603cab8: The liveness ledger's "Current state" table stops hand-maintaining its counts: the numbers + move into a generated `packages/spec/liveness/state-counts.md` carrying `merge=os-regen`, + and the eleven rows that had drifted from the gate are reconciled — each with the Notes + prose beside it re-read against the new measurement. + + **Why it was a card and not a `sed`.** The table declares its own counting method (the + gate's `--json` report, fixed in #4488) and says the count columns are never hand-edited. + Nobody re-ran the snippet, and 9 of 30 rows disagreed with the gate by the time #7377 was + filed — two more (`job`, `translation`) joined when PR #7425 re-graded four docs-shaped + rows. Several Notes cells enumerate their own dead sets BY HAND, so regenerating the + numbers alone would have left a row reading `dead 6` next to a sentence naming four, which + is worse than the drift: the prose is the part a reader believes. + + **Every delta is explained, not absorbed.** Six rows moved for one structural reason — + `field`, `action`, `hook`, `page`, `seed`, `webhook` picked up the ADR-0010 protection + envelope as the #4001 strictness campaign closed each schema (#4514/#4530/#4531/#4533/#4974), + and the gate auto-classifies those keys `live`. The rest are verdict-shaped: `flow`'s sixth + dead is `errorHandling.retryDelayMs`, tombstoned by the #4964 rename to `backoffMs`; + `view` gained three container-level keys in #4001 batch 6e (`object` live, `name`/`label` + dead) that its Note never mentioned; `app` gained `_unpublished` (#4829, a `live` key no + author may write) and its first `planned`, `navigation.runAction` (#4848); `action` gained + `description` (#7367); `job` and `translation` reached zero dead under #7425's ruling that + designer previews count as consumers. + + **`job` is the first row in the table with zero dead where the ADR-0033 exemption is still + in force**, and the row now says so out loud: the keys are still docs-shaped, still + deliberately kept, still not `authorWarn`'d — what changed is that the measurement, not the + exemption, now carries the verdict. + + **The split follows #5107.** Hand-maintained counts merge clean and WRONG: two PRs each move + a different row by their own correct delta, the rows do not overlap, and git composes a + table nobody wrote. The Notes prose stays hand-written in `README.md` — regenerating a Note + would manufacture a verdict, which that README calls worse than a missing row. + `check:liveness` gains three legs over the split (`scripts/liveness/readme-table.mts`, + unit-tested for the usual reason: on a green tree none of them can fire): the artifact must + equal what the gate measures right now, its row set and the README's must agree in both + directions, and a count column reappearing in the README fails — that last one is invisible + to the other two, and would let the table publish two sets of numbers with only one + enforced. `gen:liveness-counts` regenerates, spawning the gate rather than re-implementing + its walk, and keeps #7257's skeleton row for a governed type with no Note. + +- 9051802: fix(objectql,spec): the `name` argument is `IMetadataService`'s effective key (#7378) + + `register(type, name, data)` → `get(type, name)` now holds on `MetadataFacade` + for every `data`, which is what the other four measured implementations + (`MetadataManager` with and without a writable loader, `createMemoryMetadata`, + and the contract's own reference double) already did. Maintainer ruling of + 2026-08-11 on #7378, option (a): **the argument is the effective key and + `data.name` never overrides it.** + + **Contract (`@objectstack/spec`).** `IMetadataService.register` and `.get` now + state the rule instead of leaving it to the `@param` names — including for a + `data` that is not an object and so has no `name` to derive, since `data` is + declared `unknown`. `METADATA_ROUNDTRIP_CASES` gains an `array-data-roundtrips` + row: an array passes a `typeof data === 'object'` guard, so a store that keys by + spreading the document corrupts `[a, b]` into `{ 0: a, 1: b }` — the sibling of + the primitive row's silent loss. + + **Behaviour change (`@objectstack/objectql`).** Two `MetadataFacade.register` + paths that derived the storage key from the document now derive it from the + argument: + + - a document whose own `name` (or `id`) disagreed with the `name` argument was + filed under the document's spelling, so `get`/`exists` missed it and + `listNames` reported the other name. It is now stored, read, listed and + unregistered under the argument, with the stored `name` reconciled to it. + - a non-object `data` — a string, number, boolean, array or `null` — was + accepted with no throw and then filed under the literal key `undefined`, + readable back through no member of the class. It is now boxed as + `{ name, content }`, the shape this class's own reads already unwrap, and + round-trips unchanged. + + A host that relied on `MetadataFacade.register` keying by `data.name` or + `data.id` rather than by the argument it passed will see items move to the + argument's key. No in-tree caller does; the class reaches hosts only through the + package's root and `core` exports. + + Not ruled and deliberately unchanged: the plural `objects` type alias (that + alias is `SchemaRegistry`'s own read-side special-case, and its conformance pin + stays a measured divergence with the escalation recorded on #7378), and the + loud-refusal option (c), parked as a v18 strictness candidate. + +- f293d45: refactor(spec): split the migration registry's three append tables into per-entry files (#7297) + + `packages/spec/src/migrations/registry.ts` carried three hand-authored **append** + tables — each protocol step's `semantic` list, `RETIRED_KEYS_BY_MAJOR` and + `RETIRED_DEFS_BY_MAJOR`. Every retirement card appended to the same tail line of the + same two of them, so two cards in one window were a textual conflict by construction. + Measured on #6957 over 2026-08-06..10: `step17`'s semantic list and + `RETIRED_KEYS_BY_MAJOR[17]` conflicted in **6 of 11** contended re-merge laps, for 613 + hand-resolved lines of conflict markers in four days. + + Wall-clock was never the reason to fix it. **Both tables are consumed as sets**, so a + conflict resolution that drops a sibling's entry produces **no error anywhere**: the + tombstone `check:authorable-surface` was waiting for never arrives, and the D3 + prescription leaves the upgrade guide without a trace. + + Per the maintainer ruling on #6957 (2026-08-10, option (a)), the entries now live one + file per entry under `packages/spec/src/migrations/entries/`, concatenated into + `registry.ts`'s `` regions by `gen:migration-registry` and verified by + `check:migration-registry` (wired into `check:generated`). The filename is a pure + function of the entry id, so two cards registering different entries write different + files and merge clean, while two cards editing one entry collide in git — which is + correct and must stay true. Order is derived (sorted by id); there is deliberately no + index file. `scripts/adr-anchors/` (#7301) is the pilot this mirrors. + + **No behaviour change and no acceptance movement.** Every exported value is identical + entry-for-entry — proved before and after by deep-comparing `MIGRATIONS_BY_MAJOR`, + `RETIRED_KEYS_BY_MAJOR` and `RETIRED_DEFS_BY_MAJOR` across the change. What moved is + order: `spec-changes.json` and `docs/protocol-upgrade-guide.md` now list the 59 + semantic migrations sorted by id rather than in append order, a one-time reorder whose + line multiset is byte-identical to before. Twelve prose cross-references that pointed + at a neighbour by POSITION ("the entry above", "the trio at the top of this list") were + rewritten to name the entry, since position is no longer stable. + + ⚠️ Honest limit, carried from #6957: this removes the conflict **resolution**, not the + regeneration **lap**. `spec-changes.json` and the upgrade guide are still committed + projections (option B was rejected — the review diff is worth the laps it costs), so a + retirement card is not faster, only much harder to lose. + +- f067930: fix(driver-mongodb): take a structured `GroupByNode`, and answer `count` / + `count_distinct` the way every other backend does (#6850, part of #6814) + + `driver-mongodb` is now enrolled in the shared `AGGREGATION_CASES` standard + (`@objectstack/spec/data`), and clearing that cell fixed three divergences — all + three of the kind that ANSWER rather than fail, which is why none of them ever + surfaced as an error. + + **1. A structured `groupBy` node had no lowering at all (#6850).** + `GroupByNodeSchema` declares a union: a bare field name, or + `{ field, dateGranularity?, alias? }`. The pipeline builder annotated `groupBy` + as `string[]` and did `groupId[field] = '$' + field`, so a structured node — an + object in that loop — stringified: the `$group._id` key became the literal + `"[object Object]"` and its value the field path `"$[object Object]"`, which + matches nothing. The aggregation did not refuse and did not throw. It returned + rows grouped by a nonexistent path, under a column named `[object Object]`. + `MongoDBDriver.aggregate` passed the value through an `any` cast, which is why + the declared union never met that annotation at `tsc`. + + Both sides now spell the declared type, so the next drift between them is a + compile error. The `$group._id` keys on `alias ?? field` and its value is the + FIELD path — the projected column is renamed, the grouping does not move, which + is the rule #6401 converged the three SQL faces onto and the one + `in-memory-aggregation.ts` has always applied. The bare-string spelling emits + exactly what it emitted before. + + **2. `count_distinct` counted NULL as a distinct value (#6814).** The lowering + collects a `$addToSet` and sizes it; `$addToSet` keeps an explicit `null`, so a + nullable column answered one HIGHER than `COUNT(DISTINCT col)` — 3 where the + standard says 2. The sizing now excludes null, which is what + `COUNT(DISTINCT col)` computes on SQLite, PostgreSQL and MySQL alike and what + `objectql`'s in-memory fallback already computed. + + **3. `count(col)` counted ROWS, not values.** Measured while writing the suite + and named by neither issue: the `count` arm ignored `field` entirely and emitted + `{ $sum: 1 }` for both spellings, so `count(stage)` came back 6 — the answer + `count(*)` already has — where the standard says 4. `count(col)` now counts + non-null values, and a missing field is counted as null, the SQL reading. + + **A `dateGranularity` node is now REFUSED rather than silently ignored**, with + `NOT_IMPLEMENTED` / 501 in the ADR-0112 envelope — the same refusal, first + sentence for first sentence, that `driver-sql` and `driver-turso`'s remote + transport give for a granularity they cannot bucket (#6212). This driver + publishes no `supports.queryDateGranularity`, so the engine buckets every + granularity in memory and never pushes a bucketed node down; the refusal fires + only for a caller that reached the builder directly, which previously got a + `"[object Object]"` grouping instead. A native `$dateTrunc` lowering is + buildable and is not ruled out — it needs the engine's bucket LABELS, a + published capability record and `date-bucket-parity.test.ts`, so it is its own + change. A `groupBy` entry that is neither half of the union is refused with + `INVALID_QUERY` / 400. + + The suite that holds all of this is server-free (`mongodb-aggregation- +translation.test.ts`): this package's real-mongod suites are opt-in since #5517, + so it drives the EMITTED pipeline through a strict in-process evaluator that + refuses every shape it does not model. It holds the lowering to the shared + table; it does not answer "does MongoDB agree?", which is a real-mongod half's + question and is recorded as still open on #6814. + + `driver-memory`'s half of #6814 is untouched — it remains under the #5499 + investment freeze, and its `AGGREGATION_CASES` DEBT row stands. + +- 61ea810: fix(runtime): refuse to disable or delete a read-only package on the `/packages` lifecycle routes (#7560) + + `PATCH /packages//disable` and `DELETE /packages/` answered **200** on a + platform package, and the `DELETE` really removed it from the running process's + registry listing. One authorized API call took platform functionality out of a + live deployment. Reproduced on two platform packages in the QA run behind #7514. + + **Blast radius, measured.** The card reported that the packages come back after a + restart — true for `DELETE` (they are code-loaded, so nothing is permanently + destroyed), but **not** for `disable`: `setPackageDisabled` persists the choice + to `/package-state/.json`, which `SchemaRegistry` replays at boot. + A disabled platform package stayed disabled across restarts. + + **Two axes, not one.** #7033 / PR #7083 gave the whole `/packages` domain caller + authorization (`manage_metadata` on writes, the ADR-0106 D4 set on reads, an + anonymous floor) — _who may call the route_. This is the second, missing check + on the same routes: _what the route may do once the caller is allowed_. An + authorized admin — and `isSystem` — is now refused, because read-only is a + property of the **package**, not of the caller. The caller gate is unchanged; + tightening it would not have fixed this and would have broken legitimate admins. + + **No new vocabulary.** The refusal is ADR-0070's existing one, reused: `422` / + `WRITABLE_PACKAGE_REQUIRED`, the code `saveMetaItem` already throws when asked to + author _into_ a read-only package. The predicate behind it moved out of + `ObjectStackProtocolImplementation`'s private method into + `@objectstack/metadata-protocol`'s exported `isWritablePackage(engine, id)` and + is now **referenced** by both callers — a second hand-kept copy of "which + packages are read-only" is exactly the drift that let `DELETE` remove a platform + package while `saveMetaItem` was refusing to add one field to it. Both read-only + signals are covered: a booted code package (`engine.manifests`) and a + platform-delivered manifest `scope` of `system` / `cloud`. + + Packages an org owns (project-scoped bases, ADR-0048 authoring workspaces) still + disable, re-enable and delete exactly as before — pinned in both directions, on + the registry listing rather than on the status code, since the listing is where + the original defect's harm actually showed. + +- 97b6658: docs(spec): fix the QA `field`/`capture` path convention — no `body.` prefix (#7365) + + `TestAssertionSchema.field`'s `.describe()` text read `'Field path in the +result to check (e.g. "body.data.0.status")'`, and `TestStepSchema.capture`'s + sibling `.describe()` repeated the same `body.*` example. Neither convention + ever matched the runtime: `TestRunner.assert`/`runStep` resolve both paths + against `result` directly — the value `HttpTestAdapter.handleResponse` + returns, which is the parsed response body itself with no `body` wrapper (nor + does the platform's own response envelope, `data`/`meta`, ever nest under a + `body` key). A suite written to the documented convention resolved every path + to `undefined`. + + Filed as #7365 (observation-class finding from #7256's blast radius): with + `equals`-class operators a `body.*` path already failed loudly, so an author + worked the real convention out by trial; with `contains`, `undefined` fell out + of the switch and the assertion silently passed, so a `body.*` `contains` + reported green forever. #7256 (PR #7348) turned that silent pass into a loud + failure, which is correct, but it meant an author following the schema's own + example now hits a error that never says the _documentation_ is wrong. + + Maintainer ruling, 2026-08-11 (issue comment 5248467805): "docs follow the + adapter" — fix the `describe()` text (and the regenerated reference) to the + real convention, root-relative, no `body.` wrapper. `body.*` never worked, so + there is no stored-suite compatibility to preserve. The acceptance face is + unchanged — `field` and `capture` both stay their original Zod types; only the + description text moves. + + Both faces now read, in the file's existing one-sentence-plus-example style: + + - `field`: `'Field path in the result to check, resolved against the parsed +response body root — no "body." prefix (e.g. "data.0.status")'` + - `capture`: `'Map result fields to context variables, paths resolved against +the response body root (e.g. { "newId": "data.id" })'` + + `content/docs/references/qa/testing.mdx` is regenerated to match + (`pnpm --filter @objectstack/spec gen:docs`); `check:docs` reports all 231 + generated files in sync. + +- 814db6d: fix(spec): stop emitting a `meta.json` for a reference category that publishes no page (#7303) + + `gen:docs` wrote `content/docs/references//meta.json` for every category + it iterated, including one whose page list came out empty. The result was a + directory holding a single `{ "title": …, "pages": [] }` and nothing else: no + reference page, no `index.mdx` (§2.5 already skipped that), and no entry in the + root `meta.json`, so the route could not resolve and the link checker never saw + it. Its one measurable effect was on whoever enumerated the tree — human or + agent — who counted one category more than the docs actually publish. + + `contracts/` was the standing case. It holds TypeScript service interfaces + rather than `.zod.ts` schemas, so `gen:schema` creates `json-schema/contracts/` + and leaves it empty; `conversions`/`migrations` have no schema directory at all + and are skipped outright, while `contracts` reached the emit with zero pages. + The `meta.json` emit is now guarded on the page list being non-empty, mirroring + the guard the category `index.mdx` emit already carries, so all three behave + alike. `content/docs/references/` goes from 15 category directories to 14. + + The guard is on the page count, not on that schema-directory asymmetry, so a + future category in either shape lands the same way. + + No published page changes: the emitted file count goes 231 → 230, and the one + file that stops being written is the empty `meta.json`. The Contracts Protocol + prose documentation is unaffected — it lives at `content/docs/kernel/contracts/` + and is not generated from this tree. `contracts` also remains a declared + category in `scripts/lib/category-title.ts`; `resolveCategoryTitles` is total + over the directories in `packages/spec/src/`, so that declaration is mandatory + while the module exists. + +- 8dd98bf: + + feat(objectql)!: retire `delete()`'s by-id `beforeDelete` REPOINT, aligning it with `update()` (#6752) + + A `beforeDelete` handler on a **by-id** `delete()` may no longer move the + delete onto a different row by assigning `ctx.input.id`. The rebind is + **refused** with `HookTargetRebindError` / `ERR_HOOK_TARGET_REBIND` + (`path: 'by-id'`) — exactly what the `update()` twin and both per-row paths + already raised. Nothing is deleted, and `afterDelete` and the roll-up + recompute never run. + + **The rule is now one line, on both verbs: a by-id target is immutable in a + `before*` handler.** + + | | CLEARED id | REBOUND to another id | + | ---------------- | ------------ | -------------------------- | + | `update()` by-id | refused | refused | + | `delete()` by-id | refused | **refused** (was honoured) | + | either, per-row | refused (D4) | refused (D4) | + + **Removed keys and their prescriptions (FROM → TO):** + + | Wrote | Write instead | + | ------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | + | `beforeDelete` handler: `ctx.input.id = otherId` | `await ctx.ql.delete(object, otherId)` for that row explicitly, and let the addressed delete proceed — or `throw` from the handler to stop it | + | `beforeDelete` handler repointing to delete a set | have the **caller** pass `{ multi: true, where: … }` | + + Writing the **same** id back is unaffected and stays legal: the check is + `input.id !== id`, the `update()` check verbatim, so a handler that reads the + id or assigns it to itself is not caught. + + **This removes a capability that WORKED, and the reasoning has to be read that + way.** `delete()` had a re-resolution for a repointed target since #5272: it + re-read the new target's pre-image and rebound `previous`, so `afterDelete` and + the summary recompute saw the row actually deleted. Nothing stale ever leaked, + and the case that retires a rebind on `update()` — the write landing on a row + whose pre-image, `readonlyWhen` locks and validation rules were never evaluated + — did not apply to it. That is why #5574's engine half (PR #6697) deliberately + left the asymmetry standing and filed it as its own question. + + The 2026-08-09 maintainer ruling on #6752 retires it anyway, on three measured + axes: + + - **Compatibility cost, measured: zero.** A repository-wide grep for assignments + into a hook's `input.id`, re-run on this PR's base rather than inherited, + finds six sites and all six are this family's own pins. No consumer anywhere + repoints — not in the framework, plugins, examples or docs. + - **One rule beats two correct rules.** Two verbs answering the same slot + differently is something every hook author must hold in memory, and the + justification for the split lived in an ADR, not at the call site. + - **The surface is a footgun independent of the mechanism.** "A hook silently + redirects which row gets deleted" is a top-grade hazard for authored — and + especially AI-authored — handlers. Correctness of a mechanism does not justify + the surface it exposes. + + Aligning the other way — building `update()` the same re-resolution — stays + excluded by #5574's recorded ruling ("do not silently pick re-resolution + instead"). + + The re-read block in `delete()`'s by-id branch is **deleted, not bypassed**: its + guard was `input.id !== id && input.id`, precisely the case the refusal now + throws on, so it became unreachable the moment the refusal landed. The single + pre-dispatch pre-image read that binds `previous` for `beforeDelete` is a + different read and is untouched. + + Recorded as **ADR-0058 Amendment II.2**; the `hook-target-rebind-errors.ts` + "what this does NOT cover" section is gone, because there is no longer an + exception to remember. The #5272 pin asserting the repoint was honoured is + **flipped to assert the refusal**, not deleted, with a new negative control + pinning that a same-id rewrite stays legal. + + Supersedes the scope note in the pending `bulk-write-before-hooks-per-row` + changeset ("a `beforeDelete` handler that repoints the target is unaffected"), + which described PR #6697's deliberate carve-out and is closed by this change in + the same release. + +- 8a9c079: docs(spec): describe the RLS `using` grammar by what pushes down, not by a count (#6919) + + The TSDoc block above `RowLevelSecurityPolicySchema`'s `using` property still + opened with "The reference RLS compiler implements a deliberately **small, + fixed grammar** … **Exactly four forms compile**", then enumerated four SQL + spellings and declared "there is intentionally **no** support for `AND`/`OR`/ + `NOT`, comparison operators other than `=`". That contradicted the + `.describe()` on the _same property_ — corrected in #6762 / PR #6918 — and it + contradicted the compiler. Measured against `isSupportedRlsExpression` + (`@objectstack/formula`, `src/rls-predicate.ts`): `!=` and the full ordering + comparisons, `in` over a `current_user.*` array **and** over an inline CEL list, + string `startsWith`/`endsWith`/`contains`, `&&`, `||`, parenthesised grouping + and a bare `true` all lower to a filter and genuinely enforce. + + PR #6918 could only park a `⚠️ STALE` marker on the block, because rewriting + ~60 lines of grammar prose deserved its own review. This is that rewrite; the + marker is gone with it. + + The block is now written as the one question the compiler actually asks — + _does this predicate lower to an ObjectQL filter?_ — with the forms that lower + listed as open categories rather than a numbered set, and the forms that fail + closed listed beside them. Replacing "four" with the current number would have + been the same defect, so no count appears. Canonical CEL leads; the SQL + spelling is presented as what it is, a deprecated transitional bridge + (`sqlPredicateToCel`, ADR-0058 D1) covering only `=` → `==` and `IN` → `in`. + The property's five `@example` strings, all SQL dialect, are now CEL. + + Two boundaries the old text got wrong in the _permissive_ direction are stated + explicitly, because both are silent-fail-closed traps: SQL's parenthesised + value list does not survive the bridge (`status IN ('draft', 'pending')` fails + closed where `status in ['draft', 'pending']` lowers), and `!` negates a + parenthesised comparison but cannot negate a bare field. + + Also adds `rls-predicate-grammar-docs.pin.test.ts`, which holds the file's + three grammar faces — the published module docblock line, the property TSDoc, + and the property's `.describe()` — to one story: none may re-assert a + fixed-count or closed-set grammar, all must keep stating the fail-closed + contract, and the two operator-listing faces must name the same operators. + This grammar has now drifted twice in the same direction, and nothing compared + the faces to each other. + + No generated output changes: `gen:docs` never renders property-level TSDoc, so + `check:docs` reports all 231 files still in sync. + +- cc3555e: Mount five ledgered-but-dead routes, and gate the class that hid them (#7526) + + Three routes shipped in the ledgers, implemented in the dispatcher, and mounted + by nobody. Two of them answered a plausible `200` rather than a 404, which is + worse: `GET /meta/types` fell into the `/meta/:type` catch-all and returned + `{"type":"types","items":[]}`, shape-identical to `/meta/zzz_not_a_type`, and + `GET /meta/:type/:name/published` fell into the compound-name route and + returned a stub identical before publish **and for a name that does not exist** + — a route that structurally could not 404. `GET /meta/objects/:name/state/:field` + was the honest one: REST's `/meta` registrations topped out at three path + segments and it needs four, so it answered Hono's `notFound`. All three now + mount, `published` 404s for a bogus name, and the compound-name arity the SDK + documents (`getPublished('lead', 'views/all_leads')`) mounts with it. + + The routes were the symptom. The route ledgers are a DECLARATION and every + guard built on them (#3563 / #3587 / #3636 / #3642) reads that union as an + OBSERVATION of what is mounted, so the whole audit chain was green on this + class by construction — `/meta/objects/:name/state/:field` counted as mounted + because it was ledgered. This adds the missing observation: a route-ledger ↔ + live-mount parity gate that boots a real server, reads the mount table off it, + and asserts both directions — every ledgered route reachably mounted, every + mounted route ledgered. It never consults a second hand-written list of what is + mounted, and it PROBES reachability through the live router rather than + checking presence in a table, because a literal route registered after a + catch-all sibling is mounted and unreachable. + + `IHttpServer` grows two optional, feature-detected members for it — + `getMountedRoutes()` (the live mount table, in registration order) and + `resolveMountedRoute(method, path)` (which registration answers a concrete + request, per the router itself) — implemented by the Hono adapter. + + The gate found three more instances of the same class on its first run: + `GET /automation/actions`, `/automation/connectors` and `/automation/_status` + were ordered ahead of the `/:name` catch-all inside `dispatch()`, with a + comment saying the order was load-bearing, while the bridge that actually + mounts `/automation` registered `/:name` and never those three. They now mount. + It also found the unledgered live mounts: the four `/api/settings` routes get a + ledger of their own, and `GET /.well-known/objectstack` and the object-less + `POST /actions//:action` get rows in the dispatcher ledger. + +- 69ac82c: fix(metadata-protocol,rest,spec): derive `capabilities.search` from what serves `/search`, not from an empty service slot (#7541) + + Every REST host advertised `capabilities.search = { enabled: false }` in + `/discovery` while `GET /api/v1/search?q=…` answered `200` with real hits. This + is Prime Directive #10 inverted: not an advertised endpoint that 404s, but a + live endpoint **no conforming client will ever call**, because the document + whose only job is to say what is available said it was not. + + **Two producers, two unrelated predicates.** The capability bit came from a + registered `search` service slot (`registeredServices.has('search')`), while the + route refused on something else entirely — `registerSearchEndpoints` returns + `501 NOT_IMPLEMENTED` exactly when `typeof protocol.searchAll !== 'function'`. + Nothing in either repository registers that slot (`CORE_SERVICE_PROVIDER` + records this, verified), and the protocol implements `searchAll` + unconditionally, so the two answers were not merely capable of disagreeing — + they disagreed on every host that exists. + + `search` was the last well-known capability still on bare slot presence. Its + neighbours were moved onto serveability with the rule stated in the builder — + _"the predicate is deliberately the SAME one that decides whether the route is + advertised — what we advertise and what we claim cannot disagree"_ — most + recently `chunkedUpload` in #5672. This brings `search` onto that footing: **one + predicate, both ends.** + + - `@objectstack/metadata-protocol` — `capabilities.search` is now + `typeof this.searchAll === 'function'`, the route's own refusal predicate. + - `@objectstack/rest` — the `/discovery` producer ANDs that with + `api.enableSearch`, the flag that decides whether this server mounts the route + at all. Exactly the two-layer conjunction `transactionalBatch` already uses + with `api.enableBatch`: the protocol states what it can serve, the server + states what it mounted, and a deployment that opts out reports `false` rather + than promising a 404. Nothing was added to the route itself. + + **`services.search` is unchanged, and deliberately so.** The slot answers a + different question — `CoreServiceName` declares it "Search Engine + (Elastic/Meili)" and `ISearchService` is an index/query contract — so it still + reports _which engine occupies the slot_, while the capability reports _whether + the surface is served_. On an ordinary host those now differ + (`capabilities.search.enabled: true` beside `services.search.status: +'unavailable'`), and both statements are true. So that the two halves of one + document do not read as contradicting each other, `@objectstack/spec` gives the + slot a `REMEDY_DETAIL` sentence — the same treatment `ui` carries for the same + shape (#4146) — which keeps the unchanged "no implementation ships" fact and + adds which question the entry answers. The `status` itself stays + `unavailable`: no engine is registered, and saying otherwise would be the + original defect pointed the other way. + + **Client impact.** A client that gated its search UI on + `capabilities.search.enabled` was hiding a working feature on every deployment; + it now sees `true` wherever the endpoint really serves, and `false` when the + protocol cannot search (route `501`) or the server did not mount it (`404`). + +- e124711: docs(spec): state that a `permissions` key on a skill is REJECTED, not stripped (#7567) + + `SkillSchema`'s docblock carried a `NOTE` paragraph saying an authored + `permissions` key "is unknown to this schema and silently stripped at parse + time." That was true once, but the behaviour changed: `SkillSchema` is a + `strictObject` whose `guidance.permissions` entry now REFUSES an authored + `permissions` key outright, with a located message telling the author to gate + at the agent level instead (`agent.access` / `agent.permissions`, enforced + since #1884). The docblock's stale present tense was the only thing still + saying "stripped" — a reader could conclude the authoring surface was still + lax exactly where it is now strict. + + Only the `NOTE` paragraph's wording changes: it now says the key is rejected + at parse time and points at the located refusal message + (`guidance.permissions`) below it in the same file. The refusal message + itself is untouched — its own "this was stripped in silence" phrase narrates + the historical reason for the refusal, not current behaviour, and stays + correct as written. Every input parses byte-identically before and after this + change (`git diff` touches only comment lines); `pnpm --filter @objectstack/spec +typecheck` and the full spec test suite (9840 tests) are green, and + `check:docs` reports all 231 generated files still in sync — this paragraph + is an inner/property-level TSDoc comment, not the module-level blurb + `build-docs.ts` renders, so no generated doc changes. + + Adds a patch changeset for `@objectstack/spec`, following the #7444 / #7473 / + #7565 precedent for describe/TSDoc-only spec docs fixes. + +- 1059965: docs(spec): state `submitBehavior`'s default as mode-aware, not a single fixed kind (#7441) + + The TSDoc block above `FormViewSchema.submitBehavior` in `packages/spec/src/ui/view.zod.ts` + still read `` `thank-you` (default) — show a confirmation panel``, which the maintainer's + 2026-08-10 ruling on #7245 makes false for the internal path: `thank-you` stays the default + only on the public `/console/f/:slug` path, while the internal `/console/forms/:name` path + — where `type: 'form'` actions send operators — now defaults to redirecting to the record + that was just created. An explicit `submitBehavior` wins in either mode. + + Rewritten to state both defaults and the reasoning behind each, mirroring the contract + already landed in `content/docs/protocol/objectui/actions.mdx` and `content/docs/ui/forms.mdx` + (PR #7417). The schema itself is unchanged: `submitBehavior` stays `.optional()` with no + `.default()`, and its `.describe()` string (`'Post-submit behavior'`) is untouched — only + the source comment was wrong, and only the source comment changes. + + No generated output changes: `gen:docs` never renders property-level TSDoc, so `check:docs` + reports all 231 files still in sync (same measurement PR #7444 made for the same reason). + +- c9b809f: fix(spec): a failed `view` parse reports the branch the body claims, not the one that complains loudest (#7510) + + `ViewMetadataSchema` is a union of four members, and when a `viewKind`-carrying + ViewItem failed on a nested key, the message the author got was the CONTAINER + branch's. Measured through the real write path (`saveMetaItem`) on + `origin/main` @ `9051802`, a form field whose `publicPicker` carried an unknown + `sort` subkey was correctly refused with: + + ``` + [invalid_metadata] view/lead.contact failed spec validation: : Invalid input; + : Unrecognized key(s) on this view container: `viewKind`, `config`. + • `viewKind` belongs to a single VIEW, not to the container. Wrap it: … + ``` + + The key the author mistyped appears nowhere; what they get instead is a + confident, detailed instruction to restructure a container that was correct all + along — and an author (or an agent) who follows it mangles a working document. + + **Why it happened.** Every consumer of a failed union in this repo ranks + branches by `[issue count, carries an unrecognized_keys]`. On such a body the + container branch reports exactly ONE root `unrecognized_keys` (`viewKind` and + `config` are not container keys), while the ViewItem branch reports exactly ONE + nested `invalid_union` whose real key sits one level below where the tiebreak + looks. One issue each, and the unknown-key bonus handed it to the branch that + understood the body least. Not a `publicPicker` quirk: an unknown form-field + key, a bad field enum and a typo'd column summary all reproduced it. + + **The fix.** The union now focuses a failed parse on the branch the body + CLAIMS, using `selectViewMetadataBranch` — the same rule `diagnoseViewMetadata` + has answered with since #6391, so Studio's 422 and a consumer's diagnosis can no + longer describe one body two ways. Branches that are not the claimed one are + replaced, in place, by the "wrong kind at the root" issue shape that every + ranking already drops, so the claimed branch is what remains to be rendered. + + The card's repro now reads: + + ``` + config.sections.0.fields.0.publicPicker: + Unrecognized key(s) on this public picker configuration: `sort`. + ``` + + **No acceptance change**, by construction: the focusing is a `$ZodCheck` that + runs after the union has reached its verdict and can only rewrite an existing + issue's `errors` — it adds no issue and removes none. Verdicts, parse output and + top-level issue codes are byte-identical across the 42-body corpus in + `view-union-diagnostics.test.ts` plus 11 more measured for this change. The + `errors` array keeps its length and order for positional consumers, the + `invalid_union` envelope is untouched, a body with no discriminant is left to + the ranking exactly as before, and a genuine container failure still reads the + #4001 wrap prescription verbatim. + ## 17.0.0-rc.6 ### Major Changes @@ -391,7 +1685,7 @@ vocabulary − this`), which is what stops the next aggregate added to the spec is untouched; it is simply no longer reachable through a spec-valid request. On the dataset path nothing changes: `compileDataset` refused both by name already. - + - 3f7f14e: refactor(spec,objectql)!: retire `AggregationNode.distinct` — one face honoured it, five ignored it, and the same query answered two plausible numbers (#6815, ADR-0049) @@ -1049,7 +2343,7 @@ security } })` / `StackServerConfigSchema` (#5006) parses exactly as it did in 1 If host-implementer conformance becomes a real requirement it returns through the ENFORCE route: an adapter contract with a checker behind it, vocabulary second. - + - c3f4916: fix(spec)!: `ImportRequest.runAutomations` declares the default the import route actually applies (#6704, ADR-0049) diff --git a/packages/spec/package.json b/packages/spec/package.json index 58b38c4140..4aa9b0e1ee 100644 --- a/packages/spec/package.json +++ b/packages/spec/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/spec", - "version": "17.0.0-rc.6", + "version": "17.0.0-rc.7", "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 6173742c29..227702239a 100644 --- a/packages/triggers/trigger-api/CHANGELOG.md +++ b/packages/triggers/trigger-api/CHANGELOG.md @@ -1,5 +1,39 @@ # @objectstack/trigger-api +## 17.0.0-rc.7 + +### Patch Changes + +- Updated dependencies [5823d59] +- Updated dependencies [76d74ec] +- Updated dependencies [86f7a20] +- Updated dependencies [9c82146] +- Updated dependencies [744b8f5] +- Updated dependencies [2c1988c] +- Updated dependencies [211abdb] +- Updated dependencies [f505689] +- Updated dependencies [08363a0] +- Updated dependencies [d063a96] +- Updated dependencies [cf7c694] +- Updated dependencies [603cab8] +- Updated dependencies [9051802] +- Updated dependencies [f293d45] +- Updated dependencies [f067930] +- Updated dependencies [61ea810] +- Updated dependencies [b61afc1] +- Updated dependencies [97b6658] +- Updated dependencies [814db6d] +- Updated dependencies [8dd98bf] +- Updated dependencies [8a9c079] +- Updated dependencies [cc3555e] +- Updated dependencies [69ac82c] +- Updated dependencies [c6a4eeb] +- Updated dependencies [e124711] +- Updated dependencies [1059965] +- Updated dependencies [c9b809f] + - @objectstack/spec@17.0.0-rc.7 + - @objectstack/core@17.0.0-rc.7 + ## 17.0.0-rc.6 ### Patch Changes diff --git a/packages/triggers/trigger-api/package.json b/packages/triggers/trigger-api/package.json index 768781de2c..f79756f590 100644 --- a/packages/triggers/trigger-api/package.json +++ b/packages/triggers/trigger-api/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/trigger-api", - "version": "17.0.0-rc.6", + "version": "17.0.0-rc.7", "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 f278600226..426164cc00 100644 --- a/packages/triggers/trigger-record-change/CHANGELOG.md +++ b/packages/triggers/trigger-record-change/CHANGELOG.md @@ -1,5 +1,39 @@ # @objectstack/plugin-trigger-record-change +## 17.0.0-rc.7 + +### Patch Changes + +- Updated dependencies [5823d59] +- Updated dependencies [76d74ec] +- Updated dependencies [86f7a20] +- Updated dependencies [9c82146] +- Updated dependencies [744b8f5] +- Updated dependencies [2c1988c] +- Updated dependencies [211abdb] +- Updated dependencies [f505689] +- Updated dependencies [08363a0] +- Updated dependencies [d063a96] +- Updated dependencies [cf7c694] +- Updated dependencies [603cab8] +- Updated dependencies [9051802] +- Updated dependencies [f293d45] +- Updated dependencies [f067930] +- Updated dependencies [61ea810] +- Updated dependencies [b61afc1] +- Updated dependencies [97b6658] +- Updated dependencies [814db6d] +- Updated dependencies [8dd98bf] +- Updated dependencies [8a9c079] +- Updated dependencies [cc3555e] +- Updated dependencies [69ac82c] +- Updated dependencies [c6a4eeb] +- Updated dependencies [e124711] +- Updated dependencies [1059965] +- Updated dependencies [c9b809f] + - @objectstack/spec@17.0.0-rc.7 + - @objectstack/core@17.0.0-rc.7 + ## 17.0.0-rc.6 ### Patch Changes diff --git a/packages/triggers/trigger-record-change/package.json b/packages/triggers/trigger-record-change/package.json index d038124708..c811fcad1c 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": "17.0.0-rc.6", + "version": "17.0.0-rc.7", "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 0d59fadb10..b0d946d2b2 100644 --- a/packages/triggers/trigger-schedule/CHANGELOG.md +++ b/packages/triggers/trigger-schedule/CHANGELOG.md @@ -1,5 +1,39 @@ # @objectstack/plugin-trigger-schedule +## 17.0.0-rc.7 + +### Patch Changes + +- Updated dependencies [5823d59] +- Updated dependencies [76d74ec] +- Updated dependencies [86f7a20] +- Updated dependencies [9c82146] +- Updated dependencies [744b8f5] +- Updated dependencies [2c1988c] +- Updated dependencies [211abdb] +- Updated dependencies [f505689] +- Updated dependencies [08363a0] +- Updated dependencies [d063a96] +- Updated dependencies [cf7c694] +- Updated dependencies [603cab8] +- Updated dependencies [9051802] +- Updated dependencies [f293d45] +- Updated dependencies [f067930] +- Updated dependencies [61ea810] +- Updated dependencies [b61afc1] +- Updated dependencies [97b6658] +- Updated dependencies [814db6d] +- Updated dependencies [8dd98bf] +- Updated dependencies [8a9c079] +- Updated dependencies [cc3555e] +- Updated dependencies [69ac82c] +- Updated dependencies [c6a4eeb] +- Updated dependencies [e124711] +- Updated dependencies [1059965] +- Updated dependencies [c9b809f] + - @objectstack/spec@17.0.0-rc.7 + - @objectstack/core@17.0.0-rc.7 + ## 17.0.0-rc.6 ### Patch Changes diff --git a/packages/triggers/trigger-schedule/package.json b/packages/triggers/trigger-schedule/package.json index 1c18b5c86f..47420658e0 100644 --- a/packages/triggers/trigger-schedule/package.json +++ b/packages/triggers/trigger-schedule/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/trigger-schedule", - "version": "17.0.0-rc.6", + "version": "17.0.0-rc.7", "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 b52624d317..ca9f678268 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -1,5 +1,38 @@ # @objectstack/types +## 17.0.0-rc.7 + +### Patch Changes + +- Updated dependencies [5823d59] +- Updated dependencies [76d74ec] +- Updated dependencies [86f7a20] +- Updated dependencies [9c82146] +- Updated dependencies [744b8f5] +- Updated dependencies [2c1988c] +- Updated dependencies [211abdb] +- Updated dependencies [f505689] +- Updated dependencies [08363a0] +- Updated dependencies [d063a96] +- Updated dependencies [cf7c694] +- Updated dependencies [603cab8] +- Updated dependencies [9051802] +- Updated dependencies [f293d45] +- Updated dependencies [f067930] +- Updated dependencies [61ea810] +- Updated dependencies [b61afc1] +- Updated dependencies [97b6658] +- Updated dependencies [814db6d] +- Updated dependencies [8dd98bf] +- Updated dependencies [8a9c079] +- Updated dependencies [cc3555e] +- Updated dependencies [69ac82c] +- Updated dependencies [c6a4eeb] +- Updated dependencies [e124711] +- Updated dependencies [1059965] +- Updated dependencies [c9b809f] + - @objectstack/spec@17.0.0-rc.7 + ## 17.0.0-rc.6 ### Minor Changes diff --git a/packages/types/package.json b/packages/types/package.json index c99045a807..aa12cad7fb 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/types", - "version": "17.0.0-rc.6", + "version": "17.0.0-rc.7", "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 298d51210c..e930bf4984 100644 --- a/packages/verify/CHANGELOG.md +++ b/packages/verify/CHANGELOG.md @@ -1,5 +1,74 @@ # @objectstack/verify +## 17.0.0-rc.7 + +### Patch Changes + +- Updated dependencies [5823d59] +- Updated dependencies [76d74ec] +- Updated dependencies [59768f7] +- Updated dependencies [86f7a20] +- Updated dependencies [c546c89] +- Updated dependencies [22df871] +- Updated dependencies [51fb081] +- Updated dependencies [9c82146] +- Updated dependencies [744b8f5] +- Updated dependencies [db31402] +- Updated dependencies [2c1988c] +- Updated dependencies [211abdb] +- Updated dependencies [8e17759] +- Updated dependencies [b3de0dd] +- Updated dependencies [35b36f2] +- Updated dependencies [f505689] +- Updated dependencies [08363a0] +- Updated dependencies [245d1dc] +- Updated dependencies [05ac83d] +- Updated dependencies [d063a96] +- Updated dependencies [cf7c694] +- Updated dependencies [603cab8] +- Updated dependencies [3987a48] +- Updated dependencies [9051802] +- Updated dependencies [f293d45] +- Updated dependencies [f067930] +- Updated dependencies [7bc02f4] +- Updated dependencies [edbf873] +- Updated dependencies [61ea810] +- Updated dependencies [91eddca] +- Updated dependencies [b61afc1] +- Updated dependencies [3ac243a] +- Updated dependencies [97b6658] +- Updated dependencies [814db6d] +- Updated dependencies [af5918b] +- Updated dependencies [d6f3f2f] +- Updated dependencies [8dd98bf] +- Updated dependencies [b03b0e1] +- Updated dependencies [8a9c079] +- Updated dependencies [cc3555e] +- Updated dependencies [57292a8] +- Updated dependencies [69ac82c] +- Updated dependencies [c6a4eeb] +- Updated dependencies [23bc6e1] +- Updated dependencies [e124711] +- Updated dependencies [e51acd6] +- Updated dependencies [1059965] +- Updated dependencies [8c20f75] +- Updated dependencies [c9b809f] + - @objectstack/spec@17.0.0-rc.7 + - @objectstack/objectql@17.0.0-rc.7 + - @objectstack/rest@17.0.0-rc.7 + - @objectstack/plugin-auth@17.0.0-rc.7 + - @objectstack/runtime@17.0.0-rc.7 + - @objectstack/plugin-hono-server@17.0.0-rc.7 + - @objectstack/plugin-security@17.0.0-rc.7 + - @objectstack/service-datasource@17.0.0-rc.7 + - @objectstack/service-automation@17.0.0-rc.7 + - @objectstack/service-settings@17.0.0-rc.7 + - @objectstack/platform-objects@17.0.0-rc.7 + - @objectstack/core@17.0.0-rc.7 + - @objectstack/plugin-sharing@17.0.0-rc.7 + - @objectstack/service-analytics@17.0.0-rc.7 + - @objectstack/types@17.0.0-rc.7 + ## 17.0.0-rc.6 ### Major Changes diff --git a/packages/verify/package.json b/packages/verify/package.json index 9b33c6b30f..0722413c53 100644 --- a/packages/verify/package.json +++ b/packages/verify/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/verify", - "version": "17.0.0-rc.6", + "version": "17.0.0-rc.7", "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",