@inf-monkeys-tech/monkeys 1.0.72 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/lib/contracts/aggregate-commit.d.ts +155 -0
  2. package/lib/contracts/aggregate-commit.d.ts.map +1 -0
  3. package/lib/contracts/aggregate-commit.js +112 -0
  4. package/lib/contracts/aggregate-commit.js.map +1 -0
  5. package/lib/contracts/capability.d.ts +3 -0
  6. package/lib/contracts/capability.d.ts.map +1 -1
  7. package/lib/contracts/capability.js +1 -1
  8. package/lib/contracts/capability.js.map +1 -1
  9. package/lib/contracts/common.d.ts +2 -0
  10. package/lib/contracts/common.d.ts.map +1 -1
  11. package/lib/contracts/common.js +34 -1
  12. package/lib/contracts/common.js.map +1 -1
  13. package/lib/contracts/component-assembly.d.ts +118 -0
  14. package/lib/contracts/component-assembly.d.ts.map +1 -0
  15. package/lib/contracts/component-assembly.js +61 -0
  16. package/lib/contracts/component-assembly.js.map +1 -0
  17. package/lib/contracts/declarative-control-http.d.ts +80610 -41684
  18. package/lib/contracts/declarative-control-http.d.ts.map +1 -1
  19. package/lib/contracts/declarative-control-http.js +1596 -165
  20. package/lib/contracts/declarative-control-http.js.map +1 -1
  21. package/lib/contracts/declarative-control.d.ts +12525 -4613
  22. package/lib/contracts/declarative-control.d.ts.map +1 -1
  23. package/lib/contracts/declarative-control.js +3792 -422
  24. package/lib/contracts/declarative-control.js.map +1 -1
  25. package/lib/contracts/index.d.ts +6 -0
  26. package/lib/contracts/index.d.ts.map +1 -1
  27. package/lib/contracts/index.js +6 -0
  28. package/lib/contracts/index.js.map +1 -1
  29. package/lib/contracts/legacy-route.d.ts +15 -0
  30. package/lib/contracts/legacy-route.d.ts.map +1 -0
  31. package/lib/contracts/legacy-route.js +13 -0
  32. package/lib/contracts/legacy-route.js.map +1 -0
  33. package/lib/contracts/menu.d.ts +12 -0
  34. package/lib/contracts/menu.d.ts.map +1 -1
  35. package/lib/contracts/page-binding-dependencies.d.ts +25 -0
  36. package/lib/contracts/page-binding-dependencies.d.ts.map +1 -0
  37. package/lib/contracts/page-binding-dependencies.js +54 -0
  38. package/lib/contracts/page-binding-dependencies.js.map +1 -0
  39. package/lib/contracts/page-expression.d.ts +106 -0
  40. package/lib/contracts/page-expression.d.ts.map +1 -0
  41. package/lib/contracts/page-expression.js +136 -0
  42. package/lib/contracts/page-expression.js.map +1 -0
  43. package/lib/contracts/page-stream.d.ts +101 -0
  44. package/lib/contracts/page-stream.d.ts.map +1 -0
  45. package/lib/contracts/page-stream.js +66 -0
  46. package/lib/contracts/page-stream.js.map +1 -0
  47. package/lib/contracts/page.d.ts +24 -0
  48. package/lib/contracts/page.d.ts.map +1 -1
  49. package/lib/contracts/page.js +2 -0
  50. package/lib/contracts/page.js.map +1 -1
  51. package/lib/contracts/record-editor-draft.d.ts +95 -0
  52. package/lib/contracts/record-editor-draft.d.ts.map +1 -0
  53. package/lib/contracts/record-editor-draft.js +35 -0
  54. package/lib/contracts/record-editor-draft.js.map +1 -0
  55. package/lib/contracts/render.d.ts +607 -1
  56. package/lib/contracts/render.d.ts.map +1 -1
  57. package/lib/contracts/render.js +332 -133
  58. package/lib/contracts/render.js.map +1 -1
  59. package/lib/contracts/semantic.d.ts +48 -1
  60. package/lib/contracts/semantic.d.ts.map +1 -1
  61. package/lib/contracts/semantic.js +22 -19
  62. package/lib/contracts/semantic.js.map +1 -1
  63. package/lib/contracts/tenant.d.ts +115 -9
  64. package/lib/contracts/tenant.d.ts.map +1 -1
  65. package/lib/contracts/tenant.js +14 -1
  66. package/lib/contracts/tenant.js.map +1 -1
  67. package/lib/contracts/theme.d.ts +1 -1
  68. package/lib/esm/contracts/index.mjs +8466 -3114
  69. package/lib/esm/contracts/index.mjs.map +1 -1
  70. package/lib/esm/index.mjs +13809 -5067
  71. package/lib/esm/index.mjs.map +1 -1
  72. package/lib/esm/runtime/index.mjs +13964 -4515
  73. package/lib/esm/runtime/index.mjs.map +1 -1
  74. package/lib/esm/schemas/index.mjs +8779 -2614
  75. package/lib/esm/schemas/index.mjs.map +1 -1
  76. package/lib/json-schema/aggregate-commit-request.schema.json +426 -0
  77. package/lib/json-schema/capability-manifest.schema.json +1 -0
  78. package/lib/json-schema/capability-registry.schema.json +1 -0
  79. package/lib/json-schema/declarative-route-owner-index.schema.json +1092 -0
  80. package/lib/json-schema/declarative-workbench-catalog.schema.json +769 -0
  81. package/lib/json-schema/design-capability-catalog-artifact.schema.json +2787 -0
  82. package/lib/json-schema/domain-command-definition.schema.json +18 -0
  83. package/lib/json-schema/domain-query-definition.schema.json +1406 -0
  84. package/lib/json-schema/index.json +7 -0
  85. package/lib/json-schema/legacy-route-takeover-authorization.schema.json +601 -0
  86. package/lib/json-schema/navigation-release.schema.json +296 -0
  87. package/lib/json-schema/navigation-runtime-bundle.schema.json +48 -8
  88. package/lib/json-schema/navigation.schema.json +47 -8
  89. package/lib/json-schema/overlay-node.schema.json +883 -0
  90. package/lib/json-schema/page-definition.schema.json +34 -0
  91. package/lib/json-schema/page-release.schema.json +1520 -626
  92. package/lib/json-schema/page-runtime-bundle.schema.json +7334 -1153
  93. package/lib/json-schema/page-runtime-descriptor.schema.json +34 -0
  94. package/lib/json-schema/page.schema.json +6329 -6602
  95. package/lib/json-schema/permission-alternative-policy.schema.json +60 -0
  96. package/lib/json-schema/product-declaration.schema.json +53 -0
  97. package/lib/json-schema/render-node.schema.json +883 -0
  98. package/lib/json-schema/render-tree.schema.json +883 -0
  99. package/lib/json-schema/tenant-product-config.schema.json +88 -0
  100. package/lib/json-schema/tenant-runtime-config.schema.json +88 -0
  101. package/lib/json-schema/view-provider-descriptor.schema.json +1 -0
  102. package/lib/json-schema/workbench-release.schema.json +1520 -626
  103. package/lib/json-schema/workbench-runtime-bundle.schema.json +686 -20
  104. package/lib/json-schema/workbench.schema.json +1196 -0
  105. package/lib/runtime/component-assembly.d.ts +4 -0
  106. package/lib/runtime/component-assembly.d.ts.map +1 -0
  107. package/lib/runtime/component-assembly.js +126 -0
  108. package/lib/runtime/component-assembly.js.map +1 -0
  109. package/lib/runtime/declarative-control-compiler.d.ts +106 -20
  110. package/lib/runtime/declarative-control-compiler.d.ts.map +1 -1
  111. package/lib/runtime/declarative-control-compiler.js +1525 -280
  112. package/lib/runtime/declarative-control-compiler.js.map +1 -1
  113. package/lib/runtime/index.d.ts +5 -0
  114. package/lib/runtime/index.d.ts.map +1 -1
  115. package/lib/runtime/index.js +7 -0
  116. package/lib/runtime/index.js.map +1 -1
  117. package/lib/runtime/page-expression.d.ts +9 -0
  118. package/lib/runtime/page-expression.d.ts.map +1 -0
  119. package/lib/runtime/page-expression.js +257 -0
  120. package/lib/runtime/page-expression.js.map +1 -0
  121. package/lib/runtime/page-stream.d.ts +24 -0
  122. package/lib/runtime/page-stream.d.ts.map +1 -0
  123. package/lib/runtime/page-stream.js +65 -0
  124. package/lib/runtime/page-stream.js.map +1 -0
  125. package/lib/runtime/record-editor-draft.d.ts +29 -0
  126. package/lib/runtime/record-editor-draft.d.ts.map +1 -0
  127. package/lib/runtime/record-editor-draft.js +161 -0
  128. package/lib/runtime/record-editor-draft.js.map +1 -0
  129. package/lib/runtime/target-render-model.d.ts +4 -0
  130. package/lib/runtime/target-render-model.d.ts.map +1 -0
  131. package/lib/runtime/target-render-model.js +28 -0
  132. package/lib/runtime/target-render-model.js.map +1 -0
  133. package/lib/runtime/tenant-config.d.ts +2 -0
  134. package/lib/runtime/tenant-config.d.ts.map +1 -1
  135. package/lib/runtime/tenant-config.js +6 -1
  136. package/lib/runtime/tenant-config.js.map +1 -1
  137. package/lib/schemas/index.d.ts +5969 -2731
  138. package/lib/schemas/index.d.ts.map +1 -1
  139. package/lib/schemas/index.js +174 -95
  140. package/lib/schemas/index.js.map +1 -1
  141. package/package.json +1 -1
@@ -1,11 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.WorkbenchRuntimeBundleSchema = exports.ResolvedWorkbenchAppInstanceSchema = exports.PageRuntimeBundleSchema = exports.NavigationReleaseSchema = exports.UnavailableNavigationTargetSchema = exports.ResolvedNavigationTargetSchema = exports.NavigationSchema = exports.NavigationNodeSchema = exports.NavigationSeparatorNodeSchema = exports.NavigationTargetNodeSchema = exports.NavigationGroupNodeSchema = exports.WorkbenchReleaseSchema = exports.WorkbenchSchema = exports.WorkbenchAppInstanceSchema = exports.WorkbenchGroupSchema = exports.PageReleaseSchema = exports.PageSchema = exports.ActionBindingSchema = exports.OntologyBindingSchema = exports.CapabilityInstanceSchema = exports.BindingSourceSchema = exports.WorkbenchIdentitySchema = exports.PublicationPlanSchema = exports.PublicationPlanOperationSchema = exports.ReleaseEvidenceSchema = exports.ReleaseValidationSchema = exports.ReleaseDependencySchema = exports.ReleaseDependencyRoleSchema = exports.ReleaseOperationSchema = exports.CompiledRouteClaimSchema = exports.CompiledRouteMatcherSchema = exports.DeclarativeRouteClaimSchema = exports.RouteClaimSchema = exports.LegacyRouteClaimSchema = exports.RouteSpaceSchema = exports.RouteSpaceParameterSchema = exports.RoutePathTemplateSchema = exports.ManagementAccessSchema = exports.AccessPolicySchema = exports.ProductSurfaceSchema = exports.DeclarativeLifecycleSchema = exports.StableRefAliasMapSchema = exports.StableRefAliasSchema = exports.RevisionRefSchema = exports.StableRefSchema = exports.ReferenceVisibilitySchema = exports.TenantScopeSchema = exports.ScopedIdentityRefSchema = exports.I18nTextSchema = exports.DECLARATIVE_CONTROL_SCHEMA_VERSION = void 0;
4
- exports.DECLARATIVE_CONTROL_ONTOLOGY_DEFINITIONS = exports.DeclarativeControlOntologyDefinitionSchema = exports.NavigationRuntimeBundleSchema = exports.CompiledNavigationNodeSchema = exports.CompiledNavigationSeparatorNodeSchema = exports.CompiledNavigationTargetNodeSchema = exports.CompiledNavigationGroupNodeSchema = exports.CompiledNavigationResolvedTargetSchema = exports.CompiledNavigationDomainCommandTargetSchema = exports.CompiledNavigationRegisteredMenuActionTargetSchema = void 0;
3
+ exports.CursorWindowBindingSchema = exports.DomainQueryDefinitionSchema = exports.DomainQueryDataSourceSchema = exports.RegisteredServiceDomainQueryDataSourceSchema = exports.GovernedCatalogDomainQueryDataSourceSchema = exports.GovernedCatalogResourceKindSchema = exports.InteractionBindingSchema = exports.PageStateDefinitionSchema = exports.LegacyBrowserPreferenceImportSchema = exports.ResolvedPageEntryTransitionSchema = exports.PageEntryTransitionSchema = exports.PageStateActivationSchema = exports.PageStateConditionSchema = exports.BindingSourceSchema = exports.DeclarativeRouteClaimSchema = exports.LegacyRouteTakeoverAuthorizationSchema = exports.LegacySlotRestorationSchema = exports.WorkbenchIdentitySchema = exports.PublicationPlanSchema = exports.PublicationPlanOperationSchema = exports.ReleaseEvidenceSchema = exports.ReleaseValidationSchema = exports.ReleaseDependencySchema = exports.ReleaseDependencyRoleSchema = exports.ReleaseOperationSchema = exports.CompiledRouteClaimSchema = exports.CompiledRouteMatcherSchema = exports.RouteClaimSchema = exports.LegacyRouteClaimSchema = exports.RouteSpaceSchema = exports.RouteSpaceParameterSchema = exports.RoutePathTemplateSchema = exports.ManagementAccessSchema = exports.PermissionAlternativePolicySchema = exports.AccessPolicySchema = exports.DeclarativeRuntimeShellDescriptorSchema = exports.DeclarativeShellSurfaceChromeSchema = exports.DeclarativeShellHeaderChromeSchema = exports.ProductSurfaceSchema = exports.DeclarativeLifecycleSchema = exports.StableRefAliasMapSchema = exports.StableRefAliasSchema = exports.RevisionRefSchema = exports.StableRefSchema = exports.ReferenceVisibilitySchema = exports.TenantScopeSchema = exports.ScopedIdentityRefSchema = exports.I18nTextSchema = exports.DECLARATIVE_CONTROL_SCHEMA_VERSION = exports.analyzePageBindingDependencies = void 0;
4
+ exports.DeclarativeControlOntologyDefinitionSchema = exports.NavigationRuntimeBundleSchema = exports.CompiledNavigationNodeSchema = exports.CompiledNavigationSeparatorNodeSchema = exports.CompiledNavigationTargetNodeSchema = exports.CompiledNavigationGroupNodeSchema = exports.CompiledNavigationResolvedTargetSchema = exports.CompiledNavigationDomainCommandTargetSchema = exports.CompiledNavigationRegisteredMenuActionTargetSchema = exports.WorkbenchRuntimeBundleSchema = exports.WorkbenchRuntimeIdentitySchema = exports.ResolvedWorkbenchAppInstanceSchema = exports.PageRuntimeBundleSchema = exports.DeclarativeWorkbenchCatalogSchema = exports.DeclarativeWorkbenchCatalogEntrySchema = exports.DeclarativeRouteOwnerIndexSchema = exports.DeclarativeRouteOwnerIndexEntrySchema = exports.NavigationReleaseSchema = exports.UnavailableNavigationTargetSchema = exports.ResolvedNavigationTargetSchema = exports.NavigationSchema = exports.NavigationNodeSchema = exports.NavigationSeparatorNodeSchema = exports.NavigationTargetNodeSchema = exports.NavigationGroupNodeSchema = exports.WorkbenchReleaseSchema = exports.WorkbenchSchema = exports.WorkbenchAppInstanceSchema = exports.WorkbenchGroupSchema = exports.PageReleaseSchema = exports.ResolvedPageSchema = exports.PageSchema = exports.PageNodeSchema = exports.PageActionSchema = exports.PageDataSchema = exports.PageInteractionSchema = exports.PageEntrySchema = exports.PageEntryTargetSchema = exports.PageStateSchema = exports.PageRouteStatePresentationSchema = exports.PageMigrationEquivalenceSchema = exports.PageMigrationEquivalenceDimensionSchema = exports.ActionBindingSchema = exports.ActionResultClipboardEffectSchema = exports.ActionResultBindingEffectSchema = exports.ActionResultBindingEffectSourceSchema = exports.OntologyBindingSchema = exports.CapabilityInstanceSchema = exports.QueryBindingSchema = exports.QueryResultStateBindingSchema = void 0;
5
+ exports.DECLARATIVE_CONTROL_ONTOLOGY_DEFINITIONS = void 0;
5
6
  const zod_1 = require("zod");
6
7
  const common_1 = require("./common");
7
8
  const data_1 = require("./data");
9
+ const legacy_route_1 = require("./legacy-route");
10
+ const file_1 = require("./file");
8
11
  const render_1 = require("./render");
12
+ const page_expression_1 = require("./page-expression");
13
+ const page_binding_dependencies_1 = require("./page-binding-dependencies");
14
+ var page_binding_dependencies_2 = require("./page-binding-dependencies");
15
+ Object.defineProperty(exports, "analyzePageBindingDependencies", { enumerable: true, get: function () { return page_binding_dependencies_2.analyzePageBindingDependencies; } });
9
16
  exports.DECLARATIVE_CONTROL_SCHEMA_VERSION = 1;
10
17
  const uniqueArray = (values, identity) => {
11
18
  const seen = new Set();
@@ -17,6 +24,10 @@ const uniqueArray = (values, identity) => {
17
24
  }
18
25
  return undefined;
19
26
  };
27
+ const exactRevisionRef = (left, right) => stableRefIdentity(left) === stableRefIdentity(right) &&
28
+ left.revision === right.revision &&
29
+ left.schemaVersion === right.schemaVersion &&
30
+ left.contentHash === right.contentHash;
20
31
  exports.I18nTextSchema = zod_1.z
21
32
  .object({
22
33
  defaultLocale: common_1.LocaleIdentifierSchema,
@@ -26,9 +37,9 @@ exports.I18nTextSchema = zod_1.z
26
37
  .superRefine((value, context) => {
27
38
  if (!Object.prototype.hasOwnProperty.call(value.values, value.defaultLocale)) {
28
39
  context.addIssue({
29
- code: 'custom',
30
- path: ['values', value.defaultLocale],
31
- message: 'I18nText values must contain the default locale.',
40
+ code: "custom",
41
+ path: ["values", value.defaultLocale],
42
+ message: "I18nText values must contain the default locale.",
32
43
  });
33
44
  }
34
45
  });
@@ -48,17 +59,21 @@ exports.TenantScopeSchema = zod_1.z
48
59
  .strict()
49
60
  .superRefine((value, context) => {
50
61
  const expectedKinds = [
51
- ['tenantRef', value.tenantRef, 'tenant'],
52
- ['dataSpaceRef', value.dataSpaceRef, 'data-space'],
53
- ['teamRef', value.teamRef, 'team'],
62
+ ["tenantRef", value.tenantRef, "tenant"],
63
+ ["dataSpaceRef", value.dataSpaceRef, "data-space"],
64
+ ["teamRef", value.teamRef, "team"],
54
65
  ];
55
66
  expectedKinds.forEach(([field, reference, expectedKind]) => {
56
67
  if (reference && reference.kind !== expectedKind) {
57
- context.addIssue({ code: 'custom', path: [field, 'kind'], message: `${field} must reference ${expectedKind}.` });
68
+ context.addIssue({
69
+ code: "custom",
70
+ path: [field, "kind"],
71
+ message: `${field} must reference ${expectedKind}.`,
72
+ });
58
73
  }
59
74
  });
60
75
  });
61
- exports.ReferenceVisibilitySchema = zod_1.z.enum(['tenant', 'global', 'public']);
76
+ exports.ReferenceVisibilitySchema = zod_1.z.enum(["tenant", "global", "public"]);
62
77
  const StableRefShape = {
63
78
  kind: common_1.ContractIdentifierSchema,
64
79
  id: common_1.ContractIdentifierSchema,
@@ -67,11 +82,19 @@ const StableRefShape = {
67
82
  tenantScope: exports.TenantScopeSchema.optional(),
68
83
  };
69
84
  const validateReferenceScope = (value, context) => {
70
- if (value.visibility === 'tenant' && !value.tenantScope) {
71
- context.addIssue({ code: 'custom', path: ['tenantScope'], message: 'Tenant references require an explicit tenant scope.' });
85
+ if (value.visibility === "tenant" && !value.tenantScope) {
86
+ context.addIssue({
87
+ code: "custom",
88
+ path: ["tenantScope"],
89
+ message: "Tenant references require an explicit tenant scope.",
90
+ });
72
91
  }
73
- if (value.visibility !== 'tenant' && value.tenantScope) {
74
- context.addIssue({ code: 'custom', path: ['tenantScope'], message: 'Global and public references cannot carry a tenant scope.' });
92
+ if (value.visibility !== "tenant" && value.tenantScope) {
93
+ context.addIssue({
94
+ code: "custom",
95
+ path: ["tenantScope"],
96
+ message: "Global and public references cannot carry a tenant scope.",
97
+ });
75
98
  }
76
99
  };
77
100
  exports.StableRefSchema = zod_1.z
@@ -88,12 +111,19 @@ exports.RevisionRefSchema = zod_1.z
88
111
  .strict()
89
112
  .superRefine(validateReferenceScope);
90
113
  const scopedIdentityKey = (reference) => `${reference.kind}:${reference.id}:${reference.ownerRepo}`;
91
- const tenantScopeKey = (scope) => `${scopedIdentityKey(scope.tenantRef)}:${scopedIdentityKey(scope.dataSpaceRef)}:${scope.teamRef ? scopedIdentityKey(scope.teamRef) : ''}`;
92
- const stableRefIdentity = (reference) => `${reference.visibility}:${reference.tenantScope ? tenantScopeKey(reference.tenantScope) : ''}:${reference.kind}:${reference.id}:${reference.ownerRepo}`;
93
- const exactRevisionRef = (left, right) => stableRefIdentity(left) === stableRefIdentity(right)
94
- && left.revision === right.revision
95
- && left.schemaVersion === right.schemaVersion
96
- && left.contentHash === right.contentHash;
114
+ const tenantScopeKey = (scope) => `${scopedIdentityKey(scope.tenantRef)}:${scopedIdentityKey(scope.dataSpaceRef)}:${scope.teamRef ? scopedIdentityKey(scope.teamRef) : ""}`;
115
+ const stableRefIdentity = (reference) => `${reference.visibility}:${reference.tenantScope ? tenantScopeKey(reference.tenantScope) : ""}:${reference.kind}:${reference.id}:${reference.ownerRepo}`;
116
+ const validateTenantCompatibleReference = (reference, tenantScope, path, context) => {
117
+ if (reference.visibility === "tenant" &&
118
+ reference.tenantScope &&
119
+ tenantScopeKey(reference.tenantScope) !== tenantScopeKey(tenantScope)) {
120
+ context.addIssue({
121
+ code: "custom",
122
+ path: [...path, "tenantScope"],
123
+ message: "Reference belongs to another tenant scope.",
124
+ });
125
+ }
126
+ };
97
127
  exports.StableRefAliasSchema = zod_1.z
98
128
  .object({
99
129
  aliasRef: exports.StableRefSchema,
@@ -105,15 +135,23 @@ exports.StableRefAliasSchema = zod_1.z
105
135
  .strict()
106
136
  .superRefine((value, context) => {
107
137
  if (value.aliasRef.kind !== value.canonicalRef.kind) {
108
- context.addIssue({ code: 'custom', path: ['canonicalRef', 'kind'], message: 'Alias and canonical references must have the same kind.' });
138
+ context.addIssue({
139
+ code: "custom",
140
+ path: ["canonicalRef", "kind"],
141
+ message: "Alias and canonical references must have the same kind.",
142
+ });
109
143
  }
110
144
  if (value.validUntil && value.validUntil <= value.validFrom) {
111
- context.addIssue({ code: 'custom', path: ['validUntil'], message: 'Alias validUntil must be later than validFrom.' });
145
+ context.addIssue({
146
+ code: "custom",
147
+ path: ["validUntil"],
148
+ message: "Alias validUntil must be later than validFrom.",
149
+ });
112
150
  }
113
151
  });
114
152
  exports.StableRefAliasMapSchema = zod_1.z
115
153
  .object({
116
- contract: zod_1.z.literal('StableRefAliasMap'),
154
+ contract: zod_1.z.literal("StableRefAliasMap"),
117
155
  schemaVersion: zod_1.z.literal(exports.DECLARATIVE_CONTROL_SCHEMA_VERSION),
118
156
  tenantScope: exports.TenantScopeSchema,
119
157
  aliases: zod_1.z.array(exports.StableRefAliasSchema),
@@ -123,17 +161,78 @@ exports.StableRefAliasMapSchema = zod_1.z
123
161
  .superRefine((value, context) => {
124
162
  const duplicate = uniqueArray(value.aliases, (entry) => stableRefIdentity(entry.aliasRef));
125
163
  if (duplicate)
126
- context.addIssue({ code: 'custom', path: ['aliases'], message: `Duplicate alias reference: ${duplicate}` });
164
+ context.addIssue({
165
+ code: "custom",
166
+ path: ["aliases"],
167
+ message: `Duplicate alias reference: ${duplicate}`,
168
+ });
169
+ });
170
+ exports.DeclarativeLifecycleSchema = zod_1.z.enum([
171
+ "active",
172
+ "deprecated",
173
+ "retired",
174
+ ]);
175
+ exports.ProductSurfaceSchema = zod_1.z.enum(["studio", "kernel"]);
176
+ exports.DeclarativeShellHeaderChromeSchema = zod_1.z.discriminatedUnion("enabled", [
177
+ zod_1.z.object({ enabled: zod_1.z.literal(false) }).strict(),
178
+ zod_1.z
179
+ .object({
180
+ enabled: zod_1.z.literal(true),
181
+ navigationPlacement: zod_1.z.enum([
182
+ "studio.headbar.primary",
183
+ "kernel.primary",
184
+ ]),
185
+ })
186
+ .strict(),
187
+ ]);
188
+ exports.DeclarativeShellSurfaceChromeSchema = zod_1.z
189
+ .object({
190
+ surface: exports.ProductSurfaceSchema,
191
+ header: exports.DeclarativeShellHeaderChromeSchema,
192
+ })
193
+ .strict()
194
+ .superRefine((value, context) => {
195
+ if (!value.header.enabled)
196
+ return;
197
+ const expectedPlacement = value.surface === "studio" ? "studio.headbar.primary" : "kernel.primary";
198
+ if (value.header.navigationPlacement !== expectedPlacement) {
199
+ context.addIssue({
200
+ code: "custom",
201
+ path: ["header", "navigationPlacement"],
202
+ message: `The ${value.surface} shell header must use its governed primary Navigation placement.`,
203
+ });
204
+ }
205
+ });
206
+ exports.DeclarativeRuntimeShellDescriptorSchema = zod_1.z
207
+ .object({
208
+ shellRevisionRef: exports.RevisionRefSchema,
209
+ header: exports.DeclarativeShellHeaderChromeSchema,
210
+ })
211
+ .strict()
212
+ .superRefine((value, context) => {
213
+ if (value.shellRevisionRef.kind !== "shell") {
214
+ context.addIssue({
215
+ code: "custom",
216
+ path: ["shellRevisionRef", "kind"],
217
+ message: "Runtime shell descriptors require an exact Shell revision.",
218
+ });
219
+ }
127
220
  });
128
- exports.DeclarativeLifecycleSchema = zod_1.z.enum(['active', 'deprecated', 'retired']);
129
- exports.ProductSurfaceSchema = zod_1.z.enum(['studio', 'kernel']);
130
221
  const GroupRefSchema = exports.StableRefSchema.superRefine((value, context) => {
131
- if (value.kind !== 'group')
132
- context.addIssue({ code: 'custom', path: ['kind'], message: 'Access group references must use kind group.' });
222
+ if (value.kind !== "group")
223
+ context.addIssue({
224
+ code: "custom",
225
+ path: ["kind"],
226
+ message: "Access group references must use kind group.",
227
+ });
133
228
  });
134
229
  const AccessConditionRefSchema = exports.RevisionRefSchema.superRefine((value, context) => {
135
- if (value.kind !== 'access-condition') {
136
- context.addIssue({ code: 'custom', path: ['kind'], message: 'Access condition references must use kind access-condition.' });
230
+ if (value.kind !== "access-condition") {
231
+ context.addIssue({
232
+ code: "custom",
233
+ path: ["kind"],
234
+ message: "Access condition references must use kind access-condition.",
235
+ });
137
236
  }
138
237
  });
139
238
  exports.AccessPolicySchema = zod_1.z
@@ -148,16 +247,74 @@ exports.AccessPolicySchema = zod_1.z
148
247
  .strict()
149
248
  .superRefine((value, context) => {
150
249
  const checks = [
151
- ['groupAllOf', value.groupAllOf, (candidate) => stableRefIdentity(candidate)],
152
- ['groupAnyOf', value.groupAnyOf, (candidate) => stableRefIdentity(candidate)],
153
- ['permissionAllOf', value.permissionAllOf, String],
154
- ['permissionAnyOf', value.permissionAnyOf, String],
155
- ['conditionAllOf', value.conditionAllOf, (candidate) => `${stableRefIdentity(candidate)}@${candidate.revision}`],
250
+ [
251
+ "groupAllOf",
252
+ value.groupAllOf,
253
+ (candidate) => stableRefIdentity(candidate),
254
+ ],
255
+ [
256
+ "groupAnyOf",
257
+ value.groupAnyOf,
258
+ (candidate) => stableRefIdentity(candidate),
259
+ ],
260
+ ["permissionAllOf", value.permissionAllOf, String],
261
+ ["permissionAnyOf", value.permissionAnyOf, String],
262
+ [
263
+ "conditionAllOf",
264
+ value.conditionAllOf,
265
+ (candidate) => `${stableRefIdentity(candidate)}@${candidate.revision}`,
266
+ ],
156
267
  ];
157
268
  checks.forEach(([field, values, identity]) => {
158
269
  if (uniqueArray(values, identity))
159
- context.addIssue({ code: 'custom', path: [field], message: `${field} entries must be unique.` });
270
+ context.addIssue({
271
+ code: "custom",
272
+ path: [field],
273
+ message: `${field} entries must be unique.`,
274
+ });
275
+ });
276
+ });
277
+ /**
278
+ * A finite set of permission conjunctions. An identity is authorized when it
279
+ * satisfies every permission in at least one alternative. This is deliberately
280
+ * separate from AccessPolicy: it models a versioned rollout compatibility
281
+ * bridge such as `new-permission OR (legacy-a AND legacy-b)` without turning
282
+ * individual legacy permissions into broad aliases.
283
+ */
284
+ exports.PermissionAlternativePolicySchema = zod_1.z
285
+ .object({
286
+ contract: zod_1.z.literal("PermissionAlternativePolicy"),
287
+ schemaVersion: zod_1.z.literal(exports.DECLARATIVE_CONTROL_SCHEMA_VERSION),
288
+ policyId: common_1.ContractIdentifierSchema,
289
+ alternatives: zod_1.z.array(zod_1.z.array(common_1.ContractIdentifierSchema).min(1)).min(1),
290
+ retirementGate: zod_1.z
291
+ .object({
292
+ capability: common_1.ContractIdentifierSchema,
293
+ notBefore: common_1.IsoDateTimeSchema.optional(),
294
+ })
295
+ .strict()
296
+ .optional(),
297
+ })
298
+ .strict()
299
+ .superRefine((value, context) => {
300
+ const canonical = value.alternatives.map((set) => [...new Set(set)].sort());
301
+ canonical.forEach((set, index) => {
302
+ if (set.length !== value.alternatives[index].length) {
303
+ context.addIssue({
304
+ code: "custom",
305
+ path: ["alternatives", index],
306
+ message: "A permission alternative cannot contain duplicate permissions.",
307
+ });
308
+ }
160
309
  });
310
+ const identities = canonical.map((set) => set.join("\0"));
311
+ if (new Set(identities).size !== identities.length) {
312
+ context.addIssue({
313
+ code: "custom",
314
+ path: ["alternatives"],
315
+ message: "Permission alternatives must be unique.",
316
+ });
317
+ }
161
318
  });
162
319
  exports.ManagementAccessSchema = zod_1.z
163
320
  .object({
@@ -172,81 +329,108 @@ exports.ManagementAccessSchema = zod_1.z
172
329
  exports.RoutePathTemplateSchema = zod_1.z
173
330
  .string()
174
331
  .trim()
175
- .regex(/^\/(?!\/)/, 'Expected an application-relative path.')
332
+ .regex(/^\/(?!\/)/, "Expected an application-relative path.")
176
333
  .superRefine((value, context) => {
177
- if (value.includes('?') || value.includes('#') || value.includes('\\')) {
178
- context.addIssue({ code: 'custom', message: 'Route paths cannot contain query strings, fragments, or backslashes.' });
334
+ if (value.includes("?") || value.includes("#") || value.includes("\\")) {
335
+ context.addIssue({
336
+ code: "custom",
337
+ message: "Route paths cannot contain query strings, fragments, or backslashes.",
338
+ });
179
339
  }
180
- if (value.split('/').some((segment) => segment === '.' || segment === '..')) {
181
- context.addIssue({ code: 'custom', message: 'Route paths cannot contain traversal segments.' });
340
+ if (value.split("/").some((segment) => segment === "." || segment === "..")) {
341
+ context.addIssue({
342
+ code: "custom",
343
+ message: "Route paths cannot contain traversal segments.",
344
+ });
182
345
  }
183
- if (/^[a-z][a-z0-9+.-]*:/i.test(value) || value.includes('://')) {
184
- context.addIssue({ code: 'custom', message: 'Route paths cannot contain a scheme or host.' });
346
+ if (/^[a-z][a-z0-9+.-]*:/i.test(value) || value.includes("://")) {
347
+ context.addIssue({
348
+ code: "custom",
349
+ message: "Route paths cannot contain a scheme or host.",
350
+ });
185
351
  }
186
352
  });
187
353
  exports.RouteSpaceParameterSchema = zod_1.z
188
354
  .object({
189
355
  name: common_1.ContractIdentifierSchema,
190
- type: zod_1.z.enum(['identifier', 'integer', 'slug', 'uuid']),
356
+ type: zod_1.z.enum(["identifier", "integer", "slug", "uuid"]),
191
357
  required: zod_1.z.boolean(),
192
358
  })
193
359
  .strict();
194
360
  exports.RouteSpaceSchema = zod_1.z
195
361
  .object({
196
- contract: zod_1.z.literal('RouteSpace'),
362
+ contract: zod_1.z.literal("RouteSpace"),
197
363
  schemaVersion: zod_1.z.literal(exports.DECLARATIVE_CONTROL_SCHEMA_VERSION),
198
364
  routeSpaceId: common_1.ContractIdentifierSchema,
199
365
  supportedSurface: exports.ProductSurfaceSchema,
200
366
  basePath: exports.RoutePathTemplateSchema,
201
367
  caseSensitive: zod_1.z.boolean(),
202
- trailingSlash: zod_1.z.enum(['preserve', 'remove', 'require']),
368
+ trailingSlash: zod_1.z.enum(["preserve", "remove", "require"]),
203
369
  reservedPaths: zod_1.z.array(exports.RoutePathTemplateSchema),
204
370
  parameters: zod_1.z.array(exports.RouteSpaceParameterSchema),
205
371
  })
206
372
  .strict()
207
373
  .superRefine((value, context) => {
208
374
  if (uniqueArray(value.parameters, (parameter) => parameter.name)) {
209
- context.addIssue({ code: 'custom', path: ['parameters'], message: 'RouteSpace parameter names must be unique.' });
375
+ context.addIssue({
376
+ code: "custom",
377
+ path: ["parameters"],
378
+ message: "RouteSpace parameter names must be unique.",
379
+ });
210
380
  }
211
381
  if (uniqueArray(value.reservedPaths, (path) => path)) {
212
- context.addIssue({ code: 'custom', path: ['reservedPaths'], message: 'RouteSpace reserved paths must be unique.' });
382
+ context.addIssue({
383
+ code: "custom",
384
+ path: ["reservedPaths"],
385
+ message: "RouteSpace reserved paths must be unique.",
386
+ });
213
387
  }
214
388
  });
215
389
  const RouteClaimBaseSchema = zod_1.z
216
390
  .object({
217
- kind: zod_1.z.enum(['canonical', 'alias', 'redirect']),
391
+ kind: zod_1.z.enum(["canonical", "alias", "redirect"]),
218
392
  routeSpaceRevisionRef: exports.RevisionRefSchema,
219
393
  pathTemplate: exports.RoutePathTemplateSchema,
220
394
  redirectTargetRef: exports.StableRefSchema.optional(),
221
395
  })
222
396
  .strict()
223
397
  .superRefine((value, context) => {
224
- if (value.routeSpaceRevisionRef.kind !== 'route-space') {
225
- context.addIssue({ code: 'custom', path: ['routeSpaceRevisionRef', 'kind'], message: 'Route claims must reference a route-space revision.' });
398
+ if (value.routeSpaceRevisionRef.kind !== "route-space") {
399
+ context.addIssue({
400
+ code: "custom",
401
+ path: ["routeSpaceRevisionRef", "kind"],
402
+ message: "Route claims must reference a route-space revision.",
403
+ });
226
404
  }
227
- if (value.kind === 'redirect' && !value.redirectTargetRef) {
228
- context.addIssue({ code: 'custom', path: ['redirectTargetRef'], message: 'Redirect claims require a governed target reference.' });
405
+ if (value.kind === "redirect" && !value.redirectTargetRef) {
406
+ context.addIssue({
407
+ code: "custom",
408
+ path: ["redirectTargetRef"],
409
+ message: "Redirect claims require a governed target reference.",
410
+ });
229
411
  }
230
- if (value.kind !== 'redirect' && value.redirectTargetRef) {
231
- context.addIssue({ code: 'custom', path: ['redirectTargetRef'], message: 'Only redirect claims may declare redirectTargetRef.' });
412
+ if (value.kind !== "redirect" && value.redirectTargetRef) {
413
+ context.addIssue({
414
+ code: "custom",
415
+ path: ["redirectTargetRef"],
416
+ message: "Only redirect claims may declare redirectTargetRef.",
417
+ });
232
418
  }
233
419
  });
234
420
  /**
235
421
  * Read compatibility for schemaVersion 1 Page and Workbench records written
236
422
  * before route claims carried their owning product surface. New declarations
237
- * must use RouteClaimSchema; compilers infer this legacy form only from the
238
- * exact pinned RouteSpace.
423
+ * must use RouteClaimSchema; compilers materialize this legacy form only from
424
+ * the exact pinned RouteSpace surface.
239
425
  */
240
426
  exports.LegacyRouteClaimSchema = RouteClaimBaseSchema;
241
427
  exports.RouteClaimSchema = RouteClaimBaseSchema.safeExtend({
242
428
  surface: exports.ProductSurfaceSchema,
243
429
  }).strict();
244
- exports.DeclarativeRouteClaimSchema = exports.RouteClaimSchema;
245
- const LegacyDeclarativeRouteClaimSchema = exports.LegacyRouteClaimSchema;
246
430
  const LegacyCompiledRouteMatcherSchema = zod_1.z
247
431
  .object({
248
432
  caseSensitive: zod_1.z.boolean(),
249
- trailingSlash: zod_1.z.enum(['preserve', 'remove', 'require']),
433
+ trailingSlash: zod_1.z.enum(["preserve", "remove", "require"]),
250
434
  parameters: zod_1.z.array(exports.RouteSpaceParameterSchema),
251
435
  })
252
436
  .strict();
@@ -256,90 +440,98 @@ exports.CompiledRouteMatcherSchema = LegacyCompiledRouteMatcherSchema.safeExtend
256
440
  exports.CompiledRouteClaimSchema = exports.RouteClaimSchema.safeExtend({
257
441
  normalizedPath: exports.RoutePathTemplateSchema,
258
442
  matcher: exports.CompiledRouteMatcherSchema,
259
- }).strict();
443
+ })
444
+ .strict()
445
+ .superRefine((value, context) => {
446
+ if (value.matcher.surface !== value.surface) {
447
+ context.addIssue({
448
+ code: "custom",
449
+ path: ["matcher", "surface"],
450
+ message: "A compiled route matcher must match its claim surface.",
451
+ });
452
+ }
453
+ });
260
454
  const LegacyCompiledRouteClaimSchema = exports.LegacyRouteClaimSchema.safeExtend({
261
455
  normalizedPath: exports.RoutePathTemplateSchema,
262
456
  matcher: LegacyCompiledRouteMatcherSchema,
263
457
  }).strict();
264
- const validateDeclaredRouteSurfaces = (supportedSurfaces, routeClaims, context) => {
265
- if (uniqueArray(supportedSurfaces, (surface) => surface)) {
266
- context.addIssue({ code: 'custom', path: ['supportedSurfaces'], message: 'Supported surfaces must be unique.' });
267
- }
268
- const explicitClaims = routeClaims.filter((claim) => 'surface' in claim);
269
- if (explicitClaims.length > 0 && explicitClaims.length < routeClaims.length) {
270
- context.addIssue({ code: 'custom', path: ['routeClaims'], message: 'Route claims must either all declare surface or all omit it for legacy compatibility.' });
458
+ const validateReleaseRouteSurface = (target, context) => {
459
+ const claimSurface = "surface" in target.routeClaim ? target.routeClaim.surface : undefined;
460
+ const matcherSurface = "surface" in target.routeClaim.matcher
461
+ ? target.routeClaim.matcher.surface
462
+ : undefined;
463
+ if (claimSurface === undefined && matcherSurface === undefined)
271
464
  return;
272
- }
273
- routeClaims.forEach((claim, index) => {
274
- if ('surface' in claim && !supportedSurfaces.includes(claim.surface)) {
275
- context.addIssue({ code: 'custom', path: ['routeClaims', index, 'surface'], message: 'Route claim surface must be declared by supportedSurfaces.' });
276
- }
277
- });
278
- if (explicitClaims.length !== routeClaims.length)
465
+ if (claimSurface === target.surface && matcherSurface === target.surface)
279
466
  return;
280
- supportedSurfaces.forEach((surface) => {
281
- const canonicalCount = explicitClaims.filter((claim) => claim.surface === surface && claim.kind === 'canonical').length;
282
- if (canonicalCount !== 1) {
283
- context.addIssue({ code: 'custom', path: ['routeClaims'], message: `Surface ${surface} requires exactly one canonical route claim.` });
284
- }
467
+ context.addIssue({
468
+ code: "custom",
469
+ path: ["target", "routeClaim"],
470
+ message: "A compiled Release route claim must either be fully legacy or bind both claim and matcher to the target surface.",
285
471
  });
286
472
  };
287
- exports.ReleaseOperationSchema = zod_1.z.enum(['activate', 'deactivate', 'rollback']);
473
+ exports.ReleaseOperationSchema = zod_1.z.enum([
474
+ "activate",
475
+ "deactivate",
476
+ "rollback",
477
+ ]);
288
478
  exports.ReleaseDependencyRoleSchema = zod_1.z.enum([
289
- 'route-space',
290
- 'shell',
291
- 'page',
292
- 'page-release',
293
- 'workbench',
294
- 'workbench-release',
295
- 'navigation',
296
- 'navigation-release',
297
- 'menu-action',
298
- 'application-menu-catalog',
299
- 'capability',
300
- 'provider',
301
- 'ontology-definition',
302
- 'view',
303
- 'projection',
304
- 'action',
305
- 'token',
306
- 'schema',
307
- 'compiler',
308
- 'workflow',
309
- 'agent',
310
- 'built-in-application',
311
- 'design',
312
- 'layout-policy',
313
- 'performance-budget',
314
- 'observation-policy',
479
+ "route-space",
480
+ "shell",
481
+ "page",
482
+ "page-release",
483
+ "workbench",
484
+ "workbench-release",
485
+ "navigation",
486
+ "navigation-release",
487
+ "menu-action",
488
+ "application-menu-catalog",
489
+ "capability",
490
+ "provider",
491
+ "ontology-definition",
492
+ "query-definition",
493
+ "view",
494
+ "projection",
495
+ "action",
496
+ "token",
497
+ "schema",
498
+ "compiler",
499
+ "workflow",
500
+ "agent",
501
+ "built-in-application",
502
+ "design",
503
+ "layout-policy",
504
+ "performance-budget",
505
+ "observation-policy",
315
506
  ]);
316
507
  const DependencyKindByRole = {
317
- 'route-space': 'route-space',
318
- shell: 'shell',
319
- page: 'page',
320
- 'page-release': 'page-release',
321
- workbench: 'workbench',
322
- 'workbench-release': 'workbench-release',
323
- navigation: 'navigation',
324
- 'navigation-release': 'navigation-release',
325
- 'menu-action': 'menu-action',
326
- 'application-menu-catalog': 'application-menu-catalog',
327
- capability: 'capability',
328
- provider: 'view-provider',
329
- 'ontology-definition': 'ontology-definition',
330
- view: 'view',
331
- projection: 'projection',
332
- action: 'domain-command',
333
- token: 'design-token',
334
- schema: 'schema',
335
- compiler: 'compiler',
336
- workflow: 'workflow',
337
- agent: 'agent',
338
- 'built-in-application': 'built-in-application',
339
- design: 'design',
340
- 'layout-policy': 'layout-policy',
341
- 'performance-budget': 'performance-budget',
342
- 'observation-policy': 'observation-policy',
508
+ "route-space": "route-space",
509
+ shell: "shell",
510
+ page: "page",
511
+ "page-release": "page-release",
512
+ workbench: "workbench",
513
+ "workbench-release": "workbench-release",
514
+ navigation: "navigation",
515
+ "navigation-release": "navigation-release",
516
+ "menu-action": "menu-action",
517
+ "application-menu-catalog": "application-menu-catalog",
518
+ capability: "capability",
519
+ provider: "view-provider",
520
+ "ontology-definition": "ontology-definition",
521
+ "query-definition": "domain-query-definition",
522
+ view: "view",
523
+ projection: "projection",
524
+ action: "domain-command",
525
+ token: "design-token",
526
+ schema: "schema",
527
+ compiler: "compiler",
528
+ workflow: "workflow",
529
+ agent: "agent",
530
+ "built-in-application": "built-in-application",
531
+ design: "design",
532
+ "layout-policy": "layout-policy",
533
+ "performance-budget": "performance-budget",
534
+ "observation-policy": "observation-policy",
343
535
  };
344
536
  exports.ReleaseDependencySchema = zod_1.z
345
537
  .object({
@@ -351,15 +543,15 @@ exports.ReleaseDependencySchema = zod_1.z
351
543
  const expectedKind = DependencyKindByRole[value.role];
352
544
  if (value.revisionRef.kind !== expectedKind) {
353
545
  context.addIssue({
354
- code: 'custom',
355
- path: ['revisionRef', 'kind'],
546
+ code: "custom",
547
+ path: ["revisionRef", "kind"],
356
548
  message: `Dependency role ${value.role} requires reference kind ${expectedKind}.`,
357
549
  });
358
550
  }
359
551
  });
360
552
  exports.ReleaseValidationSchema = zod_1.z
361
553
  .object({
362
- result: zod_1.z.enum(['pass', 'fail']),
554
+ result: zod_1.z.enum(["pass", "fail"]),
363
555
  inputHash: common_1.Sha256Schema,
364
556
  diagnosticRefs: zod_1.z.array(exports.RevisionRefSchema),
365
557
  })
@@ -380,41 +572,71 @@ exports.ReleaseEvidenceSchema = zod_1.z
380
572
  .strict()
381
573
  .superRefine((value, context) => {
382
574
  const expectedKinds = [
383
- ['publicationPlanRef', value.publicationPlanRef, 'publication-plan'],
384
- ['approvalPolicyRevisionRef', value.approvalPolicyRevisionRef, 'approval-policy'],
385
- ['approvalDecisionRevisionRef', value.approvalDecisionRevisionRef, 'approval-decision'],
386
- ['actorRef', value.actorRef, 'actor'],
575
+ ["publicationPlanRef", value.publicationPlanRef, "publication-plan"],
576
+ [
577
+ "approvalPolicyRevisionRef",
578
+ value.approvalPolicyRevisionRef,
579
+ "approval-policy",
580
+ ],
581
+ [
582
+ "approvalDecisionRevisionRef",
583
+ value.approvalDecisionRevisionRef,
584
+ "approval-decision",
585
+ ],
586
+ ["actorRef", value.actorRef, "actor"],
387
587
  ];
388
588
  expectedKinds.forEach(([field, reference, expectedKind]) => {
389
589
  if (reference.kind !== expectedKind) {
390
- context.addIssue({ code: 'custom', path: [field, 'kind'], message: `${field} must reference ${expectedKind}.` });
590
+ context.addIssue({
591
+ code: "custom",
592
+ path: [field, "kind"],
593
+ message: `${field} must reference ${expectedKind}.`,
594
+ });
391
595
  }
392
596
  });
393
597
  value.evidenceRefs.forEach((reference, index) => {
394
- if (reference.kind !== 'evidence')
395
- context.addIssue({ code: 'custom', path: ['evidenceRefs', index, 'kind'], message: 'Release evidenceRefs must reference evidence revisions.' });
598
+ if (reference.kind !== "evidence")
599
+ context.addIssue({
600
+ code: "custom",
601
+ path: ["evidenceRefs", index, "kind"],
602
+ message: "Release evidenceRefs must reference evidence revisions.",
603
+ });
396
604
  });
397
605
  });
398
606
  exports.PublicationPlanOperationSchema = zod_1.z
399
607
  .object({
400
- releaseKind: zod_1.z.enum(['page-release', 'workbench-release', 'navigation-release']),
608
+ releaseKind: zod_1.z.enum([
609
+ "page-release",
610
+ "workbench-release",
611
+ "navigation-release",
612
+ ]),
401
613
  releaseSlotId: common_1.ContractIdentifierSchema,
402
614
  releaseRevisionRef: exports.RevisionRefSchema,
403
615
  expectedHeadRevisionRef: exports.RevisionRefSchema.nullable(),
404
616
  })
405
617
  .strict()
406
618
  .superRefine((value, context) => {
407
- if (value.releaseRevisionRef.kind !== value.releaseKind || value.releaseRevisionRef.id !== value.releaseSlotId) {
408
- context.addIssue({ code: 'custom', path: ['releaseRevisionRef'], message: 'Publication Plan operation must pin the exact release slot revision.' });
619
+ if (value.releaseRevisionRef.kind !== value.releaseKind ||
620
+ value.releaseRevisionRef.id !== value.releaseSlotId) {
621
+ context.addIssue({
622
+ code: "custom",
623
+ path: ["releaseRevisionRef"],
624
+ message: "Publication Plan operation must pin the exact release slot revision.",
625
+ });
409
626
  }
410
- if (value.expectedHeadRevisionRef
411
- && (value.expectedHeadRevisionRef.kind !== value.releaseKind || value.expectedHeadRevisionRef.id !== value.releaseSlotId)) {
412
- context.addIssue({ code: 'custom', path: ['expectedHeadRevisionRef'], message: 'Expected head must identify the same release slot.' });
627
+ if (value.expectedHeadRevisionRef &&
628
+ (value.expectedHeadRevisionRef.kind !== value.releaseKind ||
629
+ value.expectedHeadRevisionRef.id !== value.releaseSlotId)) {
630
+ context.addIssue({
631
+ code: "custom",
632
+ path: ["expectedHeadRevisionRef"],
633
+ message: "Expected head must identify the same release slot.",
634
+ });
413
635
  }
414
636
  });
415
637
  exports.PublicationPlanSchema = zod_1.z
416
638
  .object({
417
- contract: zod_1.z.literal('PublicationPlan'),
639
+ contract: zod_1.z.literal("PublicationPlan"),
418
640
  schemaVersion: zod_1.z.literal(exports.DECLARATIVE_CONTROL_SCHEMA_VERSION),
419
641
  planId: common_1.ContractIdentifierSchema,
420
642
  tenantScope: exports.TenantScopeSchema,
@@ -430,31 +652,66 @@ exports.PublicationPlanSchema = zod_1.z
430
652
  })
431
653
  .strict()
432
654
  .superRefine((value, context) => {
433
- if (value.environmentRef.kind !== 'environment')
434
- context.addIssue({ code: 'custom', path: ['environmentRef', 'kind'], message: 'Publication Plan requires an environment reference.' });
655
+ if (value.environmentRef.kind !== "environment")
656
+ context.addIssue({
657
+ code: "custom",
658
+ path: ["environmentRef", "kind"],
659
+ message: "Publication Plan requires an environment reference.",
660
+ });
661
+ validateTenantCompatibleReference(value.environmentRef, value.tenantScope, ["environmentRef"], context);
435
662
  const governedRefs = [
436
- ['approvalPolicyRevisionRef', value.approvalPolicyRevisionRef, 'approval-policy'],
437
- ['approvalDecisionRevisionRef', value.approvalDecisionRevisionRef, 'approval-decision'],
438
- ['actorRef', value.actorRef, 'actor'],
663
+ [
664
+ "approvalPolicyRevisionRef",
665
+ value.approvalPolicyRevisionRef,
666
+ "approval-policy",
667
+ ],
668
+ [
669
+ "approvalDecisionRevisionRef",
670
+ value.approvalDecisionRevisionRef,
671
+ "approval-decision",
672
+ ],
673
+ ["actorRef", value.actorRef, "actor"],
439
674
  ];
440
675
  governedRefs.forEach(([field, reference, expectedKind]) => {
441
676
  if (reference.kind !== expectedKind)
442
- context.addIssue({ code: 'custom', path: [field, 'kind'], message: `${field} must reference ${expectedKind}.` });
677
+ context.addIssue({
678
+ code: "custom",
679
+ path: [field, "kind"],
680
+ message: `${field} must reference ${expectedKind}.`,
681
+ });
682
+ validateTenantCompatibleReference(reference, value.tenantScope, [field], context);
443
683
  });
444
684
  value.operations.forEach((operation, index) => {
445
685
  [operation.releaseRevisionRef, operation.expectedHeadRevisionRef].forEach((reference, referenceIndex) => {
446
- if (reference?.tenantScope && tenantScopeKey(reference.tenantScope) !== tenantScopeKey(value.tenantScope)) {
447
- const field = referenceIndex === 0 ? 'releaseRevisionRef' : 'expectedHeadRevisionRef';
448
- context.addIssue({ code: 'custom', path: ['operations', index, field, 'tenantScope'], message: 'Publication Plan operation belongs to another tenant scope.' });
686
+ if (reference?.tenantScope &&
687
+ tenantScopeKey(reference.tenantScope) !==
688
+ tenantScopeKey(value.tenantScope)) {
689
+ const field = referenceIndex === 0
690
+ ? "releaseRevisionRef"
691
+ : "expectedHeadRevisionRef";
692
+ context.addIssue({
693
+ code: "custom",
694
+ path: ["operations", index, field, "tenantScope"],
695
+ message: "Publication Plan operation belongs to another tenant scope.",
696
+ });
449
697
  }
450
698
  });
451
699
  });
452
700
  value.evidenceRefs.forEach((reference, index) => {
453
- if (reference.kind !== 'evidence')
454
- context.addIssue({ code: 'custom', path: ['evidenceRefs', index, 'kind'], message: 'Publication Plan evidenceRefs must reference evidence revisions.' });
701
+ if (reference.kind !== "evidence")
702
+ context.addIssue({
703
+ code: "custom",
704
+ path: ["evidenceRefs", index, "kind"],
705
+ message: "Publication Plan evidenceRefs must reference evidence revisions.",
706
+ });
707
+ validateTenantCompatibleReference(reference, value.tenantScope, ["evidenceRefs", index], context);
455
708
  });
456
709
  if (uniqueArray(value.operations, (operation) => `${operation.releaseKind}:${operation.releaseSlotId}`)) {
457
- context.addIssue({ code: 'custom', path: ['operations'], message: 'Publication Plan release slots must be unique.' });
710
+ context.addIssue({
711
+ code: "custom",
712
+ path: ["operations"],
713
+ message: "Publication Plan release slots must be unique.",
714
+ });
458
715
  }
459
716
  });
460
717
  const IdentitySchema = zod_1.z
@@ -464,205 +721,2826 @@ const IdentitySchema = zod_1.z
464
721
  tags: zod_1.z.array(common_1.ContractIdentifierSchema).default([]),
465
722
  })
466
723
  .strict();
467
- exports.WorkbenchIdentitySchema = IdentitySchema.extend({ iconRef: exports.StableRefSchema.optional() }).strict();
724
+ exports.WorkbenchIdentitySchema = IdentitySchema.extend({
725
+ iconRef: exports.StableRefSchema.optional(),
726
+ }).strict();
727
+ exports.LegacySlotRestorationSchema = zod_1.z
728
+ .object({
729
+ legacyAdapterRevisionRef: exports.RevisionRefSchema,
730
+ sourceRevisionRef: exports.RevisionRefSchema,
731
+ inspectedSourceContentHash: common_1.Sha256Schema,
732
+ })
733
+ .strict()
734
+ .superRefine((value, context) => {
735
+ if (value.sourceRevisionRef.contentHash !== value.inspectedSourceContentHash) {
736
+ context.addIssue({
737
+ code: "custom",
738
+ path: ["inspectedSourceContentHash"],
739
+ message: "Legacy restoration must pin the exact inspected source revision hash.",
740
+ });
741
+ }
742
+ });
743
+ /**
744
+ * Exact, inspect-produced authority for taking over one predeclared legacy
745
+ * route. It is not a general reserved-route bypass: compiler validation binds
746
+ * it to one canonical claim, one target resource and the exact inspected
747
+ * source/adaptor revisions.
748
+ */
749
+ exports.LegacyRouteTakeoverAuthorizationSchema = zod_1.z
750
+ .object({
751
+ contract: zod_1.z.literal("LegacyRouteTakeoverAuthorization"),
752
+ schemaVersion: zod_1.z.literal(exports.DECLARATIVE_CONTROL_SCHEMA_VERSION),
753
+ routeSpaceRevisionRef: exports.RevisionRefSchema,
754
+ normalizedPath: exports.RoutePathTemplateSchema,
755
+ legacyAdapterRevisionRef: exports.RevisionRefSchema,
756
+ sourceRevisionRef: exports.RevisionRefSchema,
757
+ inspectedSourceContentHash: common_1.Sha256Schema,
758
+ targetResourceRef: exports.StableRefSchema,
759
+ workbenchCatalogDefaults: zod_1.z
760
+ .object({ order: zod_1.z.number().int(), isDefaultCandidate: zod_1.z.boolean() })
761
+ .strict()
762
+ .optional(),
763
+ contentHash: common_1.Sha256Schema,
764
+ })
765
+ .strict()
766
+ .superRefine((value, context) => {
767
+ if (value.routeSpaceRevisionRef.kind !== "route-space") {
768
+ context.addIssue({
769
+ code: "custom",
770
+ path: ["routeSpaceRevisionRef", "kind"],
771
+ message: "A route takeover must pin a RouteSpace revision.",
772
+ });
773
+ }
774
+ if (value.legacyAdapterRevisionRef.kind !== "legacy-route-adapter") {
775
+ context.addIssue({
776
+ code: "custom",
777
+ path: ["legacyAdapterRevisionRef", "kind"],
778
+ message: "A route takeover must pin a legacy-route-adapter revision.",
779
+ });
780
+ }
781
+ if (!["page", "workbench"].includes(value.targetResourceRef.kind)) {
782
+ context.addIssue({
783
+ code: "custom",
784
+ path: ["targetResourceRef", "kind"],
785
+ message: "A route takeover target must be a Page or Workbench.",
786
+ });
787
+ }
788
+ if (value.sourceRevisionRef.contentHash !== value.inspectedSourceContentHash) {
789
+ context.addIssue({
790
+ code: "custom",
791
+ path: ["inspectedSourceContentHash"],
792
+ message: "A route takeover must pin the exact inspected legacy source hash.",
793
+ });
794
+ }
795
+ if (value.targetResourceRef.kind === "workbench" &&
796
+ !value.workbenchCatalogDefaults) {
797
+ context.addIssue({
798
+ code: "custom",
799
+ path: ["workbenchCatalogDefaults"],
800
+ message: "A Workbench takeover must preserve exact legacy catalog order and default semantics.",
801
+ });
802
+ }
803
+ if (value.targetResourceRef.kind === "page" &&
804
+ value.workbenchCatalogDefaults) {
805
+ context.addIssue({
806
+ code: "custom",
807
+ path: ["workbenchCatalogDefaults"],
808
+ message: "Page takeover provenance cannot carry Workbench catalog defaults.",
809
+ });
810
+ }
811
+ });
812
+ /** Authoring-only route evidence. Runtime compilation deliberately strips the takeover proof. */
813
+ exports.DeclarativeRouteClaimSchema = exports.RouteClaimSchema.safeExtend({
814
+ legacyRouteTakeoverAuthorization: exports.LegacyRouteTakeoverAuthorizationSchema.optional(),
815
+ }).strict();
816
+ const LegacyDeclarativeRouteClaimSchema = exports.LegacyRouteClaimSchema.safeExtend({
817
+ legacyRouteTakeoverAuthorization: exports.LegacyRouteTakeoverAuthorizationSchema.optional(),
818
+ }).strict();
819
+ const validateDeclaredRouteSurfaces = (supportedSurfaces, routeClaims, context) => {
820
+ if (uniqueArray(supportedSurfaces, (surface) => surface)) {
821
+ context.addIssue({
822
+ code: "custom",
823
+ path: ["supportedSurfaces"],
824
+ message: "Supported surfaces must be unique.",
825
+ });
826
+ }
827
+ const explicitClaims = routeClaims.filter((claim) => "surface" in claim);
828
+ if (explicitClaims.length > 0 && explicitClaims.length < routeClaims.length) {
829
+ context.addIssue({
830
+ code: "custom",
831
+ path: ["routeClaims"],
832
+ message: "Route claims must either all declare surface or all omit it for legacy compatibility.",
833
+ });
834
+ return;
835
+ }
836
+ routeClaims.forEach((claim, index) => {
837
+ if ("surface" in claim && !supportedSurfaces.includes(claim.surface)) {
838
+ context.addIssue({
839
+ code: "custom",
840
+ path: ["routeClaims", index, "surface"],
841
+ message: "Route claim surface must be declared by supportedSurfaces.",
842
+ });
843
+ }
844
+ });
845
+ if (explicitClaims.length !== routeClaims.length)
846
+ return;
847
+ supportedSurfaces.forEach((surface) => {
848
+ const canonicalCount = explicitClaims.filter((claim) => claim.surface === surface && claim.kind === "canonical").length;
849
+ if (canonicalCount !== 1) {
850
+ context.addIssue({
851
+ code: "custom",
852
+ path: ["routeClaims"],
853
+ message: `Surface ${surface} requires exactly one canonical route claim.`,
854
+ });
855
+ }
856
+ });
857
+ };
468
858
  const ReleaseBaseShape = {
469
859
  schemaVersion: zod_1.z.literal(exports.DECLARATIVE_CONTROL_SCHEMA_VERSION),
470
860
  releaseSlotId: common_1.ContractIdentifierSchema,
471
861
  tenantScope: exports.TenantScopeSchema,
472
862
  operation: exports.ReleaseOperationSchema,
863
+ legacyRestoration: exports.LegacySlotRestorationSchema.optional(),
473
864
  dependencySnapshot: zod_1.z.array(exports.ReleaseDependencySchema),
474
865
  evidence: exports.ReleaseEvidenceSchema,
475
866
  };
867
+ const validateLegacyRestoration = (value, expectedAdapterKind, context) => {
868
+ if (value.operation === "activate" && value.legacyRestoration) {
869
+ context.addIssue({
870
+ code: "custom",
871
+ path: ["legacyRestoration"],
872
+ message: "An active declarative Release cannot also restore a legacy adapter.",
873
+ });
874
+ }
875
+ if (value.legacyRestoration?.legacyAdapterRevisionRef.kind !== undefined &&
876
+ value.legacyRestoration.legacyAdapterRevisionRef.kind !==
877
+ expectedAdapterKind) {
878
+ context.addIssue({
879
+ code: "custom",
880
+ path: ["legacyRestoration", "legacyAdapterRevisionRef", "kind"],
881
+ message: `Legacy restoration requires adapter kind ${expectedAdapterKind}.`,
882
+ });
883
+ }
884
+ };
476
885
  const validateDependencySnapshot = (snapshot, context) => {
477
886
  const duplicate = uniqueArray(snapshot, (dependency) => `${dependency.role}:${stableRefIdentity(dependency.revisionRef)}@${dependency.revisionRef.revision}`);
478
887
  if (duplicate)
479
- context.addIssue({ code: 'custom', path: ['dependencySnapshot'], message: `Duplicate dependency: ${duplicate}` });
888
+ context.addIssue({
889
+ code: "custom",
890
+ path: ["dependencySnapshot"],
891
+ message: `Duplicate dependency: ${duplicate}`,
892
+ });
480
893
  };
481
- const validateReleaseExpectedHead = (value, expectedKind, context) => {
894
+ const validateReleaseGovernanceScope = (value, expectedKind, context) => {
482
895
  const expectedHead = value.evidence.expectedHeadRevisionRef;
483
- if (expectedHead && (expectedHead.kind !== expectedKind || expectedHead.id !== value.releaseSlotId)) {
484
- context.addIssue({ code: 'custom', path: ['evidence', 'expectedHeadRevisionRef'], message: 'Expected head must identify the same release slot.' });
896
+ if (expectedHead &&
897
+ (expectedHead.kind !== expectedKind ||
898
+ expectedHead.id !== value.releaseSlotId)) {
899
+ context.addIssue({
900
+ code: "custom",
901
+ path: ["evidence", "expectedHeadRevisionRef"],
902
+ message: "Expected head must identify the same release slot.",
903
+ });
485
904
  }
486
- if (expectedHead?.tenantScope && tenantScopeKey(expectedHead.tenantScope) !== tenantScopeKey(value.tenantScope)) {
487
- context.addIssue({ code: 'custom', path: ['evidence', 'expectedHeadRevisionRef', 'tenantScope'], message: 'Expected head belongs to another tenant scope.' });
905
+ if (expectedHead?.tenantScope &&
906
+ tenantScopeKey(expectedHead.tenantScope) !==
907
+ tenantScopeKey(value.tenantScope)) {
908
+ context.addIssue({
909
+ code: "custom",
910
+ path: ["evidence", "expectedHeadRevisionRef", "tenantScope"],
911
+ message: "Expected head belongs to another tenant scope.",
912
+ });
488
913
  }
914
+ const governedEvidenceRefs = [
915
+ [["evidence", "publicationPlanRef"], value.evidence.publicationPlanRef],
916
+ [
917
+ ["evidence", "approvalPolicyRevisionRef"],
918
+ value.evidence.approvalPolicyRevisionRef,
919
+ ],
920
+ [
921
+ ["evidence", "approvalDecisionRevisionRef"],
922
+ value.evidence.approvalDecisionRevisionRef,
923
+ ],
924
+ [["evidence", "actorRef"], value.evidence.actorRef],
925
+ ...value.evidence.validation.diagnosticRefs.map((reference, index) => [
926
+ ["evidence", "validation", "diagnosticRefs", index],
927
+ reference,
928
+ ]),
929
+ ...value.evidence.evidenceRefs.map((reference, index) => [["evidence", "evidenceRefs", index], reference]),
930
+ ...(expectedHead
931
+ ? [[["evidence", "expectedHeadRevisionRef"], expectedHead]]
932
+ : []),
933
+ ...(value.legacyRestoration
934
+ ? [
935
+ [
936
+ ["legacyRestoration", "legacyAdapterRevisionRef"],
937
+ value.legacyRestoration.legacyAdapterRevisionRef,
938
+ ],
939
+ [
940
+ ["legacyRestoration", "sourceRevisionRef"],
941
+ value.legacyRestoration.sourceRevisionRef,
942
+ ],
943
+ ]
944
+ : []),
945
+ ];
946
+ governedEvidenceRefs.forEach(([path, reference]) => validateTenantCompatibleReference(reference, value.tenantScope, [...path], context));
489
947
  };
490
- exports.BindingSourceSchema = zod_1.z.discriminatedUnion('kind', [
491
- zod_1.z.object({ kind: zod_1.z.literal('constant'), value: zod_1.z.union([zod_1.z.string(), zod_1.z.number().finite(), zod_1.z.boolean(), zod_1.z.null()]) }).strict(),
492
- zod_1.z.object({ kind: zod_1.z.literal('route-parameter'), name: common_1.ContractIdentifierSchema }).strict(),
493
- zod_1.z.object({ kind: zod_1.z.literal('query-parameter'), name: common_1.ContractIdentifierSchema }).strict(),
494
- zod_1.z.object({ kind: zod_1.z.literal('identity'), name: zod_1.z.enum(['tenantId', 'teamId', 'userId']) }).strict(),
495
- zod_1.z.object({ kind: zod_1.z.literal('intent-field'), path: zod_1.z.string().trim().regex(/^[A-Za-z0-9_.-]+$/) }).strict(),
496
- zod_1.z.object({ kind: zod_1.z.literal('binding-field'), bindingId: common_1.ContractIdentifierSchema, path: zod_1.z.string().trim().regex(/^[A-Za-z0-9_.-]+$/) }).strict(),
948
+ exports.BindingSourceSchema = zod_1.z.discriminatedUnion("kind", [
949
+ zod_1.z
950
+ .object({
951
+ kind: zod_1.z.literal("scope-field"),
952
+ path: zod_1.z
953
+ .string()
954
+ .trim()
955
+ .min(1)
956
+ .max(4096)
957
+ .regex(/^[A-Za-z0-9_.-]+$/)
958
+ .refine((path) => path.split(".").length <= 16 &&
959
+ path
960
+ .split(".")
961
+ .every((part) => part.length > 0 &&
962
+ !["__proto__", "prototype", "constructor"].includes(part)), "Scope paths require safe own members."),
963
+ })
964
+ .strict(),
965
+ zod_1.z
966
+ .object({
967
+ kind: zod_1.z.literal("binding-field"),
968
+ bindingId: common_1.ContractIdentifierSchema,
969
+ path: zod_1.z
970
+ .string()
971
+ .trim()
972
+ .regex(/^[A-Za-z0-9_.-]+$/),
973
+ })
974
+ .strict(),
975
+ zod_1.z
976
+ .object({
977
+ kind: zod_1.z.literal("constant"),
978
+ value: zod_1.z.union([zod_1.z.string(), zod_1.z.number().finite(), zod_1.z.boolean(), zod_1.z.null()]),
979
+ })
980
+ .strict(),
981
+ zod_1.z
982
+ .object({
983
+ kind: zod_1.z.literal("route-parameter"),
984
+ name: common_1.ContractIdentifierSchema,
985
+ })
986
+ .strict(),
987
+ zod_1.z
988
+ .object({
989
+ kind: zod_1.z.literal("query-parameter"),
990
+ name: common_1.ContractIdentifierSchema,
991
+ })
992
+ .strict(),
993
+ zod_1.z
994
+ .object({
995
+ kind: zod_1.z.literal("identity"),
996
+ name: zod_1.z.enum(["tenantId", "teamId", "userId"]),
997
+ })
998
+ .strict(),
999
+ zod_1.z
1000
+ .object({
1001
+ kind: zod_1.z.literal("intent-field"),
1002
+ path: zod_1.z
1003
+ .string()
1004
+ .trim()
1005
+ .regex(/^[A-Za-z0-9_.-]+$/),
1006
+ })
1007
+ .strict(),
1008
+ zod_1.z
1009
+ .object({
1010
+ kind: zod_1.z.literal("page-state"),
1011
+ stateId: common_1.ContractIdentifierSchema,
1012
+ })
1013
+ .strict(),
497
1014
  ]);
498
- exports.CapabilityInstanceSchema = zod_1.z
1015
+ const ExpressionBindingSourceSchema = zod_1.z
1016
+ .object({ kind: zod_1.z.literal("expression"), expression: page_expression_1.PageExpressionSchema })
1017
+ .strict()
1018
+ .superRefine((value, context) => {
1019
+ if ((0, page_expression_1.collectPageExpressionReads)(value.expression).some((read) => read.root === "actions"))
1020
+ context.addIssue({
1021
+ code: "custom",
1022
+ path: ["expression"],
1023
+ message: "Action runtime state is presentation-only and cannot influence an input or state transition.",
1024
+ });
1025
+ });
1026
+ const FileFieldBindingSourceSchema = zod_1.z
499
1027
  .object({
500
- instanceId: common_1.ContractIdentifierSchema,
501
- nodeId: common_1.ContractIdentifierSchema,
502
- capabilityRevisionRef: exports.RevisionRefSchema,
503
- providerRevisionRef: exports.RevisionRefSchema,
504
- propertySchemaRevisionRef: exports.RevisionRefSchema,
505
- properties: common_1.JsonObjectSchema,
506
- allowedSideEffects: zod_1.z.array(zod_1.z.enum(['network', 'storage', 'navigation', 'worker', 'websocket'])),
1028
+ kind: zod_1.z.literal("file-field"),
1029
+ fileInputId: common_1.ContractIdentifierSchema,
1030
+ path: zod_1.z.enum(["fileName", "content", "canonicalUri"]),
507
1031
  })
508
1032
  .strict();
509
- exports.OntologyBindingSchema = zod_1.z
1033
+ const ActionFileInputSchema = zod_1.z
510
1034
  .object({
511
- bindingId: common_1.ContractIdentifierSchema,
512
- ontologyDefinitionRevisionRef: exports.RevisionRefSchema,
513
- viewRevisionRef: exports.RevisionRefSchema.optional(),
514
- projectionRevisionRef: exports.RevisionRefSchema.optional(),
515
- parameters: zod_1.z.record(common_1.ContractIdentifierSchema, exports.BindingSourceSchema),
516
- target: zod_1.z.object({ capabilityInstanceId: common_1.ContractIdentifierSchema, port: common_1.ContractIdentifierSchema }).strict(),
517
- renderModelSchemaRevisionRef: exports.RevisionRefSchema,
518
- pagination: zod_1.z.enum(['none', 'cursor', 'offset']),
519
- cache: zod_1.z.enum(['none', 'identity-scoped', 'tenant-scoped']),
520
- cancelOnChange: zod_1.z.boolean(),
1035
+ inputId: common_1.ContractIdentifierSchema,
1036
+ source: zod_1.z.discriminatedUnion("kind", [
1037
+ zod_1.z
1038
+ .object({
1039
+ kind: zod_1.z.literal("page-state"),
1040
+ stateId: common_1.ContractIdentifierSchema,
1041
+ })
1042
+ .strict(),
1043
+ zod_1.z
1044
+ .object({
1045
+ kind: zod_1.z.literal("intent-field"),
1046
+ path: zod_1.z
1047
+ .string()
1048
+ .trim()
1049
+ .regex(/^[A-Za-z0-9_.-]+$/),
1050
+ })
1051
+ .strict(),
1052
+ ]),
1053
+ maxBytes: zod_1.z.number().int().min(1).max(5368709120),
1054
+ upload: zod_1.z.object({ purpose: file_1.FilePurposeSchema }).strict().optional(),
1055
+ accept: zod_1.z.string().min(1).max(256).optional(),
521
1056
  })
522
1057
  .strict()
523
1058
  .superRefine((value, context) => {
524
- if ((value.viewRevisionRef ? 1 : 0) + (value.projectionRevisionRef ? 1 : 0) !== 1) {
525
- context.addIssue({ code: 'custom', path: ['viewRevisionRef'], message: 'Ontology bindings require exactly one View or Projection revision.' });
526
- }
527
- if (value.ontologyDefinitionRevisionRef.kind !== 'ontology-definition') {
528
- context.addIssue({ code: 'custom', path: ['ontologyDefinitionRevisionRef', 'kind'], message: 'Expected an ontology-definition revision.' });
529
- }
1059
+ if (!value.upload && value.maxBytes > 1048576)
1060
+ context.addIssue({
1061
+ code: "custom",
1062
+ path: ["maxBytes"],
1063
+ message: "Inline text files are limited to one MiB.",
1064
+ });
530
1065
  });
531
- exports.ActionBindingSchema = zod_1.z
1066
+ const ActionInputBindingSourceSchema = zod_1.z.discriminatedUnion("kind", [
1067
+ ...exports.BindingSourceSchema.options,
1068
+ ExpressionBindingSourceSchema,
1069
+ FileFieldBindingSourceSchema,
1070
+ ]);
1071
+ const InteractionBindingSourceSchema = zod_1.z.discriminatedUnion("kind", [
1072
+ ExpressionBindingSourceSchema,
1073
+ zod_1.z
1074
+ .object({
1075
+ kind: zod_1.z.literal("constant"),
1076
+ value: zod_1.z.union([zod_1.z.string(), zod_1.z.number().finite(), zod_1.z.boolean(), zod_1.z.null()]),
1077
+ })
1078
+ .strict(),
1079
+ zod_1.z
1080
+ .object({
1081
+ kind: zod_1.z.literal("intent-field"),
1082
+ path: zod_1.z
1083
+ .string()
1084
+ .trim()
1085
+ .regex(/^[A-Za-z0-9_.-]+$/),
1086
+ })
1087
+ .strict(),
1088
+ zod_1.z
1089
+ .object({
1090
+ kind: zod_1.z.literal("result-field"),
1091
+ path: zod_1.z
1092
+ .string()
1093
+ .trim()
1094
+ .regex(/^[A-Za-z0-9_.-]+$/),
1095
+ })
1096
+ .strict(),
1097
+ zod_1.z
1098
+ .object({
1099
+ kind: zod_1.z.literal("page-state"),
1100
+ stateId: common_1.ContractIdentifierSchema,
1101
+ })
1102
+ .strict(),
1103
+ ]);
1104
+ const PageStateComparableLiteralSchema = zod_1.z.union([
1105
+ zod_1.z.string(),
1106
+ zod_1.z.number().finite(),
1107
+ zod_1.z.boolean(),
1108
+ zod_1.z.null(),
1109
+ ]);
1110
+ exports.PageStateConditionSchema = zod_1.z.discriminatedUnion("predicate", [
1111
+ zod_1.z
1112
+ .object({
1113
+ stateId: common_1.ContractIdentifierSchema,
1114
+ predicate: zod_1.z.literal("equals"),
1115
+ value: PageStateComparableLiteralSchema,
1116
+ })
1117
+ .strict(),
1118
+ zod_1.z
1119
+ .object({
1120
+ stateId: common_1.ContractIdentifierSchema,
1121
+ predicate: zod_1.z.literal("not-equals"),
1122
+ value: PageStateComparableLiteralSchema,
1123
+ })
1124
+ .strict(),
1125
+ zod_1.z
1126
+ .object({
1127
+ stateId: common_1.ContractIdentifierSchema,
1128
+ predicate: zod_1.z.literal("truthy"),
1129
+ })
1130
+ .strict(),
1131
+ ]);
1132
+ /**
1133
+ * A recursive boolean expression over governed Page state. Keeping leaf
1134
+ * conditions inside the original `conditions` array preserves the v1 flat
1135
+ * declaration while allowing groups to be nested without a parallel DSL.
1136
+ */
1137
+ exports.PageStateActivationSchema = zod_1.z.lazy(() => zod_1.z
532
1138
  .object({
533
- bindingId: common_1.ContractIdentifierSchema,
534
- commandRevisionRef: exports.RevisionRefSchema,
535
- source: zod_1.z.object({ capabilityInstanceId: common_1.ContractIdentifierSchema, port: common_1.ContractIdentifierSchema }).strict(),
536
- sourceIntentSchemaRevisionRef: exports.RevisionRefSchema,
537
- inputSchemaRevisionRef: exports.RevisionRefSchema,
538
- inputMapping: zod_1.z.record(common_1.ContractIdentifierSchema, exports.BindingSourceSchema),
539
- accessPolicy: exports.AccessPolicySchema,
540
- confirmation: exports.I18nTextSchema.optional(),
541
- idempotencyKeySource: zod_1.z.enum(['interaction', 'record-and-interaction', 'caller-provided']),
542
- compensationCommandRevisionRef: exports.RevisionRefSchema.optional(),
543
- resultSchemaRevisionRef: exports.RevisionRefSchema,
544
- success: zod_1.z.object({
545
- refreshBindingIds: zod_1.z.array(common_1.ContractIdentifierSchema),
546
- navigationTargetRef: exports.StableRefSchema.optional(),
547
- }).strict(),
548
- recovery: zod_1.z.enum(['retry-safe', 'compensating-command', 'manual-review']),
549
- lineageRequired: zod_1.z.literal(true),
1139
+ operator: zod_1.z.enum(["all", "any"]),
1140
+ conditions: zod_1.z
1141
+ .array(zod_1.z.union([exports.PageStateConditionSchema, exports.PageStateActivationSchema]))
1142
+ .min(1),
1143
+ })
1144
+ .strict());
1145
+ const forEachPageStateCondition = (activation, visit, path = []) => {
1146
+ activation.conditions.forEach((candidate, index) => {
1147
+ const candidatePath = [...path, "conditions", index];
1148
+ if ("operator" in candidate) {
1149
+ forEachPageStateCondition(candidate, visit, candidatePath);
1150
+ return;
1151
+ }
1152
+ visit(candidate, candidatePath);
1153
+ });
1154
+ };
1155
+ const PageRouteValueSourceSchema = zod_1.z.discriminatedUnion("kind", [
1156
+ zod_1.z
1157
+ .object({
1158
+ kind: zod_1.z.literal("route-parameter"),
1159
+ name: common_1.ContractIdentifierSchema,
1160
+ })
1161
+ .strict(),
1162
+ zod_1.z
1163
+ .object({
1164
+ kind: zod_1.z.literal("constant"),
1165
+ value: zod_1.z.union([zod_1.z.string(), zod_1.z.number().finite(), zod_1.z.boolean()]),
1166
+ })
1167
+ .strict(),
1168
+ zod_1.z
1169
+ .object({
1170
+ kind: zod_1.z.literal("page-state"),
1171
+ stateId: common_1.ContractIdentifierSchema,
1172
+ })
1173
+ .strict(),
1174
+ ]);
1175
+ /**
1176
+ * Declares an ordered, state-driven route transition owned by one exact Page
1177
+ * revision. The compiler resolves targetRef to one active governed Release;
1178
+ * raw URLs and application-specific route switches are deliberately excluded.
1179
+ */
1180
+ exports.PageEntryTransitionSchema = zod_1.z
1181
+ .object({
1182
+ browsingContext: zod_1.z.enum(["same", "new"]).optional(),
1183
+ gestureSource: zod_1.z
1184
+ .object({
1185
+ capabilityInstanceId: common_1.ContractIdentifierSchema,
1186
+ port: common_1.ContractIdentifierSchema,
1187
+ })
1188
+ .strict()
1189
+ .optional(),
1190
+ transitionId: common_1.ContractIdentifierSchema,
1191
+ activation: exports.PageStateActivationSchema,
1192
+ targetRef: exports.StableRefSchema,
1193
+ pathParameters: zod_1.z.record(common_1.ContractIdentifierSchema, PageRouteValueSourceSchema),
1194
+ query: zod_1.z
1195
+ .object({
1196
+ preserve: zod_1.z.boolean(),
1197
+ remove: zod_1.z.array(common_1.ContractIdentifierSchema),
1198
+ set: zod_1.z.record(common_1.ContractIdentifierSchema, PageRouteValueSourceSchema),
1199
+ })
1200
+ .strict(),
550
1201
  })
551
1202
  .strict()
552
1203
  .superRefine((value, context) => {
553
- if (value.commandRevisionRef.kind !== 'domain-command') {
554
- context.addIssue({ code: 'custom', path: ['commandRevisionRef', 'kind'], message: 'Action bindings must reference a domain-command revision.' });
555
- }
556
- if (value.sourceIntentSchemaRevisionRef.kind !== 'schema') {
557
- context.addIssue({ code: 'custom', path: ['sourceIntentSchemaRevisionRef', 'kind'], message: 'Action source intents must pin a schema revision.' });
1204
+ if ((value.browsingContext === "new") !== Boolean(value.gestureSource)) {
1205
+ context.addIssue({
1206
+ code: "custom",
1207
+ path: ["gestureSource"],
1208
+ message: "New-context entry transitions require an exact gesture source; same-context transitions must omit it.",
1209
+ });
558
1210
  }
559
- if (value.inputSchemaRevisionRef.kind !== 'schema') {
560
- context.addIssue({ code: 'custom', path: ['inputSchemaRevisionRef', 'kind'], message: 'Action command inputs must pin a schema revision.' });
1211
+ if (!["page", "workbench"].includes(value.targetRef.kind)) {
1212
+ context.addIssue({
1213
+ code: "custom",
1214
+ path: ["targetRef", "kind"],
1215
+ message: "Page entry transitions must reference a governed Page or Workbench.",
1216
+ });
561
1217
  }
562
- if (value.recovery === 'compensating-command' && !value.compensationCommandRevisionRef) {
563
- context.addIssue({ code: 'custom', path: ['compensationCommandRevisionRef'], message: 'Compensating recovery requires a compensation command.' });
1218
+ if (new Set(value.query.remove).size !== value.query.remove.length) {
1219
+ context.addIssue({
1220
+ code: "custom",
1221
+ path: ["query", "remove"],
1222
+ message: "Removed query parameter names must be unique.",
1223
+ });
564
1224
  }
565
1225
  });
566
- exports.PageSchema = zod_1.z
1226
+ exports.ResolvedPageEntryTransitionSchema = exports.PageEntryTransitionSchema.safeExtend({
1227
+ targetRevisionRef: exports.RevisionRefSchema,
1228
+ targetReleaseRevisionRef: exports.RevisionRefSchema.optional(),
1229
+ targetAccessPolicy: exports.AccessPolicySchema,
1230
+ targetRouteClaim: exports.CompiledRouteClaimSchema,
1231
+ }).strict();
1232
+ exports.LegacyBrowserPreferenceImportSchema = zod_1.z
567
1233
  .object({
568
- contract: zod_1.z.literal('Page'),
569
- schemaVersion: zod_1.z.literal(exports.DECLARATIVE_CONTROL_SCHEMA_VERSION),
570
- pageId: common_1.ContractIdentifierSchema,
571
- tenantScope: exports.TenantScopeSchema,
572
- identity: IdentitySchema,
573
- supportedSurfaces: zod_1.z.array(exports.ProductSurfaceSchema).min(1),
574
- lifecycle: exports.DeclarativeLifecycleSchema,
575
- routeClaims: zod_1.z.array(zod_1.z.union([exports.DeclarativeRouteClaimSchema, LegacyDeclarativeRouteClaimSchema])).min(1),
576
- shellRevisionRef: exports.RevisionRefSchema,
577
- renderTree: render_1.RenderTreeSchema,
578
- capabilityInstances: zod_1.z.array(exports.CapabilityInstanceSchema).min(1),
579
- ontologyBindings: zod_1.z.array(exports.OntologyBindingSchema),
580
- actionBindings: zod_1.z.array(exports.ActionBindingSchema),
581
- pageAccessPolicy: exports.AccessPolicySchema,
582
- managementAccess: exports.ManagementAccessSchema,
583
- tokenRevisionRefs: zod_1.z.array(exports.RevisionRefSchema).min(1),
584
- performanceBudgetRef: exports.RevisionRefSchema,
585
- observationPolicyRevisionRef: exports.RevisionRefSchema,
586
- privacyClassification: zod_1.z.enum(['public', 'internal', 'confidential', 'restricted']),
1234
+ storageKey: zod_1.z.string().trim().min(1).max(256),
1235
+ jsonPath: zod_1.z
1236
+ .array(zod_1.z.union([
1237
+ zod_1.z.string().trim().min(1).max(128),
1238
+ zod_1.z.object({ stateId: common_1.ContractIdentifierSchema }).strict(),
1239
+ ]))
1240
+ .min(1)
1241
+ .max(16)
1242
+ .optional(),
1243
+ valueType: zod_1.z.enum(["string", "number", "boolean-01", "json"]),
1244
+ })
1245
+ .strict();
1246
+ exports.PageStateDefinitionSchema = zod_1.z
1247
+ .object({
1248
+ stateId: common_1.ContractIdentifierSchema,
1249
+ scopeNodeId: common_1.ContractIdentifierSchema.optional(),
1250
+ initialValue: page_expression_1.PageExpressionSchema.optional(),
1251
+ schemaRevisionRef: exports.RevisionRefSchema,
1252
+ defaultValue: common_1.JsonValueSchema.optional(),
1253
+ persistence: zod_1.z.enum([
1254
+ "none",
1255
+ "session",
1256
+ "url",
1257
+ "tenant-preference",
1258
+ "url-with-tenant-preference",
1259
+ ]),
1260
+ urlWriteback: zod_1.z.enum(["synchronize", "never"]).optional(),
1261
+ preferencePartitionStateId: common_1.ContractIdentifierSchema.optional(),
1262
+ legacyBrowserPreferenceImport: exports.LegacyBrowserPreferenceImportSchema.optional(),
587
1263
  })
588
1264
  .strict()
589
1265
  .superRefine((value, context) => {
590
- validateDeclaredRouteSurfaces(value.supportedSurfaces, value.routeClaims, context);
591
- const uniqueness = [
592
- ['capabilityInstances', value.capabilityInstances, (candidate) => String(candidate.instanceId)],
593
- ['ontologyBindings', value.ontologyBindings, (candidate) => String(candidate.bindingId)],
594
- ['actionBindings', value.actionBindings, (candidate) => String(candidate.bindingId)],
595
- ];
596
- uniqueness.forEach(([field, values, identity]) => {
1266
+ if (value.scopeNodeId && value.persistence !== "none")
1267
+ context.addIssue({
1268
+ code: "custom",
1269
+ path: ["persistence"],
1270
+ message: "Repeated instance state must not persist outside its instance.",
1271
+ });
1272
+ if (value.initialValue &&
1273
+ !value.scopeNodeId &&
1274
+ (value.persistence !== "none" ||
1275
+ value.initialValue.kind !== "read" ||
1276
+ value.initialValue.root !== "state" ||
1277
+ value.initialValue.path.length !== 1))
1278
+ context.addIssue({
1279
+ code: "custom",
1280
+ path: ["initialValue"],
1281
+ message: "Root initialization must directly read one persisted Page state into non-persistent state.",
1282
+ });
1283
+ if (value.schemaRevisionRef.kind !== "schema") {
1284
+ context.addIssue({
1285
+ code: "custom",
1286
+ path: ["schemaRevisionRef", "kind"],
1287
+ message: "Page state must pin an exact schema revision.",
1288
+ });
1289
+ }
1290
+ if (value.preferencePartitionStateId !== undefined &&
1291
+ value.persistence !== "tenant-preference" &&
1292
+ value.persistence !== "url-with-tenant-preference") {
1293
+ context.addIssue({
1294
+ code: "custom",
1295
+ path: ["preferencePartitionStateId"],
1296
+ message: "Preference partitioning requires tenant preference state.",
1297
+ });
1298
+ }
1299
+ if (value.urlWriteback !== undefined &&
1300
+ value.persistence !== "url" &&
1301
+ value.persistence !== "url-with-tenant-preference") {
1302
+ context.addIssue({
1303
+ code: "custom",
1304
+ path: ["urlWriteback"],
1305
+ message: "URL writeback is only valid for URL-backed Page state.",
1306
+ });
1307
+ }
1308
+ });
1309
+ exports.InteractionBindingSchema = zod_1.z
1310
+ .object({
1311
+ bindingId: common_1.ContractIdentifierSchema,
1312
+ source: zod_1.z
1313
+ .object({
1314
+ capabilityInstanceId: common_1.ContractIdentifierSchema,
1315
+ port: common_1.ContractIdentifierSchema,
1316
+ })
1317
+ .strict(),
1318
+ sourceIntentSchemaRevisionRef: exports.RevisionRefSchema,
1319
+ sourceResultSchemaRevisionRef: exports.RevisionRefSchema.optional(),
1320
+ targetStateId: common_1.ContractIdentifierSchema,
1321
+ transition: zod_1.z.enum(["set", "merge", "toggle", "append", "remove", "reset"]),
1322
+ inputMapping: zod_1.z.record(common_1.ContractIdentifierSchema, InteractionBindingSourceSchema),
1323
+ })
1324
+ .strict()
1325
+ .superRefine((value, context) => {
1326
+ if (value.sourceIntentSchemaRevisionRef.kind !== "schema") {
1327
+ context.addIssue({
1328
+ code: "custom",
1329
+ path: ["sourceIntentSchemaRevisionRef", "kind"],
1330
+ message: "Interaction source intents must pin a schema revision.",
1331
+ });
1332
+ }
1333
+ const mapsResult = Object.values(value.inputMapping).some((source) => source.kind === "result-field" ||
1334
+ (source.kind === "expression" &&
1335
+ (0, page_expression_1.collectPageExpressionReads)(source.expression).some((read) => read.root === "result")));
1336
+ if (mapsResult && !value.sourceResultSchemaRevisionRef) {
1337
+ context.addIssue({
1338
+ code: "custom",
1339
+ path: ["sourceResultSchemaRevisionRef"],
1340
+ message: "Result-field interactions must pin the exact Action result schema revision.",
1341
+ });
1342
+ }
1343
+ if (value.sourceResultSchemaRevisionRef?.kind !== undefined &&
1344
+ value.sourceResultSchemaRevisionRef.kind !== "schema") {
1345
+ context.addIssue({
1346
+ code: "custom",
1347
+ path: ["sourceResultSchemaRevisionRef", "kind"],
1348
+ message: "Interaction source results must pin a schema revision.",
1349
+ });
1350
+ }
1351
+ if (!mapsResult && value.sourceResultSchemaRevisionRef) {
1352
+ context.addIssue({
1353
+ code: "custom",
1354
+ path: ["sourceResultSchemaRevisionRef"],
1355
+ message: "Interaction result schemas are only valid when inputMapping declares a result-field source.",
1356
+ });
1357
+ }
1358
+ const mappedInputs = Object.keys(value.inputMapping);
1359
+ if ((value.transition === "toggle" || value.transition === "reset") &&
1360
+ mappedInputs.length > 0) {
1361
+ context.addIssue({
1362
+ code: "custom",
1363
+ path: ["inputMapping"],
1364
+ message: `${value.transition} transitions cannot declare mapped inputs.`,
1365
+ });
1366
+ }
1367
+ if (value.transition !== "toggle" &&
1368
+ value.transition !== "reset" &&
1369
+ mappedInputs.length === 0) {
1370
+ context.addIssue({
1371
+ code: "custom",
1372
+ path: ["inputMapping"],
1373
+ message: `${value.transition} transitions require at least one mapped input.`,
1374
+ });
1375
+ }
1376
+ });
1377
+ exports.GovernedCatalogResourceKindSchema = zod_1.z.enum([
1378
+ "tag",
1379
+ "tag-group",
1380
+ "feature-column",
1381
+ ]);
1382
+ exports.GovernedCatalogDomainQueryDataSourceSchema = zod_1.z
1383
+ .object({
1384
+ kind: zod_1.z.literal("governed-catalog"),
1385
+ resourceKind: exports.GovernedCatalogResourceKindSchema,
1386
+ })
1387
+ .strict();
1388
+ exports.RegisteredServiceDomainQueryDataSourceSchema = zod_1.z
1389
+ .object({
1390
+ kind: zod_1.z.literal("registered-service"),
1391
+ })
1392
+ .strict();
1393
+ exports.DomainQueryDataSourceSchema = zod_1.z.discriminatedUnion("kind", [
1394
+ zod_1.z.object({ kind: zod_1.z.literal("exact-view") }).strict(),
1395
+ zod_1.z
1396
+ .object({
1397
+ kind: zod_1.z.literal("tenant-catalog"),
1398
+ resource: zod_1.z.enum(["ontology", "view"]),
1399
+ ontologyIdParameter: common_1.ContractIdentifierSchema.optional(),
1400
+ })
1401
+ .strict()
1402
+ .superRefine((source, context) => {
1403
+ if (source.resource === "view" && !source.ontologyIdParameter) {
1404
+ context.addIssue({
1405
+ code: "custom",
1406
+ path: ["ontologyIdParameter"],
1407
+ message: "A tenant View catalog must declare the input parameter that scopes it to one Ontology.",
1408
+ });
1409
+ }
1410
+ if (source.resource === "ontology" && source.ontologyIdParameter) {
1411
+ context.addIssue({
1412
+ code: "custom",
1413
+ path: ["ontologyIdParameter"],
1414
+ message: "An Ontology catalog cannot be pre-scoped by an Ontology input.",
1415
+ });
1416
+ }
1417
+ }),
1418
+ zod_1.z
1419
+ .object({
1420
+ kind: zod_1.z.literal("tenant-current-view"),
1421
+ ontologyIdParameter: common_1.ContractIdentifierSchema,
1422
+ viewIdParameter: common_1.ContractIdentifierSchema,
1423
+ })
1424
+ .strict(),
1425
+ zod_1.z.object({ kind: zod_1.z.literal("page-state") }).strict(),
1426
+ exports.GovernedCatalogDomainQueryDataSourceSchema,
1427
+ exports.RegisteredServiceDomainQueryDataSourceSchema,
1428
+ ]);
1429
+ exports.DomainQueryDefinitionSchema = zod_1.z
1430
+ .object({
1431
+ contract: zod_1.z.literal("DomainQueryDefinition"),
1432
+ schemaVersion: zod_1.z.literal(exports.DECLARATIVE_CONTROL_SCHEMA_VERSION),
1433
+ queryId: common_1.ContractIdentifierSchema,
1434
+ tenantScope: exports.TenantScopeSchema,
1435
+ dataSource: exports.DomainQueryDataSourceSchema.optional(),
1436
+ handlerRef: common_1.EntityRefSchema.optional(),
1437
+ ontologyDefinitionRevisionRef: exports.RevisionRefSchema.optional(),
1438
+ viewRevisionRef: exports.RevisionRefSchema.optional(),
1439
+ canonicalDataViewRevisionRef: exports.RevisionRefSchema.optional(),
1440
+ inputSchemaRevisionRef: exports.RevisionRefSchema,
1441
+ resultSchemaRevisionRef: exports.RevisionRefSchema,
1442
+ accessPolicy: exports.AccessPolicySchema,
1443
+ lineageRequired: zod_1.z.literal(true),
1444
+ })
1445
+ .strict()
1446
+ .superRefine((value, context) => {
1447
+ const sourceKind = value.dataSource?.kind ?? "exact-view";
1448
+ const exactDataRefs = [
1449
+ value.ontologyDefinitionRevisionRef,
1450
+ value.viewRevisionRef,
1451
+ value.canonicalDataViewRevisionRef,
1452
+ ];
1453
+ if (sourceKind === "exact-view" &&
1454
+ exactDataRefs.some((reference) => !reference)) {
1455
+ context.addIssue({
1456
+ code: "custom",
1457
+ path: ["dataSource"],
1458
+ message: "An exact-view Domain Query must pin Ontology, governed View, and canonical Data View revisions.",
1459
+ });
1460
+ }
1461
+ if (sourceKind !== "exact-view" && exactDataRefs.some(Boolean)) {
1462
+ context.addIssue({
1463
+ code: "custom",
1464
+ path: ["dataSource"],
1465
+ message: "A non-View Domain Query cannot also pin one fixed View.",
1466
+ });
1467
+ }
1468
+ if (value.dataSource &&
1469
+ (!value.handlerRef || value.handlerRef.version === undefined)) {
1470
+ context.addIssue({
1471
+ code: "custom",
1472
+ path: ["handlerRef"],
1473
+ message: "A source-aware Domain Query must pin its release-owned handler version.",
1474
+ });
1475
+ }
1476
+ const refs = [
1477
+ ...(sourceKind === "exact-view" && value.ontologyDefinitionRevisionRef
1478
+ ? [
1479
+ [
1480
+ "ontologyDefinitionRevisionRef",
1481
+ value.ontologyDefinitionRevisionRef,
1482
+ "ontology-definition",
1483
+ ],
1484
+ ]
1485
+ : []),
1486
+ ...(sourceKind === "exact-view" && value.viewRevisionRef
1487
+ ? [["viewRevisionRef", value.viewRevisionRef, "view"]]
1488
+ : []),
1489
+ ...(sourceKind === "exact-view" && value.canonicalDataViewRevisionRef
1490
+ ? [
1491
+ [
1492
+ "canonicalDataViewRevisionRef",
1493
+ value.canonicalDataViewRevisionRef,
1494
+ "view",
1495
+ ],
1496
+ ]
1497
+ : []),
1498
+ ["inputSchemaRevisionRef", value.inputSchemaRevisionRef, "schema"],
1499
+ ["resultSchemaRevisionRef", value.resultSchemaRevisionRef, "schema"],
1500
+ ];
1501
+ refs.forEach(([field, reference, expectedKind]) => {
1502
+ if (reference.kind !== expectedKind) {
1503
+ context.addIssue({
1504
+ code: "custom",
1505
+ path: [field, "kind"],
1506
+ message: `${field} must reference ${expectedKind}.`,
1507
+ });
1508
+ }
1509
+ validateTenantCompatibleReference(reference, value.tenantScope, [field], context);
1510
+ });
1511
+ [
1512
+ ...value.accessPolicy.groupAllOf,
1513
+ ...value.accessPolicy.groupAnyOf,
1514
+ ].forEach((reference, index) => validateTenantCompatibleReference(reference, value.tenantScope, ["accessPolicy", "groups", index], context));
1515
+ value.accessPolicy.conditionAllOf.forEach((reference, index) => validateTenantCompatibleReference(reference, value.tenantScope, ["accessPolicy", "conditionAllOf", index], context));
1516
+ if (value.viewRevisionRef &&
1517
+ value.canonicalDataViewRevisionRef &&
1518
+ exactRevisionRef(value.viewRevisionRef, value.canonicalDataViewRevisionRef)) {
1519
+ context.addIssue({
1520
+ code: "custom",
1521
+ path: ["canonicalDataViewRevisionRef"],
1522
+ message: "Governed View adapter and canonical data.view revisions must be distinct.",
1523
+ });
1524
+ }
1525
+ });
1526
+ exports.CursorWindowBindingSchema = zod_1.z
1527
+ .object({
1528
+ sourceCapabilityInstanceId: common_1.ContractIdentifierSchema.optional(),
1529
+ pageChangePort: common_1.ContractIdentifierSchema,
1530
+ pageChangeIntentSchemaRevisionRef: exports.RevisionRefSchema,
1531
+ })
1532
+ .strict()
1533
+ .superRefine((value, context) => {
1534
+ if (value.pageChangeIntentSchemaRevisionRef.kind !== "schema") {
1535
+ context.addIssue({
1536
+ code: "custom",
1537
+ path: ["pageChangeIntentSchemaRevisionRef", "kind"],
1538
+ message: "Cursor-window page-change intents must pin a schema revision.",
1539
+ });
1540
+ }
1541
+ });
1542
+ exports.QueryResultStateBindingSchema = zod_1.z
1543
+ .object({
1544
+ targetStateId: common_1.ContractIdentifierSchema,
1545
+ targetStateSchemaRevisionRef: exports.RevisionRefSchema,
1546
+ source: zod_1.z
1547
+ .object({ kind: zod_1.z.enum(["page-info-total", "model-total"]) })
1548
+ .strict(),
1549
+ })
1550
+ .strict()
1551
+ .superRefine((value, context) => {
1552
+ if (value.targetStateSchemaRevisionRef.kind !== "schema") {
1553
+ context.addIssue({
1554
+ code: "custom",
1555
+ path: ["targetStateSchemaRevisionRef", "kind"],
1556
+ message: "Query result state bindings must pin a Page-state schema revision.",
1557
+ });
1558
+ }
1559
+ });
1560
+ exports.QueryBindingSchema = zod_1.z
1561
+ .object({
1562
+ bindingId: common_1.ContractIdentifierSchema,
1563
+ queryDefinitionRevisionRef: exports.RevisionRefSchema,
1564
+ parameters: zod_1.z.record(common_1.ContractIdentifierSchema, exports.BindingSourceSchema),
1565
+ target: zod_1.z
1566
+ .object({
1567
+ capabilityInstanceId: common_1.ContractIdentifierSchema,
1568
+ port: common_1.ContractIdentifierSchema,
1569
+ })
1570
+ .strict(),
1571
+ renderModelSchemaRevisionRef: exports.RevisionRefSchema,
1572
+ targetProjection: zod_1.z
1573
+ .object({
1574
+ expression: page_expression_1.PageExpressionSchema,
1575
+ schemaRevisionRef: exports.RevisionRefSchema,
1576
+ })
1577
+ .strict()
1578
+ .optional(),
1579
+ streamTargetProjection: zod_1.z
1580
+ .object({
1581
+ expression: page_expression_1.PageExpressionSchema,
1582
+ schemaRevisionRef: exports.RevisionRefSchema,
1583
+ })
1584
+ .strict()
1585
+ .optional(),
1586
+ stateEffects: zod_1.z
1587
+ .array(zod_1.z
1588
+ .object({
1589
+ targetStateId: common_1.ContractIdentifierSchema,
1590
+ value: page_expression_1.PageExpressionSchema,
1591
+ when: page_expression_1.PageExpressionSchema.optional(),
1592
+ })
1593
+ .strict())
1594
+ .max(32)
1595
+ .optional(),
1596
+ queryWhen: exports.PageStateActivationSchema.optional(),
1597
+ accessFailure: zod_1.z.literal("render-forbidden").optional(),
1598
+ resultStateBindings: zod_1.z
1599
+ .array(exports.QueryResultStateBindingSchema)
1600
+ .max(32)
1601
+ .optional(),
1602
+ execution: zod_1.z.enum(["server", "local-state"]).default("server"),
1603
+ pagination: zod_1.z.enum(["none", "cursor", "offset"]),
1604
+ cursorWindow: exports.CursorWindowBindingSchema.optional(),
1605
+ cache: zod_1.z.enum(["none", "identity-scoped", "tenant-scoped"]),
1606
+ cancelOnChange: zod_1.z.boolean(),
1607
+ refreshPolicy: zod_1.z
1608
+ .object({
1609
+ intervalMs: zod_1.z.number().int().min(1000).max(300000),
1610
+ when: page_expression_1.PageExpressionSchema.optional(),
1611
+ })
1612
+ .strict()
1613
+ .optional(),
1614
+ })
1615
+ .strict()
1616
+ .superRefine((value, context) => {
1617
+ if (value.targetProjection) {
1618
+ if (value.targetProjection.schemaRevisionRef.kind !== "schema")
1619
+ context.addIssue({
1620
+ code: "custom",
1621
+ path: ["targetProjection", "schemaRevisionRef"],
1622
+ message: "Query target projections require an exact target schema revision.",
1623
+ });
1624
+ for (const read of (0, page_expression_1.collectExternalPageExpressionReads)(value.targetProjection.expression))
1625
+ if (read.root !== "model")
1626
+ context.addIssue({
1627
+ code: "custom",
1628
+ path: ["targetProjection", "expression"],
1629
+ message: "Query target projections may read only the validated raw model.",
1630
+ });
1631
+ }
1632
+ if (value.streamTargetProjection) {
1633
+ const projection = value.streamTargetProjection;
1634
+ if (projection.schemaRevisionRef.kind !== "schema")
1635
+ context.addIssue({
1636
+ code: "custom",
1637
+ path: ["streamTargetProjection", "schemaRevisionRef"],
1638
+ message: "Stream target projections require an exact target schema revision.",
1639
+ });
1640
+ for (const read of (0, page_expression_1.collectExternalPageExpressionReads)(projection.expression))
1641
+ if (read.root !== "model")
1642
+ context.addIssue({
1643
+ code: "custom",
1644
+ path: ["streamTargetProjection", "expression"],
1645
+ message: "Stream target projections may read only the verified query and stream envelope.",
1646
+ });
1647
+ if (value.execution !== "server" || value.pagination !== "none")
1648
+ context.addIssue({
1649
+ code: "custom",
1650
+ path: ["streamTargetProjection"],
1651
+ message: "Stream target projections require a non-paginated Server query.",
1652
+ });
1653
+ }
1654
+ const effects = value.stateEffects ?? [];
1655
+ if (new Set(effects.map((effect) => effect.targetStateId)).size !==
1656
+ effects.length)
1657
+ context.addIssue({
1658
+ code: "custom",
1659
+ path: ["stateEffects"],
1660
+ message: "A query completion may update each state only once.",
1661
+ });
1662
+ for (const [index, effect] of effects.entries())
1663
+ for (const expression of [
1664
+ effect.value,
1665
+ ...(effect.when ? [effect.when] : []),
1666
+ ]) {
1667
+ for (const read of (0, page_expression_1.collectPageExpressionReads)(expression))
1668
+ if (!["model", "state", "scope"].includes(read.root))
1669
+ context.addIssue({
1670
+ code: "custom",
1671
+ path: ["stateEffects", index],
1672
+ message: "Query state effects may read only model, state, and scope.",
1673
+ });
1674
+ }
1675
+ if (effects.length &&
1676
+ (value.execution !== "server" || value.pagination !== "none"))
1677
+ context.addIssue({
1678
+ code: "custom",
1679
+ path: ["stateEffects"],
1680
+ message: "Query state effects require a non-paginated Server query.",
1681
+ });
1682
+ if (value.refreshPolicy?.when) {
1683
+ for (const read of (0, page_expression_1.collectExternalPageExpressionReads)(value.refreshPolicy.when)) {
1684
+ if (read.root !== "model" &&
1685
+ !(read.root === "actions" &&
1686
+ read.path.length === 2 &&
1687
+ read.path[1] === "pending"))
1688
+ context.addIssue({
1689
+ code: "custom",
1690
+ path: ["refreshPolicy", "when"],
1691
+ message: "Automatic refresh conditions may read only the verified raw model and declared action pending state.",
1692
+ });
1693
+ }
1694
+ }
1695
+ if (value.refreshPolicy &&
1696
+ (value.execution !== "server" || value.pagination !== "none")) {
1697
+ context.addIssue({
1698
+ code: "custom",
1699
+ path: ["refreshPolicy"],
1700
+ message: "Automatic refresh requires a non-paginated Server query.",
1701
+ });
1702
+ }
1703
+ if (value.queryDefinitionRevisionRef.kind !== "domain-query-definition") {
1704
+ context.addIssue({
1705
+ code: "custom",
1706
+ path: ["queryDefinitionRevisionRef", "kind"],
1707
+ message: "Query bindings must pin a governed domain-query-definition revision.",
1708
+ });
1709
+ }
1710
+ if (value.renderModelSchemaRevisionRef.kind !== "schema") {
1711
+ context.addIssue({
1712
+ code: "custom",
1713
+ path: ["renderModelSchemaRevisionRef", "kind"],
1714
+ message: "Query bindings must pin a render-model schema revision.",
1715
+ });
1716
+ }
1717
+ if (value.execution === "local-state" && value.pagination !== "none") {
1718
+ context.addIssue({
1719
+ code: "custom",
1720
+ path: ["pagination"],
1721
+ message: "Local Page-state queries cannot paginate.",
1722
+ });
1723
+ }
1724
+ if (value.execution === "local-state" && value.accessFailure) {
1725
+ context.addIssue({
1726
+ code: "custom",
1727
+ path: ["accessFailure"],
1728
+ message: "Only a Server query can render an independently governed access failure.",
1729
+ });
1730
+ }
1731
+ if (value.execution === "local-state" &&
1732
+ (value.resultStateBindings?.length ?? 0) > 0) {
1733
+ context.addIssue({
1734
+ code: "custom",
1735
+ path: ["resultStateBindings"],
1736
+ message: "Only Server queries can project governed result totals into Page state.",
1737
+ });
1738
+ }
1739
+ const targetStateIds = value.resultStateBindings?.map((binding) => binding.targetStateId) ?? [];
1740
+ if (new Set(targetStateIds).size !== targetStateIds.length) {
1741
+ context.addIssue({
1742
+ code: "custom",
1743
+ path: ["resultStateBindings"],
1744
+ message: "A Query binding can project a governed result total to each Page state at most once.",
1745
+ });
1746
+ }
1747
+ if (value.cursorWindow && value.pagination !== "cursor") {
1748
+ context.addIssue({
1749
+ code: "custom",
1750
+ path: ["cursorWindow"],
1751
+ message: "Cursor-window navigation requires cursor pagination.",
1752
+ });
1753
+ }
1754
+ if (value.cursorWindow && value.execution !== "server") {
1755
+ context.addIssue({
1756
+ code: "custom",
1757
+ path: ["cursorWindow"],
1758
+ message: "Cursor-window navigation requires Server query execution.",
1759
+ });
1760
+ }
1761
+ });
1762
+ exports.CapabilityInstanceSchema = zod_1.z
1763
+ .object({
1764
+ instanceId: common_1.ContractIdentifierSchema,
1765
+ nodeId: common_1.ContractIdentifierSchema,
1766
+ capabilityRevisionRef: exports.RevisionRefSchema,
1767
+ providerRevisionRef: exports.RevisionRefSchema,
1768
+ propertySchemaRevisionRef: exports.RevisionRefSchema,
1769
+ properties: common_1.JsonObjectSchema,
1770
+ propertyBindings: zod_1.z.array(page_expression_1.PagePropertyBindingSchema).max(128).optional(),
1771
+ eventPayloadBindings: zod_1.z
1772
+ .array(zod_1.z
1773
+ .object({
1774
+ port: common_1.ContractIdentifierSchema,
1775
+ expression: page_expression_1.PageExpressionSchema,
1776
+ })
1777
+ .strict())
1778
+ .max(32)
1779
+ .optional(),
1780
+ eventEffects: zod_1.z
1781
+ .array(zod_1.z
1782
+ .object({
1783
+ sourcePort: common_1.ContractIdentifierSchema,
1784
+ sourceIntentSchemaRevisionRef: exports.RevisionRefSchema,
1785
+ refreshBindingIds: zod_1.z
1786
+ .array(common_1.ContractIdentifierSchema)
1787
+ .min(1)
1788
+ .max(128),
1789
+ })
1790
+ .strict())
1791
+ .max(32)
1792
+ .optional(),
1793
+ accessPolicy: exports.AccessPolicySchema.optional(),
1794
+ activationWhen: exports.PageStateActivationSchema.optional(),
1795
+ allowedSideEffects: zod_1.z.array(zod_1.z.enum([
1796
+ "network",
1797
+ "storage",
1798
+ "navigation",
1799
+ "clipboard",
1800
+ "worker",
1801
+ "websocket",
1802
+ ])),
1803
+ })
1804
+ .strict();
1805
+ exports.OntologyBindingSchema = zod_1.z
1806
+ .object({
1807
+ bindingId: common_1.ContractIdentifierSchema,
1808
+ ontologyDefinitionRevisionRef: exports.RevisionRefSchema,
1809
+ viewRevisionRef: exports.RevisionRefSchema,
1810
+ canonicalDataViewRevisionRef: exports.RevisionRefSchema,
1811
+ parameters: zod_1.z.record(common_1.ContractIdentifierSchema, exports.BindingSourceSchema),
1812
+ target: zod_1.z
1813
+ .object({
1814
+ capabilityInstanceId: common_1.ContractIdentifierSchema,
1815
+ port: common_1.ContractIdentifierSchema,
1816
+ })
1817
+ .strict(),
1818
+ renderModelSchemaRevisionRef: exports.RevisionRefSchema,
1819
+ pagination: zod_1.z.enum(["none", "cursor", "offset"]),
1820
+ cursorWindow: exports.CursorWindowBindingSchema.optional(),
1821
+ cache: zod_1.z.enum(["none", "identity-scoped", "tenant-scoped"]),
1822
+ cancelOnChange: zod_1.z.boolean(),
1823
+ })
1824
+ .strict()
1825
+ .superRefine((value, context) => {
1826
+ if (value.viewRevisionRef.kind !== "view") {
1827
+ context.addIssue({
1828
+ code: "custom",
1829
+ path: ["viewRevisionRef", "kind"],
1830
+ message: "Ontology bindings require an exact governed View revision.",
1831
+ });
1832
+ }
1833
+ if (value.canonicalDataViewRevisionRef.kind !== "view") {
1834
+ context.addIssue({
1835
+ code: "custom",
1836
+ path: ["canonicalDataViewRevisionRef", "kind"],
1837
+ message: "Ontology bindings require an exact canonical data.view revision.",
1838
+ });
1839
+ }
1840
+ if (exactRevisionRef(value.viewRevisionRef, value.canonicalDataViewRevisionRef)) {
1841
+ context.addIssue({
1842
+ code: "custom",
1843
+ path: ["canonicalDataViewRevisionRef"],
1844
+ message: "Governed View adapter and canonical data.view revisions must be distinct.",
1845
+ });
1846
+ }
1847
+ if (value.ontologyDefinitionRevisionRef.kind !== "ontology-definition") {
1848
+ context.addIssue({
1849
+ code: "custom",
1850
+ path: ["ontologyDefinitionRevisionRef", "kind"],
1851
+ message: "Expected an ontology-definition revision.",
1852
+ });
1853
+ }
1854
+ if (value.cursorWindow && value.pagination !== "cursor") {
1855
+ context.addIssue({
1856
+ code: "custom",
1857
+ path: ["cursorWindow"],
1858
+ message: "Cursor-window navigation requires cursor pagination.",
1859
+ });
1860
+ }
1861
+ });
1862
+ exports.ActionResultBindingEffectSourceSchema = zod_1.z.discriminatedUnion("kind", [
1863
+ zod_1.z
1864
+ .object({
1865
+ kind: zod_1.z.literal("result-field"),
1866
+ path: zod_1.z
1867
+ .string()
1868
+ .trim()
1869
+ .regex(/^[A-Za-z0-9_.-]+$/),
1870
+ })
1871
+ .strict(),
1872
+ zod_1.z.object({ kind: zod_1.z.literal("constant"), value: common_1.JsonValueSchema }).strict(),
1873
+ zod_1.z
1874
+ .object({
1875
+ kind: zod_1.z.literal("collection-length"),
1876
+ offset: zod_1.z.number().int().min(-1000).max(1000),
1877
+ })
1878
+ .strict(),
1879
+ ]);
1880
+ exports.ActionResultBindingEffectSchema = zod_1.z
1881
+ .object({
1882
+ bindingId: common_1.ContractIdentifierSchema,
1883
+ operation: zod_1.z.enum(["upsert-append", "remove-exact"]),
1884
+ collectionPath: zod_1.z.array(common_1.ContractIdentifierSchema).min(1).max(8),
1885
+ identityPath: zod_1.z.array(common_1.ContractIdentifierSchema).min(1).max(8),
1886
+ mappings: zod_1.z
1887
+ .array(zod_1.z
1888
+ .object({
1889
+ targetPath: zod_1.z.array(common_1.ContractIdentifierSchema).min(1).max(8),
1890
+ source: exports.ActionResultBindingEffectSourceSchema,
1891
+ })
1892
+ .strict())
1893
+ .min(1)
1894
+ .max(64),
1895
+ })
1896
+ .strict()
1897
+ .superRefine((value, context) => {
1898
+ const targetPaths = value.mappings.map(({ targetPath }) => targetPath.join("."));
1899
+ if (new Set(targetPaths).size !== targetPaths.length) {
1900
+ context.addIssue({
1901
+ code: "custom",
1902
+ path: ["mappings"],
1903
+ message: "Result binding effect target paths must be unique.",
1904
+ });
1905
+ }
1906
+ if (!targetPaths.includes(value.identityPath.join("."))) {
1907
+ context.addIssue({
1908
+ code: "custom",
1909
+ path: ["identityPath"],
1910
+ message: "A result binding effect must map the exact identity path of the projected item.",
1911
+ });
1912
+ }
1913
+ const identityMapping = value.mappings.find(({ targetPath }) => targetPath.join(".") === value.identityPath.join("."));
1914
+ if (identityMapping?.source.kind === "collection-length") {
1915
+ context.addIssue({
1916
+ code: "custom",
1917
+ path: ["identityPath"],
1918
+ message: "A projected item identity must come from the verified result or a declared constant.",
1919
+ });
1920
+ }
1921
+ if (value.operation === "remove-exact" && value.mappings.length !== 1) {
1922
+ context.addIssue({
1923
+ code: "custom",
1924
+ path: ["mappings"],
1925
+ message: "An exact removal declares only the verified identity mapping used to remove one item.",
1926
+ });
1927
+ }
1928
+ });
1929
+ exports.ActionResultClipboardEffectSchema = zod_1.z
1930
+ .object({
1931
+ source: zod_1.z
1932
+ .object({
1933
+ kind: zod_1.z.literal("result-field"),
1934
+ path: zod_1.z
1935
+ .string()
1936
+ .trim()
1937
+ .regex(/^[A-Za-z0-9_.-]+$/),
1938
+ })
1939
+ .strict(),
1940
+ copiedToast: exports.I18nTextSchema.optional(),
1941
+ fallbackToast: exports.I18nTextSchema.superRefine((value, context) => {
1942
+ for (const [locale, message] of Object.entries(value.values)) {
1943
+ if (!message.includes("{value}")) {
1944
+ context.addIssue({
1945
+ code: "custom",
1946
+ path: ["values", locale],
1947
+ message: "Clipboard fallback feedback must visibly include the exact verified value placeholder.",
1948
+ });
1949
+ }
1950
+ }
1951
+ }),
1952
+ })
1953
+ .strict();
1954
+ exports.ActionBindingSchema = zod_1.z
1955
+ .object({
1956
+ bindingId: common_1.ContractIdentifierSchema,
1957
+ commandRevisionRef: exports.RevisionRefSchema,
1958
+ source: zod_1.z
1959
+ .object({
1960
+ capabilityInstanceId: common_1.ContractIdentifierSchema,
1961
+ port: common_1.ContractIdentifierSchema,
1962
+ })
1963
+ .strict(),
1964
+ sourceIntentSchemaRevisionRef: exports.RevisionRefSchema,
1965
+ inputSchemaRevisionRef: exports.RevisionRefSchema,
1966
+ when: page_expression_1.PageExpressionSchema.optional(),
1967
+ fileInputs: zod_1.z.array(ActionFileInputSchema).min(1).max(4).optional(),
1968
+ inputMapping: zod_1.z.record(common_1.ContractIdentifierSchema, ActionInputBindingSourceSchema),
1969
+ sensitiveInputPaths: common_1.SensitiveResultPathsSchema.optional(),
1970
+ accessPolicy: exports.AccessPolicySchema,
1971
+ confirmation: exports.I18nTextSchema.optional(),
1972
+ idempotencyKeySource: zod_1.z.enum([
1973
+ "interaction",
1974
+ "record-and-interaction",
1975
+ "caller-provided",
1976
+ ]),
1977
+ compensationCommandRevisionRef: exports.RevisionRefSchema.optional(),
1978
+ resultSchemaRevisionRef: exports.RevisionRefSchema,
1979
+ success: zod_1.z
1980
+ .object({
1981
+ download: zod_1.z
1982
+ .discriminatedUnion("kind", [
1983
+ zod_1.z.object({ kind: zod_1.z.literal("native") }).strict(),
1984
+ zod_1.z
1985
+ .object({
1986
+ kind: zod_1.z.literal("text-artifact"),
1987
+ fileNamePath: page_expression_1.PageValuePathSchema.min(1),
1988
+ mimeTypePath: page_expression_1.PageValuePathSchema.min(1),
1989
+ contentPath: page_expression_1.PageValuePathSchema.min(1),
1990
+ maxBytes: zod_1.z.number().int().min(1).max(1048576),
1991
+ })
1992
+ .strict(),
1993
+ ])
1994
+ .optional(),
1995
+ refreshBindingIds: zod_1.z.array(common_1.ContractIdentifierSchema),
1996
+ ephemeralResult: zod_1.z
1997
+ .object({
1998
+ kind: zod_1.z.literal("one-time-value"),
1999
+ valuePath: common_1.SensitiveResultPathSchema,
2000
+ labelPath: common_1.SensitiveResultPathSchema,
2001
+ title: exports.I18nTextSchema,
2002
+ description: exports.I18nTextSchema,
2003
+ copySuccessToast: exports.I18nTextSchema,
2004
+ copyFailureToast: exports.I18nTextSchema,
2005
+ })
2006
+ .strict()
2007
+ .optional(),
2008
+ resultBindingEffects: zod_1.z
2009
+ .array(exports.ActionResultBindingEffectSchema)
2010
+ .max(64)
2011
+ .optional(),
2012
+ clipboard: exports.ActionResultClipboardEffectSchema.optional(),
2013
+ navigationTargetRef: exports.StableRefSchema.optional(),
2014
+ toast: exports.I18nTextSchema.optional(),
2015
+ })
2016
+ .strict(),
2017
+ recovery: zod_1.z.enum(["retry-safe", "compensating-command", "manual-review"]),
2018
+ lineageRequired: zod_1.z.literal(true),
2019
+ })
2020
+ .strict()
2021
+ .superRefine((value, context) => {
2022
+ const fileIds = new Set();
2023
+ for (const file of value.fileInputs ?? []) {
2024
+ if (fileIds.has(file.inputId))
2025
+ context.addIssue({
2026
+ code: "custom",
2027
+ path: ["fileInputs"],
2028
+ message: "File input ids must be unique.",
2029
+ });
2030
+ fileIds.add(file.inputId);
2031
+ if (!Object.values(value.inputMapping).some((source) => source.kind === "file-field" && source.fileInputId === file.inputId))
2032
+ context.addIssue({
2033
+ code: "custom",
2034
+ path: ["fileInputs"],
2035
+ message: "File inputs require an explicit governed input mapping.",
2036
+ });
2037
+ }
2038
+ for (const [name, source] of Object.entries(value.inputMapping))
2039
+ if (source.kind === "file-field") {
2040
+ const file = value.fileInputs?.find((file) => file.inputId === source.fileInputId);
2041
+ if ((source.path === "canonicalUri" && !file?.upload) ||
2042
+ (source.path === "content" && file?.upload))
2043
+ context.addIssue({
2044
+ code: "custom",
2045
+ path: ["inputMapping", name],
2046
+ message: "File field must match its declared transport mode.",
2047
+ });
2048
+ if (!fileIds.has(source.fileInputId))
2049
+ context.addIssue({
2050
+ code: "custom",
2051
+ path: ["inputMapping", name],
2052
+ message: "File fields must reference a declared file input.",
2053
+ });
2054
+ if (source.path === "content" &&
2055
+ !value.sensitiveInputPaths?.includes(`/${name}`))
2056
+ context.addIssue({
2057
+ code: "custom",
2058
+ path: ["sensitiveInputPaths"],
2059
+ message: "File content must be declared as a sensitive command input.",
2060
+ });
2061
+ }
2062
+ if (value.when)
2063
+ for (const read of (0, page_expression_1.collectPageExpressionReads)(value.when)) {
2064
+ if (!["intent", "state", "scope"].includes(read.root))
2065
+ context.addIssue({
2066
+ code: "custom",
2067
+ path: ["when"],
2068
+ message: "Action conditions may read only intent, declared Page state, and instance scope.",
2069
+ });
2070
+ }
2071
+ if (value.success.ephemeralResult) {
2072
+ const { valuePath, labelPath } = value.success.ephemeralResult;
2073
+ const segments = (path) => path.split("/").slice(1);
2074
+ const valueSegments = segments(valuePath);
2075
+ const labelSegments = segments(labelPath);
2076
+ const sharedLength = Math.min(valueSegments.length, labelSegments.length);
2077
+ if (valueSegments
2078
+ .slice(0, sharedLength)
2079
+ .every((segment, index) => segment === labelSegments[index])) {
2080
+ context.addIssue({
2081
+ code: "custom",
2082
+ path: ["success", "ephemeralResult", "labelPath"],
2083
+ message: "One-time result labels cannot overlap the sensitive value path.",
2084
+ });
2085
+ }
2086
+ }
2087
+ if (value.success.ephemeralResult &&
2088
+ (value.success.resultBindingEffects?.length || 0) > 0) {
2089
+ context.addIssue({
2090
+ code: "custom",
2091
+ path: ["success", "resultBindingEffects"],
2092
+ message: "One-time result presentation cannot share a result with durable binding effects.",
2093
+ });
2094
+ }
2095
+ if (value.commandRevisionRef.kind !== "domain-command") {
2096
+ context.addIssue({
2097
+ code: "custom",
2098
+ path: ["commandRevisionRef", "kind"],
2099
+ message: "Action bindings must reference a domain-command revision.",
2100
+ });
2101
+ }
2102
+ if (value.sourceIntentSchemaRevisionRef.kind !== "schema") {
2103
+ context.addIssue({
2104
+ code: "custom",
2105
+ path: ["sourceIntentSchemaRevisionRef", "kind"],
2106
+ message: "Action source intents must pin a schema revision.",
2107
+ });
2108
+ }
2109
+ if (value.inputSchemaRevisionRef.kind !== "schema") {
2110
+ context.addIssue({
2111
+ code: "custom",
2112
+ path: ["inputSchemaRevisionRef", "kind"],
2113
+ message: "Action command inputs must pin a schema revision.",
2114
+ });
2115
+ }
2116
+ if (value.recovery === "compensating-command" &&
2117
+ !value.compensationCommandRevisionRef) {
2118
+ context.addIssue({
2119
+ code: "custom",
2120
+ path: ["compensationCommandRevisionRef"],
2121
+ message: "Compensating recovery requires a compensation command.",
2122
+ });
2123
+ }
2124
+ });
2125
+ exports.PageMigrationEquivalenceDimensionSchema = zod_1.z.enum([
2126
+ "url",
2127
+ "navigation",
2128
+ "access",
2129
+ "deep-link",
2130
+ "layout",
2131
+ "size",
2132
+ "spacing",
2133
+ "design-tokens",
2134
+ "responsive",
2135
+ "view-modes",
2136
+ "search-filter",
2137
+ "editing",
2138
+ "detail",
2139
+ "history",
2140
+ "dialogs",
2141
+ "keyboard",
2142
+ "loading",
2143
+ "empty",
2144
+ "error",
2145
+ "forbidden",
2146
+ ]);
2147
+ exports.PageMigrationEquivalenceSchema = zod_1.z
2148
+ .object({
2149
+ contract: zod_1.z.literal("PageMigrationEquivalence"),
2150
+ schemaVersion: zod_1.z.literal(1),
2151
+ policy: zod_1.z.literal("preserve-ui-ux"),
2152
+ baseline: zod_1.z
2153
+ .object({
2154
+ repository: common_1.ContractIdentifierSchema,
2155
+ revision: zod_1.z.string().regex(/^[0-9a-f]{40}$/),
2156
+ pageId: common_1.ContractIdentifierSchema,
2157
+ routePath: exports.RoutePathTemplateSchema,
2158
+ })
2159
+ .strict(),
2160
+ protectedDimensions: zod_1.z
2161
+ .array(exports.PageMigrationEquivalenceDimensionSchema)
2162
+ .min(1),
2163
+ viewports: zod_1.z
2164
+ .array(zod_1.z
2165
+ .object({
2166
+ viewportId: common_1.ContractIdentifierSchema,
2167
+ width: zod_1.z.number().int().min(320).max(7680),
2168
+ height: zod_1.z.number().int().min(480).max(4320),
2169
+ })
2170
+ .strict())
2171
+ .min(2),
2172
+ scenarios: zod_1.z
2173
+ .array(zod_1.z
2174
+ .object({
2175
+ scenarioId: common_1.ContractIdentifierSchema,
2176
+ viewportIds: zod_1.z.array(common_1.ContractIdentifierSchema).min(1),
2177
+ })
2178
+ .strict())
2179
+ .min(1),
2180
+ evidence: zod_1.z
2181
+ .object({
2182
+ sideBySideVisual: zod_1.z.literal(true),
2183
+ domSnapshot: zod_1.z.literal(true),
2184
+ consoleErrors: zod_1.z.literal("none"),
2185
+ })
2186
+ .strict(),
2187
+ allowedDifferences: zod_1.z.array(zod_1.z
2188
+ .object({
2189
+ differenceId: common_1.ContractIdentifierSchema,
2190
+ requirementRevisionRef: exports.RevisionRefSchema,
2191
+ })
2192
+ .strict()),
2193
+ })
2194
+ .strict()
2195
+ .superRefine((value, context) => {
2196
+ if (uniqueArray(value.protectedDimensions, (candidate) => candidate)) {
2197
+ context.addIssue({
2198
+ code: "custom",
2199
+ path: ["protectedDimensions"],
2200
+ message: "Protected UI/UX dimensions must be unique.",
2201
+ });
2202
+ }
2203
+ if (uniqueArray(value.viewports, (candidate) => candidate.viewportId)) {
2204
+ context.addIssue({
2205
+ code: "custom",
2206
+ path: ["viewports"],
2207
+ message: "Migration equivalence viewport identities must be unique.",
2208
+ });
2209
+ }
2210
+ if (uniqueArray(value.scenarios, (candidate) => candidate.scenarioId)) {
2211
+ context.addIssue({
2212
+ code: "custom",
2213
+ path: ["scenarios"],
2214
+ message: "Migration equivalence scenario identities must be unique.",
2215
+ });
2216
+ }
2217
+ const viewportIds = new Set(value.viewports.map((viewport) => viewport.viewportId));
2218
+ value.scenarios.forEach((scenario, index) => {
2219
+ scenario.viewportIds.forEach((viewportId, viewportIndex) => {
2220
+ if (!viewportIds.has(viewportId)) {
2221
+ context.addIssue({
2222
+ code: "custom",
2223
+ path: ["scenarios", index, "viewportIds", viewportIndex],
2224
+ message: `Migration equivalence scenario references unknown viewport ${viewportId}.`,
2225
+ });
2226
+ }
2227
+ });
2228
+ });
2229
+ });
2230
+ exports.PageRouteStatePresentationSchema = zod_1.z
2231
+ .object({
2232
+ surface: exports.ProductSurfaceSchema,
2233
+ state: zod_1.z.literal("forbidden"),
2234
+ kind: zod_1.z.literal("status"),
2235
+ presentation: zod_1.z.enum(["panel", "page"]),
2236
+ title: exports.I18nTextSchema,
2237
+ description: exports.I18nTextSchema.optional(),
2238
+ })
2239
+ .strict()
2240
+ .superRefine((value, context) => {
2241
+ const localizedFields = [
2242
+ ["title", value.title, 160],
2243
+ ["description", value.description, 1000],
2244
+ ];
2245
+ localizedFields.forEach(([field, copy, maxLength]) => {
2246
+ if (!copy)
2247
+ return;
2248
+ const entries = Object.entries(copy.values);
2249
+ if (entries.length > 16) {
2250
+ context.addIssue({
2251
+ code: "custom",
2252
+ path: [field, "values"],
2253
+ message: "Route-state presentation copy supports at most 16 locales.",
2254
+ });
2255
+ }
2256
+ entries.forEach(([locale, text]) => {
2257
+ if (text.length > maxLength) {
2258
+ context.addIssue({
2259
+ code: "custom",
2260
+ path: [field, "values", locale],
2261
+ message: `Route-state ${field} copy must contain at most ${maxLength} characters.`,
2262
+ });
2263
+ }
2264
+ });
2265
+ });
2266
+ });
2267
+ exports.PageStateSchema = exports.PageStateDefinitionSchema.omit({
2268
+ schemaRevisionRef: true,
2269
+ })
2270
+ .extend({
2271
+ stateId: common_1.ContractIdentifierSchema,
2272
+ schema: common_1.ContractIdentifierSchema,
2273
+ })
2274
+ .strict();
2275
+ exports.PageEntryTargetSchema = zod_1.z
2276
+ .object({
2277
+ kind: zod_1.z.enum(["page", "workbench"]),
2278
+ id: common_1.ContractIdentifierSchema,
2279
+ })
2280
+ .strict();
2281
+ exports.PageEntrySchema = exports.PageEntryTransitionSchema.omit({
2282
+ targetRef: true,
2283
+ })
2284
+ .extend({
2285
+ target: exports.PageEntryTargetSchema,
2286
+ })
2287
+ .strict();
2288
+ exports.PageInteractionSchema = exports.InteractionBindingSchema.omit({
2289
+ source: true,
2290
+ sourceIntentSchemaRevisionRef: true,
2291
+ sourceResultSchemaRevisionRef: true,
2292
+ })
2293
+ .extend({
2294
+ port: common_1.ContractIdentifierSchema,
2295
+ })
2296
+ .strict();
2297
+ const PageCursorWindowSchema = exports.CursorWindowBindingSchema.omit({
2298
+ pageChangeIntentSchemaRevisionRef: true,
2299
+ }).strict();
2300
+ const PageResultStateBindingSchema = exports.QueryResultStateBindingSchema.omit({
2301
+ targetStateSchemaRevisionRef: true,
2302
+ }).strict();
2303
+ exports.PageDataSchema = exports.QueryBindingSchema.omit({
2304
+ queryDefinitionRevisionRef: true,
2305
+ target: true,
2306
+ renderModelSchemaRevisionRef: true,
2307
+ targetProjection: true,
2308
+ streamTargetProjection: true,
2309
+ cursorWindow: true,
2310
+ resultStateBindings: true,
2311
+ })
2312
+ .extend({
2313
+ query: common_1.ContractIdentifierSchema,
2314
+ port: common_1.ContractIdentifierSchema,
2315
+ targetProjection: zod_1.z
2316
+ .object({ expression: page_expression_1.PageExpressionSchema })
2317
+ .strict()
2318
+ .optional(),
2319
+ streamTargetProjection: zod_1.z
2320
+ .object({ expression: page_expression_1.PageExpressionSchema })
2321
+ .strict()
2322
+ .optional(),
2323
+ cursorWindow: PageCursorWindowSchema.optional(),
2324
+ resultStateBindings: zod_1.z
2325
+ .array(PageResultStateBindingSchema)
2326
+ .max(32)
2327
+ .optional(),
2328
+ })
2329
+ .strict();
2330
+ exports.PageActionSchema = exports.ActionBindingSchema.omit({
2331
+ commandRevisionRef: true,
2332
+ source: true,
2333
+ sourceIntentSchemaRevisionRef: true,
2334
+ inputSchemaRevisionRef: true,
2335
+ compensationCommandRevisionRef: true,
2336
+ resultSchemaRevisionRef: true,
2337
+ })
2338
+ .extend({
2339
+ command: common_1.ContractIdentifierSchema,
2340
+ port: common_1.ContractIdentifierSchema,
2341
+ compensationCommand: common_1.ContractIdentifierSchema.optional(),
2342
+ })
2343
+ .strict();
2344
+ const PageEventEffectSchema = zod_1.z
2345
+ .object({
2346
+ port: common_1.ContractIdentifierSchema,
2347
+ refresh: zod_1.z.array(common_1.ContractIdentifierSchema).min(1).max(128),
2348
+ })
2349
+ .strict();
2350
+ exports.PageNodeSchema = zod_1.z.lazy(() => zod_1.z
2351
+ .object({
2352
+ id: common_1.ContractIdentifierSchema,
2353
+ component: common_1.ContractIdentifierSchema,
2354
+ kind: render_1.RenderNodeKindSchema.optional(),
2355
+ slot: common_1.ContractIdentifierSchema.optional(),
2356
+ props: common_1.JsonObjectSchema.optional(),
2357
+ bindings: zod_1.z.array(page_expression_1.PagePropertyBindingSchema).max(128).optional(),
2358
+ model: common_1.JsonObjectSchema.optional(),
2359
+ style: render_1.RenderStyleSchema.optional(),
2360
+ layout: render_1.RenderLayoutSchema.optional(),
2361
+ responsive: zod_1.z.array(render_1.RenderResponsiveRuleSchema).optional(),
2362
+ surface: render_1.RenderSurfaceSchema.optional(),
2363
+ scroll: render_1.RenderScrollSchema.optional(),
2364
+ activation: render_1.RenderActivationSchema.optional(),
2365
+ lifecycle: render_1.RenderLifecycleSchema.optional(),
2366
+ state: render_1.RenderNodeStateSchema.optional(),
2367
+ access: exports.AccessPolicySchema.optional(),
2368
+ activeWhen: exports.PageStateActivationSchema.optional(),
2369
+ repeat: zod_1.z
2370
+ .object({
2371
+ source: page_expression_1.PageExpressionSchema,
2372
+ keyPath: page_expression_1.PageValuePathSchema.min(1),
2373
+ limit: zod_1.z.number().int().min(1).max(1000).optional(),
2374
+ })
2375
+ .strict()
2376
+ .optional(),
2377
+ data: zod_1.z.array(exports.PageDataSchema).optional(),
2378
+ actions: zod_1.z.array(exports.PageActionSchema).optional(),
2379
+ on: zod_1.z.array(exports.PageInteractionSchema).optional(),
2380
+ effects: zod_1.z.array(PageEventEffectSchema).optional(),
2381
+ eventPayloads: zod_1.z
2382
+ .array(zod_1.z
2383
+ .object({
2384
+ port: common_1.ContractIdentifierSchema,
2385
+ expression: page_expression_1.PageExpressionSchema,
2386
+ })
2387
+ .strict())
2388
+ .optional(),
2389
+ children: zod_1.z.array(exports.PageNodeSchema).optional(),
2390
+ })
2391
+ .strict());
2392
+ exports.PageSchema = zod_1.z
2393
+ .object({
2394
+ contract: zod_1.z.literal("Page"),
2395
+ schemaVersion: zod_1.z.literal(exports.DECLARATIVE_CONTROL_SCHEMA_VERSION),
2396
+ pageId: common_1.ContractIdentifierSchema,
2397
+ tenantScope: exports.TenantScopeSchema,
2398
+ identity: IdentitySchema,
2399
+ surface: exports.ProductSurfaceSchema,
2400
+ route: exports.RoutePathTemplateSchema,
2401
+ routeSpace: common_1.ContractIdentifierSchema.optional(),
2402
+ lifecycle: exports.DeclarativeLifecycleSchema.default("active"),
2403
+ routeStatePresentations: zod_1.z
2404
+ .array(exports.PageRouteStatePresentationSchema)
2405
+ .max(8)
2406
+ .optional(),
2407
+ shell: common_1.ContractIdentifierSchema.optional(),
2408
+ body: exports.PageNodeSchema,
2409
+ state: zod_1.z.array(exports.PageStateSchema).optional(),
2410
+ entryTransitions: zod_1.z.array(exports.PageEntrySchema).optional(),
2411
+ access: exports.AccessPolicySchema,
2412
+ managementAccess: exports.ManagementAccessSchema,
2413
+ tokens: zod_1.z.array(common_1.ContractIdentifierSchema).optional(),
2414
+ performanceBudget: common_1.ContractIdentifierSchema.optional(),
2415
+ observationPolicy: common_1.ContractIdentifierSchema.optional(),
2416
+ privacyClassification: zod_1.z
2417
+ .enum(["public", "internal", "confidential", "restricted"])
2418
+ .default("internal"),
2419
+ })
2420
+ .strict()
2421
+ .superRefine((page, context) => {
2422
+ const ids = new Set();
2423
+ const dataIds = new Set();
2424
+ const actionIds = new Set();
2425
+ const interactionIds = new Set();
2426
+ const visit = (node, path) => {
2427
+ if (ids.has(node.id))
2428
+ context.addIssue({
2429
+ code: "custom",
2430
+ path: [...path, "id"],
2431
+ message: `Duplicate Page node id ${node.id}.`,
2432
+ });
2433
+ ids.add(node.id);
2434
+ for (const [field, values, target] of [
2435
+ ["data", node.data ?? [], dataIds],
2436
+ ["actions", node.actions ?? [], actionIds],
2437
+ ["on", node.on ?? [], interactionIds],
2438
+ ])
2439
+ for (const [index, value] of values.entries()) {
2440
+ if (target.has(value.bindingId))
2441
+ context.addIssue({
2442
+ code: "custom",
2443
+ path: [...path, field, index, "bindingId"],
2444
+ message: `Duplicate Page binding id ${value.bindingId}.`,
2445
+ });
2446
+ target.add(value.bindingId);
2447
+ }
2448
+ (node.children ?? []).forEach((child, index) => visit(child, [...path, "children", index]));
2449
+ };
2450
+ visit(page.body, ["body"]);
2451
+ const stateIds = (page.state ?? []).map((entry) => entry.stateId);
2452
+ if (new Set(stateIds).size !== stateIds.length)
2453
+ context.addIssue({
2454
+ code: "custom",
2455
+ path: ["state"],
2456
+ message: "Page state ids must be unique.",
2457
+ });
2458
+ });
2459
+ exports.ResolvedPageSchema = zod_1.z
2460
+ .object({
2461
+ contract: zod_1.z.literal("Page"),
2462
+ schemaVersion: zod_1.z.literal(exports.DECLARATIVE_CONTROL_SCHEMA_VERSION),
2463
+ pageId: common_1.ContractIdentifierSchema,
2464
+ tenantScope: exports.TenantScopeSchema,
2465
+ identity: IdentitySchema,
2466
+ supportedSurfaces: zod_1.z.array(exports.ProductSurfaceSchema).min(1),
2467
+ lifecycle: exports.DeclarativeLifecycleSchema,
2468
+ legacyRoutePolicy: legacy_route_1.LegacyRoutePolicySchema.optional(),
2469
+ migrationEquivalence: exports.PageMigrationEquivalenceSchema.optional(),
2470
+ routeStatePresentations: zod_1.z
2471
+ .array(exports.PageRouteStatePresentationSchema)
2472
+ .max(8)
2473
+ .optional(),
2474
+ routeClaims: zod_1.z
2475
+ .array(zod_1.z.union([
2476
+ exports.DeclarativeRouteClaimSchema,
2477
+ LegacyDeclarativeRouteClaimSchema,
2478
+ ]))
2479
+ .min(1),
2480
+ shellRevisionRef: exports.RevisionRefSchema,
2481
+ renderTree: render_1.RenderTreeSchema,
2482
+ capabilityInstances: zod_1.z.array(exports.CapabilityInstanceSchema).min(1),
2483
+ stateDefinitions: zod_1.z.array(exports.PageStateDefinitionSchema).optional(),
2484
+ entryTransitions: zod_1.z.array(exports.PageEntryTransitionSchema).optional(),
2485
+ interactionBindings: zod_1.z.array(exports.InteractionBindingSchema).optional(),
2486
+ ontologyBindings: zod_1.z.array(exports.OntologyBindingSchema),
2487
+ queryBindings: zod_1.z.array(exports.QueryBindingSchema).optional(),
2488
+ actionBindings: zod_1.z.array(exports.ActionBindingSchema),
2489
+ pageAccessPolicy: exports.AccessPolicySchema,
2490
+ managementAccess: exports.ManagementAccessSchema,
2491
+ tokenRevisionRefs: zod_1.z.array(exports.RevisionRefSchema).min(1),
2492
+ performanceBudgetRef: exports.RevisionRefSchema,
2493
+ observationPolicyRevisionRef: exports.RevisionRefSchema,
2494
+ privacyClassification: zod_1.z.enum([
2495
+ "public",
2496
+ "internal",
2497
+ "confidential",
2498
+ "restricted",
2499
+ ]),
2500
+ })
2501
+ .strict()
2502
+ .superRefine((value, context) => {
2503
+ validateDeclaredRouteSurfaces(value.supportedSurfaces, value.routeClaims, context);
2504
+ const routeStatePresentations = value.routeStatePresentations ?? [];
2505
+ if (uniqueArray(routeStatePresentations, (candidate) => `${candidate.surface}:${candidate.state}`)) {
2506
+ context.addIssue({
2507
+ code: "custom",
2508
+ path: ["routeStatePresentations"],
2509
+ message: "Page route-state presentations must be unique per surface and state.",
2510
+ });
2511
+ }
2512
+ routeStatePresentations.forEach((presentation, index) => {
2513
+ if (!value.supportedSurfaces.includes(presentation.surface)) {
2514
+ context.addIssue({
2515
+ code: "custom",
2516
+ path: ["routeStatePresentations", index, "surface"],
2517
+ message: "Page route-state presentation surface must be declared by supportedSurfaces.",
2518
+ });
2519
+ }
2520
+ });
2521
+ const stateDefinitions = value.stateDefinitions ?? [];
2522
+ const entryTransitions = value.entryTransitions ?? [];
2523
+ const interactionBindings = value.interactionBindings ?? [];
2524
+ const queryBindings = value.queryBindings ?? [];
2525
+ stateDefinitions.forEach((definition, index) => {
2526
+ const partitionStateId = definition.preferencePartitionStateId;
2527
+ const dynamicLegacySegments = definition.legacyBrowserPreferenceImport?.jsonPath?.filter((segment) => typeof segment !== "string") ?? [];
2528
+ if (!partitionStateId) {
2529
+ if (dynamicLegacySegments.length > 0) {
2530
+ context.addIssue({
2531
+ code: "custom",
2532
+ path: [
2533
+ "stateDefinitions",
2534
+ index,
2535
+ "legacyBrowserPreferenceImport",
2536
+ "jsonPath",
2537
+ ],
2538
+ message: "A dynamic legacy preference path requires a declared preference partition state.",
2539
+ });
2540
+ }
2541
+ return;
2542
+ }
2543
+ const partitionDefinition = stateDefinitions.find((candidate) => candidate.stateId === partitionStateId);
2544
+ if (partitionStateId === definition.stateId ||
2545
+ !partitionDefinition ||
2546
+ partitionDefinition.preferencePartitionStateId) {
2547
+ context.addIssue({
2548
+ code: "custom",
2549
+ path: ["stateDefinitions", index, "preferencePartitionStateId"],
2550
+ message: "Preference partitioning must reference a distinct, non-partitioned Page state.",
2551
+ });
2552
+ }
2553
+ definition.legacyBrowserPreferenceImport?.jsonPath?.forEach((segment, segmentIndex) => {
2554
+ if (typeof segment !== "string" &&
2555
+ segment.stateId !== partitionStateId) {
2556
+ context.addIssue({
2557
+ code: "custom",
2558
+ path: [
2559
+ "stateDefinitions",
2560
+ index,
2561
+ "legacyBrowserPreferenceImport",
2562
+ "jsonPath",
2563
+ segmentIndex,
2564
+ ],
2565
+ message: "A dynamic legacy preference path must use the declared preference partition state.",
2566
+ });
2567
+ }
2568
+ });
2569
+ });
2570
+ const uniqueness = [
2571
+ [
2572
+ "capabilityInstances",
2573
+ value.capabilityInstances,
2574
+ (candidate) => String(candidate.instanceId),
2575
+ ],
2576
+ [
2577
+ "stateDefinitions",
2578
+ stateDefinitions,
2579
+ (candidate) => String(candidate.stateId),
2580
+ ],
2581
+ [
2582
+ "entryTransitions",
2583
+ entryTransitions,
2584
+ (candidate) => String(candidate.transitionId),
2585
+ ],
2586
+ [
2587
+ "interactionBindings",
2588
+ interactionBindings,
2589
+ (candidate) => String(candidate.bindingId),
2590
+ ],
2591
+ [
2592
+ "ontologyBindings",
2593
+ value.ontologyBindings,
2594
+ (candidate) => String(candidate.bindingId),
2595
+ ],
2596
+ [
2597
+ "queryBindings",
2598
+ queryBindings,
2599
+ (candidate) => String(candidate.bindingId),
2600
+ ],
2601
+ [
2602
+ "actionBindings",
2603
+ value.actionBindings,
2604
+ (candidate) => String(candidate.bindingId),
2605
+ ],
2606
+ ];
2607
+ uniqueness.forEach(([field, values, identity]) => {
597
2608
  if (uniqueArray(values, identity))
598
- context.addIssue({ code: 'custom', path: [field], message: `${field} identities must be unique.` });
2609
+ context.addIssue({
2610
+ code: "custom",
2611
+ path: [field],
2612
+ message: `${field} identities must be unique.`,
2613
+ });
2614
+ });
2615
+ const instanceIds = new Set(value.capabilityInstances.map((instance) => instance.instanceId));
2616
+ const stateIds = new Set(stateDefinitions.map((state) => state.stateId));
2617
+ value.capabilityInstances.forEach((instance, index) => {
2618
+ const ports = new Set();
2619
+ const payloadPorts = new Set();
2620
+ instance.eventPayloadBindings?.forEach((binding, bindingIndex) => {
2621
+ const path = [
2622
+ "capabilityInstances",
2623
+ index,
2624
+ "eventPayloadBindings",
2625
+ bindingIndex,
2626
+ ];
2627
+ if (payloadPorts.has(binding.port))
2628
+ context.addIssue({
2629
+ code: "custom",
2630
+ path,
2631
+ message: "An event payload can have only one declarative projection.",
2632
+ });
2633
+ payloadPorts.add(binding.port);
2634
+ for (const read of (0, page_expression_1.collectPageExpressionReads)(binding.expression)) {
2635
+ if (read.root === "actions" ||
2636
+ read.root === "result" ||
2637
+ (read.root === "state" && !stateIds.has(read.path[0] ?? "")) ||
2638
+ (read.root === "bindings" &&
2639
+ ![...value.ontologyBindings, ...queryBindings].some((candidate) => candidate.bindingId === read.path[0])))
2640
+ context.addIssue({
2641
+ code: "custom",
2642
+ path,
2643
+ message: "Event payload projections require local event, model, scope, declared query results, or declared state.",
2644
+ });
2645
+ }
2646
+ });
2647
+ instance.eventEffects?.forEach((effect, effectIndex) => {
2648
+ const path = [
2649
+ "capabilityInstances",
2650
+ index,
2651
+ "eventEffects",
2652
+ effectIndex,
2653
+ ];
2654
+ if (effect.sourceIntentSchemaRevisionRef.kind !== "schema" ||
2655
+ ports.has(effect.sourcePort))
2656
+ context.addIssue({
2657
+ code: "custom",
2658
+ path,
2659
+ message: "Event effects require one exact source schema per output port.",
2660
+ });
2661
+ ports.add(effect.sourcePort);
2662
+ if (value.actionBindings.some((binding) => binding.source.capabilityInstanceId === instance.instanceId &&
2663
+ binding.source.port === effect.sourcePort))
2664
+ context.addIssue({
2665
+ code: "custom",
2666
+ path,
2667
+ message: "An Action output port must declare refresh effects through Action.success.",
2668
+ });
2669
+ for (const id of effect.refreshBindingIds)
2670
+ if (![...value.ontologyBindings, ...queryBindings].some((binding) => binding.bindingId === id))
2671
+ context.addIssue({
2672
+ code: "custom",
2673
+ path,
2674
+ message: "Event effect references an unknown query binding.",
2675
+ });
2676
+ });
2677
+ });
2678
+ const repeatNodes = new Set(value.renderTree.nodes
2679
+ .filter((node) => node.repeat)
2680
+ .map((node) => node.nodeId));
2681
+ stateDefinitions.forEach((definition, index) => {
2682
+ if (definition.scopeNodeId && !repeatNodes.has(definition.scopeNodeId))
2683
+ context.addIssue({
2684
+ code: "custom",
2685
+ path: ["stateDefinitions", index, "scopeNodeId"],
2686
+ message: "Instance state must reference an existing repeated RenderNode.",
2687
+ });
2688
+ if (definition.initialValue && !definition.scopeNodeId) {
2689
+ const expression = definition.initialValue;
2690
+ const source = expression.kind === "read"
2691
+ ? stateDefinitions.find((state) => state.stateId === expression.path[0] && !state.scopeNodeId)
2692
+ : undefined;
2693
+ if (!source ||
2694
+ source.initialValue ||
2695
+ !["tenant-preference", "url-with-tenant-preference"].includes(source.persistence))
2696
+ context.addIssue({
2697
+ code: "custom",
2698
+ path: ["stateDefinitions", index, "initialValue"],
2699
+ message: "Root initialization requires an independently hydrated tenant preference; initialization chains are forbidden.",
2700
+ });
2701
+ }
2702
+ if (definition.initialValue) {
2703
+ for (const read of (0, page_expression_1.collectPageExpressionReads)(definition.initialValue)) {
2704
+ if (!["scope", "state"].includes(read.root) ||
2705
+ (read.root === "state" &&
2706
+ !stateDefinitions.some((state) => state.stateId === read.path[0] && !state.scopeNodeId)))
2707
+ context.addIssue({
2708
+ code: "custom",
2709
+ path: ["stateDefinitions", index, "initialValue"],
2710
+ message: "Instance initial values can read only their item scope and declared Page state.",
2711
+ });
2712
+ }
2713
+ }
2714
+ });
2715
+ value.renderTree.nodes.forEach((node, index) => {
2716
+ if (!node.repeat)
2717
+ return;
2718
+ for (const read of (0, page_expression_1.collectPageExpressionReads)(node.repeat.source)) {
2719
+ if (read.root === "actions" ||
2720
+ read.root === "intent" ||
2721
+ read.root === "result" ||
2722
+ read.root === "model" ||
2723
+ (read.root === "state" && !stateIds.has(read.path[0] ?? "")) ||
2724
+ (read.root === "bindings" &&
2725
+ ![...value.ontologyBindings, ...queryBindings].some((binding) => binding.bindingId === read.path[0])))
2726
+ context.addIssue({
2727
+ code: "custom",
2728
+ path: ["renderTree", "nodes", index, "repeat", "source"],
2729
+ message: "Repeated nodes require declared Page state, query results, or parent item scope.",
2730
+ });
2731
+ }
2732
+ });
2733
+ // A declaration can consume its own instance or ancestors, never an arbitrary sibling row.
2734
+ const renderNodesById = new Map(value.renderTree.nodes.map((node) => [node.nodeId, node]));
2735
+ const instanceNodes = new Map(value.capabilityInstances.map((instance) => [
2736
+ instance.instanceId,
2737
+ instance.nodeId,
2738
+ ]));
2739
+ const scopesForNode = (nodeId) => {
2740
+ const scopes = new Set();
2741
+ const visited = new Set();
2742
+ let node = nodeId ? renderNodesById.get(nodeId) : undefined;
2743
+ while (node && !visited.has(node.nodeId)) {
2744
+ visited.add(node.nodeId);
2745
+ if (node.repeat)
2746
+ scopes.add(node.nodeId);
2747
+ node = node.parentNodeId
2748
+ ? renderNodesById.get(node.parentNodeId)
2749
+ : undefined;
2750
+ }
2751
+ return scopes;
2752
+ };
2753
+ const queryOwners = new Map([...value.ontologyBindings, ...queryBindings].map((binding) => [
2754
+ binding.bindingId,
2755
+ [
2756
+ ...scopesForNode(instanceNodes.get(binding.target.capabilityInstanceId)),
2757
+ ][0],
2758
+ ]));
2759
+ const actionScopes = new Map(value.actionBindings.map((binding) => [
2760
+ binding.bindingId,
2761
+ scopesForNode(instanceNodes.get(binding.source.capabilityInstanceId)),
2762
+ ]));
2763
+ const actionOwners = new Map([...actionScopes].map(([id, scopes]) => [id, [...scopes][0]]));
2764
+ if (actionOwners.size !== value.actionBindings.length)
2765
+ context.addIssue({
2766
+ code: "custom",
2767
+ path: ["actionBindings"],
2768
+ message: "Action binding identifiers must be unique.",
2769
+ });
2770
+ const checkScopedReads = (reads, scopes, path) => {
2771
+ for (const read of reads) {
2772
+ const owner = read.root === "state"
2773
+ ? stateDefinitions.find((state) => state.stateId === read.path[0])
2774
+ ?.scopeNodeId
2775
+ : read.root === "bindings"
2776
+ ? queryOwners.get(read.path[0])
2777
+ : read.root === "actions"
2778
+ ? actionOwners.get(read.path[0])
2779
+ : undefined;
2780
+ // A parent may observe only aggregate pending for its descendant action scopes.
2781
+ // Error codes and individual row state remain scoped; unrelated repeat branches cannot aggregate.
2782
+ const pendingAggregate = read.root === "actions" &&
2783
+ read.path.length === 2 &&
2784
+ read.path[1] === "pending" &&
2785
+ actionScopes.has(read.path[0]) &&
2786
+ [...scopes].every((scope) => actionScopes.get(read.path[0]).has(scope));
2787
+ if (owner && !scopes.has(owner) && !pendingAggregate)
2788
+ context.addIssue({
2789
+ code: "custom",
2790
+ path,
2791
+ message: "A binding cannot read state, query results, or individual action status from a sibling or descendant instance.",
2792
+ });
2793
+ }
2794
+ };
2795
+ const checkScopedSources = (sources, scopes, path) => {
2796
+ Object.entries(sources).forEach(([name, source]) => {
2797
+ if (source.kind === "expression")
2798
+ checkScopedReads((0, page_expression_1.collectPageExpressionReads)(source.expression), scopes, [...path, name]);
2799
+ if (source.kind === "page-state")
2800
+ checkScopedReads([{ kind: "read", root: "state", path: [source.stateId] }], scopes, [...path, name]);
2801
+ if (source.kind === "binding-field")
2802
+ checkScopedReads([{ kind: "read", root: "bindings", path: [source.bindingId] }], scopes, [...path, name]);
2803
+ if (source.kind === "scope-field" && scopes.size === 0)
2804
+ context.addIssue({
2805
+ code: "custom",
2806
+ path: [...path, name],
2807
+ message: "A scope field requires a repeated instance.",
2808
+ });
2809
+ });
2810
+ };
2811
+ value.capabilityInstances.forEach((instance, index) => instance.eventPayloadBindings?.forEach((binding, bindingIndex) => checkScopedReads((0, page_expression_1.collectPageExpressionReads)(binding.expression), scopesForNode(instance.nodeId), ["capabilityInstances", index, "eventPayloadBindings", bindingIndex])));
2812
+ value.capabilityInstances.forEach((instance, index) => instance.propertyBindings?.forEach((binding, bindingIndex) => {
2813
+ checkScopedReads((0, page_expression_1.collectPageExpressionReads)(binding.expression), scopesForNode(instance.nodeId), ["capabilityInstances", index, "propertyBindings", bindingIndex]);
2814
+ }));
2815
+ for (const [collection, bindings] of [
2816
+ ["ontologyBindings", value.ontologyBindings],
2817
+ ["queryBindings", queryBindings],
2818
+ ]) {
2819
+ bindings.forEach((binding, index) => checkScopedSources(binding.parameters, scopesForNode(instanceNodes.get(binding.target.capabilityInstanceId)), [collection, index, "parameters"]));
2820
+ }
2821
+ value.actionBindings.forEach((binding, index) => {
2822
+ const scopes = scopesForNode(instanceNodes.get(binding.source.capabilityInstanceId));
2823
+ checkScopedSources(binding.inputMapping, scopes, [
2824
+ "actionBindings",
2825
+ index,
2826
+ "inputMapping",
2827
+ ]);
2828
+ for (const [fileIndex, file] of (binding.fileInputs ?? []).entries()) {
2829
+ if (file.source.kind === "page-state") {
2830
+ const stateId = file.source.stateId;
2831
+ const state = stateDefinitions.find((candidate) => candidate.stateId === stateId);
2832
+ if (!state || state.persistence !== "none")
2833
+ context.addIssue({
2834
+ code: "custom",
2835
+ path: ["actionBindings", index, "fileInputs", fileIndex],
2836
+ message: "File handles require declared nonpersistent Page state.",
2837
+ });
2838
+ checkScopedSources({ file: file.source }, scopes, [
2839
+ "actionBindings",
2840
+ index,
2841
+ "fileInputs",
2842
+ fileIndex,
2843
+ ]);
2844
+ }
2845
+ }
2846
+ if (binding.when) {
2847
+ const reads = (0, page_expression_1.collectPageExpressionReads)(binding.when);
2848
+ checkScopedReads(reads, scopes, ["actionBindings", index, "when"]);
2849
+ for (const read of reads)
2850
+ if (read.root === "state" && !stateIds.has(read.path[0]))
2851
+ context.addIssue({
2852
+ code: "custom",
2853
+ path: ["actionBindings", index, "when"],
2854
+ message: "Action condition references an unknown Page state.",
2855
+ });
2856
+ }
2857
+ });
2858
+ interactionBindings.forEach((binding, index) => {
2859
+ const sourceScopes = scopesForNode(instanceNodes.get(binding.source.capabilityInstanceId));
2860
+ const targetScope = stateDefinitions.find((state) => state.stateId === binding.targetStateId)?.scopeNodeId;
2861
+ if (targetScope && !sourceScopes.has(targetScope))
2862
+ context.addIssue({
2863
+ code: "custom",
2864
+ path: ["interactionBindings", index, "targetStateId"],
2865
+ message: "An interaction must target its own instance or an ancestor.",
2866
+ });
2867
+ checkScopedSources(binding.inputMapping, targetScope ? scopesForNode(targetScope) : new Set(), ["interactionBindings", index, "inputMapping"]);
2868
+ });
2869
+ value.renderTree.nodes.forEach((node, index) => {
2870
+ if (node.repeat)
2871
+ checkScopedReads((0, page_expression_1.collectPageExpressionReads)(node.repeat.source), scopesForNode(node.parentNodeId), ["renderTree", "nodes", index, "repeat", "source"]);
2872
+ });
2873
+ entryTransitions.forEach((transition, transitionIndex) => {
2874
+ if (transition.gestureSource &&
2875
+ (!instanceIds.has(transition.gestureSource.capabilityInstanceId) ||
2876
+ !interactionBindings.some((binding) => binding.source.capabilityInstanceId ===
2877
+ transition.gestureSource.capabilityInstanceId &&
2878
+ binding.source.port === transition.gestureSource.port))) {
2879
+ context.addIssue({
2880
+ code: "custom",
2881
+ path: ["entryTransitions", transitionIndex, "gestureSource"],
2882
+ message: "Entry gesture source must match an existing capability interaction source.",
2883
+ });
2884
+ }
2885
+ if (transition.targetRef.kind === "page" &&
2886
+ transition.targetRef.id === value.pageId) {
2887
+ context.addIssue({
2888
+ code: "custom",
2889
+ path: ["entryTransitions", transitionIndex, "targetRef"],
2890
+ message: "A Page cannot route into itself on entry.",
2891
+ });
2892
+ }
2893
+ forEachPageStateCondition(transition.activation, (condition, conditionPath) => {
2894
+ if (!stateIds.has(condition.stateId)) {
2895
+ context.addIssue({
2896
+ code: "custom",
2897
+ path: [
2898
+ "entryTransitions",
2899
+ transitionIndex,
2900
+ "activation",
2901
+ ...conditionPath,
2902
+ "stateId",
2903
+ ],
2904
+ message: `Entry transition references unknown Page state ${condition.stateId}.`,
2905
+ });
2906
+ }
2907
+ });
2908
+ const declaredRouteParameters = new Set(value.routeClaims.flatMap((claim) => [...claim.pathTemplate.matchAll(/:([A-Za-z][A-Za-z0-9_-]*)/g)].map((match) => match[1])));
2909
+ for (const source of [
2910
+ ...Object.values(transition.pathParameters),
2911
+ ...Object.values(transition.query.set),
2912
+ ]) {
2913
+ if (source.kind === "route-parameter" &&
2914
+ !declaredRouteParameters.has(source.name)) {
2915
+ context.addIssue({
2916
+ code: "custom",
2917
+ path: ["entryTransitions", transitionIndex],
2918
+ message: `Entry transition references unknown source route parameter ${source.name}.`,
2919
+ });
2920
+ }
2921
+ }
2922
+ const stateSources = [
2923
+ ...Object.values(transition.pathParameters).flatMap((source) => source.kind === "page-state" ? [source.stateId] : []),
2924
+ ...Object.values(transition.query.set).flatMap((source) => source.kind === "page-state" ? [source.stateId] : []),
2925
+ ];
2926
+ stateSources.forEach((stateId) => {
2927
+ if (!stateIds.has(stateId)) {
2928
+ context.addIssue({
2929
+ code: "custom",
2930
+ path: ["entryTransitions", transitionIndex],
2931
+ message: `Entry transition references unknown Page state ${stateId}.`,
2932
+ });
2933
+ }
2934
+ });
2935
+ });
2936
+ const validatePageStateSources = (sources, path) => {
2937
+ Object.entries(sources).forEach(([name, source]) => {
2938
+ if (source.kind === "expression") {
2939
+ for (const read of (0, page_expression_1.collectPageExpressionReads)(source.expression)) {
2940
+ if ((read.root === "state" &&
2941
+ (!read.path[0] || !stateIds.has(read.path[0]))) ||
2942
+ read.root === "model" ||
2943
+ read.root === "bindings" ||
2944
+ (read.root === "result" && path[0] !== "interactionBindings")) {
2945
+ context.addIssue({
2946
+ code: "custom",
2947
+ path: [...path, name, "expression"],
2948
+ message: "Expression references unavailable context or an undeclared Page state.",
2949
+ });
2950
+ }
2951
+ }
2952
+ }
2953
+ if (source.kind === "page-state" && !stateIds.has(source.stateId)) {
2954
+ context.addIssue({
2955
+ code: "custom",
2956
+ path: [...path, name, "stateId"],
2957
+ message: `Unknown Page state: ${source.stateId}`,
2958
+ });
2959
+ }
2960
+ });
2961
+ };
2962
+ interactionBindings.forEach((binding, index) => {
2963
+ if (!instanceIds.has(binding.source.capabilityInstanceId)) {
2964
+ context.addIssue({
2965
+ code: "custom",
2966
+ path: [
2967
+ "interactionBindings",
2968
+ index,
2969
+ "source",
2970
+ "capabilityInstanceId",
2971
+ ],
2972
+ message: "Interaction binding sources an unknown capability instance.",
2973
+ });
2974
+ }
2975
+ if (!stateIds.has(binding.targetStateId)) {
2976
+ context.addIssue({
2977
+ code: "custom",
2978
+ path: ["interactionBindings", index, "targetStateId"],
2979
+ message: "Interaction binding targets an unknown Page state.",
2980
+ });
2981
+ }
2982
+ validatePageStateSources(binding.inputMapping, [
2983
+ "interactionBindings",
2984
+ index,
2985
+ "inputMapping",
2986
+ ]);
2987
+ if (Object.values(binding.inputMapping).some((source) => source.kind === "result-field" ||
2988
+ (source.kind === "expression" &&
2989
+ (0, page_expression_1.collectPageExpressionReads)(source.expression).some((read) => read.root === "result")))) {
2990
+ const action = value.actionBindings.find((candidate) => candidate.source.capabilityInstanceId ===
2991
+ binding.source.capabilityInstanceId &&
2992
+ candidate.source.port === binding.source.port);
2993
+ if (!action) {
2994
+ context.addIssue({
2995
+ code: "custom",
2996
+ path: ["interactionBindings", index, "source"],
2997
+ message: "Result-field interactions must source one declared Action binding.",
2998
+ });
2999
+ }
3000
+ else if (!binding.sourceResultSchemaRevisionRef ||
3001
+ !exactRevisionRef(binding.sourceResultSchemaRevisionRef, action.resultSchemaRevisionRef)) {
3002
+ context.addIssue({
3003
+ code: "custom",
3004
+ path: [
3005
+ "interactionBindings",
3006
+ index,
3007
+ "sourceResultSchemaRevisionRef",
3008
+ ],
3009
+ message: "Interaction result schema must exactly match the sourced Action result schema.",
3010
+ });
3011
+ }
3012
+ }
3013
+ });
3014
+ value.capabilityInstances.forEach((instance, index) => {
3015
+ const paths = [];
3016
+ instance.propertyBindings?.forEach((binding, bindingIndex) => {
3017
+ const path = [
3018
+ "capabilityInstances",
3019
+ index,
3020
+ "propertyBindings",
3021
+ bindingIndex,
3022
+ ];
3023
+ if (instance.capabilityRevisionRef.id.startsWith("monkeys.design.component.")) {
3024
+ const [group, member, field] = binding.targetPath;
3025
+ const messages = instance.properties.messages;
3026
+ const message = messages && typeof messages === "object" && !Array.isArray(messages)
3027
+ ? messages[member]
3028
+ : undefined;
3029
+ const declaredMessage = message && typeof message === "object" && !Array.isArray(message);
3030
+ const allowed = (group === "props" && binding.targetPath.length >= 2) ||
3031
+ (group === "messages" &&
3032
+ declaredMessage &&
3033
+ ((field === "values" && binding.targetPath.length >= 3) ||
3034
+ (binding.targetPath.length === 3 &&
3035
+ (field === "key" || field === "textI18n") &&
3036
+ Object.prototype.hasOwnProperty.call(message, field))));
3037
+ if (!allowed)
3038
+ context.addIssue({
3039
+ code: "custom",
3040
+ path: [...path, "targetPath"],
3041
+ message: "Component expressions can update property values or declared message fields, never executable wiring.",
3042
+ });
3043
+ }
3044
+ if (paths.some((previous) => previous
3045
+ .slice(0, Math.min(previous.length, binding.targetPath.length))
3046
+ .every((key, i) => key === binding.targetPath[i]))) {
3047
+ context.addIssue({
3048
+ code: "custom",
3049
+ path: [...path, "targetPath"],
3050
+ message: "Dynamic property targets must not overlap.",
3051
+ });
3052
+ }
3053
+ paths.push(binding.targetPath);
3054
+ (0, page_expression_1.visitPageExpression)(binding.expression, (expression) => {
3055
+ if (expression.kind !== "read")
3056
+ return;
3057
+ if (expression.root === "state" &&
3058
+ (!expression.path[0] || !stateIds.has(expression.path[0]))) {
3059
+ context.addIssue({
3060
+ code: "custom",
3061
+ path: [...path, "expression"],
3062
+ message: "Property expressions must reference a declared Page state.",
3063
+ });
3064
+ }
3065
+ if (expression.root === "bindings" &&
3066
+ ![...value.ontologyBindings, ...queryBindings].some((candidate) => candidate.bindingId === expression.path[0])) {
3067
+ context.addIssue({
3068
+ code: "custom",
3069
+ path: [...path, "expression"],
3070
+ message: "Property expressions must reference a declared Page query binding.",
3071
+ });
3072
+ }
3073
+ if (expression.root === "actions" &&
3074
+ (expression.path.length !== 2 ||
3075
+ !actionOwners.has(expression.path[0]) ||
3076
+ !["pending", "errorCode"].includes(expression.path[1]))) {
3077
+ context.addIssue({
3078
+ code: "custom",
3079
+ path: [...path, "expression"],
3080
+ message: "Property expressions may read only pending or errorCode from a declared Action binding.",
3081
+ });
3082
+ }
3083
+ if (expression.root === "intent" || expression.root === "result") {
3084
+ context.addIssue({
3085
+ code: "custom",
3086
+ path: [...path, "expression"],
3087
+ message: "Property expressions cannot read transient event or Action results.",
3088
+ });
3089
+ }
3090
+ });
3091
+ });
3092
+ if (!instance.activationWhen)
3093
+ return;
3094
+ forEachPageStateCondition(instance.activationWhen, (condition, conditionPath) => {
3095
+ if (!stateIds.has(condition.stateId)) {
3096
+ context.addIssue({
3097
+ code: "custom",
3098
+ path: [
3099
+ "capabilityInstances",
3100
+ index,
3101
+ "activationWhen",
3102
+ ...conditionPath,
3103
+ "stateId",
3104
+ ],
3105
+ message: "Capability activation condition references an unknown Page state.",
3106
+ });
3107
+ }
3108
+ });
599
3109
  });
600
- const instanceIds = new Set(value.capabilityInstances.map((instance) => instance.instanceId));
601
3110
  value.ontologyBindings.forEach((binding, index) => {
602
3111
  if (!instanceIds.has(binding.target.capabilityInstanceId)) {
603
- context.addIssue({ code: 'custom', path: ['ontologyBindings', index, 'target', 'capabilityInstanceId'], message: 'Ontology binding targets an unknown capability instance.' });
3112
+ context.addIssue({
3113
+ code: "custom",
3114
+ path: ["ontologyBindings", index, "target", "capabilityInstanceId"],
3115
+ message: "Ontology binding targets an unknown capability instance.",
3116
+ });
3117
+ }
3118
+ validatePageStateSources(binding.parameters, [
3119
+ "ontologyBindings",
3120
+ index,
3121
+ "parameters",
3122
+ ]);
3123
+ });
3124
+ queryBindings.forEach((binding, index) => {
3125
+ if (!instanceIds.has(binding.target.capabilityInstanceId)) {
3126
+ context.addIssue({
3127
+ code: "custom",
3128
+ path: ["queryBindings", index, "target", "capabilityInstanceId"],
3129
+ message: "Query binding targets an unknown capability instance.",
3130
+ });
3131
+ }
3132
+ validatePageStateSources(binding.parameters, [
3133
+ "queryBindings",
3134
+ index,
3135
+ "parameters",
3136
+ ]);
3137
+ if (binding.queryWhen) {
3138
+ forEachPageStateCondition(binding.queryWhen, (condition, conditionPath) => {
3139
+ if (!stateIds.has(condition.stateId)) {
3140
+ context.addIssue({
3141
+ code: "custom",
3142
+ path: [
3143
+ "queryBindings",
3144
+ index,
3145
+ "queryWhen",
3146
+ ...conditionPath,
3147
+ "stateId",
3148
+ ],
3149
+ message: "Query activation condition references an unknown Page state.",
3150
+ });
3151
+ }
3152
+ });
3153
+ }
3154
+ if (binding.refreshPolicy?.when) {
3155
+ const path = ["queryBindings", index, "refreshPolicy", "when"];
3156
+ const reads = (0, page_expression_1.collectExternalPageExpressionReads)(binding.refreshPolicy.when);
3157
+ checkScopedReads(reads, scopesForNode(instanceNodes.get(binding.target.capabilityInstanceId)), path);
3158
+ for (const read of reads)
3159
+ if (read.root === "actions" && !actionScopes.has(read.path[0]))
3160
+ context.addIssue({
3161
+ code: "custom",
3162
+ path,
3163
+ message: "Automatic refresh condition references an unknown action binding.",
3164
+ });
3165
+ }
3166
+ const effectOwners = new Set(binding.stateEffects?.map((effect) => stateDefinitions.find((definition) => definition.stateId === effect.targetStateId)?.scopeNodeId ?? "") ?? []);
3167
+ if (effectOwners.size > 1)
3168
+ context.addIssue({
3169
+ code: "custom",
3170
+ path: ["queryBindings", index, "stateEffects"],
3171
+ message: "A query completion must update a single state owner atomically.",
3172
+ });
3173
+ binding.stateEffects?.forEach((effect, effectIndex) => {
3174
+ const path = ["queryBindings", index, "stateEffects", effectIndex];
3175
+ const state = stateDefinitions.find((definition) => definition.stateId === effect.targetStateId);
3176
+ const scopes = scopesForNode(instanceNodes.get(binding.target.capabilityInstanceId));
3177
+ if (!state || (state.scopeNodeId && !scopes.has(state.scopeNodeId)))
3178
+ context.addIssue({
3179
+ code: "custom",
3180
+ path: [...path, "targetStateId"],
3181
+ message: "A query effect must target declared state in its own scope or an ancestor.",
3182
+ });
3183
+ for (const expression of [
3184
+ effect.value,
3185
+ ...(effect.when ? [effect.when] : []),
3186
+ ]) {
3187
+ const reads = (0, page_expression_1.collectPageExpressionReads)(expression);
3188
+ checkScopedReads(reads, state?.scopeNodeId ? scopesForNode(state.scopeNodeId) : new Set(), path);
3189
+ for (const read of reads)
3190
+ if (read.root === "state" && !stateIds.has(read.path[0]))
3191
+ context.addIssue({
3192
+ code: "custom",
3193
+ path,
3194
+ message: "Query effect references an unknown Page state.",
3195
+ });
3196
+ }
3197
+ });
3198
+ binding.resultStateBindings?.forEach((resultBinding, resultIndex) => {
3199
+ const stateDefinition = stateDefinitions.find((definition) => definition.stateId === resultBinding.targetStateId);
3200
+ if (!stateDefinition) {
3201
+ context.addIssue({
3202
+ code: "custom",
3203
+ path: [
3204
+ "queryBindings",
3205
+ index,
3206
+ "resultStateBindings",
3207
+ resultIndex,
3208
+ "targetStateId",
3209
+ ],
3210
+ message: "Query result binding targets an unknown Page state.",
3211
+ });
3212
+ return;
3213
+ }
3214
+ if (!exactRevisionRef(resultBinding.targetStateSchemaRevisionRef, stateDefinition.schemaRevisionRef)) {
3215
+ context.addIssue({
3216
+ code: "custom",
3217
+ path: [
3218
+ "queryBindings",
3219
+ index,
3220
+ "resultStateBindings",
3221
+ resultIndex,
3222
+ "targetStateSchemaRevisionRef",
3223
+ ],
3224
+ message: "Query result binding must pin the exact target Page-state schema revision.",
3225
+ });
3226
+ }
3227
+ if (stateDefinition.persistence !== "none") {
3228
+ context.addIssue({
3229
+ code: "custom",
3230
+ path: [
3231
+ "queryBindings",
3232
+ index,
3233
+ "resultStateBindings",
3234
+ resultIndex,
3235
+ "targetStateId",
3236
+ ],
3237
+ message: "Query result state projections must target non-persistent Page state.",
3238
+ });
3239
+ }
3240
+ });
3241
+ });
3242
+ const dependencyBindings = [...value.ontologyBindings, ...queryBindings];
3243
+ (0, page_binding_dependencies_1.analyzePageBindingDependencies)(dependencyBindings).errors.forEach((error) => {
3244
+ const ontologyIndex = value.ontologyBindings.findIndex((binding) => binding.bindingId === error.bindingId);
3245
+ const collection = ontologyIndex >= 0 ? "ontologyBindings" : "queryBindings";
3246
+ const index = ontologyIndex >= 0
3247
+ ? ontologyIndex
3248
+ : queryBindings.findIndex((binding) => binding.bindingId === error.bindingId);
3249
+ context.addIssue({
3250
+ code: "custom",
3251
+ path: [collection, index, "parameters"],
3252
+ message: `Page binding dependency ${error.code}: ${error.dependencyId ?? error.bindingId}`,
3253
+ });
3254
+ });
3255
+ const projectedQueryStateIds = new Set();
3256
+ queryBindings.forEach((binding, index) => {
3257
+ binding.resultStateBindings?.forEach((resultBinding, resultIndex) => {
3258
+ if (projectedQueryStateIds.has(resultBinding.targetStateId)) {
3259
+ context.addIssue({
3260
+ code: "custom",
3261
+ path: [
3262
+ "queryBindings",
3263
+ index,
3264
+ "resultStateBindings",
3265
+ resultIndex,
3266
+ "targetStateId",
3267
+ ],
3268
+ message: "One Page state can have only one Server Query result owner.",
3269
+ });
3270
+ }
3271
+ projectedQueryStateIds.add(resultBinding.targetStateId);
3272
+ });
3273
+ });
3274
+ queryBindings.forEach((binding, index) => {
3275
+ if (binding.execution !== "server")
3276
+ return;
3277
+ const readStateIds = new Set(Object.values(binding.parameters).flatMap((source) => source.kind === "page-state" ? [source.stateId] : []));
3278
+ if (binding.queryWhen) {
3279
+ forEachPageStateCondition(binding.queryWhen, (condition) => readStateIds.add(condition.stateId));
3280
+ }
3281
+ const feedbackStateId = [...readStateIds].find((stateId) => projectedQueryStateIds.has(stateId));
3282
+ if (feedbackStateId) {
3283
+ context.addIssue({
3284
+ code: "custom",
3285
+ path: ["queryBindings", index],
3286
+ message: `Server Query bindings cannot read projected Query result state: ${feedbackStateId}`,
3287
+ });
3288
+ }
3289
+ });
3290
+ const cursorWindowBindings = [
3291
+ ...value.ontologyBindings.map((binding, index) => ({
3292
+ binding,
3293
+ index,
3294
+ collection: "ontologyBindings",
3295
+ })),
3296
+ ...queryBindings.map((binding, index) => ({
3297
+ binding,
3298
+ index,
3299
+ collection: "queryBindings",
3300
+ })),
3301
+ ].filter((candidate) => candidate.binding.cursorWindow !== undefined);
3302
+ const cursorWindowSources = new Set();
3303
+ cursorWindowBindings.forEach(({ binding, index, collection }) => {
3304
+ const sourceId = binding.cursorWindow.sourceCapabilityInstanceId ??
3305
+ binding.target.capabilityInstanceId;
3306
+ if (!instanceIds.has(sourceId))
3307
+ context.addIssue({
3308
+ code: "custom",
3309
+ path: [
3310
+ collection,
3311
+ index,
3312
+ "cursorWindow",
3313
+ "sourceCapabilityInstanceId",
3314
+ ],
3315
+ message: "Cursor-window source must reference a declared capability instance.",
3316
+ });
3317
+ const sourceScopes = [...scopesForNode(instanceNodes.get(sourceId))];
3318
+ const targetScopes = [
3319
+ ...scopesForNode(instanceNodes.get(binding.target.capabilityInstanceId)),
3320
+ ];
3321
+ if (sourceScopes.length !== targetScopes.length ||
3322
+ sourceScopes.some((id, index) => id !== targetScopes[index]))
3323
+ context.addIssue({
3324
+ code: "custom",
3325
+ path: [
3326
+ collection,
3327
+ index,
3328
+ "cursorWindow",
3329
+ "sourceCapabilityInstanceId",
3330
+ ],
3331
+ message: "Cursor-window source and query target must share the same repeated scope.",
3332
+ });
3333
+ const sourceKey = `${sourceId}:${binding.cursorWindow.pageChangePort}`;
3334
+ if (cursorWindowSources.has(sourceKey)) {
3335
+ context.addIssue({
3336
+ code: "custom",
3337
+ path: [collection, index, "cursorWindow", "pageChangePort"],
3338
+ message: "A capability output port can govern at most one cursor-window binding.",
3339
+ });
3340
+ }
3341
+ cursorWindowSources.add(sourceKey);
3342
+ const conflictingInteraction = interactionBindings.some((candidate) => candidate.source.capabilityInstanceId === sourceId &&
3343
+ candidate.source.port === binding.cursorWindow.pageChangePort);
3344
+ const conflictingAction = value.actionBindings.some((candidate) => candidate.source.capabilityInstanceId === sourceId &&
3345
+ candidate.source.port === binding.cursorWindow.pageChangePort);
3346
+ if (conflictingInteraction || conflictingAction) {
3347
+ context.addIssue({
3348
+ code: "custom",
3349
+ path: [collection, index, "cursorWindow", "pageChangePort"],
3350
+ message: "Cursor-window page-change ports cannot also drive Page state or Domain Actions.",
3351
+ });
604
3352
  }
605
3353
  });
606
3354
  value.actionBindings.forEach((binding, index) => {
607
3355
  if (!instanceIds.has(binding.source.capabilityInstanceId)) {
608
- context.addIssue({ code: 'custom', path: ['actionBindings', index, 'source', 'capabilityInstanceId'], message: 'Action binding sources an unknown capability instance.' });
3356
+ context.addIssue({
3357
+ code: "custom",
3358
+ path: ["actionBindings", index, "source", "capabilityInstanceId"],
3359
+ message: "Action binding sources an unknown capability instance.",
3360
+ });
609
3361
  }
3362
+ validatePageStateSources(binding.inputMapping, [
3363
+ "actionBindings",
3364
+ index,
3365
+ "inputMapping",
3366
+ ]);
610
3367
  binding.success.refreshBindingIds.forEach((bindingId) => {
611
- if (!value.ontologyBindings.some((candidate) => candidate.bindingId === bindingId)) {
612
- context.addIssue({ code: 'custom', path: ['actionBindings', index, 'success', 'refreshBindingIds'], message: `Unknown refresh binding: ${bindingId}` });
3368
+ if (!value.ontologyBindings.some((candidate) => candidate.bindingId === bindingId) &&
3369
+ !queryBindings.some((candidate) => candidate.bindingId === bindingId)) {
3370
+ context.addIssue({
3371
+ code: "custom",
3372
+ path: ["actionBindings", index, "success", "refreshBindingIds"],
3373
+ message: `Unknown refresh binding: ${bindingId}`,
3374
+ });
613
3375
  }
614
3376
  });
3377
+ const effectBindingIds = binding.success.resultBindingEffects?.map((effect) => effect.bindingId) ?? [];
3378
+ if (new Set(effectBindingIds).size !== effectBindingIds.length) {
3379
+ context.addIssue({
3380
+ code: "custom",
3381
+ path: ["actionBindings", index, "success", "resultBindingEffects"],
3382
+ message: "An Action can declare at most one result effect for each target binding.",
3383
+ });
3384
+ }
3385
+ binding.success.resultBindingEffects?.forEach((effect, effectIndex) => {
3386
+ if (!value.ontologyBindings.some((candidate) => candidate.bindingId === effect.bindingId) &&
3387
+ !queryBindings.some((candidate) => candidate.bindingId === effect.bindingId)) {
3388
+ context.addIssue({
3389
+ code: "custom",
3390
+ path: [
3391
+ "actionBindings",
3392
+ index,
3393
+ "success",
3394
+ "resultBindingEffects",
3395
+ effectIndex,
3396
+ "bindingId",
3397
+ ],
3398
+ message: `Unknown result effect binding: ${effect.bindingId}`,
3399
+ });
3400
+ }
3401
+ if (binding.success.refreshBindingIds.includes(effect.bindingId)) {
3402
+ context.addIssue({
3403
+ code: "custom",
3404
+ path: [
3405
+ "actionBindings",
3406
+ index,
3407
+ "success",
3408
+ "resultBindingEffects",
3409
+ effectIndex,
3410
+ "bindingId",
3411
+ ],
3412
+ message: "A result-projected binding cannot also be refreshed by the same Action.",
3413
+ });
3414
+ }
3415
+ });
3416
+ if (binding.success.clipboard) {
3417
+ const sourceInstance = value.capabilityInstances.find((instance) => instance.instanceId === binding.source.capabilityInstanceId);
3418
+ if (!sourceInstance?.allowedSideEffects.includes("clipboard"))
3419
+ context.addIssue({
3420
+ code: "custom",
3421
+ path: ["actionBindings", index, "success", "clipboard"],
3422
+ message: "An Action result clipboard effect requires clipboard permission on its source capability instance.",
3423
+ });
3424
+ }
615
3425
  });
616
- if (value.shellRevisionRef.kind !== 'shell')
617
- context.addIssue({ code: 'custom', path: ['shellRevisionRef', 'kind'], message: 'Page shellRevisionRef must reference a shell.' });
3426
+ if (value.shellRevisionRef.kind !== "shell")
3427
+ context.addIssue({
3428
+ code: "custom",
3429
+ path: ["shellRevisionRef", "kind"],
3430
+ message: "Page shellRevisionRef must reference a shell.",
3431
+ });
618
3432
  value.capabilityInstances.forEach((instance, index) => {
3433
+ if (instance.accessPolicy) {
3434
+ [
3435
+ ...instance.accessPolicy.groupAllOf,
3436
+ ...instance.accessPolicy.groupAnyOf,
3437
+ ...instance.accessPolicy.conditionAllOf,
3438
+ ].forEach((reference, refIndex) => validateTenantCompatibleReference(reference, value.tenantScope, ["capabilityInstances", index, "accessPolicy", refIndex], context));
3439
+ }
619
3440
  const refs = [
620
- ['capabilityRevisionRef', instance.capabilityRevisionRef, 'capability'],
621
- ['providerRevisionRef', instance.providerRevisionRef, 'view-provider'],
622
- ['propertySchemaRevisionRef', instance.propertySchemaRevisionRef, 'schema'],
3441
+ ["capabilityRevisionRef", instance.capabilityRevisionRef, "capability"],
3442
+ ["providerRevisionRef", instance.providerRevisionRef, "view-provider"],
3443
+ [
3444
+ "propertySchemaRevisionRef",
3445
+ instance.propertySchemaRevisionRef,
3446
+ "schema",
3447
+ ],
623
3448
  ];
624
3449
  refs.forEach(([field, reference, expectedKind]) => {
625
3450
  if (reference.kind !== expectedKind)
626
- context.addIssue({ code: 'custom', path: ['capabilityInstances', index, field, 'kind'], message: `${field} must reference ${expectedKind}.` });
3451
+ context.addIssue({
3452
+ code: "custom",
3453
+ path: ["capabilityInstances", index, field, "kind"],
3454
+ message: `${field} must reference ${expectedKind}.`,
3455
+ });
627
3456
  });
628
3457
  });
629
3458
  value.tokenRevisionRefs.forEach((reference, index) => {
630
- if (reference.kind !== 'design-token')
631
- context.addIssue({ code: 'custom', path: ['tokenRevisionRefs', index, 'kind'], message: 'Page token references must use kind design-token.' });
3459
+ if (reference.kind !== "design-token")
3460
+ context.addIssue({
3461
+ code: "custom",
3462
+ path: ["tokenRevisionRefs", index, "kind"],
3463
+ message: "Page token references must use kind design-token.",
3464
+ });
632
3465
  });
633
- if (value.performanceBudgetRef.kind !== 'performance-budget')
634
- context.addIssue({ code: 'custom', path: ['performanceBudgetRef', 'kind'], message: 'Page requires a performance-budget revision.' });
635
- if (value.observationPolicyRevisionRef.kind !== 'observation-policy')
636
- context.addIssue({ code: 'custom', path: ['observationPolicyRevisionRef', 'kind'], message: 'Page requires an observation-policy revision.' });
3466
+ if (value.performanceBudgetRef.kind !== "performance-budget")
3467
+ context.addIssue({
3468
+ code: "custom",
3469
+ path: ["performanceBudgetRef", "kind"],
3470
+ message: "Page requires a performance-budget revision.",
3471
+ });
3472
+ if (value.observationPolicyRevisionRef.kind !== "observation-policy")
3473
+ context.addIssue({
3474
+ code: "custom",
3475
+ path: ["observationPolicyRevisionRef", "kind"],
3476
+ message: "Page requires an observation-policy revision.",
3477
+ });
637
3478
  });
638
3479
  exports.PageReleaseSchema = zod_1.z
639
3480
  .object({
640
- contract: zod_1.z.literal('PageRelease'),
3481
+ contract: zod_1.z.literal("PageRelease"),
641
3482
  ...ReleaseBaseShape,
642
3483
  pageRevisionRef: exports.RevisionRefSchema,
643
- target: zod_1.z.object({
3484
+ target: zod_1.z
3485
+ .object({
644
3486
  environmentRef: exports.StableRefSchema,
645
3487
  surface: exports.ProductSurfaceSchema,
646
3488
  routeSpaceRevisionRef: exports.RevisionRefSchema,
647
3489
  normalizedPath: exports.RoutePathTemplateSchema,
648
- routeClaim: zod_1.z.union([exports.CompiledRouteClaimSchema, LegacyCompiledRouteClaimSchema]),
649
- }).strict(),
3490
+ routeClaim: zod_1.z.union([
3491
+ exports.CompiledRouteClaimSchema,
3492
+ LegacyCompiledRouteClaimSchema,
3493
+ ]),
3494
+ legacyRouteTakeoverAuthorization: exports.LegacyRouteTakeoverAuthorizationSchema.optional(),
3495
+ })
3496
+ .strict(),
650
3497
  })
651
3498
  .strict()
652
3499
  .superRefine((value, context) => {
3500
+ validateLegacyRestoration(value, "legacy-route-adapter", context);
653
3501
  validateDependencySnapshot(value.dependencySnapshot, context);
654
- validateReleaseExpectedHead(value, 'page-release', context);
655
- if (value.pageRevisionRef.kind !== 'page')
656
- context.addIssue({ code: 'custom', path: ['pageRevisionRef', 'kind'], message: 'Expected a page revision.' });
657
- if (value.target.environmentRef.kind !== 'environment')
658
- context.addIssue({ code: 'custom', path: ['target', 'environmentRef', 'kind'], message: 'Page release target requires an environment reference.' });
659
- if (value.target.routeSpaceRevisionRef.kind !== 'route-space')
660
- context.addIssue({ code: 'custom', path: ['target', 'routeSpaceRevisionRef', 'kind'], message: 'Page release target requires a route-space revision.' });
661
- if (value.target.normalizedPath !== value.target.routeClaim.normalizedPath || !exactRevisionRef(value.target.routeSpaceRevisionRef, value.target.routeClaim.routeSpaceRevisionRef)) {
662
- context.addIssue({ code: 'custom', path: ['target', 'routeClaim'], message: 'Page Release route authority must pin the exact compiled claim and normalized path.' });
663
- }
664
- if ('surface' in value.target.routeClaim && value.target.routeClaim.surface !== value.target.surface) {
665
- context.addIssue({ code: 'custom', path: ['target', 'routeClaim', 'surface'], message: 'Page Release route claim must match the target surface.' });
3502
+ validateReleaseGovernanceScope(value, "page-release", context);
3503
+ if (value.pageRevisionRef.kind !== "page")
3504
+ context.addIssue({
3505
+ code: "custom",
3506
+ path: ["pageRevisionRef", "kind"],
3507
+ message: "Expected a page revision.",
3508
+ });
3509
+ if (value.target.environmentRef.kind !== "environment")
3510
+ context.addIssue({
3511
+ code: "custom",
3512
+ path: ["target", "environmentRef", "kind"],
3513
+ message: "Page release target requires an environment reference.",
3514
+ });
3515
+ if (value.target.routeSpaceRevisionRef.kind !== "route-space")
3516
+ context.addIssue({
3517
+ code: "custom",
3518
+ path: ["target", "routeSpaceRevisionRef", "kind"],
3519
+ message: "Page release target requires a route-space revision.",
3520
+ });
3521
+ validateReleaseRouteSurface(value.target, context);
3522
+ if (value.target.normalizedPath !== value.target.routeClaim.normalizedPath ||
3523
+ !exactRevisionRef(value.target.routeSpaceRevisionRef, value.target.routeClaim.routeSpaceRevisionRef)) {
3524
+ context.addIssue({
3525
+ code: "custom",
3526
+ path: ["target", "routeClaim"],
3527
+ message: "Page Release route authority must pin the exact compiled claim and normalized path.",
3528
+ });
3529
+ }
3530
+ const takeover = value.target.legacyRouteTakeoverAuthorization;
3531
+ if (takeover &&
3532
+ (value.target.routeClaim.kind !== "canonical" ||
3533
+ takeover.normalizedPath !== value.target.normalizedPath ||
3534
+ !exactRevisionRef(takeover.routeSpaceRevisionRef, value.target.routeSpaceRevisionRef) ||
3535
+ takeover.targetResourceRef.kind !== "page" ||
3536
+ takeover.targetResourceRef.id !== value.pageRevisionRef.id ||
3537
+ takeover.targetResourceRef.ownerRepo !==
3538
+ value.pageRevisionRef.ownerRepo)) {
3539
+ context.addIssue({
3540
+ code: "custom",
3541
+ path: ["target", "legacyRouteTakeoverAuthorization"],
3542
+ message: "A Page route takeover must bind the exact canonical claim, RouteSpace and target Page.",
3543
+ });
666
3544
  }
667
3545
  });
668
3546
  exports.WorkbenchGroupSchema = zod_1.z
@@ -678,130 +3556,253 @@ exports.WorkbenchGroupSchema = zod_1.z
678
3556
  exports.WorkbenchAppInstanceSchema = zod_1.z
679
3557
  .object({
680
3558
  instanceId: common_1.ContractIdentifierSchema,
681
- kind: zod_1.z.enum(['built-in-application', 'workflow-form', 'workflow', 'agent', 'design', 'capability']),
3559
+ kind: zod_1.z.enum([
3560
+ "built-in-application",
3561
+ "workflow-form",
3562
+ "workflow",
3563
+ "agent",
3564
+ "design",
3565
+ "capability",
3566
+ ]),
682
3567
  targetRevisionRef: exports.RevisionRefSchema,
683
3568
  providerRevisionRef: exports.RevisionRefSchema,
684
3569
  inputSchemaRevisionRef: exports.RevisionRefSchema,
685
3570
  input: common_1.JsonObjectSchema,
686
3571
  groupId: common_1.ContractIdentifierSchema,
687
3572
  order: zod_1.z.number().int(),
688
- display: zod_1.z.object({ name: exports.I18nTextSchema.optional(), iconRef: exports.StableRefSchema.optional() }).strict(),
3573
+ display: zod_1.z
3574
+ .object({
3575
+ name: exports.I18nTextSchema.optional(),
3576
+ iconRef: exports.StableRefSchema.optional(),
3577
+ })
3578
+ .strict(),
689
3579
  accessPolicy: exports.AccessPolicySchema,
690
3580
  })
691
3581
  .strict();
692
3582
  exports.WorkbenchSchema = zod_1.z
693
3583
  .object({
694
- contract: zod_1.z.literal('Workbench'),
3584
+ contract: zod_1.z.literal("Workbench"),
695
3585
  schemaVersion: zod_1.z.literal(exports.DECLARATIVE_CONTROL_SCHEMA_VERSION),
696
3586
  workbenchId: common_1.ContractIdentifierSchema,
697
3587
  tenantScope: exports.TenantScopeSchema,
698
- purpose: zod_1.z.enum(['instance', 'template']),
3588
+ purpose: zod_1.z.enum(["instance", "template"]),
699
3589
  sourceTemplateRevisionRef: exports.RevisionRefSchema.optional(),
700
3590
  identity: exports.WorkbenchIdentitySchema,
701
3591
  supportedSurfaces: zod_1.z.array(exports.ProductSurfaceSchema).min(1),
702
3592
  lifecycle: exports.DeclarativeLifecycleSchema,
703
- routeClaims: zod_1.z.array(zod_1.z.union([exports.DeclarativeRouteClaimSchema, LegacyDeclarativeRouteClaimSchema])).min(1),
3593
+ routeClaims: zod_1.z
3594
+ .array(zod_1.z.union([
3595
+ exports.DeclarativeRouteClaimSchema,
3596
+ LegacyDeclarativeRouteClaimSchema,
3597
+ ]))
3598
+ .min(1),
704
3599
  groups: zod_1.z.array(exports.WorkbenchGroupSchema).min(1),
705
3600
  appInstances: zod_1.z.array(exports.WorkbenchAppInstanceSchema).min(1),
706
- defaultEntry: zod_1.z.object({ groupId: common_1.ContractIdentifierSchema, instanceId: common_1.ContractIdentifierSchema, showDefaultGroup: zod_1.z.boolean() }).strict(),
707
- layout: zod_1.z.object({
3601
+ defaultEntry: zod_1.z
3602
+ .object({
3603
+ groupId: common_1.ContractIdentifierSchema,
3604
+ instanceId: common_1.ContractIdentifierSchema,
3605
+ showDefaultGroup: zod_1.z.boolean(),
3606
+ })
3607
+ .strict(),
3608
+ layout: zod_1.z
3609
+ .object({
708
3610
  hostCapabilityRevisionRef: exports.RevisionRefSchema,
709
3611
  hostProviderRevisionRef: exports.RevisionRefSchema,
710
3612
  layoutPolicyRevisionRef: exports.RevisionRefSchema,
711
3613
  tokenRevisionRefs: zod_1.z.array(exports.RevisionRefSchema).min(1),
712
- }).strict(),
3614
+ })
3615
+ .strict(),
713
3616
  workbenchAccessPolicy: exports.AccessPolicySchema,
714
3617
  managementAccess: exports.ManagementAccessSchema,
715
- personalPreferencesPolicy: zod_1.z.object({
716
- allowed: zod_1.z.array(zod_1.z.enum(['collapsed-groups', 'recent-entry', 'layout-density'])),
717
- authority: zod_1.z.literal('identity-overlay'),
718
- }).strict(),
3618
+ personalPreferencesPolicy: zod_1.z
3619
+ .object({
3620
+ allowed: zod_1.z.array(zod_1.z.enum(["collapsed-groups", "recent-entry", "layout-density"])),
3621
+ authority: zod_1.z.literal("identity-overlay"),
3622
+ })
3623
+ .strict(),
719
3624
  performanceBudgetRef: exports.RevisionRefSchema,
720
3625
  observationPolicyRevisionRef: exports.RevisionRefSchema,
721
- privacyClassification: zod_1.z.enum(['public', 'internal', 'confidential', 'restricted']),
3626
+ privacyClassification: zod_1.z.enum([
3627
+ "public",
3628
+ "internal",
3629
+ "confidential",
3630
+ "restricted",
3631
+ ]),
722
3632
  })
723
3633
  .strict()
724
3634
  .superRefine((value, context) => {
725
3635
  validateDeclaredRouteSurfaces(value.supportedSurfaces, value.routeClaims, context);
726
- if (value.purpose === 'template' && value.sourceTemplateRevisionRef) {
727
- context.addIssue({ code: 'custom', path: ['sourceTemplateRevisionRef'], message: 'Templates cannot derive from another template at runtime.' });
3636
+ if (value.purpose === "template" && value.sourceTemplateRevisionRef) {
3637
+ context.addIssue({
3638
+ code: "custom",
3639
+ path: ["sourceTemplateRevisionRef"],
3640
+ message: "Templates cannot derive from another template at runtime.",
3641
+ });
728
3642
  }
729
3643
  const duplicateGroup = uniqueArray(value.groups, (group) => group.groupId);
730
3644
  if (duplicateGroup)
731
- context.addIssue({ code: 'custom', path: ['groups'], message: `Duplicate Workbench group: ${duplicateGroup}` });
3645
+ context.addIssue({
3646
+ code: "custom",
3647
+ path: ["groups"],
3648
+ message: `Duplicate Workbench group: ${duplicateGroup}`,
3649
+ });
732
3650
  const duplicateInstance = uniqueArray(value.appInstances, (instance) => instance.instanceId);
733
3651
  if (duplicateInstance)
734
- context.addIssue({ code: 'custom', path: ['appInstances'], message: `Duplicate Workbench instance: ${duplicateInstance}` });
3652
+ context.addIssue({
3653
+ code: "custom",
3654
+ path: ["appInstances"],
3655
+ message: `Duplicate Workbench instance: ${duplicateInstance}`,
3656
+ });
735
3657
  const groupIds = new Set(value.groups.map((group) => group.groupId));
736
3658
  value.appInstances.forEach((instance, index) => {
737
3659
  if (!groupIds.has(instance.groupId))
738
- context.addIssue({ code: 'custom', path: ['appInstances', index, 'groupId'], message: 'Workbench app references an unknown group.' });
3660
+ context.addIssue({
3661
+ code: "custom",
3662
+ path: ["appInstances", index, "groupId"],
3663
+ message: "Workbench app references an unknown group.",
3664
+ });
739
3665
  });
740
3666
  const defaultInstance = value.appInstances.find((instance) => instance.instanceId === value.defaultEntry.instanceId);
741
- if (!defaultInstance || defaultInstance.groupId !== value.defaultEntry.groupId) {
742
- context.addIssue({ code: 'custom', path: ['defaultEntry'], message: 'Workbench default entry must reference an app in the declared group.' });
3667
+ if (!defaultInstance ||
3668
+ defaultInstance.groupId !== value.defaultEntry.groupId) {
3669
+ context.addIssue({
3670
+ code: "custom",
3671
+ path: ["defaultEntry"],
3672
+ message: "Workbench default entry must reference an app in the declared group.",
3673
+ });
743
3674
  }
744
3675
  const targetKindByInstanceKind = {
745
- 'built-in-application': 'built-in-application',
746
- 'workflow-form': 'workflow',
747
- workflow: 'workflow',
748
- agent: 'agent',
749
- design: 'design',
750
- capability: 'capability',
3676
+ "built-in-application": "built-in-application",
3677
+ "workflow-form": "workflow",
3678
+ workflow: "workflow",
3679
+ agent: "agent",
3680
+ design: "design",
3681
+ capability: "capability",
751
3682
  };
752
3683
  value.appInstances.forEach((instance, index) => {
753
- if (instance.targetRevisionRef.kind !== targetKindByInstanceKind[instance.kind])
754
- context.addIssue({ code: 'custom', path: ['appInstances', index, 'targetRevisionRef', 'kind'], message: `Workbench ${instance.kind} target has an incompatible reference kind.` });
755
- if (instance.providerRevisionRef.kind !== 'view-provider')
756
- context.addIssue({ code: 'custom', path: ['appInstances', index, 'providerRevisionRef', 'kind'], message: 'Workbench app provider must use kind view-provider.' });
757
- if (instance.inputSchemaRevisionRef.kind !== 'schema')
758
- context.addIssue({ code: 'custom', path: ['appInstances', index, 'inputSchemaRevisionRef', 'kind'], message: 'Workbench app input must pin a schema revision.' });
3684
+ if (instance.targetRevisionRef.kind !==
3685
+ targetKindByInstanceKind[instance.kind])
3686
+ context.addIssue({
3687
+ code: "custom",
3688
+ path: ["appInstances", index, "targetRevisionRef", "kind"],
3689
+ message: `Workbench ${instance.kind} target has an incompatible reference kind.`,
3690
+ });
3691
+ if (instance.providerRevisionRef.kind !== "view-provider")
3692
+ context.addIssue({
3693
+ code: "custom",
3694
+ path: ["appInstances", index, "providerRevisionRef", "kind"],
3695
+ message: "Workbench app provider must use kind view-provider.",
3696
+ });
3697
+ if (instance.inputSchemaRevisionRef.kind !== "schema")
3698
+ context.addIssue({
3699
+ code: "custom",
3700
+ path: ["appInstances", index, "inputSchemaRevisionRef", "kind"],
3701
+ message: "Workbench app input must pin a schema revision.",
3702
+ });
759
3703
  });
760
3704
  const layoutRefs = [
761
- ['hostCapabilityRevisionRef', value.layout.hostCapabilityRevisionRef, 'capability'],
762
- ['hostProviderRevisionRef', value.layout.hostProviderRevisionRef, 'view-provider'],
763
- ['layoutPolicyRevisionRef', value.layout.layoutPolicyRevisionRef, 'layout-policy'],
3705
+ [
3706
+ "hostCapabilityRevisionRef",
3707
+ value.layout.hostCapabilityRevisionRef,
3708
+ "capability",
3709
+ ],
3710
+ [
3711
+ "hostProviderRevisionRef",
3712
+ value.layout.hostProviderRevisionRef,
3713
+ "view-provider",
3714
+ ],
3715
+ [
3716
+ "layoutPolicyRevisionRef",
3717
+ value.layout.layoutPolicyRevisionRef,
3718
+ "layout-policy",
3719
+ ],
764
3720
  ];
765
3721
  layoutRefs.forEach(([field, reference, expectedKind]) => {
766
3722
  if (reference.kind !== expectedKind)
767
- context.addIssue({ code: 'custom', path: ['layout', field, 'kind'], message: `${field} must reference ${expectedKind}.` });
3723
+ context.addIssue({
3724
+ code: "custom",
3725
+ path: ["layout", field, "kind"],
3726
+ message: `${field} must reference ${expectedKind}.`,
3727
+ });
768
3728
  });
769
3729
  value.layout.tokenRevisionRefs.forEach((reference, index) => {
770
- if (reference.kind !== 'design-token')
771
- context.addIssue({ code: 'custom', path: ['layout', 'tokenRevisionRefs', index, 'kind'], message: 'Workbench token references must use kind design-token.' });
3730
+ if (reference.kind !== "design-token")
3731
+ context.addIssue({
3732
+ code: "custom",
3733
+ path: ["layout", "tokenRevisionRefs", index, "kind"],
3734
+ message: "Workbench token references must use kind design-token.",
3735
+ });
772
3736
  });
773
3737
  });
774
3738
  exports.WorkbenchReleaseSchema = zod_1.z
775
3739
  .object({
776
- contract: zod_1.z.literal('WorkbenchRelease'),
3740
+ contract: zod_1.z.literal("WorkbenchRelease"),
777
3741
  ...ReleaseBaseShape,
778
3742
  workbenchRevisionRef: exports.RevisionRefSchema,
779
- target: zod_1.z.object({
3743
+ target: zod_1.z
3744
+ .object({
780
3745
  environmentRef: exports.StableRefSchema,
781
3746
  surface: exports.ProductSurfaceSchema,
782
3747
  workbenchId: common_1.ContractIdentifierSchema,
783
3748
  routeSpaceRevisionRef: exports.RevisionRefSchema,
784
3749
  normalizedPath: exports.RoutePathTemplateSchema,
785
- routeClaim: zod_1.z.union([exports.CompiledRouteClaimSchema, LegacyCompiledRouteClaimSchema]),
3750
+ routeClaim: zod_1.z.union([
3751
+ exports.CompiledRouteClaimSchema,
3752
+ LegacyCompiledRouteClaimSchema,
3753
+ ]),
3754
+ legacyRouteTakeoverAuthorization: exports.LegacyRouteTakeoverAuthorizationSchema.optional(),
786
3755
  order: zod_1.z.number().int(),
787
3756
  isDefaultCandidate: zod_1.z.boolean(),
788
- }).strict(),
3757
+ })
3758
+ .strict(),
789
3759
  })
790
3760
  .strict()
791
3761
  .superRefine((value, context) => {
3762
+ validateLegacyRestoration(value, "legacy-workbench-adapter", context);
792
3763
  validateDependencySnapshot(value.dependencySnapshot, context);
793
- validateReleaseExpectedHead(value, 'workbench-release', context);
794
- if (value.workbenchRevisionRef.kind !== 'workbench')
795
- context.addIssue({ code: 'custom', path: ['workbenchRevisionRef', 'kind'], message: 'Expected a workbench revision.' });
796
- if (value.target.environmentRef.kind !== 'environment')
797
- context.addIssue({ code: 'custom', path: ['target', 'environmentRef', 'kind'], message: 'Workbench release target requires an environment reference.' });
798
- if (value.target.routeSpaceRevisionRef.kind !== 'route-space')
799
- context.addIssue({ code: 'custom', path: ['target', 'routeSpaceRevisionRef', 'kind'], message: 'Workbench release target requires a route-space revision.' });
800
- if (value.target.normalizedPath !== value.target.routeClaim.normalizedPath || !exactRevisionRef(value.target.routeSpaceRevisionRef, value.target.routeClaim.routeSpaceRevisionRef)) {
801
- context.addIssue({ code: 'custom', path: ['target', 'routeClaim'], message: 'Workbench Release route authority must pin the exact compiled claim and normalized path.' });
802
- }
803
- if ('surface' in value.target.routeClaim && value.target.routeClaim.surface !== value.target.surface) {
804
- context.addIssue({ code: 'custom', path: ['target', 'routeClaim', 'surface'], message: 'Workbench Release route claim must match the target surface.' });
3764
+ validateReleaseGovernanceScope(value, "workbench-release", context);
3765
+ if (value.workbenchRevisionRef.kind !== "workbench")
3766
+ context.addIssue({
3767
+ code: "custom",
3768
+ path: ["workbenchRevisionRef", "kind"],
3769
+ message: "Expected a workbench revision.",
3770
+ });
3771
+ if (value.target.environmentRef.kind !== "environment")
3772
+ context.addIssue({
3773
+ code: "custom",
3774
+ path: ["target", "environmentRef", "kind"],
3775
+ message: "Workbench release target requires an environment reference.",
3776
+ });
3777
+ if (value.target.routeSpaceRevisionRef.kind !== "route-space")
3778
+ context.addIssue({
3779
+ code: "custom",
3780
+ path: ["target", "routeSpaceRevisionRef", "kind"],
3781
+ message: "Workbench release target requires a route-space revision.",
3782
+ });
3783
+ validateReleaseRouteSurface(value.target, context);
3784
+ if (value.target.normalizedPath !== value.target.routeClaim.normalizedPath ||
3785
+ !exactRevisionRef(value.target.routeSpaceRevisionRef, value.target.routeClaim.routeSpaceRevisionRef)) {
3786
+ context.addIssue({
3787
+ code: "custom",
3788
+ path: ["target", "routeClaim"],
3789
+ message: "Workbench Release route authority must pin the exact compiled claim and normalized path.",
3790
+ });
3791
+ }
3792
+ const takeover = value.target.legacyRouteTakeoverAuthorization;
3793
+ if (takeover &&
3794
+ (value.target.routeClaim.kind !== "canonical" ||
3795
+ takeover.normalizedPath !== value.target.normalizedPath ||
3796
+ !exactRevisionRef(takeover.routeSpaceRevisionRef, value.target.routeSpaceRevisionRef) ||
3797
+ takeover.targetResourceRef.kind !== "workbench" ||
3798
+ takeover.targetResourceRef.id !== value.workbenchRevisionRef.id ||
3799
+ takeover.targetResourceRef.ownerRepo !==
3800
+ value.workbenchRevisionRef.ownerRepo)) {
3801
+ context.addIssue({
3802
+ code: "custom",
3803
+ path: ["target", "legacyRouteTakeoverAuthorization"],
3804
+ message: "A Workbench route takeover must bind the exact canonical claim, RouteSpace and target Workbench.",
3805
+ });
805
3806
  }
806
3807
  });
807
3808
  const NavigationNodeBaseShape = {
@@ -810,29 +3811,35 @@ const NavigationNodeBaseShape = {
810
3811
  order: zod_1.z.number().int(),
811
3812
  disabled: zod_1.z.boolean().optional(),
812
3813
  };
813
- exports.NavigationGroupNodeSchema = zod_1.z.object({
3814
+ exports.NavigationGroupNodeSchema = zod_1.z
3815
+ .object({
814
3816
  ...NavigationNodeBaseShape,
815
- kind: zod_1.z.literal('group'),
3817
+ kind: zod_1.z.literal("group"),
816
3818
  label: exports.I18nTextSchema,
817
3819
  iconRef: exports.StableRefSchema.optional(),
818
3820
  collapsedByDefault: zod_1.z.boolean(),
819
3821
  audience: exports.AccessPolicySchema,
820
- }).strict();
821
- exports.NavigationTargetNodeSchema = zod_1.z.object({
3822
+ })
3823
+ .strict();
3824
+ exports.NavigationTargetNodeSchema = zod_1.z
3825
+ .object({
822
3826
  ...NavigationNodeBaseShape,
823
- kind: zod_1.z.literal('target'),
3827
+ kind: zod_1.z.literal("target"),
824
3828
  label: exports.I18nTextSchema,
825
3829
  iconRef: exports.StableRefSchema.optional(),
826
- tone: zod_1.z.enum(['default', 'danger']).optional(),
3830
+ tone: zod_1.z.enum(["default", "danger"]).optional(),
827
3831
  targetRef: exports.StableRefSchema,
828
3832
  parameterMapping: zod_1.z.record(common_1.ContractIdentifierSchema, exports.BindingSourceSchema),
829
3833
  audience: exports.AccessPolicySchema,
830
- }).strict();
831
- exports.NavigationSeparatorNodeSchema = zod_1.z.object({
3834
+ })
3835
+ .strict();
3836
+ exports.NavigationSeparatorNodeSchema = zod_1.z
3837
+ .object({
832
3838
  ...NavigationNodeBaseShape,
833
- kind: zod_1.z.literal('separator'),
834
- }).strict();
835
- exports.NavigationNodeSchema = zod_1.z.discriminatedUnion('kind', [
3839
+ kind: zod_1.z.literal("separator"),
3840
+ })
3841
+ .strict();
3842
+ exports.NavigationNodeSchema = zod_1.z.discriminatedUnion("kind", [
836
3843
  exports.NavigationGroupNodeSchema,
837
3844
  exports.NavigationTargetNodeSchema,
838
3845
  exports.NavigationSeparatorNodeSchema,
@@ -841,28 +3848,48 @@ const validateNavigationTree = (nodes, context) => {
841
3848
  const byId = new Map();
842
3849
  nodes.forEach((node, index) => {
843
3850
  if (byId.has(node.nodeId))
844
- context.addIssue({ code: 'custom', path: ['nodes', index, 'nodeId'], message: `Duplicate Navigation node: ${node.nodeId}` });
3851
+ context.addIssue({
3852
+ code: "custom",
3853
+ path: ["nodes", index, "nodeId"],
3854
+ message: `Duplicate Navigation node: ${node.nodeId}`,
3855
+ });
845
3856
  else
846
3857
  byId.set(node.nodeId, { node, index });
847
3858
  });
848
3859
  const siblingOrders = new Set();
849
3860
  nodes.forEach((node, index) => {
850
- const orderKey = `${node.parentNodeId ?? ''}:${node.order}`;
3861
+ const orderKey = `${node.parentNodeId ?? ""}:${node.order}`;
851
3862
  if (siblingOrders.has(orderKey))
852
- context.addIssue({ code: 'custom', path: ['nodes', index, 'order'], message: 'Sibling Navigation order values must be unique.' });
3863
+ context.addIssue({
3864
+ code: "custom",
3865
+ path: ["nodes", index, "order"],
3866
+ message: "Sibling Navigation order values must be unique.",
3867
+ });
853
3868
  siblingOrders.add(orderKey);
854
3869
  if (node.parentNodeId) {
855
3870
  const parent = byId.get(node.parentNodeId)?.node;
856
3871
  if (!parent)
857
- context.addIssue({ code: 'custom', path: ['nodes', index, 'parentNodeId'], message: 'Navigation node has an unknown parent.' });
858
- else if (parent.kind !== 'group')
859
- context.addIssue({ code: 'custom', path: ['nodes', index, 'parentNodeId'], message: 'Navigation parents must be groups.' });
3872
+ context.addIssue({
3873
+ code: "custom",
3874
+ path: ["nodes", index, "parentNodeId"],
3875
+ message: "Navigation node has an unknown parent.",
3876
+ });
3877
+ else if (parent.kind !== "group")
3878
+ context.addIssue({
3879
+ code: "custom",
3880
+ path: ["nodes", index, "parentNodeId"],
3881
+ message: "Navigation parents must be groups.",
3882
+ });
860
3883
  }
861
3884
  const ancestors = new Set([node.nodeId]);
862
3885
  let parentId = node.parentNodeId;
863
3886
  while (parentId) {
864
3887
  if (ancestors.has(parentId)) {
865
- context.addIssue({ code: 'custom', path: ['nodes', index, 'parentNodeId'], message: `Navigation cycle contains ${node.nodeId}.` });
3888
+ context.addIssue({
3889
+ code: "custom",
3890
+ path: ["nodes", index, "parentNodeId"],
3891
+ message: `Navigation cycle contains ${node.nodeId}.`,
3892
+ });
866
3893
  break;
867
3894
  }
868
3895
  ancestors.add(parentId);
@@ -872,7 +3899,7 @@ const validateNavigationTree = (nodes, context) => {
872
3899
  };
873
3900
  exports.NavigationSchema = zod_1.z
874
3901
  .object({
875
- contract: zod_1.z.literal('Navigation'),
3902
+ contract: zod_1.z.literal("Navigation"),
876
3903
  schemaVersion: zod_1.z.literal(exports.DECLARATIVE_CONTROL_SCHEMA_VERSION),
877
3904
  navigationId: common_1.ContractIdentifierSchema,
878
3905
  tenantScope: exports.TenantScopeSchema,
@@ -889,8 +3916,13 @@ exports.NavigationSchema = zod_1.z
889
3916
  .superRefine((value, context) => {
890
3917
  validateNavigationTree(value.nodes, context);
891
3918
  value.nodes.forEach((node, index) => {
892
- if (node.kind === 'target' && !['page', 'workbench', 'menu-action', 'domain-command'].includes(node.targetRef.kind)) {
893
- context.addIssue({ code: 'custom', path: ['nodes', index, 'targetRef', 'kind'], message: 'Navigation targets must reference Page, Workbench, registered Menu Action, or DomainCommand identities.' });
3919
+ if (node.kind === "target" &&
3920
+ !["page", "workbench", "menu-action", "domain-command"].includes(node.targetRef.kind)) {
3921
+ context.addIssue({
3922
+ code: "custom",
3923
+ path: ["nodes", index, "targetRef", "kind"],
3924
+ message: "Navigation targets must reference Page, Workbench, registered Menu Action, or DomainCommand identities.",
3925
+ });
894
3926
  }
895
3927
  });
896
3928
  });
@@ -903,45 +3935,68 @@ exports.ResolvedNavigationTargetSchema = zod_1.z
903
3935
  })
904
3936
  .strict();
905
3937
  /** A reviewed missing Page reference is retained without inventing an executable revision. */
906
- exports.UnavailableNavigationTargetSchema = zod_1.z.object({
3938
+ exports.UnavailableNavigationTargetSchema = zod_1.z
3939
+ .object({
907
3940
  nodeId: common_1.ContractIdentifierSchema,
908
- stableTargetRef: exports.StableRefSchema.refine((reference) => reference.kind === 'page', 'Only missing Pages can be isolated.'),
909
- reason: zod_1.z.literal('page-missing'),
3941
+ stableTargetRef: exports.StableRefSchema.refine((reference) => reference.kind === "page", "Only missing Pages can be isolated."),
3942
+ reason: zod_1.z.literal("page-missing"),
910
3943
  accessPolicy: exports.AccessPolicySchema.nullable(),
911
- }).strict();
3944
+ })
3945
+ .strict();
912
3946
  exports.NavigationReleaseSchema = zod_1.z
913
3947
  .object({
914
- contract: zod_1.z.literal('NavigationRelease'),
3948
+ contract: zod_1.z.literal("NavigationRelease"),
915
3949
  ...ReleaseBaseShape,
916
3950
  navigationRevisionRef: exports.RevisionRefSchema,
917
- target: zod_1.z.object({
3951
+ target: zod_1.z
3952
+ .object({
918
3953
  environmentRef: exports.StableRefSchema,
919
3954
  surface: exports.ProductSurfaceSchema,
920
3955
  placement: common_1.ContractIdentifierSchema,
921
- }).strict(),
3956
+ })
3957
+ .strict(),
922
3958
  resolvedTargets: zod_1.z.array(exports.ResolvedNavigationTargetSchema),
923
3959
  unavailableTargets: zod_1.z.array(exports.UnavailableNavigationTargetSchema).optional(),
924
3960
  })
925
3961
  .strict()
926
3962
  .superRefine((value, context) => {
3963
+ validateLegacyRestoration(value, "legacy-navigation-adapter", context);
927
3964
  validateDependencySnapshot(value.dependencySnapshot, context);
928
- validateReleaseExpectedHead(value, 'navigation-release', context);
929
- if (value.navigationRevisionRef.kind !== 'navigation')
930
- context.addIssue({ code: 'custom', path: ['navigationRevisionRef', 'kind'], message: 'Expected a navigation revision.' });
931
- if (value.target.environmentRef.kind !== 'environment')
932
- context.addIssue({ code: 'custom', path: ['target', 'environmentRef', 'kind'], message: 'Navigation release target requires an environment reference.' });
3965
+ validateReleaseGovernanceScope(value, "navigation-release", context);
3966
+ if (value.navigationRevisionRef.kind !== "navigation")
3967
+ context.addIssue({
3968
+ code: "custom",
3969
+ path: ["navigationRevisionRef", "kind"],
3970
+ message: "Expected a navigation revision.",
3971
+ });
3972
+ if (value.target.environmentRef.kind !== "environment")
3973
+ context.addIssue({
3974
+ code: "custom",
3975
+ path: ["target", "environmentRef", "kind"],
3976
+ message: "Navigation release target requires an environment reference.",
3977
+ });
933
3978
  if (uniqueArray(value.resolvedTargets, (target) => target.nodeId))
934
- context.addIssue({ code: 'custom', path: ['resolvedTargets'], message: 'Resolved Navigation node IDs must be unique.' });
3979
+ context.addIssue({
3980
+ code: "custom",
3981
+ path: ["resolvedTargets"],
3982
+ message: "Resolved Navigation node IDs must be unique.",
3983
+ });
935
3984
  if (uniqueArray([...value.resolvedTargets, ...(value.unavailableTargets ?? [])], (target) => target.nodeId)) {
936
- context.addIssue({ code: 'custom', path: ['unavailableTargets'], message: 'Navigation target resolutions must have unique node IDs.' });
3985
+ context.addIssue({
3986
+ code: "custom",
3987
+ path: ["unavailableTargets"],
3988
+ message: "Navigation target resolutions must have unique node IDs.",
3989
+ });
937
3990
  }
938
3991
  });
939
- const RuntimeDiagnosticSchema = zod_1.z.object({
3992
+ const RuntimeDiagnosticSchema = zod_1.z
3993
+ .object({
940
3994
  code: common_1.ContractIdentifierSchema,
941
- severity: zod_1.z.enum(['info', 'warning', 'error']),
3995
+ severity: zod_1.z.enum(["info", "warning", "error"]),
942
3996
  path: zod_1.z.string().trim().min(1),
943
3997
  message: zod_1.z.string().trim().min(1),
944
- }).strict();
3998
+ })
3999
+ .strict();
945
4000
  const RuntimeBundleBaseShape = {
946
4001
  schemaVersion: zod_1.z.literal(exports.DECLARATIVE_CONTROL_SCHEMA_VERSION),
947
4002
  tenantScope: exports.TenantScopeSchema,
@@ -953,57 +4008,344 @@ const RuntimeBundleBaseShape = {
953
4008
  rebuildable: zod_1.z.literal(true),
954
4009
  diagnostics: zod_1.z.array(RuntimeDiagnosticSchema),
955
4010
  };
956
- exports.PageRuntimeBundleSchema = zod_1.z.object({
957
- contract: zod_1.z.literal('PageRuntimeBundle'),
4011
+ const validateRuntimeBundleReference = (reference, tenantScope, path, expectedKind, expectedId, context) => {
4012
+ if (reference.kind !== expectedKind) {
4013
+ context.addIssue({
4014
+ code: "custom",
4015
+ path: [path, "kind"],
4016
+ message: `${path} must reference ${expectedKind}.`,
4017
+ });
4018
+ }
4019
+ if (expectedId !== undefined && reference.id !== expectedId) {
4020
+ context.addIssue({
4021
+ code: "custom",
4022
+ path: [path, "id"],
4023
+ message: `${path} must identify ${expectedId}.`,
4024
+ });
4025
+ }
4026
+ validateTenantCompatibleReference(reference, tenantScope, [path], context);
4027
+ };
4028
+ const validateRuntimeBundleBase = (value, expectedReleaseKind, context) => {
4029
+ validateRuntimeBundleReference(value.releaseRevisionRef, value.tenantScope, "releaseRevisionRef", expectedReleaseKind, undefined, context);
4030
+ validateRuntimeBundleReference(value.compilerRevisionRef, value.tenantScope, "compilerRevisionRef", "compiler", undefined, context);
4031
+ };
4032
+ exports.DeclarativeRouteOwnerIndexEntrySchema = zod_1.z
4033
+ .object({
4034
+ resourceKind: zod_1.z.enum(["page", "workbench"]),
4035
+ releaseSlotId: common_1.ContractIdentifierSchema,
4036
+ activeReleaseRevisionRef: exports.RevisionRefSchema,
4037
+ routeClaim: exports.CompiledRouteClaimSchema,
4038
+ authority: zod_1.z.enum(["declarative", "legacy", "unavailable"]),
4039
+ legacyRestoration: exports.LegacySlotRestorationSchema.optional(),
4040
+ })
4041
+ .strict()
4042
+ .superRefine((value, context) => {
4043
+ if (value.authority === "legacy" && !value.legacyRestoration) {
4044
+ context.addIssue({
4045
+ code: "custom",
4046
+ path: ["legacyRestoration"],
4047
+ message: "A restored legacy route must pin its exact inspected source and adapter revisions.",
4048
+ });
4049
+ }
4050
+ if (value.authority !== "legacy" && value.legacyRestoration) {
4051
+ context.addIssue({
4052
+ code: "custom",
4053
+ path: ["legacyRestoration"],
4054
+ message: "Only a restored legacy route can carry legacy restoration provenance.",
4055
+ });
4056
+ }
4057
+ });
4058
+ exports.DeclarativeRouteOwnerIndexSchema = zod_1.z
4059
+ .object({
4060
+ contract: zod_1.z.literal("DeclarativeRouteOwnerIndex"),
4061
+ schemaVersion: zod_1.z.literal(exports.DECLARATIVE_CONTROL_SCHEMA_VERSION),
4062
+ tenantScope: exports.TenantScopeSchema,
4063
+ environmentRef: exports.StableRefSchema,
4064
+ surface: exports.ProductSurfaceSchema,
4065
+ generation: zod_1.z.number().int().positive(),
4066
+ entries: zod_1.z.array(exports.DeclarativeRouteOwnerIndexEntrySchema).max(4096),
4067
+ contentHash: common_1.Sha256Schema,
4068
+ rebuildable: zod_1.z.literal(true),
4069
+ })
4070
+ .strict()
4071
+ .superRefine((value, context) => {
4072
+ const identities = value.entries.map((entry) => `${entry.resourceKind}:${entry.releaseSlotId}`);
4073
+ if (new Set(identities).size !== identities.length) {
4074
+ context.addIssue({
4075
+ code: "custom",
4076
+ path: ["entries"],
4077
+ message: "Route owner index entries must be unique by Release slot.",
4078
+ });
4079
+ }
4080
+ if (identities.some((identity, index) => index > 0 && identities[index - 1].localeCompare(identity) > 0)) {
4081
+ context.addIssue({
4082
+ code: "custom",
4083
+ path: ["entries"],
4084
+ message: "Route owner index entries must use deterministic Release-slot order.",
4085
+ });
4086
+ }
4087
+ });
4088
+ exports.DeclarativeWorkbenchCatalogEntrySchema = zod_1.z
4089
+ .object({
4090
+ workbenchId: common_1.ContractIdentifierSchema,
4091
+ authority: zod_1.z.enum(["declarative", "legacy", "unavailable"]),
4092
+ identity: exports.WorkbenchIdentitySchema,
4093
+ order: zod_1.z.number().int(),
4094
+ isDefaultCandidate: zod_1.z.boolean(),
4095
+ activeReleaseRevisionRef: exports.RevisionRefSchema.optional(),
4096
+ legacyAdapterRevisionRef: exports.RevisionRefSchema.optional(),
4097
+ })
4098
+ .strict()
4099
+ .superRefine((value, context) => {
4100
+ if (value.authority === "declarative") {
4101
+ if (value.activeReleaseRevisionRef?.kind !== "workbench-release") {
4102
+ context.addIssue({
4103
+ code: "custom",
4104
+ path: ["activeReleaseRevisionRef"],
4105
+ message: "A declarative Workbench catalog entry requires an exact Workbench Release.",
4106
+ });
4107
+ }
4108
+ if (value.legacyAdapterRevisionRef) {
4109
+ context.addIssue({
4110
+ code: "custom",
4111
+ path: ["legacyAdapterRevisionRef"],
4112
+ message: "A declarative Workbench catalog entry cannot carry a legacy adapter.",
4113
+ });
4114
+ }
4115
+ return;
4116
+ }
4117
+ if (value.activeReleaseRevisionRef) {
4118
+ context.addIssue({
4119
+ code: "custom",
4120
+ path: ["activeReleaseRevisionRef"],
4121
+ message: "A non-declarative Workbench entry cannot expose a Workbench Release.",
4122
+ });
4123
+ }
4124
+ if (value.authority === "legacy" &&
4125
+ value.legacyAdapterRevisionRef?.kind !== "legacy-workbench-adapter") {
4126
+ context.addIssue({
4127
+ code: "custom",
4128
+ path: ["legacyAdapterRevisionRef"],
4129
+ message: "A legacy Workbench entry requires an exact legacy-workbench-adapter revision.",
4130
+ });
4131
+ }
4132
+ if (value.authority === "unavailable" && value.legacyAdapterRevisionRef) {
4133
+ context.addIssue({
4134
+ code: "custom",
4135
+ path: ["legacyAdapterRevisionRef"],
4136
+ message: "An unavailable Workbench entry cannot carry a legacy adapter.",
4137
+ });
4138
+ }
4139
+ });
4140
+ exports.DeclarativeWorkbenchCatalogSchema = zod_1.z
4141
+ .object({
4142
+ contract: zod_1.z.literal("DeclarativeWorkbenchCatalog"),
4143
+ schemaVersion: zod_1.z.literal(exports.DECLARATIVE_CONTROL_SCHEMA_VERSION),
4144
+ tenantScope: exports.TenantScopeSchema,
4145
+ environmentRef: exports.StableRefSchema,
4146
+ surface: exports.ProductSurfaceSchema,
4147
+ generation: zod_1.z.number().int().positive(),
4148
+ entries: zod_1.z.array(exports.DeclarativeWorkbenchCatalogEntrySchema).max(4096),
4149
+ contentHash: common_1.Sha256Schema,
4150
+ rebuildable: zod_1.z.literal(true),
4151
+ })
4152
+ .strict()
4153
+ .superRefine((value, context) => {
4154
+ if (value.environmentRef.kind !== "environment") {
4155
+ context.addIssue({
4156
+ code: "custom",
4157
+ path: ["environmentRef", "kind"],
4158
+ message: "A Workbench catalog requires an Environment reference.",
4159
+ });
4160
+ }
4161
+ const ids = value.entries.map((entry) => entry.workbenchId);
4162
+ if (new Set(ids).size !== ids.length) {
4163
+ context.addIssue({
4164
+ code: "custom",
4165
+ path: ["entries"],
4166
+ message: "Workbench catalog identities must be unique.",
4167
+ });
4168
+ }
4169
+ if (value.entries.filter((entry) => entry.authority !== "unavailable" && entry.isDefaultCandidate).length > 1) {
4170
+ context.addIssue({
4171
+ code: "custom",
4172
+ path: ["entries"],
4173
+ message: "The effective Workbench catalog may have at most one default.",
4174
+ });
4175
+ }
4176
+ const sorted = [...value.entries].sort((left, right) => left.order - right.order ||
4177
+ left.workbenchId.localeCompare(right.workbenchId));
4178
+ if (sorted.some((entry, index) => entry.workbenchId !== value.entries[index]?.workbenchId)) {
4179
+ context.addIssue({
4180
+ code: "custom",
4181
+ path: ["entries"],
4182
+ message: "Workbench catalog entries must use deterministic order plus Workbench identity.",
4183
+ });
4184
+ }
4185
+ });
4186
+ exports.PageRuntimeBundleSchema = zod_1.z
4187
+ .object({
4188
+ contract: zod_1.z.literal("PageRuntimeBundle"),
958
4189
  ...RuntimeBundleBaseShape,
959
4190
  pageId: common_1.ContractIdentifierSchema,
960
4191
  pageRevisionRef: exports.RevisionRefSchema,
961
4192
  surface: exports.ProductSurfaceSchema,
962
4193
  routeClaims: zod_1.z.array(exports.CompiledRouteClaimSchema),
4194
+ routeStatePresentations: zod_1.z
4195
+ .array(exports.PageRouteStatePresentationSchema)
4196
+ .default([]),
963
4197
  shellRevisionRef: exports.RevisionRefSchema,
4198
+ shellDescriptor: exports.DeclarativeRuntimeShellDescriptorSchema,
964
4199
  renderTree: render_1.RenderTreeSchema,
965
4200
  capabilityInstances: zod_1.z.array(exports.CapabilityInstanceSchema),
4201
+ deniedCapabilityInstanceIds: zod_1.z.array(common_1.ContractIdentifierSchema).default([]),
4202
+ capabilityAccessEvaluated: zod_1.z.literal(true).optional(),
4203
+ stateDefinitions: zod_1.z.array(exports.PageStateDefinitionSchema).default([]),
4204
+ entryTransitions: zod_1.z.array(exports.ResolvedPageEntryTransitionSchema).default([]),
4205
+ interactionBindings: zod_1.z.array(exports.InteractionBindingSchema).default([]),
966
4206
  ontologyBindings: zod_1.z.array(exports.OntologyBindingSchema),
4207
+ queryBindings: zod_1.z.array(exports.QueryBindingSchema).default([]),
967
4208
  actionBindings: zod_1.z.array(exports.ActionBindingSchema),
968
4209
  pageAccessPolicy: exports.AccessPolicySchema,
969
4210
  tokenRevisionRefs: zod_1.z.array(exports.RevisionRefSchema),
970
4211
  performanceBudgetRef: exports.RevisionRefSchema,
971
4212
  observationPolicyRevisionRef: exports.RevisionRefSchema,
972
- privacyClassification: zod_1.z.enum(['public', 'internal', 'confidential', 'restricted']),
973
- }).strict();
4213
+ privacyClassification: zod_1.z.enum([
4214
+ "public",
4215
+ "internal",
4216
+ "confidential",
4217
+ "restricted",
4218
+ ]),
4219
+ })
4220
+ .strict()
4221
+ .superRefine((value, context) => {
4222
+ const instanceIds = new Set(value.capabilityInstances.map((instance) => instance.instanceId));
4223
+ if (new Set(value.deniedCapabilityInstanceIds).size !==
4224
+ value.deniedCapabilityInstanceIds.length ||
4225
+ value.deniedCapabilityInstanceIds.some((id) => !instanceIds.has(id))) {
4226
+ context.addIssue({
4227
+ code: "custom",
4228
+ path: ["deniedCapabilityInstanceIds"],
4229
+ message: "Denied capability identities must be unique declared instances.",
4230
+ });
4231
+ }
4232
+ validateRuntimeBundleBase(value, "page-release", context);
4233
+ value.routeClaims.forEach((claim, index) => {
4234
+ if (claim.surface !== value.surface) {
4235
+ context.addIssue({
4236
+ code: "custom",
4237
+ path: ["routeClaims", index, "surface"],
4238
+ message: "Runtime route claims must match the bundle surface.",
4239
+ });
4240
+ }
4241
+ });
4242
+ validateRuntimeBundleReference(value.pageRevisionRef, value.tenantScope, "pageRevisionRef", "page", value.pageId, context);
4243
+ value.routeStatePresentations.forEach((presentation, index) => {
4244
+ if (presentation.surface !== value.surface) {
4245
+ context.addIssue({
4246
+ code: "custom",
4247
+ path: ["routeStatePresentations", index, "surface"],
4248
+ message: "Runtime route-state presentations must match the compiled Page surface.",
4249
+ });
4250
+ }
4251
+ });
4252
+ });
974
4253
  exports.ResolvedWorkbenchAppInstanceSchema = exports.WorkbenchAppInstanceSchema.extend({
975
4254
  targetAccessPolicy: exports.AccessPolicySchema,
976
4255
  }).strict();
977
- const WorkbenchRuntimeTargetSchema = exports.WorkbenchReleaseSchema.shape.target.safeExtend({
4256
+ exports.WorkbenchRuntimeIdentitySchema = zod_1.z
4257
+ .object({
4258
+ name: exports.I18nTextSchema,
4259
+ description: exports.I18nTextSchema.optional(),
4260
+ })
4261
+ .strict();
4262
+ const WorkbenchRuntimeTargetSchema = exports.WorkbenchReleaseSchema.shape.target
4263
+ .safeExtend({
978
4264
  routeClaim: exports.CompiledRouteClaimSchema,
979
- }).strict();
980
- exports.WorkbenchRuntimeBundleSchema = zod_1.z.object({
981
- contract: zod_1.z.literal('WorkbenchRuntimeBundle'),
4265
+ })
4266
+ .strict();
4267
+ exports.WorkbenchRuntimeBundleSchema = zod_1.z
4268
+ .object({
4269
+ contract: zod_1.z.literal("WorkbenchRuntimeBundle"),
982
4270
  ...RuntimeBundleBaseShape,
983
4271
  workbenchId: common_1.ContractIdentifierSchema,
984
4272
  workbenchRevisionRef: exports.RevisionRefSchema,
4273
+ identity: exports.WorkbenchRuntimeIdentitySchema,
985
4274
  surface: exports.ProductSurfaceSchema,
986
4275
  routeClaims: zod_1.z.array(exports.CompiledRouteClaimSchema),
987
4276
  groups: zod_1.z.array(exports.WorkbenchGroupSchema),
988
4277
  appInstances: zod_1.z.array(exports.ResolvedWorkbenchAppInstanceSchema),
989
- defaultEntry: exports.WorkbenchSchema.shape.defaultEntry,
4278
+ defaultEntry: exports.WorkbenchSchema.shape.defaultEntry.nullable(),
990
4279
  layout: exports.WorkbenchSchema.shape.layout,
991
4280
  workbenchAccessPolicy: exports.AccessPolicySchema,
992
4281
  personalPreferencesPolicy: exports.WorkbenchSchema.shape.personalPreferencesPolicy,
993
4282
  target: WorkbenchRuntimeTargetSchema,
994
4283
  performanceBudgetRef: exports.RevisionRefSchema,
995
4284
  observationPolicyRevisionRef: exports.RevisionRefSchema,
996
- privacyClassification: zod_1.z.enum(['public', 'internal', 'confidential', 'restricted']),
997
- }).strict();
4285
+ privacyClassification: zod_1.z.enum([
4286
+ "public",
4287
+ "internal",
4288
+ "confidential",
4289
+ "restricted",
4290
+ ]),
4291
+ })
4292
+ .strict()
4293
+ .superRefine((value, context) => {
4294
+ validateRuntimeBundleBase(value, "workbench-release", context);
4295
+ value.routeClaims.forEach((claim, index) => {
4296
+ if (claim.surface !== value.surface) {
4297
+ context.addIssue({
4298
+ code: "custom",
4299
+ path: ["routeClaims", index, "surface"],
4300
+ message: "Runtime route claims must match the bundle surface.",
4301
+ });
4302
+ }
4303
+ });
4304
+ validateRuntimeBundleReference(value.workbenchRevisionRef, value.tenantScope, "workbenchRevisionRef", "workbench", value.workbenchId, context);
4305
+ if (value.appInstances.length === 0) {
4306
+ if (value.defaultEntry !== null) {
4307
+ context.addIssue({
4308
+ code: "custom",
4309
+ path: ["defaultEntry"],
4310
+ message: "An empty Workbench runtime bundle must use a null default entry.",
4311
+ });
4312
+ }
4313
+ return;
4314
+ }
4315
+ if (value.defaultEntry === null) {
4316
+ context.addIssue({
4317
+ code: "custom",
4318
+ path: ["defaultEntry"],
4319
+ message: "A non-empty Workbench runtime bundle requires a default entry.",
4320
+ });
4321
+ return;
4322
+ }
4323
+ const defaultInstance = value.appInstances.find((instance) => instance.instanceId === value.defaultEntry?.instanceId);
4324
+ if (!defaultInstance ||
4325
+ defaultInstance.groupId !== value.defaultEntry.groupId) {
4326
+ context.addIssue({
4327
+ code: "custom",
4328
+ path: ["defaultEntry"],
4329
+ message: "Workbench runtime default entry must reference a visible app in the declared group.",
4330
+ });
4331
+ }
4332
+ if (!value.groups.some((group) => group.groupId === value.defaultEntry?.groupId)) {
4333
+ context.addIssue({
4334
+ code: "custom",
4335
+ path: ["defaultEntry", "groupId"],
4336
+ message: "Workbench runtime default entry must reference a visible group.",
4337
+ });
4338
+ }
4339
+ });
998
4340
  const CompiledNavigationTargetSchema = exports.ResolvedNavigationTargetSchema.extend({
999
- kind: zod_1.z.literal('route'),
4341
+ kind: zod_1.z.literal("route"),
1000
4342
  accessPolicy: exports.AccessPolicySchema,
1001
4343
  routeClaim: exports.CompiledRouteClaimSchema,
1002
4344
  }).strict();
1003
4345
  exports.CompiledNavigationRegisteredMenuActionTargetSchema = exports.ResolvedNavigationTargetSchema.extend({
1004
- kind: zod_1.z.literal('registered-menu-action'),
4346
+ kind: zod_1.z.literal("registered-menu-action"),
1005
4347
  accessPolicy: exports.AccessPolicySchema,
1006
- execution: zod_1.z.literal('client'),
4348
+ execution: zod_1.z.literal("client"),
1007
4349
  applicationId: common_1.ContractIdentifierSchema,
1008
4350
  actionRef: common_1.ContractIdentifierSchema,
1009
4351
  inputSchemaRef: common_1.ContractIdentifierSchema.optional(),
@@ -1011,19 +4353,21 @@ exports.CompiledNavigationRegisteredMenuActionTargetSchema = exports.ResolvedNav
1011
4353
  sourceCatalogRevisionRef: exports.RevisionRefSchema,
1012
4354
  }).strict();
1013
4355
  exports.CompiledNavigationDomainCommandTargetSchema = exports.ResolvedNavigationTargetSchema.extend({
1014
- kind: zod_1.z.literal('governed-domain-command'),
4356
+ kind: zod_1.z.literal("governed-domain-command"),
1015
4357
  accessPolicy: exports.AccessPolicySchema,
1016
- execution: zod_1.z.literal('server'),
4358
+ execution: zod_1.z.literal("server"),
1017
4359
  commandRevisionRef: exports.RevisionRefSchema,
1018
4360
  inputSchemaRevisionRef: exports.RevisionRefSchema,
1019
4361
  resultSchemaRevisionRef: exports.RevisionRefSchema.optional(),
1020
4362
  input: common_1.JsonObjectSchema,
1021
4363
  }).strict();
1022
- exports.CompiledNavigationResolvedTargetSchema = zod_1.z.discriminatedUnion('kind', [
4364
+ exports.CompiledNavigationResolvedTargetSchema = zod_1.z.discriminatedUnion("kind", [
1023
4365
  CompiledNavigationTargetSchema,
1024
4366
  exports.CompiledNavigationRegisteredMenuActionTargetSchema,
1025
4367
  exports.CompiledNavigationDomainCommandTargetSchema,
1026
- exports.UnavailableNavigationTargetSchema.omit({ reason: true }).extend({ kind: zod_1.z.literal('unavailable') }).strict(),
4368
+ exports.UnavailableNavigationTargetSchema.omit({ reason: true })
4369
+ .extend({ kind: zod_1.z.literal("unavailable") })
4370
+ .strict(),
1027
4371
  ]);
1028
4372
  exports.CompiledNavigationGroupNodeSchema = exports.NavigationGroupNodeSchema.extend({
1029
4373
  ancestorAccessPolicies: zod_1.z.array(exports.AccessPolicySchema),
@@ -1031,24 +4375,39 @@ exports.CompiledNavigationGroupNodeSchema = exports.NavigationGroupNodeSchema.ex
1031
4375
  exports.CompiledNavigationTargetNodeSchema = exports.NavigationTargetNodeSchema.extend({
1032
4376
  ancestorAccessPolicies: zod_1.z.array(exports.AccessPolicySchema),
1033
4377
  resolvedTarget: exports.CompiledNavigationResolvedTargetSchema,
1034
- }).strict().superRefine((node, context) => {
1035
- if (node.resolvedTarget.nodeId !== node.nodeId || stableRefIdentity(node.resolvedTarget.stableTargetRef) !== stableRefIdentity(node.targetRef)) {
1036
- context.addIssue({ code: 'custom', path: ['resolvedTarget'], message: 'Resolved target identity must match the source node.' });
4378
+ })
4379
+ .strict()
4380
+ .superRefine((node, context) => {
4381
+ if (node.resolvedTarget.nodeId !== node.nodeId ||
4382
+ stableRefIdentity(node.resolvedTarget.stableTargetRef) !==
4383
+ stableRefIdentity(node.targetRef)) {
4384
+ context.addIssue({
4385
+ code: "custom",
4386
+ path: ["resolvedTarget"],
4387
+ message: "Resolved target identity must match the source node.",
4388
+ });
1037
4389
  }
1038
- if (node.resolvedTarget.kind === 'unavailable' && (node.disabled !== true || Object.keys(node.parameterMapping).length > 0)) {
1039
- context.addIssue({ code: 'custom', path: ['resolvedTarget'], message: 'Unavailable targets must be disabled and contain no executable input.' });
4390
+ if (node.resolvedTarget.kind === "unavailable" &&
4391
+ (node.disabled !== true ||
4392
+ Object.keys(node.parameterMapping).length > 0)) {
4393
+ context.addIssue({
4394
+ code: "custom",
4395
+ path: ["resolvedTarget"],
4396
+ message: "Unavailable targets must be disabled and contain no executable input.",
4397
+ });
1040
4398
  }
1041
4399
  });
1042
4400
  exports.CompiledNavigationSeparatorNodeSchema = exports.NavigationSeparatorNodeSchema.extend({
1043
4401
  ancestorAccessPolicies: zod_1.z.array(exports.AccessPolicySchema),
1044
4402
  }).strict();
1045
- exports.CompiledNavigationNodeSchema = zod_1.z.discriminatedUnion('kind', [
4403
+ exports.CompiledNavigationNodeSchema = zod_1.z.discriminatedUnion("kind", [
1046
4404
  exports.CompiledNavigationGroupNodeSchema,
1047
4405
  exports.CompiledNavigationTargetNodeSchema,
1048
4406
  exports.CompiledNavigationSeparatorNodeSchema,
1049
4407
  ]);
1050
- exports.NavigationRuntimeBundleSchema = zod_1.z.object({
1051
- contract: zod_1.z.literal('NavigationRuntimeBundle'),
4408
+ exports.NavigationRuntimeBundleSchema = zod_1.z
4409
+ .object({
4410
+ contract: zod_1.z.literal("NavigationRuntimeBundle"),
1052
4411
  ...RuntimeBundleBaseShape,
1053
4412
  navigationId: common_1.ContractIdentifierSchema,
1054
4413
  navigationRevisionRef: exports.RevisionRefSchema,
@@ -1057,27 +4416,38 @@ exports.NavigationRuntimeBundleSchema = zod_1.z.object({
1057
4416
  nodes: zod_1.z.array(exports.CompiledNavigationNodeSchema),
1058
4417
  performanceBudgetRef: exports.RevisionRefSchema,
1059
4418
  observationPolicyRevisionRef: exports.RevisionRefSchema,
1060
- }).strict();
4419
+ })
4420
+ .strict()
4421
+ .superRefine((value, context) => {
4422
+ validateRuntimeBundleBase(value, "navigation-release", context);
4423
+ validateRuntimeBundleReference(value.navigationRevisionRef, value.tenantScope, "navigationRevisionRef", "navigation", value.navigationId, context);
4424
+ });
1061
4425
  exports.DeclarativeControlOntologyDefinitionSchema = data_1.OntologyDefinitionSchema.extend({
1062
- classification: zod_1.z.literal('control'),
1063
- discovery: zod_1.z.object({
4426
+ classification: zod_1.z.literal("control"),
4427
+ discovery: zod_1.z
4428
+ .object({
1064
4429
  ordinaryDataBrowser: zod_1.z.literal(false),
1065
4430
  businessSearch: zod_1.z.literal(false),
1066
4431
  businessStatistics: zod_1.z.literal(false),
1067
4432
  ordinaryExport: zod_1.z.literal(false),
1068
4433
  genericWrite: zod_1.z.literal(false),
1069
- }).strict(),
4434
+ })
4435
+ .strict(),
1070
4436
  }).strict();
1071
4437
  const controlDefinition = (ontologyId, bodySchemaRef) => exports.DeclarativeControlOntologyDefinitionSchema.parse({
1072
- contract: 'OntologyDefinition',
4438
+ contract: "OntologyDefinition",
1073
4439
  ontologyId,
1074
- dataSpaceId: 'monkeys.control',
1075
- ownerRepo: 'monkeys-js-sdk',
4440
+ dataSpaceId: "monkeys.control",
4441
+ ownerRepo: "monkeys-js-sdk",
1076
4442
  bodySchemaRef,
1077
- authority: { service: 'monkeys-data-server', storage: 'domain-record', scope: 'tenant' },
4443
+ authority: {
4444
+ service: "monkeys-data-server",
4445
+ storage: "domain-record",
4446
+ scope: "tenant",
4447
+ },
1078
4448
  relationKinds: [],
1079
4449
  metricKinds: [],
1080
- classification: 'control',
4450
+ classification: "control",
1081
4451
  discovery: {
1082
4452
  ordinaryDataBrowser: false,
1083
4453
  businessSearch: false,
@@ -1087,11 +4457,11 @@ const controlDefinition = (ontologyId, bodySchemaRef) => exports.DeclarativeCont
1087
4457
  },
1088
4458
  });
1089
4459
  exports.DECLARATIVE_CONTROL_ONTOLOGY_DEFINITIONS = Object.freeze([
1090
- controlDefinition('monkeys.system.page', 'monkeys.system.page/v1'),
1091
- controlDefinition('monkeys.system.page-release', 'monkeys.system.page-release/v1'),
1092
- controlDefinition('monkeys.system.workbench', 'monkeys.system.workbench/v1'),
1093
- controlDefinition('monkeys.system.workbench-release', 'monkeys.system.workbench-release/v1'),
1094
- controlDefinition('monkeys.system.navigation', 'monkeys.system.navigation/v1'),
1095
- controlDefinition('monkeys.system.navigation-release', 'monkeys.system.navigation-release/v1'),
4460
+ controlDefinition("monkeys.system.page", "monkeys.system.page/v1"),
4461
+ controlDefinition("monkeys.system.page-release", "monkeys.system.page-release/v1"),
4462
+ controlDefinition("monkeys.system.workbench", "monkeys.system.workbench/v1"),
4463
+ controlDefinition("monkeys.system.workbench-release", "monkeys.system.workbench-release/v1"),
4464
+ controlDefinition("monkeys.system.navigation", "monkeys.system.navigation/v1"),
4465
+ controlDefinition("monkeys.system.navigation-release", "monkeys.system.navigation-release/v1"),
1096
4466
  ]);
1097
4467
  //# sourceMappingURL=declarative-control.js.map