@a5c-ai/krate 5.0.1-staging.00fa5317c

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 (256) hide show
  1. package/Dockerfile +31 -0
  2. package/README.md +183 -0
  3. package/bin/krate-demo.mjs +23 -0
  4. package/bin/krate-server.mjs +14 -0
  5. package/dist/krate-controller-ui.json +3205 -0
  6. package/dist/krate-lifecycle.json +201 -0
  7. package/dist/krate-runtime-snapshot.json +3125 -0
  8. package/dist/krate-summary.json +724 -0
  9. package/docs/README.md +61 -0
  10. package/docs/agents/README.md +83 -0
  11. package/docs/agents/acceptance-test-matrix.md +193 -0
  12. package/docs/agents/agent-mux-adapter-contract.md +167 -0
  13. package/docs/agents/agent-mux-source-map.md +310 -0
  14. package/docs/agents/agent-run-memory-import-spec.md +256 -0
  15. package/docs/agents/agent-stack-management-spec.md +421 -0
  16. package/docs/agents/api-contract-spec.md +309 -0
  17. package/docs/agents/artifacts-writeback-spec.md +145 -0
  18. package/docs/agents/chart-packaging-spec.md +128 -0
  19. package/docs/agents/ci-orchestration-spec.md +140 -0
  20. package/docs/agents/context-assembly-spec.md +219 -0
  21. package/docs/agents/controller-reconciliation-spec.md +255 -0
  22. package/docs/agents/crd-schema-spec.md +315 -0
  23. package/docs/agents/decision-log-open-questions.md +169 -0
  24. package/docs/agents/developer-implementation-checklist.md +329 -0
  25. package/docs/agents/dispatching-design.md +262 -0
  26. package/docs/agents/gaps-agent-mux-to-krate-crds.md +298 -0
  27. package/docs/agents/glossary.md +66 -0
  28. package/docs/agents/implementation-blueprint.md +324 -0
  29. package/docs/agents/implementation-rollout-slices.md +251 -0
  30. package/docs/agents/memory-context-integration-spec.md +194 -0
  31. package/docs/agents/memory-ontology-schema-spec.md +253 -0
  32. package/docs/agents/memory-operations-runbook.md +121 -0
  33. package/docs/agents/mvp-vertical-slice-spec.md +146 -0
  34. package/docs/agents/observability-audit-spec.md +265 -0
  35. package/docs/agents/operator-runbook.md +174 -0
  36. package/docs/agents/org-memory-api-payload-examples.md +333 -0
  37. package/docs/agents/org-memory-controller-sequence-spec.md +181 -0
  38. package/docs/agents/org-memory-e2e-fixture-plan.md +161 -0
  39. package/docs/agents/org-memory-ui-implementation-map.md +114 -0
  40. package/docs/agents/org-memory-vertical-slice-spec.md +168 -0
  41. package/docs/agents/org-resource-model-delta-spec.md +111 -0
  42. package/docs/agents/org-route-resource-model-spec.md +183 -0
  43. package/docs/agents/org-scoping-namespace-spec.md +114 -0
  44. package/docs/agents/rbac-secrets-management-spec.md +406 -0
  45. package/docs/agents/repository-page-integration-spec.md +255 -0
  46. package/docs/agents/resource-contract-examples.md +808 -0
  47. package/docs/agents/resource-relationship-map.md +190 -0
  48. package/docs/agents/security-threat-model.md +188 -0
  49. package/docs/agents/shared-memory-company-brain-spec.md +358 -0
  50. package/docs/agents/storage-migration-spec.md +168 -0
  51. package/docs/agents/subagent-orchestration-spec.md +152 -0
  52. package/docs/agents/system-overview.md +88 -0
  53. package/docs/agents/tools-mcp-skills-spec.md +189 -0
  54. package/docs/agents/traceability-matrix.md +79 -0
  55. package/docs/agents/ui-flow-spec.md +211 -0
  56. package/docs/agents/ui-ux-system-spec.md +426 -0
  57. package/docs/agents/workspace-lifecycle-spec.md +166 -0
  58. package/docs/architecture-spec.md +78 -0
  59. package/docs/components/control-plane.md +78 -0
  60. package/docs/components/data-plane.md +69 -0
  61. package/docs/components/hooks-events.md +67 -0
  62. package/docs/components/identity-rbac-policy.md +73 -0
  63. package/docs/components/kubevela-oam.md +70 -0
  64. package/docs/components/operations-publishing.md +81 -0
  65. package/docs/components/runners-ci.md +66 -0
  66. package/docs/components/web-ui.md +94 -0
  67. package/docs/external/README.md +47 -0
  68. package/docs/external/bidirectional-sync-design.md +134 -0
  69. package/docs/external/cicd-interface.md +64 -0
  70. package/docs/external/external-backend-controllers.md +170 -0
  71. package/docs/external/external-backend-crds.md +234 -0
  72. package/docs/external/external-backend-ui-spec.md +151 -0
  73. package/docs/external/external-backend-ux-flows.md +115 -0
  74. package/docs/external/external-object-mapping.md +125 -0
  75. package/docs/external/git-forge-interface.md +68 -0
  76. package/docs/external/github-integration-design.md +151 -0
  77. package/docs/external/issue-tracking-interface.md +66 -0
  78. package/docs/external/provider-capability-manifests.md +204 -0
  79. package/docs/external/provider-catalog.md +139 -0
  80. package/docs/external/provider-rollout-testing.md +78 -0
  81. package/docs/external/research-results.md +48 -0
  82. package/docs/external/security-auth-permissions.md +81 -0
  83. package/docs/external/sync-state-machines.md +108 -0
  84. package/docs/external/unified-external-backend-model.md +107 -0
  85. package/docs/external/user-facing-changes.md +67 -0
  86. package/docs/gaps.md +161 -0
  87. package/docs/install.md +94 -0
  88. package/docs/krate-design.md +334 -0
  89. package/docs/local-minikube.md +55 -0
  90. package/docs/ontology/README.md +32 -0
  91. package/docs/ontology/bounded-contexts.md +29 -0
  92. package/docs/ontology/events-and-hooks.md +32 -0
  93. package/docs/ontology/oam-kubevela.md +32 -0
  94. package/docs/ontology/operations-and-release.md +25 -0
  95. package/docs/ontology/personas-and-actors.md +32 -0
  96. package/docs/ontology/policies-and-invariants.md +33 -0
  97. package/docs/ontology/problem-space.md +30 -0
  98. package/docs/ontology/resource-contracts.md +40 -0
  99. package/docs/ontology/resource-taxonomy.md +42 -0
  100. package/docs/ontology/runners-and-ci.md +29 -0
  101. package/docs/ontology/solution-space.md +24 -0
  102. package/docs/ontology/storage-and-data-boundaries.md +29 -0
  103. package/docs/ontology/validation-matrix.md +24 -0
  104. package/docs/ontology/web-ui-excellent-flows.md +32 -0
  105. package/docs/ontology/workflows.md +39 -0
  106. package/docs/ontology/world.md +35 -0
  107. package/docs/openapi.yaml +1275 -0
  108. package/docs/product-requirements.md +62 -0
  109. package/docs/roadmap-mvp.md +87 -0
  110. package/docs/system-requirements.md +90 -0
  111. package/docs/tests/README.md +53 -0
  112. package/docs/tests/agent-qa-plan.md +63 -0
  113. package/docs/tests/browser-ui-tests.md +62 -0
  114. package/docs/tests/ci-quality-gates.md +48 -0
  115. package/docs/tests/coverage-model.md +64 -0
  116. package/docs/tests/e2e-scenario-tests.md +53 -0
  117. package/docs/tests/fixtures-test-data.md +63 -0
  118. package/docs/tests/observability-reliability-tests.md +54 -0
  119. package/docs/tests/product-test-matrix.md +145 -0
  120. package/docs/tests/qa-adoption-roadmap.md +130 -0
  121. package/docs/tests/qa-automation-plan.md +101 -0
  122. package/docs/tests/security-compliance-tests.md +57 -0
  123. package/docs/tests/test-framework-tools.md +88 -0
  124. package/docs/tests/test-suite-layout.md +121 -0
  125. package/docs/tests/unit-integration-tests.md +48 -0
  126. package/docs/todo-kyverno +714 -0
  127. package/docs/todos.md +4 -0
  128. package/docs/user-stories.md +78 -0
  129. package/examples/minikube-demo.yaml +190 -0
  130. package/examples/oam-application.yaml +23 -0
  131. package/examples/policy-kyverno-pr-title.yaml +18 -0
  132. package/package.json +63 -0
  133. package/scripts/build.mjs +29 -0
  134. package/scripts/setup-minikube.mjs +65 -0
  135. package/scripts/smoke.mjs +37 -0
  136. package/scripts/validate-doc-coverage.mjs +152 -0
  137. package/scripts/validate-package.mjs +93 -0
  138. package/scripts/validate-ui.mjs +278 -0
  139. package/src/agent-adapter-controller.js +169 -0
  140. package/src/agent-approval-controller.js +170 -0
  141. package/src/agent-context-bundles.js +242 -0
  142. package/src/agent-dispatch-controller.js +209 -0
  143. package/src/agent-gateway-config-controller.js +147 -0
  144. package/src/agent-memory-controller.js +357 -0
  145. package/src/agent-memory-import.js +327 -0
  146. package/src/agent-memory-query.js +292 -0
  147. package/src/agent-memory-repository-source-controller.js +255 -0
  148. package/src/agent-mux-client.js +280 -0
  149. package/src/agent-permission-review.js +250 -0
  150. package/src/agent-project-controller.js +117 -0
  151. package/src/agent-provider-config-controller.js +150 -0
  152. package/src/agent-secret-config-grant-controller.js +282 -0
  153. package/src/agent-session-transcript-controller.js +189 -0
  154. package/src/agent-stack-controller.js +347 -0
  155. package/src/agent-subagent-controller.js +160 -0
  156. package/src/agent-transport-binding-controller.js +121 -0
  157. package/src/agent-trigger-controller.js +381 -0
  158. package/src/agent-workspace-controller.js +702 -0
  159. package/src/agent-writeback-controller.js +302 -0
  160. package/src/api-controller.js +541 -0
  161. package/src/argocd-gitops.js +43 -0
  162. package/src/async-controller.js +207 -0
  163. package/src/audit-controller.js +191 -0
  164. package/src/auth.js +307 -0
  165. package/src/component-catalog.js +41 -0
  166. package/src/control-plane.js +136 -0
  167. package/src/controller-client.js +72 -0
  168. package/src/controller-ui.js +617 -0
  169. package/src/data-plane.js +179 -0
  170. package/src/event-bus.js +61 -0
  171. package/src/external/conflict-controller.js +225 -0
  172. package/src/external/github/auth.js +96 -0
  173. package/src/external/github/cicd.js +180 -0
  174. package/src/external/github/git-forge.js +240 -0
  175. package/src/external/github/index.js +144 -0
  176. package/src/external/github/issue-tracking.js +163 -0
  177. package/src/external/provider-adapter.js +161 -0
  178. package/src/external/provider-resource-factory.js +161 -0
  179. package/src/external/sync-controller.js +235 -0
  180. package/src/external/webhook-controller.js +144 -0
  181. package/src/external/write-controller.js +283 -0
  182. package/src/gitea-backend.js +131 -0
  183. package/src/gitea-service.js +173 -0
  184. package/src/handoff.js +98 -0
  185. package/src/hooks-events.js +63 -0
  186. package/src/http-server.js +377 -0
  187. package/src/identity-policy.js +86 -0
  188. package/src/index.js +57 -0
  189. package/src/kubernetes-controller-async.js +511 -0
  190. package/src/kubernetes-controller.js +878 -0
  191. package/src/kubernetes-resource-gateway.js +48 -0
  192. package/src/notification-controller.js +178 -0
  193. package/src/operations.js +112 -0
  194. package/src/org-scoping.js +5 -0
  195. package/src/resource-model.js +221 -0
  196. package/src/runner-controller.js +272 -0
  197. package/src/runners-ci.js +48 -0
  198. package/src/runtime.js +196 -0
  199. package/src/snapshot-cache.js +157 -0
  200. package/src/web-ui.js +40 -0
  201. package/tests/agent-adapter-controller.test.js +361 -0
  202. package/tests/agent-approval-controller.test.js +173 -0
  203. package/tests/agent-context-bundles.test.js +278 -0
  204. package/tests/agent-dispatch-controller.test.js +315 -0
  205. package/tests/agent-gateway-config-controller.test.js +386 -0
  206. package/tests/agent-memory-controller.test.js +308 -0
  207. package/tests/agent-memory-import-snapshot.test.js +477 -0
  208. package/tests/agent-memory-query.test.js +404 -0
  209. package/tests/agent-memory-repository-source.test.js +514 -0
  210. package/tests/agent-mux-client.test.js +204 -0
  211. package/tests/agent-permission-review-v2.test.js +317 -0
  212. package/tests/agent-permission-review.test.js +209 -0
  213. package/tests/agent-project-controller.test.js +302 -0
  214. package/tests/agent-provider-config-controller.test.js +376 -0
  215. package/tests/agent-resources.test.js +228 -0
  216. package/tests/agent-secret-config-grant.test.js +231 -0
  217. package/tests/agent-session-transcript-controller.test.js +499 -0
  218. package/tests/agent-stack-controller.test.js +221 -0
  219. package/tests/agent-subagent-controller.test.js +201 -0
  220. package/tests/agent-transport-binding-controller.test.js +294 -0
  221. package/tests/agent-trigger-controller.test.js +211 -0
  222. package/tests/agent-trigger-routes.test.js +190 -0
  223. package/tests/agent-trigger-sources.test.js +245 -0
  224. package/tests/agent-workspace-controller.test.js +181 -0
  225. package/tests/agent-writeback.test.js +292 -0
  226. package/tests/approval-persistence.test.js +171 -0
  227. package/tests/async-controller.test.js +252 -0
  228. package/tests/audit-controller.test.js +227 -0
  229. package/tests/codespace-controller.test.js +318 -0
  230. package/tests/deployment.test.js +407 -0
  231. package/tests/e2e/lifecycle.test.js +117 -0
  232. package/tests/event-bus-integration.test.js +190 -0
  233. package/tests/external-github-forge.test.js +560 -0
  234. package/tests/external-github-issues-cicd.test.js +520 -0
  235. package/tests/external-integration.test.js +470 -0
  236. package/tests/external-persistence.test.js +340 -0
  237. package/tests/external-provider-adapter.test.js +365 -0
  238. package/tests/external-resource-model.test.js +215 -0
  239. package/tests/external-webhook-sync.test.js +287 -0
  240. package/tests/external-write-conflict.test.js +353 -0
  241. package/tests/gitea-service.test.js +253 -0
  242. package/tests/health-check-real.test.js +165 -0
  243. package/tests/integration/full-flow.test.js +266 -0
  244. package/tests/krate.test.js +756 -0
  245. package/tests/memory-search-wiring.test.js +270 -0
  246. package/tests/notification-controller.test.js +196 -0
  247. package/tests/notification-integration.test.js +179 -0
  248. package/tests/org-scoping.test.js +687 -0
  249. package/tests/runner-controller.test.js +327 -0
  250. package/tests/runner-integration.test.js +231 -0
  251. package/tests/session-cookie-hmac.test.js +151 -0
  252. package/tests/snapshot-performance.test.js +247 -0
  253. package/tests/sse-events.test.js +107 -0
  254. package/tests/webhook-trigger.test.js +198 -0
  255. package/tests/workspace-volumes.test.js +312 -0
  256. package/tests/writeback-persistence.test.js +207 -0
@@ -0,0 +1,308 @@
1
+ import assert from 'node:assert/strict';
2
+ import test from 'node:test';
3
+ import { createAgentMemoryController } from '../src/agent-memory-controller.js';
4
+
5
+ function makeRecords() {
6
+ return [
7
+ {
8
+ id: 'service/auth-api',
9
+ nodeKind: 'Service',
10
+ attributes: { name: 'auth-api', language: 'typescript', team: 'platform' },
11
+ edges: [
12
+ { target: 'service/user-db', kind: 'depends-on' },
13
+ { target: 'team/platform', kind: 'owned-by' },
14
+ ],
15
+ },
16
+ {
17
+ id: 'service/user-db',
18
+ nodeKind: 'Service',
19
+ attributes: { name: 'user-db', language: 'go', team: 'data' },
20
+ edges: [
21
+ { target: 'infra/postgres-cluster', kind: 'depends-on' },
22
+ ],
23
+ },
24
+ {
25
+ id: 'team/platform',
26
+ nodeKind: 'Team',
27
+ attributes: { name: 'platform', lead: 'alice' },
28
+ edges: [],
29
+ },
30
+ {
31
+ id: 'infra/postgres-cluster',
32
+ nodeKind: 'Infrastructure',
33
+ attributes: { name: 'postgres-cluster', provider: 'aws' },
34
+ edges: [],
35
+ },
36
+ {
37
+ id: 'runbook/deploy-auth',
38
+ nodeKind: 'Runbook',
39
+ attributes: { name: 'deploy-auth', service: 'auth-api' },
40
+ edges: [
41
+ { target: 'service/auth-api', kind: 'references' },
42
+ ],
43
+ },
44
+ ];
45
+ }
46
+
47
+ function makeDocuments() {
48
+ return [
49
+ { path: 'docs/architecture.md', content: 'The auth-api service handles authentication.\nIt uses JWT tokens for session management.\nThe service connects to user-db for persistence.' },
50
+ { path: 'docs/runbooks/deploy.md', content: 'Step 1: Run the deploy script.\nStep 2: Verify health checks.\nStep 3: Monitor error rates.' },
51
+ { path: 'src/auth/handler.ts', content: 'export function handleAuth(req) {\n const token = req.headers.authorization;\n return validateToken(token);\n}' },
52
+ { path: 'configs/prod.yaml', content: 'database:\n host: prod-db.internal\n port: 5432\n password: [redacted]' },
53
+ ];
54
+ }
55
+
56
+ test('createMemorySnapshot creates valid resource with digests', () => {
57
+ const controller = createAgentMemoryController();
58
+ const records = makeRecords();
59
+ const documents = makeDocuments();
60
+
61
+ const snapshot = controller.createMemorySnapshot({
62
+ memoryRepository: 'company-brain',
63
+ requestedRef: 'main',
64
+ resolvedCommit: 'abc123def456',
65
+ queryManifest: { include: ['Service', 'Team'] },
66
+ selectedRecords: records,
67
+ selectedDocuments: documents,
68
+ ontologyDigest: 'onto-digest-1',
69
+ namespace: 'krate-org-default',
70
+ organizationRef: 'acme',
71
+ });
72
+
73
+ assert.equal(snapshot.kind, 'AgentMemorySnapshot');
74
+ assert.ok(snapshot.metadata.name.startsWith('memsnapshot-'));
75
+ assert.equal(snapshot.spec.memoryRepository, 'company-brain');
76
+ assert.equal(snapshot.spec.requestedRef, 'main');
77
+ assert.equal(snapshot.spec.resolvedCommit, 'abc123def456');
78
+ assert.ok(snapshot.spec.queryManifestDigest, 'Should have queryManifestDigest');
79
+ assert.ok(snapshot.spec.selectedRecordsDigest, 'Should have selectedRecordsDigest');
80
+ assert.ok(snapshot.spec.selectedDocumentsDigest, 'Should have selectedDocumentsDigest');
81
+ assert.equal(snapshot.spec.ontologyDigest, 'onto-digest-1');
82
+ assert.equal(snapshot.spec.recordCount, records.length);
83
+ assert.equal(snapshot.spec.documentCount, documents.length);
84
+ assert.equal(snapshot.status.phase, 'Pinned');
85
+ });
86
+
87
+ test('searchGraph filters by node kind', () => {
88
+ const controller = createAgentMemoryController();
89
+ const records = makeRecords();
90
+
91
+ const result = controller.searchGraph({ records, kinds: ['Service'], query: '' });
92
+
93
+ assert.equal(result.totalMatches, 2, 'Should match exactly 2 Service records');
94
+ assert.ok(result.matches.every(m => m.record.nodeKind === 'Service'));
95
+ });
96
+
97
+ test('searchGraph matches query text', () => {
98
+ const controller = createAgentMemoryController();
99
+ const records = makeRecords();
100
+
101
+ const result = controller.searchGraph({ records, kinds: [], query: 'auth' });
102
+
103
+ assert.ok(result.totalMatches >= 1, 'Should match at least auth-api');
104
+ const authMatch = result.matches.find(m => m.record.id === 'service/auth-api');
105
+ assert.ok(authMatch, 'Should include auth-api in matches');
106
+ assert.equal(authMatch.score, 2, 'ID match should score 2');
107
+ });
108
+
109
+ test('searchGraph respects edgeDepth', () => {
110
+ const controller = createAgentMemoryController();
111
+ const records = makeRecords();
112
+
113
+ // edgeDepth=1: from auth-api should reach user-db and team/platform but NOT postgres-cluster
114
+ const depth1 = controller.searchGraph({ records, kinds: ['Service'], query: 'auth-api', edgeDepth: 1 });
115
+ const authMatch1 = depth1.matches.find(m => m.record.id === 'service/auth-api');
116
+ assert.ok(authMatch1, 'Should find auth-api');
117
+ const depth1Targets = authMatch1.edges.map(e => e.target);
118
+ assert.ok(depth1Targets.includes('service/user-db'), 'Depth 1 should include user-db');
119
+ assert.ok(!depth1Targets.includes('infra/postgres-cluster'), 'Depth 1 should NOT include postgres-cluster');
120
+
121
+ // edgeDepth=2: should also reach postgres-cluster
122
+ const depth2 = controller.searchGraph({ records, kinds: ['Service'], query: 'auth-api', edgeDepth: 2 });
123
+ const authMatch2 = depth2.matches.find(m => m.record.id === 'service/auth-api');
124
+ const depth2Targets = authMatch2.edges.map(e => e.target);
125
+ assert.ok(depth2Targets.includes('infra/postgres-cluster'), 'Depth 2 should include postgres-cluster');
126
+ });
127
+
128
+ test('searchGrep finds pattern matches', () => {
129
+ const controller = createAgentMemoryController();
130
+ const documents = makeDocuments();
131
+
132
+ const result = controller.searchGrep({ documents, pattern: 'auth', maxMatches: 25 });
133
+
134
+ assert.ok(result.totalMatches >= 1, 'Should find auth pattern');
135
+ assert.ok(result.excerpts.some(e => e.path === 'docs/architecture.md'), 'Should match in architecture.md');
136
+ assert.ok(result.excerpts.every(e => e.lineNumber > 0), 'Every excerpt should have a lineNumber');
137
+ assert.ok(result.excerpts.every(e => typeof e.context === 'string'), 'Every excerpt should have context');
138
+ });
139
+
140
+ test('searchGrep caps at maxMatches', () => {
141
+ const controller = createAgentMemoryController();
142
+ const documents = makeDocuments();
143
+
144
+ const result = controller.searchGrep({ documents, pattern: 'the', maxMatches: 2 });
145
+
146
+ assert.ok(result.totalMatches <= 2, 'Should not exceed maxMatches');
147
+ assert.ok(result.excerpts.length <= 2, 'Excerpts length should not exceed maxMatches');
148
+ });
149
+
150
+ test('searchGrep filters by path patterns', () => {
151
+ const controller = createAgentMemoryController();
152
+ const documents = makeDocuments();
153
+
154
+ const result = controller.searchGrep({ documents, paths: ['docs/*'], pattern: 'deploy' });
155
+
156
+ assert.ok(result.totalMatches >= 1, 'Should find deploy in docs');
157
+ assert.ok(result.excerpts.every(e => e.path.startsWith('docs/')), 'All matches should be in docs/');
158
+ });
159
+
160
+ test('resolveTimeTravel mode=current returns latest commit', () => {
161
+ const controller = createAgentMemoryController();
162
+ const commits = [
163
+ { sha: 'latest-sha', timestamp: '2026-05-10T10:00:00Z' },
164
+ { sha: 'older-sha', timestamp: '2026-05-09T10:00:00Z' },
165
+ ];
166
+
167
+ const result = controller.resolveTimeTravel({ mode: 'current', commits });
168
+
169
+ assert.equal(result.resolvedCommit, 'latest-sha');
170
+ assert.equal(result.mode, 'current');
171
+ assert.ok(result.resolvedAt);
172
+ });
173
+
174
+ test('resolveTimeTravel mode=ref-at-time finds correct commit', () => {
175
+ const controller = createAgentMemoryController();
176
+ const commits = [
177
+ { sha: 'c3', timestamp: '2026-05-10T10:00:00Z' },
178
+ { sha: 'c2', timestamp: '2026-05-08T10:00:00Z' },
179
+ { sha: 'c1', timestamp: '2026-05-05T10:00:00Z' },
180
+ ];
181
+
182
+ const result = controller.resolveTimeTravel({
183
+ mode: 'ref-at-time',
184
+ requestedTime: '2026-05-09T00:00:00Z',
185
+ commits,
186
+ });
187
+
188
+ assert.equal(result.resolvedCommit, 'c2', 'Should resolve to c2 (latest before requested time)');
189
+ assert.equal(result.mode, 'ref-at-time');
190
+ assert.ok(result.staleBy !== null, 'staleBy should be set');
191
+ });
192
+
193
+ test('scanForRedaction catches API keys', () => {
194
+ const controller = createAgentMemoryController();
195
+ const content = 'API_KEY = sk-test1234567890abcdefghij\nSome normal text\nSECRET_KEY=my-super-secret-value';
196
+
197
+ const result = controller.scanForRedaction(content);
198
+
199
+ assert.equal(result.clean, false, 'Content should not be clean');
200
+ assert.ok(result.redactionCount > 0, 'Should have redactions');
201
+ assert.ok(result.redactionsByKind['secret-key'] > 0, 'Should catch secret-key pattern');
202
+ assert.ok(result.redactedContent.includes('[REDACTED:'), 'Redacted content should have markers');
203
+ assert.ok(!result.redactedContent.includes('my-super-secret-value'), 'Secret should be redacted');
204
+ });
205
+
206
+ test('scanForRedaction catches provider tokens', () => {
207
+ const controller = createAgentMemoryController();
208
+ const content = 'token: ghp_abcdefghijklmnopqrstuvwxyz1234567890\nslack: xoxb-123-456-abcdefghij';
209
+
210
+ const result = controller.scanForRedaction(content);
211
+
212
+ assert.equal(result.clean, false);
213
+ assert.ok(result.redactionsByKind['provider-token'] > 0, 'Should catch provider-token pattern');
214
+ });
215
+
216
+ test('validateOntology catches missing required fields', () => {
217
+ const controller = createAgentMemoryController();
218
+ const records = [
219
+ { id: 'svc/a', nodeKind: 'Service', attributes: { name: 'a' }, edges: [] },
220
+ { id: 'svc/b', nodeKind: 'Service', attributes: { name: 'b', language: 'go' }, edges: [] },
221
+ ];
222
+ const ontology = {
223
+ requiredFields: { Service: ['name', 'language', 'team'] },
224
+ allowedEdgeKinds: ['depends-on', 'owned-by'],
225
+ };
226
+
227
+ const result = controller.validateOntology({ records, ontology });
228
+
229
+ assert.equal(result.valid, false, 'Should be invalid due to missing fields');
230
+ assert.ok(result.errors.length >= 2, 'Should have errors for missing language and team on svc/a, and team on svc/b');
231
+ const missingLang = result.errors.find(e => e.record === 'svc/a' && e.field === 'language');
232
+ assert.ok(missingLang, 'Should report missing language on svc/a');
233
+ const missingTeam = result.errors.find(e => e.record === 'svc/a' && e.field === 'team');
234
+ assert.ok(missingTeam, 'Should report missing team on svc/a');
235
+ });
236
+
237
+ test('validateOntology passes valid records', () => {
238
+ const controller = createAgentMemoryController();
239
+ const records = [
240
+ { id: 'svc/a', nodeKind: 'Service', attributes: { name: 'a', language: 'ts' }, edges: [{ target: 'svc/b', kind: 'depends-on' }] },
241
+ { id: 'svc/b', nodeKind: 'Service', attributes: { name: 'b', language: 'go' }, edges: [] },
242
+ ];
243
+ const ontology = {
244
+ requiredFields: { Service: ['name', 'language'] },
245
+ allowedEdgeKinds: ['depends-on', 'owned-by'],
246
+ };
247
+
248
+ const result = controller.validateOntology({ records, ontology });
249
+
250
+ assert.equal(result.valid, true, 'Should be valid');
251
+ assert.equal(result.errors.length, 0);
252
+ });
253
+
254
+ test('createImport sets phase=Pending', () => {
255
+ const controller = createAgentMemoryController();
256
+
257
+ const importResource = controller.createImport({
258
+ organizationRef: 'acme',
259
+ memoryRepository: 'company-brain',
260
+ source: 'babysitter-run/run-123',
261
+ include: { kinds: ['decision', 'learning'] },
262
+ validationPolicy: 'strict',
263
+ namespace: 'krate-org-default',
264
+ });
265
+
266
+ assert.equal(importResource.kind, 'AgentRunMemoryImport');
267
+ assert.ok(importResource.metadata.name.startsWith('memimport-'));
268
+ assert.equal(importResource.status.phase, 'Pending');
269
+ assert.equal(importResource.spec.memoryRepository, 'company-brain');
270
+ assert.equal(importResource.spec.source, 'babysitter-run/run-123');
271
+ assert.equal(importResource.spec.validationPolicy, 'strict');
272
+ });
273
+
274
+ test('processImport advances phases', () => {
275
+ const controller = createAgentMemoryController();
276
+
277
+ let importResource = controller.createImport({
278
+ organizationRef: 'acme',
279
+ memoryRepository: 'company-brain',
280
+ source: 'run-1',
281
+ include: { kinds: ['all'] },
282
+ namespace: 'krate-org-default',
283
+ });
284
+
285
+ assert.equal(importResource.status.phase, 'Pending');
286
+
287
+ // Pending -> Collecting
288
+ importResource = controller.processImport({ importResource, content: 'some content' });
289
+ assert.equal(importResource.status.phase, 'Collecting');
290
+
291
+ // Collecting -> Redacting (triggers scanForRedaction)
292
+ importResource = controller.processImport({ importResource, content: 'API_KEY=secret123' });
293
+ assert.equal(importResource.status.phase, 'Redacting');
294
+ assert.ok(importResource.status.redactionScan, 'Should have redaction scan result');
295
+ assert.equal(importResource.status.redactionScan.clean, false, 'Should detect secret');
296
+
297
+ // Redacting -> Normalizing
298
+ importResource = controller.processImport({ importResource, content: 'normalized' });
299
+ assert.equal(importResource.status.phase, 'Normalizing');
300
+
301
+ // Normalizing -> Validating
302
+ importResource = controller.processImport({ importResource, content: 'validated' });
303
+ assert.equal(importResource.status.phase, 'Validating');
304
+
305
+ // Validating -> AwaitingReview
306
+ importResource = controller.processImport({ importResource, content: '' });
307
+ assert.equal(importResource.status.phase, 'AwaitingReview');
308
+ });