@native-knowledge/knowledge-sdk 0.1.0-rc.1 → 0.1.0-rc.2

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 (206) hide show
  1. package/LICENSE +202 -21
  2. package/NOTICE +29 -0
  3. package/README.md +26 -38
  4. package/dist/{types/sdk/agent-entry.d.ts → agent-entry.d.ts} +3 -3
  5. package/dist/agent-entry.js +153 -0
  6. package/dist/{types/sdk/agent-guidance-error.d.ts → agent-guidance-error.d.ts} +1 -1
  7. package/dist/agent-guidance-error.js +46 -0
  8. package/dist/auth.d.ts +124 -0
  9. package/dist/auth.js +165 -0
  10. package/dist/{types/sdk/index.d.ts → index.d.ts} +15 -14
  11. package/dist/index.js +159 -6570
  12. package/dist/internal/contracts/artifact.js +103 -0
  13. package/dist/internal/contracts/collection-control.js +69 -0
  14. package/dist/internal/contracts/collection.js +174 -0
  15. package/dist/internal/contracts/common.js +16 -0
  16. package/dist/internal/contracts/currentness.js +221 -0
  17. package/dist/internal/contracts/event.js +35 -0
  18. package/dist/internal/contracts/evidence.js +171 -0
  19. package/dist/{types → internal}/contracts/index.d.ts +0 -1
  20. package/dist/internal/contracts/index.js +54 -0
  21. package/dist/internal/contracts/material-capability.js +8 -0
  22. package/dist/internal/contracts/material-carrier.js +15 -0
  23. package/dist/internal/contracts/material-context.js +9 -0
  24. package/dist/internal/contracts/material-read.js +12 -0
  25. package/dist/internal/contracts/observation.js +39 -0
  26. package/dist/internal/contracts/persistence.js +239 -0
  27. package/dist/internal/contracts/project-intent.js +121 -0
  28. package/dist/internal/contracts/projection.js +194 -0
  29. package/dist/internal/contracts/public-reference.js +87 -0
  30. package/dist/internal/contracts/reference-record.js +55 -0
  31. package/dist/internal/contracts/remote-file.js +159 -0
  32. package/dist/internal/contracts/resource-scope.js +38 -0
  33. package/dist/internal/contracts/review-packet.js +61 -0
  34. package/dist/internal/contracts/review-plane.js +89 -0
  35. package/dist/internal/contracts/rich-document.js +184 -0
  36. package/dist/internal/contracts/runtime-compatibility.js +55 -0
  37. package/dist/internal/contracts/runtime.js +68 -0
  38. package/dist/internal/contracts/scheduler.js +256 -0
  39. package/dist/internal/contracts/signal.js +77 -0
  40. package/dist/internal/contracts/source-governance.js +194 -0
  41. package/dist/internal/contracts/source.js +32 -0
  42. package/dist/internal/contracts/tenant-budget.js +34 -0
  43. package/dist/internal/contracts/tenant-collection-request.js +58 -0
  44. package/dist/internal/contracts/tenant-collection.js +66 -0
  45. package/dist/internal/contracts/tenant-currentness.js +26 -0
  46. package/dist/internal/contracts/tenant-management.js +27 -0
  47. package/dist/internal/contracts/tenant-material-api.js +46 -0
  48. package/dist/internal/contracts/tenant-material-json-schema.js +16 -0
  49. package/dist/internal/contracts/tenant-pdf-text.js +13 -0
  50. package/dist/internal/contracts/tenant-project-control.js +19 -0
  51. package/dist/internal/contracts/tenant-public-reference.js +26 -0
  52. package/dist/internal/contracts/tenant-resource-api.js +70 -0
  53. package/dist/internal/contracts/tenant-resource.js +118 -0
  54. package/dist/internal/contracts/tenant-rich-document.js +17 -0
  55. package/dist/internal/contracts/tenant-source-binding.js +33 -0
  56. package/dist/internal/contracts/tenant-source-bridge.js +9 -0
  57. package/dist/internal/contracts/tenant-source-cutover.js +26 -0
  58. package/dist/internal/contracts/tenant-source-document.js +38 -0
  59. package/dist/internal/contracts/tenant-source-lease.js +5 -0
  60. package/dist/internal/contracts/tenant-source.js +83 -0
  61. package/dist/internal/contracts/tenant-web-collection.js +118 -0
  62. package/dist/internal/contracts/tenant-web-content-plan.js +39 -0
  63. package/dist/internal/contracts/tenant-web-content-result.js +15 -0
  64. package/dist/internal/contracts/tenant-web-content.js +16 -0
  65. package/dist/internal/contracts/tenant-web-crawl.js +55 -0
  66. package/dist/internal/contracts/tenant-web-dynamic.js +68 -0
  67. package/dist/internal/contracts/tenant-web-results.js +41 -0
  68. package/dist/internal/contracts/tenant-web-workflow.js +29 -0
  69. package/dist/internal/serving-contracts/agent-catalog.js +56 -0
  70. package/dist/internal/serving-contracts/agent-entry.js +57 -0
  71. package/dist/internal/serving-contracts/agent-guidance-shapes.js +12 -0
  72. package/dist/internal/serving-contracts/agent-input-hints.js +104 -0
  73. package/dist/internal/serving-contracts/body-search.js +16 -0
  74. package/dist/internal/serving-contracts/consumer.js +45 -0
  75. package/dist/internal/serving-contracts/core.js +76 -0
  76. package/dist/internal/serving-contracts/http.js +64 -0
  77. package/dist/{types → internal}/serving-contracts/index.d.ts +1 -0
  78. package/dist/internal/serving-contracts/index.js +25 -0
  79. package/dist/internal/serving-contracts/management.js +15 -0
  80. package/dist/internal/serving-contracts/material-capabilities.js +14 -0
  81. package/dist/internal/serving-contracts/material-index-status.js +5 -0
  82. package/dist/internal/serving-contracts/mcp.js +140 -0
  83. package/dist/internal/serving-contracts/tenant-governance.js +13 -0
  84. package/dist/internal/serving-contracts/tenant-management.js +89 -0
  85. package/dist/internal/serving-contracts/tenant-project.js +39 -0
  86. package/dist/internal/serving-contracts/tenant-runtime.js +37 -0
  87. package/dist/internal/serving-contracts/tenant-session.d.ts +87 -0
  88. package/dist/internal/serving-contracts/tenant-session.js +8 -0
  89. package/dist/internal/serving-contracts/tenant-web-content.js +20 -0
  90. package/dist/internal/serving-contracts/tenant-web-crawl.js +13 -0
  91. package/dist/internal/serving-contracts/tenant-web-dynamic.js +20 -0
  92. package/dist/internal/serving-contracts/tenant-web-workflow.js +36 -0
  93. package/dist/internal/serving-contracts/tenant-web.js +53 -0
  94. package/dist/internal/serving-contracts/tenant-workspace.js +28 -0
  95. package/dist/internal/serving-contracts/workflow.js +37 -0
  96. package/dist/material-stream.js +29 -0
  97. package/dist/{types/sdk/oauth.d.ts → oauth.d.ts} +18 -18
  98. package/dist/oauth.js +539 -0
  99. package/dist/{types/sdk/resource.d.ts → resource.d.ts} +5 -5
  100. package/dist/resource.js +123 -0
  101. package/dist/session.d.ts +4 -0
  102. package/dist/session.js +3 -0
  103. package/dist/tenant-client.d.ts +169 -0
  104. package/dist/tenant-client.js +58 -0
  105. package/dist/{types/sdk/tenant-management.d.ts → tenant-management.d.ts} +6 -6
  106. package/dist/tenant-management.js +149 -0
  107. package/dist/{types/sdk/tenant-project.d.ts → tenant-project.d.ts} +1 -1
  108. package/dist/tenant-project.js +63 -0
  109. package/dist/{types/sdk/tenant-runtime.d.ts → tenant-runtime.d.ts} +1 -1
  110. package/dist/tenant-runtime.js +17 -0
  111. package/dist/{types/sdk/tenant-web-content.d.ts → tenant-web-content.d.ts} +1 -1
  112. package/dist/tenant-web-content.js +70 -0
  113. package/dist/{types/sdk/tenant-web-crawl.d.ts → tenant-web-crawl.d.ts} +1 -1
  114. package/dist/tenant-web-crawl.js +39 -0
  115. package/dist/{types/sdk/tenant-web-dynamic.d.ts → tenant-web-dynamic.d.ts} +1 -1
  116. package/dist/tenant-web-dynamic.js +39 -0
  117. package/dist/{types/sdk/tenant-web-workflow.d.ts → tenant-web-workflow.d.ts} +1 -1
  118. package/dist/tenant-web-workflow.js +63 -0
  119. package/dist/{types/sdk/tenant-web.d.ts → tenant-web.d.ts} +1 -1
  120. package/dist/tenant-web.js +39 -0
  121. package/dist/{types/sdk/tenant-workspace.d.ts → tenant-workspace.d.ts} +1 -1
  122. package/dist/tenant-workspace.js +21 -0
  123. package/dist/token-provider.d.ts +14 -0
  124. package/dist/token-provider.js +21 -0
  125. package/package.json +27 -15
  126. package/dist/types/contracts/resource-transfer.d.ts +0 -24
  127. package/dist/types/sdk/resource-integrity.d.ts +0 -21
  128. package/dist/types/sdk/transport.d.ts +0 -16
  129. /package/dist/{types → internal}/contracts/artifact.d.ts +0 -0
  130. /package/dist/{types → internal}/contracts/collection-control.d.ts +0 -0
  131. /package/dist/{types → internal}/contracts/collection.d.ts +0 -0
  132. /package/dist/{types → internal}/contracts/common.d.ts +0 -0
  133. /package/dist/{types → internal}/contracts/currentness.d.ts +0 -0
  134. /package/dist/{types → internal}/contracts/event.d.ts +0 -0
  135. /package/dist/{types → internal}/contracts/evidence.d.ts +0 -0
  136. /package/dist/{types → internal}/contracts/material-capability.d.ts +0 -0
  137. /package/dist/{types → internal}/contracts/material-carrier.d.ts +0 -0
  138. /package/dist/{types → internal}/contracts/material-context.d.ts +0 -0
  139. /package/dist/{types → internal}/contracts/material-read.d.ts +0 -0
  140. /package/dist/{types → internal}/contracts/observation.d.ts +0 -0
  141. /package/dist/{types → internal}/contracts/persistence.d.ts +0 -0
  142. /package/dist/{types → internal}/contracts/project-intent.d.ts +0 -0
  143. /package/dist/{types → internal}/contracts/projection.d.ts +0 -0
  144. /package/dist/{types → internal}/contracts/public-reference.d.ts +0 -0
  145. /package/dist/{types → internal}/contracts/reference-record.d.ts +0 -0
  146. /package/dist/{types → internal}/contracts/remote-file.d.ts +0 -0
  147. /package/dist/{types → internal}/contracts/resource-scope.d.ts +0 -0
  148. /package/dist/{types → internal}/contracts/review-packet.d.ts +0 -0
  149. /package/dist/{types → internal}/contracts/review-plane.d.ts +0 -0
  150. /package/dist/{types → internal}/contracts/rich-document.d.ts +0 -0
  151. /package/dist/{types → internal}/contracts/runtime-compatibility.d.ts +0 -0
  152. /package/dist/{types → internal}/contracts/runtime.d.ts +0 -0
  153. /package/dist/{types → internal}/contracts/scheduler.d.ts +0 -0
  154. /package/dist/{types → internal}/contracts/signal.d.ts +0 -0
  155. /package/dist/{types → internal}/contracts/source-governance.d.ts +0 -0
  156. /package/dist/{types → internal}/contracts/source.d.ts +0 -0
  157. /package/dist/{types → internal}/contracts/tenant-budget.d.ts +0 -0
  158. /package/dist/{types → internal}/contracts/tenant-collection-request.d.ts +0 -0
  159. /package/dist/{types → internal}/contracts/tenant-collection.d.ts +0 -0
  160. /package/dist/{types → internal}/contracts/tenant-currentness.d.ts +0 -0
  161. /package/dist/{types → internal}/contracts/tenant-management.d.ts +0 -0
  162. /package/dist/{types → internal}/contracts/tenant-material-api.d.ts +0 -0
  163. /package/dist/{types → internal}/contracts/tenant-pdf-text.d.ts +0 -0
  164. /package/dist/{types → internal}/contracts/tenant-project-control.d.ts +0 -0
  165. /package/dist/{types → internal}/contracts/tenant-public-reference.d.ts +0 -0
  166. /package/dist/{types → internal}/contracts/tenant-resource-api.d.ts +0 -0
  167. /package/dist/{types → internal}/contracts/tenant-resource.d.ts +0 -0
  168. /package/dist/{types → internal}/contracts/tenant-rich-document.d.ts +0 -0
  169. /package/dist/{types → internal}/contracts/tenant-source-binding.d.ts +0 -0
  170. /package/dist/{types → internal}/contracts/tenant-source-bridge.d.ts +0 -0
  171. /package/dist/{types → internal}/contracts/tenant-source-cutover.d.ts +0 -0
  172. /package/dist/{types → internal}/contracts/tenant-source-document.d.ts +0 -0
  173. /package/dist/{types → internal}/contracts/tenant-source-lease.d.ts +0 -0
  174. /package/dist/{types → internal}/contracts/tenant-source.d.ts +0 -0
  175. /package/dist/{types → internal}/contracts/tenant-web-collection.d.ts +0 -0
  176. /package/dist/{types → internal}/contracts/tenant-web-content-plan.d.ts +0 -0
  177. /package/dist/{types → internal}/contracts/tenant-web-content-result.d.ts +0 -0
  178. /package/dist/{types → internal}/contracts/tenant-web-content.d.ts +0 -0
  179. /package/dist/{types → internal}/contracts/tenant-web-crawl.d.ts +0 -0
  180. /package/dist/{types → internal}/contracts/tenant-web-dynamic.d.ts +0 -0
  181. /package/dist/{types → internal}/contracts/tenant-web-results.d.ts +0 -0
  182. /package/dist/{types → internal}/contracts/tenant-web-workflow.d.ts +0 -0
  183. /package/dist/{types → internal}/serving-contracts/agent-catalog.d.ts +0 -0
  184. /package/dist/{types → internal}/serving-contracts/agent-entry.d.ts +0 -0
  185. /package/dist/{types → internal}/serving-contracts/agent-guidance-shapes.d.ts +0 -0
  186. /package/dist/{types → internal}/serving-contracts/agent-input-hints.d.ts +0 -0
  187. /package/dist/{types → internal}/serving-contracts/body-search.d.ts +0 -0
  188. /package/dist/{types → internal}/serving-contracts/consumer.d.ts +0 -0
  189. /package/dist/{types → internal}/serving-contracts/core.d.ts +0 -0
  190. /package/dist/{types → internal}/serving-contracts/http.d.ts +0 -0
  191. /package/dist/{types → internal}/serving-contracts/management.d.ts +0 -0
  192. /package/dist/{types → internal}/serving-contracts/material-capabilities.d.ts +0 -0
  193. /package/dist/{types → internal}/serving-contracts/material-index-status.d.ts +0 -0
  194. /package/dist/{types → internal}/serving-contracts/mcp.d.ts +0 -0
  195. /package/dist/{types → internal}/serving-contracts/tenant-governance.d.ts +0 -0
  196. /package/dist/{types → internal}/serving-contracts/tenant-management.d.ts +0 -0
  197. /package/dist/{types → internal}/serving-contracts/tenant-project.d.ts +0 -0
  198. /package/dist/{types → internal}/serving-contracts/tenant-runtime.d.ts +0 -0
  199. /package/dist/{types → internal}/serving-contracts/tenant-web-content.d.ts +0 -0
  200. /package/dist/{types → internal}/serving-contracts/tenant-web-crawl.d.ts +0 -0
  201. /package/dist/{types → internal}/serving-contracts/tenant-web-dynamic.d.ts +0 -0
  202. /package/dist/{types → internal}/serving-contracts/tenant-web-workflow.d.ts +0 -0
  203. /package/dist/{types → internal}/serving-contracts/tenant-web.d.ts +0 -0
  204. /package/dist/{types → internal}/serving-contracts/tenant-workspace.d.ts +0 -0
  205. /package/dist/{types → internal}/serving-contracts/workflow.d.ts +0 -0
  206. /package/dist/{types/sdk/material-stream.d.ts → material-stream.d.ts} +0 -0
@@ -0,0 +1,256 @@
1
+ import { z } from 'zod';
2
+ import { idSchema, isoDateTimeSchema, projectKeySchema, schemaVersionSchema } from './common.js';
3
+ import { signalProfileNameSchema } from './signal.js';
4
+ import { runtimeCapabilitySchema } from './runtime.js';
5
+ export const TIPP_UNIVERSE_MAX_RESOURCE_BYTES = 8 * 1024 * 1024;
6
+ const deploymentPathSchema = z.string().trim().min(1).max(4096).refine((value) => !value.includes('\0'), 'path must not contain NUL');
7
+ const scheduledWorkloadBaseSchema = z.object({
8
+ workloadId: idSchema,
9
+ projectKey: projectKeySchema,
10
+ priority: z.number().int().min(0).max(1000),
11
+ intervalSeconds: z.number().int().min(60).max(7 * 24 * 60 * 60),
12
+ timeoutSeconds: z.number().int().min(30).max(2 * 60 * 60).default(15 * 60),
13
+ assignmentFile: deploymentPathSchema,
14
+ initialDueAt: isoDateTimeSchema.optional(),
15
+ }).strict();
16
+ const acquisitionInvocationSchema = z.object({
17
+ command: z.literal('acquisition-run'),
18
+ programDirectory: deploymentPathSchema,
19
+ fileRootsFile: deploymentPathSchema.optional(),
20
+ }).strict();
21
+ const reviewPacketInvocationSchema = z.object({
22
+ command: z.literal('review-packet-project'),
23
+ }).strict();
24
+ // 自动发布只消费已持久化的事件和 Agent 输入,不触发任何来源采集。
25
+ const autoPublicationInvocationSchema = z.object({
26
+ command: z.literal('auto-publication-tick'),
27
+ // 同项目发布并发有固定上限;旧 manifest 无此字段时采用 Runner 默认值。
28
+ concurrency: z.number().int().min(1).max(4).optional(),
29
+ }).strict();
30
+ const publicReferenceInvocationSchema = z.object({ command: z.literal('public-reference-tick'), policyFile: deploymentPathSchema, identityDatabase: deploymentPathSchema }).strict();
31
+ const feedProjectInvocationSchema = z.object({
32
+ command: z.literal('feed-project'),
33
+ }).strict();
34
+ const procurementProjectInvocationSchema = z.object({
35
+ command: z.literal('procurement-project'),
36
+ }).strict();
37
+ const pkValuationStatusProjectInvocationSchema = z.object({
38
+ command: z.literal('pk-valuation-status-project'),
39
+ }).strict();
40
+ const pkStandardsProjectInvocationSchema = z.object({
41
+ command: z.literal('pk-standards-project'),
42
+ }).strict();
43
+ const cpecProjectInvocationSchema = z.object({
44
+ command: z.literal('cpec-project'),
45
+ }).strict();
46
+ const tippUniverseProjectInvocationSchema = z.object({
47
+ command: z.literal('tipp-universe-project'),
48
+ chapterBatch: z.number().int().min(1).max(96).default(4),
49
+ maxResourceBytes: z.number().int().min(64 * 1024).max(16 * 1024 * 1024).default(TIPP_UNIVERSE_MAX_RESOURCE_BYTES),
50
+ }).strict();
51
+ const tippDetailProjectInvocationSchema = z.object({
52
+ command: z.literal('tipp-detail-project'),
53
+ detailBatch: z.number().int().min(1).max(1000).default(50),
54
+ detailConcurrency: z.number().int().min(1).max(4).optional(),
55
+ maxResourceBytes: z.number().int().min(64 * 1024).max(16 * 1024 * 1024).default(4 * 1024 * 1024),
56
+ }).strict();
57
+ const tippTariffProjectInvocationSchema = z.object({
58
+ command: z.literal('tipp-tariff-project'),
59
+ }).strict();
60
+ const tippRegulatoryProjectInvocationSchema = z.object({
61
+ command: z.literal('tipp-regulatory-project'),
62
+ }).strict();
63
+ const pkTariffReconciliationProjectInvocationSchema = z.object({
64
+ command: z.literal('pk-tariff-reconciliation-project'),
65
+ }).strict();
66
+ const collectionInvocationSchema = z.object({
67
+ command: z.literal('collection-tick'),
68
+ maxResourceBytes: z.number().int().min(1024).max(64 * 1024 * 1024).default(16 * 1024 * 1024),
69
+ batchLimit: z.number().int().min(1).max(10_000).default(100),
70
+ fileRootsFile: deploymentPathSchema.optional(),
71
+ }).strict();
72
+ const collectionProjectionInvocationSchema = z.object({ command: z.literal('collection-projection-tick'), limit: z.number().int().min(1).max(100).default(25) }).strict();
73
+ const signalCollectInvocationSchema = z.object({
74
+ command: z.literal('signal-collect'),
75
+ programFile: deploymentPathSchema,
76
+ profile: signalProfileNameSchema,
77
+ }).strict();
78
+ const signalComposeInvocationSchema = z.object({
79
+ command: z.literal('signal-compose'),
80
+ programFile: deploymentPathSchema,
81
+ }).strict();
82
+ const customsCorpusInvocationSchema = z.object({
83
+ command: z.literal('customs-corpus-run'),
84
+ programFile: deploymentPathSchema,
85
+ adapter: z.enum(['us-hts', 'us-cross', 'ca-tariff', 'ca-rulings', 'eu-ebti', 'pk-tariff', 'pk-import-sro', 'pk-tax-authorities', 'pk-classification', 'pk-valuation', 'za-determinations', 'eg-nafeza', 'ae-tariff', 'sa-tariff', 'ru-eaeu']),
86
+ refreshStoredDocuments: z.boolean().optional(),
87
+ // GCC 重新访问官方来源必须显式启用,历史文件导入不触发网络。
88
+ refreshRemoteBundle: z.boolean().optional(),
89
+ }).strict();
90
+ const locationCorpusInvocationSchema = z.object({
91
+ command: z.literal('location-corpus-run'),
92
+ programFile: deploymentPathSchema,
93
+ adapter: z.literal('unlocode'),
94
+ }).strict();
95
+ export const schedulerInvocationSchema = z.discriminatedUnion('command', [
96
+ z.object({ command: z.literal('business-information-collect'), maxSources: z.number().int().min(1).max(32).default(8), maxResourceBytes: z.number().int().min(1024).max(16 * 1024 * 1024).default(2 * 1024 * 1024), fileRootsFile: deploymentPathSchema.optional() }).strict(),
97
+ z.object({ command: z.literal('pk-import-rules-project'), acquireLinkedDocuments: z.boolean().default(false), documentBatch: z.number().int().min(1).max(50).default(20), maxDocumentBytes: z.number().int().min(1024).max(32 * 1024 * 1024).default(16 * 1024 * 1024) }).strict(),
98
+ acquisitionInvocationSchema,
99
+ collectionInvocationSchema,
100
+ collectionProjectionInvocationSchema,
101
+ z.object({ command: z.literal('project-projection-tick'),
102
+ maxRows: z.number().int().min(1).max(100).optional(),
103
+ maxDependencyRows: z.number().int().min(1).max(10000).optional(),
104
+ maxBytes: z.number().int().min(1).max(16 * 1024 ** 3).optional(),
105
+ maxMs: z.number().int().min(1).max(600000).optional(),
106
+ }).strict(),
107
+ reviewPacketInvocationSchema,
108
+ autoPublicationInvocationSchema,
109
+ publicReferenceInvocationSchema,
110
+ feedProjectInvocationSchema,
111
+ procurementProjectInvocationSchema,
112
+ pkValuationStatusProjectInvocationSchema,
113
+ pkStandardsProjectInvocationSchema,
114
+ cpecProjectInvocationSchema,
115
+ tippUniverseProjectInvocationSchema,
116
+ tippDetailProjectInvocationSchema,
117
+ tippTariffProjectInvocationSchema,
118
+ tippRegulatoryProjectInvocationSchema,
119
+ pkTariffReconciliationProjectInvocationSchema,
120
+ signalCollectInvocationSchema,
121
+ signalComposeInvocationSchema,
122
+ customsCorpusInvocationSchema,
123
+ locationCorpusInvocationSchema,
124
+ ]);
125
+ export const scheduledWorkloadSchema = scheduledWorkloadBaseSchema.extend({
126
+ invocation: schedulerInvocationSchema,
127
+ }).strict().superRefine((value, ctx) => {
128
+ let expected;
129
+ switch (value.invocation.command) {
130
+ case 'acquisition-run':
131
+ expected = `project:${value.projectKey}:acquisition`;
132
+ break;
133
+ case 'collection-projection-tick':
134
+ expected = `project:${value.projectKey}:material-projection`;
135
+ break;
136
+ case 'project-projection-tick':
137
+ expected = `project:${value.projectKey}:catalog-projection`;
138
+ break;
139
+ case 'collection-tick':
140
+ expected = `project:${value.projectKey}:collection`;
141
+ break;
142
+ case 'review-packet-project':
143
+ expected = `project:${value.projectKey}:review-packets`;
144
+ break;
145
+ case 'auto-publication-tick':
146
+ expected = `project:${value.projectKey}:auto-publication`;
147
+ break;
148
+ case 'public-reference-tick':
149
+ expected = `project:${value.projectKey}:public-reference-publication`;
150
+ break;
151
+ case 'feed-project':
152
+ expected = `project:${value.projectKey}:feed-project`;
153
+ break;
154
+ case 'procurement-project':
155
+ expected = `project:${value.projectKey}:procurement-project`;
156
+ break;
157
+ case 'pk-valuation-status-project':
158
+ expected = `project:${value.projectKey}:pk-valuation-status-project`;
159
+ break;
160
+ case 'pk-standards-project':
161
+ expected = `project:${value.projectKey}:pk-standards-project`;
162
+ break;
163
+ case 'pk-import-rules-project':
164
+ expected = `project:${value.projectKey}:pk-import-rules-project`;
165
+ break;
166
+ case 'cpec-project':
167
+ expected = `project:${value.projectKey}:cpec-project`;
168
+ break;
169
+ case 'business-information-collect':
170
+ expected = `project:${value.projectKey}:business-information-collect`;
171
+ break;
172
+ case 'tipp-universe-project':
173
+ expected = `project:${value.projectKey}:tipp-universe-project`;
174
+ break;
175
+ case 'tipp-detail-project':
176
+ expected = `project:${value.projectKey}:tipp-detail-project`;
177
+ break;
178
+ case 'tipp-tariff-project':
179
+ expected = `project:${value.projectKey}:tipp-tariff-project`;
180
+ break;
181
+ case 'tipp-regulatory-project':
182
+ expected = `project:${value.projectKey}:tipp-regulatory-project`;
183
+ break;
184
+ case 'pk-tariff-reconciliation-project':
185
+ expected = `project:${value.projectKey}:pk-tariff-reconciliation-project`;
186
+ break;
187
+ case 'signal-collect':
188
+ expected = `project:${value.projectKey}:signal:${value.invocation.profile}`;
189
+ break;
190
+ case 'signal-compose':
191
+ expected = `project:${value.projectKey}:signal:compose`;
192
+ break;
193
+ case 'customs-corpus-run':
194
+ expected = `project:${value.projectKey}:customs:${value.invocation.adapter}`;
195
+ break;
196
+ case 'location-corpus-run':
197
+ expected = `project:${value.projectKey}:locations:${value.invocation.adapter}`;
198
+ break;
199
+ }
200
+ if (value.workloadId !== expected) {
201
+ ctx.addIssue({ code: 'custom', path: ['workloadId'], message: `workloadId must be ${expected}` });
202
+ }
203
+ });
204
+ export const nodeSchedulerManifestSchema = z.object({
205
+ schemaVersion: schemaVersionSchema,
206
+ nodeId: idSchema,
207
+ capabilities: z.array(runtimeCapabilitySchema).max(128).default(['network:http']),
208
+ maxWorkloadsPerTick: z.number().int().min(1).max(32).default(8),
209
+ workloads: z.array(scheduledWorkloadSchema).max(256),
210
+ }).strict().superRefine((value, ctx) => {
211
+ const seen = new Set();
212
+ const capabilities = new Set(value.capabilities);
213
+ value.workloads.forEach((workload, index) => {
214
+ if (seen.has(workload.workloadId))
215
+ ctx.addIssue({ code: 'custom', path: ['workloads', index, 'workloadId'], message: 'duplicate workloadId' });
216
+ seen.add(workload.workloadId);
217
+ if (workload.invocation.command === 'business-information-collect' && !capabilities.has('network:http'))
218
+ ctx.addIssue({ code: 'custom', path: ['workloads', index, 'invocation'], message: 'public business collection requires network:http capability' });
219
+ if ((workload.invocation.command === 'collection-tick' || workload.invocation.command === 'collection-projection-tick') && !capabilities.has('network:http')) {
220
+ ctx.addIssue({ code: 'custom', path: ['workloads', index, 'invocation'], message: 'collection tick requires network:http capability' });
221
+ }
222
+ if (workload.invocation.command === 'signal-collect') {
223
+ if (!capabilities.has('network:http')) {
224
+ ctx.addIssue({ code: 'custom', path: ['workloads', index, 'invocation'], message: 'signal collection requires network:http capability' });
225
+ }
226
+ if (['tiktok', 'douyin', 'meta', 'deep-social'].includes(workload.invocation.profile) && !capabilities.has('browser:playwright')) {
227
+ ctx.addIssue({ code: 'custom', path: ['workloads', index, 'invocation'], message: `profile ${workload.invocation.profile} requires browser:playwright capability` });
228
+ }
229
+ }
230
+ if (workload.invocation.command === 'location-corpus-run' && !capabilities.has('network:http')) {
231
+ ctx.addIssue({ code: 'custom', path: ['workloads', index, 'invocation'], message: 'reference corpus collection requires network:http capability' });
232
+ }
233
+ if (workload.invocation.command === 'tipp-universe-project' && !capabilities.has('network:http')) {
234
+ ctx.addIssue({ code: 'custom', path: ['workloads', index, 'invocation'], message: 'TIPP universe collection requires network:http capability' });
235
+ }
236
+ if (workload.invocation.command === 'tipp-detail-project' && !capabilities.has('network:http')) {
237
+ ctx.addIssue({ code: 'custom', path: ['workloads', index, 'invocation'], message: 'TIPP detail collection requires network:http capability' });
238
+ }
239
+ if (workload.invocation.command === 'customs-corpus-run') {
240
+ if (workload.invocation.refreshRemoteBundle) {
241
+ if (!['ae-tariff', 'sa-tariff'].includes(workload.invocation.adapter))
242
+ ctx.addIssue({ code: 'custom', path: ['workloads', index, 'invocation', 'refreshRemoteBundle'], message: 'GCC refresh requires ae-tariff or sa-tariff adapter' });
243
+ if (!capabilities.has('network:http'))
244
+ ctx.addIssue({ code: 'custom', path: ['workloads', index, 'invocation'], message: 'GCC refresh requires network:http capability' });
245
+ }
246
+ if (workload.invocation.refreshStoredDocuments && !['pk-import-sro', 'ru-eaeu'].includes(workload.invocation.adapter)) {
247
+ ctx.addIssue({ code: 'custom', path: ['workloads', index, 'invocation', 'refreshStoredDocuments'], message: 'stored document refresh requires pk-import-sro or ru-eaeu adapter' });
248
+ }
249
+ const localVerifiedBundleAdapter = ['pk-valuation', 'za-determinations', 'ae-tariff', 'sa-tariff'].includes(workload.invocation.adapter);
250
+ if (!localVerifiedBundleAdapter && !capabilities.has('network:http')) {
251
+ ctx.addIssue({ code: 'custom', path: ['workloads', index, 'invocation'], message: `customs adapter ${workload.invocation.adapter} requires network:http capability` });
252
+ }
253
+ }
254
+ });
255
+ });
256
+ export const scheduledWorkerCommands = schedulerInvocationSchema.options.map(option => option.shape.command.value);
@@ -0,0 +1,77 @@
1
+ import { z } from 'zod';
2
+ import { idSchema, isoDateTimeSchema, projectKeySchema, schemaVersionSchema, sha256Schema, stableUriSchema, } from './common.js';
3
+ export const signalProfileNameSchema = z.enum([
4
+ 'trends',
5
+ 'hn',
6
+ 'github',
7
+ 'autocomplete',
8
+ 'youtube',
9
+ 'tiktok',
10
+ 'douyin',
11
+ 'meta',
12
+ 'deep-social',
13
+ ]);
14
+ export const signalSourceHealthSchema = z.object({
15
+ ok: z.boolean(),
16
+ items: z.number().int().nonnegative().optional(),
17
+ state: z.string().trim().min(1).max(128).optional(),
18
+ note: z.string().trim().max(2000).optional(),
19
+ error: z.string().trim().max(2000).optional(),
20
+ }).catchall(z.unknown());
21
+ export const signalSourceSnapshotSchema = z.object({
22
+ schemaVersion: schemaVersionSchema,
23
+ projectKey: projectKeySchema,
24
+ projectRef: stableUriSchema.optional(),
25
+ sourceRef: stableUriSchema.optional(),
26
+ sourceRevisionRef: stableUriSchema.optional(),
27
+ sourceKey: idSchema,
28
+ profile: signalProfileNameSchema,
29
+ collectedAt: isoDateTimeSchema,
30
+ contentHash: sha256Schema,
31
+ evidenceId: idSchema,
32
+ signalCount: z.number().int().nonnegative(),
33
+ health: signalSourceHealthSchema,
34
+ }).strict();
35
+ export const signalSourceAttemptSchema = z.object({
36
+ schemaVersion: schemaVersionSchema,
37
+ projectKey: projectKeySchema,
38
+ projectRef: stableUriSchema.optional(),
39
+ sourceRef: stableUriSchema.optional(),
40
+ sourceRevisionRef: stableUriSchema.optional(),
41
+ sourceKey: idSchema,
42
+ profile: signalProfileNameSchema,
43
+ lastAttemptAt: isoDateTimeSchema,
44
+ lastSuccessAt: isoDateTimeSchema.nullable(),
45
+ success: z.boolean(),
46
+ durationMs: z.number().int().nonnegative(),
47
+ state: z.string().trim().min(1).max(128).nullable(),
48
+ error: z.string().trim().max(2000).nullable(),
49
+ }).strict();
50
+ export const signalGenerationSchema = z.object({
51
+ schemaVersion: schemaVersionSchema,
52
+ projectKey: projectKeySchema,
53
+ projectRef: stableUriSchema.optional(),
54
+ generationKey: sha256Schema,
55
+ scoringProfile: z.string().trim().min(1).max(128),
56
+ generatedAt: isoDateTimeSchema,
57
+ snapshotManifest: z.record(idSchema, sha256Schema),
58
+ historyBasis: z.array(sha256Schema).max(512).default([]),
59
+ contentHash: sha256Schema,
60
+ candidateCount: z.number().int().nonnegative(),
61
+ observationCount: z.number().int().nonnegative(),
62
+ }).strict();
63
+ export const signalHistoryCandidateSchema = z.object({
64
+ query: z.string().trim().min(1).max(1000),
65
+ score: z.number().finite(),
66
+ sources: z.array(idSchema).max(64),
67
+ }).strict();
68
+ export const signalHistorySeedSchema = z.object({
69
+ schemaVersion: schemaVersionSchema,
70
+ projectKey: projectKeySchema,
71
+ projectRef: stableUriSchema.optional(),
72
+ historyKey: sha256Schema,
73
+ generatedAt: isoDateTimeSchema,
74
+ scoringVersion: z.number().int().positive(),
75
+ origin: z.string().trim().min(1).max(128),
76
+ candidates: z.array(signalHistoryCandidateSchema).max(120),
77
+ }).strict();
@@ -0,0 +1,194 @@
1
+ import { z } from 'zod';
2
+ import { accessClassificationSchema, idSchema, isoDateTimeSchema, projectKeySchema, schemaVersionSchema, stableUriSchema, } from './common.js';
3
+ export const sourceExpectationSchema = z.enum(['REQUIRED', 'OPTIONAL', 'CONDITIONAL']);
4
+ export const sourceDeclaredStateSchema = z.enum([
5
+ 'CONFIGURED',
6
+ 'PENDING_DISCOVERY',
7
+ 'KNOWN_MISSING',
8
+ 'ACCESS_CONTROLLED',
9
+ 'NEED_AUTHORIZED_SOURCE',
10
+ 'DEFERRED',
11
+ 'RETIRED',
12
+ ]);
13
+ export const sourceCoverageStateSchema = z.enum([
14
+ 'ACQUIRED',
15
+ 'CONFIGURED_UNOBSERVED',
16
+ 'PARTIAL',
17
+ 'BLOCKED',
18
+ 'ACCESS_CONTROLLED',
19
+ 'PENDING_DISCOVERY',
20
+ 'KNOWN_MISSING',
21
+ 'NEED_AUTHORIZED_SOURCE',
22
+ 'DEFERRED',
23
+ 'RETIRED',
24
+ ]);
25
+ const shortText = z.string().trim().min(1).max(512);
26
+ const roleSchema = z.string().trim().min(1).max(256);
27
+ export const sourceDiscoveryPolicySchema = z.object({
28
+ hostMode: z.enum(['ALLOWLIST', 'EVIDENCE_OBSERVED']).default('ALLOWLIST'),
29
+ allowedHosts: z.array(z.string().trim().toLowerCase().min(1).max(253)).max(256).default([]),
30
+ forbiddenHostSuffixes: z.array(z.string().trim().toLowerCase().min(1).max(253)).max(256).default([]),
31
+ allowedPathPrefixes: z.array(z.string().trim().startsWith('/').max(2048)).min(1).max(128),
32
+ }).strict().superRefine((value, ctx) => {
33
+ if (value.hostMode === 'ALLOWLIST' && !value.allowedHosts.length)
34
+ ctx.addIssue({ code: 'custom', path: ['allowedHosts'], message: 'ALLOWLIST discovery requires at least one allowed host' });
35
+ const allowed = new Set(value.allowedHosts);
36
+ for (const suffix of value.forbiddenHostSuffixes)
37
+ if (allowed.has(suffix))
38
+ ctx.addIssue({ code: 'custom', path: ['forbiddenHostSuffixes'], message: `Host cannot be both allowed and forbidden: ${suffix}` });
39
+ });
40
+ export const sourceUniverseEntrySchema = z.object({
41
+ sourceId: idSchema,
42
+ familyId: idSchema,
43
+ acquisitionSourceIds: z.array(idSchema).max(64).default([]),
44
+ expectation: sourceExpectationSchema,
45
+ authority: shortText,
46
+ access: accessClassificationSchema,
47
+ freshness: shortText,
48
+ semanticRoles: z.array(roleSchema).max(64).default([]),
49
+ locator: stableUriSchema.nullable().default(null),
50
+ declaredState: sourceDeclaredStateSchema,
51
+ expectedOwner: shortText.nullable().default(null),
52
+ requiredFor: z.array(idSchema).max(128).default([]),
53
+ discoveryPolicy: sourceDiscoveryPolicySchema.nullable().default(null),
54
+ notes: z.string().trim().max(2000).nullable().default(null),
55
+ }).strict().superRefine((value, ctx) => {
56
+ if (value.declaredState === 'CONFIGURED' && value.locator === null) {
57
+ ctx.addIssue({ code: 'custom', path: ['locator'], message: 'CONFIGURED source requires locator' });
58
+ }
59
+ if (['PENDING_DISCOVERY', 'KNOWN_MISSING', 'ACCESS_CONTROLLED', 'NEED_AUTHORIZED_SOURCE'].includes(value.declaredState) && value.expectation === 'OPTIONAL' && !value.requiredFor.length) {
60
+ ctx.addIssue({ code: 'custom', path: ['requiredFor'], message: 'unresolved optional source must declare why it is tracked' });
61
+ }
62
+ });
63
+ export const sourceUniverseSchema = z.object({
64
+ schemaVersion: schemaVersionSchema,
65
+ projectKey: projectKeySchema,
66
+ asOf: isoDateTimeSchema,
67
+ sources: z.array(sourceUniverseEntrySchema).min(1).max(5000),
68
+ }).strict().superRefine((value, ctx) => {
69
+ const ids = new Set();
70
+ for (let i = 0; i < value.sources.length; i += 1) {
71
+ const id = value.sources[i].sourceId;
72
+ if (ids.has(id))
73
+ ctx.addIssue({ code: 'custom', path: ['sources', i, 'sourceId'], message: 'sourceId must be unique' });
74
+ ids.add(id);
75
+ }
76
+ });
77
+ export const sourceCoverageEntrySchema = z.object({
78
+ sourceId: idSchema,
79
+ familyId: idSchema,
80
+ expectation: sourceExpectationSchema,
81
+ declaredState: sourceDeclaredStateSchema,
82
+ coverageState: sourceCoverageStateSchema,
83
+ configuredItemCount: z.number().int().nonnegative(),
84
+ observedItemCount: z.number().int().nonnegative(),
85
+ acquiredItemCount: z.number().int().nonnegative(),
86
+ blockedItemCount: z.number().int().nonnegative(),
87
+ accessControlledItemCount: z.number().int().nonnegative(),
88
+ evidenceRefs: z.array(stableUriSchema).max(2048),
89
+ blockers: z.array(shortText).max(256),
90
+ }).strict();
91
+ export const sourceCoverageAssessmentSchema = z.object({
92
+ schemaVersion: schemaVersionSchema,
93
+ projectKey: projectKeySchema,
94
+ assessedAt: isoDateTimeSchema,
95
+ complete: z.boolean(),
96
+ requiredSourceCount: z.number().int().nonnegative(),
97
+ coveredRequiredSourceCount: z.number().int().nonnegative(),
98
+ entries: z.array(sourceCoverageEntrySchema).max(5000),
99
+ blockers: z.array(shortText).max(1000),
100
+ }).strict();
101
+ export const sourceGapStateSchema = z.enum([
102
+ 'PENDING_DISCOVERY',
103
+ 'KNOWN_MISSING',
104
+ 'ACCESS_CONTROLLED',
105
+ 'NEED_AUTHORIZED_SOURCE',
106
+ 'DEFERRED',
107
+ ]);
108
+ export const sourceGapSchema = z.object({
109
+ schemaVersion: schemaVersionSchema,
110
+ gapId: idSchema,
111
+ projectKey: projectKeySchema,
112
+ sourceId: idSchema,
113
+ familyId: idSchema,
114
+ state: sourceGapStateSchema,
115
+ access: accessClassificationSchema,
116
+ expectedOwner: shortText.nullable(),
117
+ reason: z.string().trim().min(1).max(2000),
118
+ requiredFor: z.array(idSchema).max(128),
119
+ evidenceRefs: z.array(stableUriSchema).max(256),
120
+ recordedAt: isoDateTimeSchema,
121
+ }).strict();
122
+ const discoveryLinkIdSchema = z.string().trim().min(1).max(128).regex(/^[A-Za-z0-9][A-Za-z0-9._-]*$/);
123
+ const discoveredLinkSchema = z.object({
124
+ linkId: discoveryLinkIdSchema,
125
+ url: z.url(),
126
+ locator: z.string().trim().min(1).max(2048),
127
+ parentEvidenceRef: stableUriSchema,
128
+ title: z.string().trim().min(1).max(500).optional(),
129
+ }).strict();
130
+ export const sourceDiscoveryProposalSchema = z.object({
131
+ schemaVersion: schemaVersionSchema,
132
+ projectKey: projectKeySchema,
133
+ proposalId: idSchema,
134
+ familyId: idSchema,
135
+ createdAt: isoDateTimeSchema,
136
+ observedLinks: z.array(discoveredLinkSchema).min(1).max(1000),
137
+ selectedLinkIds: z.array(discoveryLinkIdSchema).max(1000),
138
+ completeness: z.object({
139
+ claim: z.enum(['COMPLETE', 'INCOMPLETE']),
140
+ missing: z.array(z.string().trim().min(1).max(500)).max(1000),
141
+ notes: z.string().trim().max(4000).nullable().default(null),
142
+ }).strict(),
143
+ }).strict();
144
+ export const sourceDiscoveryValidationSchema = z.object({
145
+ schemaVersion: schemaVersionSchema,
146
+ projectKey: projectKeySchema,
147
+ proposalId: idSchema,
148
+ familyId: idSchema,
149
+ proposalHash: z.string().regex(/^sha256:[a-f0-9]{64}$/),
150
+ valid: z.boolean(),
151
+ selectedSources: z.array(z.object({ linkId: idSchema, url: z.url(), parentEvidenceRef: stableUriSchema }).strict()).max(1000),
152
+ completeness: z.object({ claim: z.enum(['COMPLETE', 'INCOMPLETE']), missing: z.array(z.string()).max(1000), notes: z.string().nullable() }).strict(),
153
+ evidenceRefs: z.array(stableUriSchema).max(1000),
154
+ errors: z.array(shortText).max(1000),
155
+ warnings: z.array(shortText).max(1000),
156
+ }).strict();
157
+ export const sourceDiscoveryReceiptSchema = z.object({
158
+ schemaVersion: schemaVersionSchema,
159
+ projectKey: projectKeySchema,
160
+ proposalId: idSchema,
161
+ familyId: idSchema,
162
+ proposalHash: z.string().regex(/^sha256:[a-f0-9]{64}$/),
163
+ state: z.enum(['COMPLETE', 'REVIEWED_PARTIAL']),
164
+ proposalRef: stableUriSchema,
165
+ reviewRef: stableUriSchema,
166
+ reviewedAt: isoDateTimeSchema,
167
+ selectedSources: z.array(z.object({ linkId: idSchema, url: z.url(), parentEvidenceRef: stableUriSchema }).strict()).max(1000),
168
+ completeness: z.object({ claim: z.enum(['COMPLETE', 'INCOMPLETE']), missing: z.array(z.string()).max(1000), notes: z.string().nullable() }).strict(),
169
+ evidenceRefs: z.array(stableUriSchema).max(1000),
170
+ configMutationPerformed: z.literal(false),
171
+ }).strict().superRefine((value, ctx) => {
172
+ if (value.state === 'COMPLETE' && (value.completeness.claim !== 'COMPLETE' || value.completeness.missing.length))
173
+ ctx.addIssue({ code: 'custom', path: ['state'], message: 'COMPLETE receipt requires complete proposal without missing sources' });
174
+ if (value.state === 'REVIEWED_PARTIAL' && value.completeness.claim !== 'INCOMPLETE')
175
+ ctx.addIssue({ code: 'custom', path: ['state'], message: 'REVIEWED_PARTIAL receipt requires INCOMPLETE proposal' });
176
+ });
177
+ export const sourceAdmissionMatchSchema = z.object({
178
+ url: z.url(),
179
+ status: z.enum(['ADMITTED', 'BLOCKED', 'MISSING', 'DUPLICATE']),
180
+ universeSourceId: idSchema.nullable(),
181
+ acquisitionSourceId: idSchema.nullable(),
182
+ concreteSourceId: idSchema.nullable(),
183
+ issues: z.array(shortText).max(128),
184
+ }).strict();
185
+ export const sourceAdmissionAssessmentSchema = z.object({
186
+ schemaVersion: schemaVersionSchema,
187
+ projectKey: projectKeySchema,
188
+ familyId: idSchema,
189
+ state: z.enum(['ADMITTED', 'BLOCKED']),
190
+ selectedSourceCount: z.number().int().nonnegative(),
191
+ matches: z.array(sourceAdmissionMatchSchema).max(1000),
192
+ blockers: z.array(shortText).max(1000),
193
+ configMutationPerformed: z.literal(false),
194
+ }).strict();
@@ -0,0 +1,32 @@
1
+ import { z } from 'zod';
2
+ import { accessClassificationSchema, idSchema, projectKeySchema, schemaVersionSchema, stableUriSchema, } from './common.js';
3
+ export const sourceKindSchema = z.enum([
4
+ 'WEB',
5
+ 'API',
6
+ 'FILE',
7
+ 'REPOSITORY',
8
+ 'FEED',
9
+ 'SOCIAL',
10
+ 'BROWSER',
11
+ 'MANUAL',
12
+ 'OTHER',
13
+ ]);
14
+ export const sourceDefinitionSchema = z.object({
15
+ schemaVersion: schemaVersionSchema,
16
+ sourceId: idSchema,
17
+ projectKey: projectKeySchema.optional(),
18
+ kind: sourceKindSchema,
19
+ authority: z.string().trim().min(1).max(256),
20
+ access: accessClassificationSchema,
21
+ canonicalUri: stableUriSchema.optional(),
22
+ refreshPolicy: z.string().trim().min(1).max(256),
23
+ enabled: z.boolean(),
24
+ tags: z.array(z.string().trim().min(1).max(128)).max(64).default([]),
25
+ }).strict();
26
+ export const collectorDefinitionSchema = z.object({
27
+ schemaVersion: schemaVersionSchema,
28
+ collectorId: idSchema,
29
+ version: z.string().trim().min(1).max(128),
30
+ supportedSourceKinds: z.array(sourceKindSchema).min(1),
31
+ capabilities: z.array(z.string().trim().min(1).max(128)).max(64),
32
+ }).strict();
@@ -0,0 +1,34 @@
1
+ /** Host-authored admission accounting, independent of business authorization and receipt schemas. */
2
+ import { z } from 'zod';
3
+ import { createHash } from 'node:crypto';
4
+ import { materialTenantIdSchema } from './material-context.js';
5
+ import { isoDateTimeSchema } from './common.js';
6
+ import { parseTenantCollectionBatchRef } from './tenant-collection.js';
7
+ import { tenantStorageKey } from './resource-scope.js';
8
+ const positive = (max) => z.number().int().min(1).max(max);
9
+ export const tenantBudgetPolicySchema = z.object({ tenantId: materialTenantIdSchema, maxInFlight: positive(32), maxWorkUnits: positive(1_000_000), maxRuntimeMs: positive(86_400_000), weight: positive(8), paused: z.boolean() }).strict();
10
+ export const tenantBudgetConfigSchema = z.object({ schemaVersion: z.literal(1), windowSeconds: z.number().int().min(60).max(86400), maxInFlight: positive(128), maxWaitRounds: positive(2048), tenants: z.array(tenantBudgetPolicySchema).min(1).max(128) }).strict().superRefine((value, ctx) => {
11
+ if (new Set(value.tenants.map(t => t.tenantId)).size !== value.tenants.length || value.tenants.some(t => t.maxInFlight > value.maxInFlight) || value.tenants.reduce((sum, t) => sum + t.weight, 0) > value.maxWaitRounds)
12
+ ctx.addIssue({ code: 'custom', message: 'Unique Tenants, Host limits and weighted waiting bound are required' });
13
+ });
14
+ export const tenantBudgetCandidateSchema = z.object({ key: z.string().regex(/^[a-f0-9]{64}$/), tenantId: materialTenantIdSchema, workUnits: positive(100_000), runtimeMs: z.number().int().min(1000).max(7_200_000) }).strict();
15
+ export const tenantBudgetReservationSchema = tenantBudgetCandidateSchema.extend({ admissionId: z.string().uuid(), nodeId: z.string().regex(/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/), startedAt: isoDateTimeSchema, expiresAt: isoDateTimeSchema, windowStart: isoDateTimeSchema }).strict();
16
+ export const tenantBudgetReasonSchema = z.enum(['READY', 'TENANT_UNCONFIGURED', 'PAUSED', 'HOST_IN_FLIGHT', 'TENANT_IN_FLIGHT', 'WORK_BUDGET', 'TIME_BUDGET', 'WORK_ACTIVE']);
17
+ /** 两小时是整个准入的硬上限;短任务保留结算余量,合法的上限任务不因此被排除。 */
18
+ export function tenantLegacyAdmissionRuntimeMs(timeoutSeconds) {
19
+ if (!Number.isInteger(timeoutSeconds) || timeoutSeconds < 30 || timeoutSeconds > 7200)
20
+ throw new Error('TENANT_LEGACY_TIMEOUT_INVALID');
21
+ return Math.min(7_200_000, timeoutSeconds * 1000 + 2000);
22
+ }
23
+ export function tenantCollectionAdmissionKey(tenantId, batchRef) {
24
+ const batch = parseTenantCollectionBatchRef(batchRef);
25
+ if (!batch || batch.storageKey !== tenantStorageKey(tenantId))
26
+ throw new Error('TENANT_BUDGET_WORK_SCOPE_INVALID');
27
+ return createHash('sha256').update(JSON.stringify(['TENANT_COLLECTION_ADMISSION_V1', tenantId, batchRef])).digest('hex');
28
+ }
29
+ export function tenantLegacyAdmissionKey(tenantId, workloadId) {
30
+ materialTenantIdSchema.parse(tenantId);
31
+ if (typeof workloadId !== 'string' || workloadId.length > 256 || !/^project:[A-Za-z0-9][A-Za-z0-9._-]{0,127}:.+$/.test(workloadId))
32
+ throw new Error('TENANT_BUDGET_WORK_SCOPE_INVALID');
33
+ return createHash('sha256').update(JSON.stringify(['TENANT_LEGACY_ADMISSION_V1', tenantId, workloadId])).digest('hex');
34
+ }
@@ -0,0 +1,58 @@
1
+ /** 请求归因与 project-blind 批次分离;只保存委托身份,不保存可使用的 token。 */
2
+ import { createHash } from 'node:crypto';
3
+ import { z } from 'zod';
4
+ import { idSchema, isoDateTimeSchema, stableUriSchema, sha256Schema } from './common.js';
5
+ import { resourceScopeSchema, tenantStorageKey, parseTenantResourceRef, tenantResourceRefSchema } from './resource-scope.js';
6
+ import { materialTenantIdSchema } from './material-context.js';
7
+ import { knowledgeActorContextSchema } from './project-intent.js';
8
+ import { tenantCollectionPlanSchema, tenantCollectionCycleSchema, tenantCollectionBatchIdentity, tenantCapturedEvidenceIdentity } from './tenant-collection.js';
9
+ export const tenantCollectionRequestAuthoritySchema = z.discriminatedUnion('type', [
10
+ z.object({ type: z.literal('HOST') }).strict(),
11
+ z.object({ type: z.literal('OAUTH'), authorityVersion: z.literal(2), clientId: idSchema, grantId: idSchema, resource: stableUriSchema }).strict(),
12
+ ]);
13
+ export function tenantCollectionRequestKey(requestId) { return createHash('sha256').update(tenantCollectionCycleSchema.parse(requestId)).digest('hex'); }
14
+ export function tenantCollectionRequestRef(tenantId, requestId) { return `tenant-collection-request://${tenantStorageKey(tenantId)}/${tenantCollectionRequestKey(requestId)}`; }
15
+ export const tenantCollectionRequestSchema = z.object({
16
+ schemaVersion: z.literal(2), tenantId: materialTenantIdSchema, requestId: tenantCollectionCycleSchema, requestRef: stableUriSchema,
17
+ context: resourceScopeSchema, actor: knowledgeActorContextSchema, authority: tenantCollectionRequestAuthoritySchema,
18
+ plan: tenantCollectionPlanSchema, trigger: z.enum(['MANUAL', 'DUE']), cycleId: tenantCollectionCycleSchema, batchId: z.string().regex(/^batch_[a-f0-9]{64}$/), batchRef: stableUriSchema, requestedAt: isoDateTimeSchema,
19
+ }).strict().superRefine((value, ctx) => {
20
+ const expected = tenantCollectionBatchIdentity(value.tenantId, value.plan.revision, value.trigger, value.cycleId);
21
+ if (value.context.tenantId !== value.tenantId || value.actor.tenantId !== value.tenantId || value.plan.tenantId !== value.tenantId || value.requestRef !== tenantCollectionRequestRef(value.tenantId, value.requestId))
22
+ ctx.addIssue({ code: 'custom', path: ['context'], message: 'Request must retain exact Tenant/context/request identity' });
23
+ if (value.batchId !== expected.batchId || value.batchRef !== expected.batchRef)
24
+ ctx.addIssue({ code: 'custom', path: ['batchRef'], message: 'Request cannot retarget a different frozen batch' });
25
+ if (value.trigger === 'DUE' && value.authority.type !== 'HOST')
26
+ ctx.addIssue({ code: 'custom', path: ['trigger'], message: 'Only an explicit Host dispatcher may request DUE' });
27
+ });
28
+ const completionV1 = z.object({
29
+ schemaVersion: z.literal(1), tenantId: materialTenantIdSchema, requestRef: stableUriSchema, batchRef: stableUriSchema,
30
+ phase: z.enum(['RAW_REGISTERED', 'DERIVED_REGISTERED']), evidenceRef: stableUriSchema, contentHash: sha256Schema,
31
+ runId: idSchema, runtimeNodeId: idSchema, completedAt: isoDateTimeSchema,
32
+ }).strict();
33
+ export const tenantCollectionCompletionSchema = z.union([completionV1, completionV1.extend({ schemaVersion: z.literal(2), phase: z.literal('DERIVED_REGISTERED'), documentRef: tenantResourceRefSchema }).strict()]);
34
+ export function assertTenantCollectionCompletion(request, raw) {
35
+ const completion = tenantCollectionCompletionSchema.parse(raw), expected = tenantCapturedEvidenceIdentity({ tenantId: request.tenantId, batchRef: request.batchRef, sourceRevisionRef: request.plan.source.revisionRef });
36
+ const expectedPhase = request.plan.source.semantics.representation.format === 'RAW' ? 'RAW_REGISTERED' : 'DERIVED_REGISTERED';
37
+ if (completion.tenantId !== request.tenantId || completion.requestRef !== request.requestRef || completion.batchRef !== request.batchRef || completion.evidenceRef !== expected.ref || completion.phase !== expectedPhase)
38
+ throw new Error('TENANT_COLLECTION_COMPLETION_MISMATCH');
39
+ if (expectedPhase === 'DERIVED_REGISTERED') {
40
+ const document = completion.schemaVersion === 2 ? parseTenantResourceRef(completion.documentRef) : null;
41
+ if (!document || document.storageKey !== tenantStorageKey(request.tenantId) || document.resourceType !== 'source_document')
42
+ throw new Error('TENANT_COLLECTION_DERIVATION_UNPROVEN');
43
+ }
44
+ else if (completion.schemaVersion !== 1)
45
+ throw new Error('TENANT_COLLECTION_COMPLETION_MISMATCH');
46
+ return completion;
47
+ }
48
+ /** Admission retirement is not acquisition failure or business completion. */
49
+ export const TENANT_REQUEST_ADMISSION_STOP_CAPABILITY = 'TENANT_REQUEST_ADMISSION_STOP_V1';
50
+ export const tenantCollectionAdmissionStopSchema = z.object({ schemaVersion: z.literal(1), tenantId: materialTenantIdSchema, requestRef: stableUriSchema, requestHash: sha256Schema, reason: z.enum(['GRANT_REVOKED', 'DELEGATION_SUPERSEDED']), stoppedAt: isoDateTimeSchema }).strict();
51
+ /** Acquisition outcome only: a failed request is neither completed nor delegation-retired. */
52
+ export const tenantCollectionFailureSchema = z.object({
53
+ schemaVersion: z.literal(1), tenantId: materialTenantIdSchema, requestRef: stableUriSchema, requestHash: sha256Schema, batchRef: stableUriSchema,
54
+ runId: idSchema, runtimeNodeId: idSchema, receiptHash: sha256Schema, failedAt: isoDateTimeSchema, errorCode: z.literal('TENANT_SOURCE_HTTP_TERMINAL'),
55
+ }).strict();
56
+ export function isTenantCollectionTerminalFailure(request, receipt) {
57
+ return receipt.status === 'FAILED' && receipt.errorCode === 'TENANT_SOURCE_HTTP_TERMINAL' && receipt.workloadId === request.plan.workloadId && receipt.collectionBatchRef === request.batchRef && receipt.inputFingerprint === request.plan.revision && receipt.projectRef === undefined && receipt.projectIntentRef === undefined && receipt.evidenceCount === 0 && receipt.observationCount === 0 && Date.parse(receipt.finishedAt) >= Date.parse(receipt.startedAt) && request.plan.source.semantics.target.kind === 'URL' && request.plan.source.semantics.credential.type === 'PUBLIC';
58
+ }