@danielblomma/cortex-mcp 2.0.15 → 2.0.18

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 (33) hide show
  1. package/README.md +5 -3
  2. package/package.json +1 -1
  3. package/scaffold/mcp/package-lock.json +59 -60
  4. package/scaffold/mcp/package.json +2 -2
  5. package/scaffold/mcp/src/cli/stage.ts +15 -18
  6. package/scaffold/mcp/src/cli/telemetry-test.ts +2 -1
  7. package/scaffold/mcp/src/core/license.ts +3 -2
  8. package/scaffold/mcp/src/core/telemetry/collector.ts +5 -4
  9. package/scaffold/mcp/src/core/telemetry/state-dir.ts +40 -0
  10. package/scaffold/mcp/src/core/validators/builtins.ts +24 -4
  11. package/scaffold/mcp/src/core/workflow/index.ts +1 -0
  12. package/scaffold/mcp/src/core/workflow/mcp-tools.ts +15 -25
  13. package/scaffold/mcp/src/core/workflow/resolution.ts +113 -0
  14. package/scaffold/mcp/src/daemon/main.ts +4 -3
  15. package/scaffold/mcp/src/enterprise/index.ts +16 -1
  16. package/scaffold/mcp/src/enterprise/reviews/policy-selection.ts +65 -0
  17. package/scaffold/mcp/src/enterprise/reviews/push.ts +55 -4
  18. package/scaffold/mcp/src/enterprise/reviews/trust-state.ts +305 -0
  19. package/scaffold/mcp/src/enterprise/tools/enterprise.ts +40 -47
  20. package/scaffold/mcp/src/enterprise/tools/harness.ts +2 -0
  21. package/scaffold/mcp/src/enterprise/workflow/state.ts +21 -0
  22. package/scaffold/mcp/tests/enterprise-review-trust.test.mjs +318 -0
  23. package/scaffold/mcp/tests/fixtures/org-skillz-contract.json +59 -0
  24. package/scaffold/mcp/tests/fixtures/review-trust-contract.json +111 -0
  25. package/scaffold/mcp/tests/review-policy-selection.test.mjs +85 -0
  26. package/scaffold/mcp/tests/review-trust-contract.test.mjs +167 -0
  27. package/scaffold/mcp/tests/review-validator-source.test.mjs +52 -0
  28. package/scaffold/mcp/tests/skill-sync-checker.test.mjs +277 -0
  29. package/scaffold/mcp/tests/telemetry-collector.test.mjs +31 -1
  30. package/scaffold/mcp/tests/workflow-cli.test.mjs +102 -1
  31. package/scaffold/mcp/tests/workflow-mcp-tools.test.mjs +22 -0
  32. package/scaffold/mcp/tests/workflow-synced-registry.test.mjs +56 -0
  33. package/scaffold/scripts/parsers/node_modules/.package-lock.json +0 -1
@@ -13,7 +13,9 @@ import type { InjectionMatch } from "../../core/policy/injection.js";
13
13
  import { getLastPush } from "../telemetry/sync.js";
14
14
  import { syncFromCloud, syncFromLocal, getLastSync } from "../policy/sync.js";
15
15
  import { queueViolation } from "../violations/push.js";
16
- import { queueReviewResult } from "../reviews/push.js";
16
+ import { getReviewPushContext, queueReviewResult } from "../reviews/push.js";
17
+ import { partitionReviewPolicies } from "../reviews/policy-selection.js";
18
+ import { recordQueuedReviewTrustState } from "../reviews/trust-state.js";
17
19
  import { pushWorkflowSnapshot } from "../workflow/push.js";
18
20
  import { OUTBOUND_DATA_BOUNDARY } from "../privacy/boundary.js";
19
21
  import {
@@ -31,11 +33,7 @@ import {
31
33
  } from "../workflow/state.js";
32
34
  import { queryAuditLog } from "../../core/audit/query.js";
33
35
  import { checkAccess, getAccessDeniedMessage, type Role } from "../../core/rbac/check.js";
34
- import {
35
- getGenericEvaluator,
36
- getValidator,
37
- runValidators,
38
- } from "../../core/validators/engine.js";
36
+ import { runValidators } from "../../core/validators/engine.js";
39
37
  import "../../core/validators/builtins.js";
40
38
  import { recordToolActivity } from "../index.js";
41
39
 
@@ -904,41 +902,10 @@ export function registerEnterpriseTools(
904
902
  // rules. Predefined rules leave type/config null and route to the
905
903
  // name-based validator registry.
906
904
  const policies = policyStore.getMergedPolicies();
907
- const skippedPolicies = policies
908
- .filter((p) => p.enforce)
909
- .filter((p) => p.id === "require-code-review" || (p.type ? !getGenericEvaluator(p.type) : !getValidator(p.id)))
910
- .map((p) => {
911
- if (p.id === "require-code-review") {
912
- return {
913
- policy_id: p.id,
914
- kind: p.kind ?? null,
915
- type: p.type ?? null,
916
- reason: "Current context.review invocation is the review being recorded; validate this policy from workflow state on the next run.",
917
- };
918
- }
919
- return {
920
- policy_id: p.id,
921
- kind: p.kind ?? null,
922
- type: p.type ?? null,
923
- reason: p.type
924
- ? `No evaluator registered for type "${p.type}"`
925
- : "No executable validator registered for this policy",
926
- };
927
- });
928
-
929
- const enforced = policies
930
- .filter((p) => p.enforce)
931
- .filter((p) => {
932
- if (p.id === "require-code-review") return false;
933
- if (p.type) return Boolean(getGenericEvaluator(p.type));
934
- return Boolean(getValidator(p.id));
935
- })
936
- .map((p) => ({
937
- id: p.id,
938
- type: p.type ?? null,
939
- config: p.config ?? null,
940
- severity: p.severity ?? "block",
941
- }));
905
+ const {
906
+ enforced,
907
+ skipped: skippedPolicies,
908
+ } = partitionReviewPolicies(policies);
942
909
 
943
910
  const now = new Date().toISOString();
944
911
 
@@ -964,9 +931,9 @@ export function registerEnterpriseTools(
964
931
  occurred_at: now,
965
932
  });
966
933
  }
967
- queueReviewResult({
968
- policy_id: r.policy_id,
969
- pass: r.pass,
934
+ queueReviewResult({
935
+ policy_id: r.policy_id,
936
+ pass: r.pass,
970
937
  severity: r.severity,
971
938
  message: r.message,
972
939
  detail: r.detail,
@@ -1001,20 +968,43 @@ export function registerEnterpriseTools(
1001
968
  reviewed_files: reviewedFiles,
1002
969
  });
1003
970
  const lastReview = workflowState.last_review;
971
+ const reviewedAt = lastReview?.reviewed_at ?? now;
1004
972
  if (lastReview) {
1005
973
  writeFileSync(
1006
974
  join(contextDir, "review-status.json"),
1007
975
  `${JSON.stringify({
1008
976
  reviewed: lastReview.status === "passed",
1009
977
  reviewer: "context.review",
1010
- timestamp: lastReview.reviewed_at,
978
+ timestamp: reviewedAt,
1011
979
  scope: parsed.scope,
1012
980
  reviewed_files: reviewedFiles,
1013
981
  }, null, 2)}\n`,
1014
982
  "utf8",
1015
983
  );
1016
984
  }
1017
- await pushWorkflowStateIfConfigured(config, workflowState);
985
+ const trustState = recordQueuedReviewTrustState(
986
+ {
987
+ contextDir,
988
+ projectRoot,
989
+ repo: getReviewPushContext().repo,
990
+ instance_id: getReviewPushContext().instance_id,
991
+ session_id: getReviewPushContext().session_id,
992
+ task_id: process.env.CORTEX_ACTIVE_TASK_ID?.trim() || undefined,
993
+ },
994
+ {
995
+ reviewedAt,
996
+ summary: {
997
+ total: output.summary.total,
998
+ passed: output.summary.passed,
999
+ failed: output.summary.failed,
1000
+ warnings: output.summary.warnings,
1001
+ skipped: skippedPolicies.length,
1002
+ },
1003
+ skippedPolicies: skippedPolicies,
1004
+ },
1005
+ );
1006
+ const workflowWithTrust = loadWorkflowState(contextDir);
1007
+ await pushWorkflowStateIfConfigured(config, workflowWithTrust);
1018
1008
 
1019
1009
  return buildToolResult({
1020
1010
  scope: parsed.scope,
@@ -1024,7 +1014,10 @@ export function registerEnterpriseTools(
1024
1014
  ...output.summary,
1025
1015
  skipped: skippedPolicies.length,
1026
1016
  },
1027
- workflow: workflowState,
1017
+ workflow: workflowWithTrust,
1018
+ workflow_source: trustState.workflow.source,
1019
+ delivery: trustState.delivery,
1020
+ trust_warnings: trustState.trust_warnings,
1028
1021
  });
1029
1022
  },
1030
1023
  );
@@ -1,4 +1,5 @@
1
1
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { isEnforcedMode } from "../../hooks/shared.js";
2
3
  import {
3
4
  WorkflowAdvanceInput,
4
5
  WorkflowEnvelopeInput,
@@ -38,6 +39,7 @@ export function registerHarnessTools(server: McpServer): void {
38
39
  async (input) => buildResult(
39
40
  runWorkflowStart(WorkflowStartInput.parse(input ?? {}), {
40
41
  cwd: resolveProjectRoot(),
42
+ bundledFallbackPolicy: isEnforcedMode(resolveProjectRoot()) ? "block" : "allow",
41
43
  }) as ToolPayload,
42
44
  ),
43
45
  );
@@ -10,6 +10,7 @@ import type {
10
10
  ReviewResult,
11
11
  ReviewSummary,
12
12
  } from "../../core/validators/engine.js";
13
+ import type { ReviewTrustState } from "../reviews/trust-state.js";
13
14
 
14
15
  export type WorkflowPhase =
15
16
  | "planning"
@@ -111,6 +112,7 @@ export type WorkflowState = {
111
112
  notes: WorkflowNote[];
112
113
  todos: WorkflowTodo[];
113
114
  history: WorkflowHistoryEntry[];
115
+ review_trust: ReviewTrustState | null;
114
116
  };
115
117
 
116
118
  export type WorkflowMutationResult = {
@@ -145,6 +147,10 @@ function workflowStatePath(contextDir: string): string {
145
147
  return join(workflowDir(contextDir), "state.json");
146
148
  }
147
149
 
150
+ export function hasWorkflowState(contextDir: string): boolean {
151
+ return existsSync(workflowStatePath(contextDir));
152
+ }
153
+
148
154
  function workflowReviewsDir(contextDir: string): string {
149
155
  return join(workflowDir(contextDir), "reviews");
150
156
  }
@@ -195,6 +201,7 @@ function initialState(): WorkflowState {
195
201
  notes: [],
196
202
  todos: [],
197
203
  history: [],
204
+ review_trust: null,
198
205
  };
199
206
  }
200
207
 
@@ -457,6 +464,20 @@ export function recordWorkflowUpdate(
457
464
  );
458
465
  }
459
466
 
467
+ export function setWorkflowReviewTrust(
468
+ contextDir: string,
469
+ reviewTrust: ReviewTrustState,
470
+ ): WorkflowState {
471
+ if (!hasWorkflowState(contextDir)) {
472
+ const state = initialState();
473
+ state.review_trust = reviewTrust;
474
+ return writeState(contextDir, withRecalculatedApproval(state, true));
475
+ }
476
+ const state = loadWorkflowState(contextDir);
477
+ state.review_trust = reviewTrust;
478
+ return writeState(contextDir, withRecalculatedApproval(state, true));
479
+ }
480
+
460
481
  export function addWorkflowNote(
461
482
  contextDir: string,
462
483
  input: { title: string; details: string }
@@ -0,0 +1,318 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import fs from "node:fs";
4
+ import os from "node:os";
5
+ import path from "node:path";
6
+
7
+ import {
8
+ loadReviewTrustState,
9
+ recordQueuedReviewTrustState,
10
+ } from "../dist/enterprise/reviews/trust-state.js";
11
+ import {
12
+ pendingCount,
13
+ pushReviewResults,
14
+ queueReviewResult,
15
+ setReviewPushContext,
16
+ } from "../dist/enterprise/reviews/push.js";
17
+
18
+ function makeProject() {
19
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "cortex-review-trust-"));
20
+ const contextDir = path.join(root, ".context");
21
+ fs.mkdirSync(contextDir, { recursive: true });
22
+ return { root, contextDir };
23
+ }
24
+
25
+ function writeTaskState(root, taskId, workflowId = "secure-build") {
26
+ const taskDir = path.join(root, ".agents", taskId);
27
+ fs.mkdirSync(taskDir, { recursive: true });
28
+ fs.writeFileSync(
29
+ path.join(taskDir, "state.json"),
30
+ JSON.stringify(
31
+ {
32
+ workflow_id: workflowId,
33
+ outcome: "in_progress",
34
+ },
35
+ null,
36
+ 2,
37
+ ),
38
+ "utf8",
39
+ );
40
+ }
41
+
42
+ function queueOneReview(reviewedAt = "2026-05-17T10:00:00.000Z") {
43
+ queueReviewResult({
44
+ policy_id: "no-secrets-in-code",
45
+ pass: true,
46
+ severity: "info",
47
+ message: "No new secrets found",
48
+ reviewed_at: reviewedAt,
49
+ });
50
+ }
51
+
52
+ test.afterEach(async () => {
53
+ const originalFetch = globalThis.fetch;
54
+ globalThis.fetch = async () => ({ ok: true, status: 200 });
55
+ try {
56
+ while (pendingCount() > 0) {
57
+ await pushReviewResults("https://example.com", "ent_test");
58
+ }
59
+ } finally {
60
+ globalThis.fetch = originalFetch;
61
+ }
62
+ });
63
+
64
+ test("review trust state persists queued review evidence", () => {
65
+ const { root, contextDir } = makeProject();
66
+ const state = recordQueuedReviewTrustState(
67
+ {
68
+ contextDir,
69
+ projectRoot: root,
70
+ repo: "demo-repo",
71
+ instance_id: "abc123",
72
+ session_id: "session-1",
73
+ },
74
+ {
75
+ reviewedAt: "2026-05-17T10:00:00.000Z",
76
+ summary: {
77
+ total: 2,
78
+ passed: 1,
79
+ failed: 1,
80
+ warnings: 0,
81
+ skipped: 1,
82
+ },
83
+ skippedPolicies: [
84
+ {
85
+ policy_id: "require-code-review",
86
+ kind: "predefined",
87
+ type: null,
88
+ reason: "validate this policy from workflow state on the next run.",
89
+ },
90
+ ],
91
+ },
92
+ );
93
+
94
+ assert.equal(state.delivery.status, "queued");
95
+ assert.equal(state.review_summary.total, 2);
96
+ assert.equal(state.skipped_policies.length, 1);
97
+ assert.ok(fs.existsSync(path.join(contextDir, "review-trust.json")));
98
+ assert.match(
99
+ state.trust_warnings.map((warning) => warning.code).join(","),
100
+ /workflow-unresolved/,
101
+ );
102
+ });
103
+
104
+ test("review trust state writes workflow state even when no workflow file exists yet", () => {
105
+ const { contextDir } = makeProject();
106
+ const state = loadReviewTrustState(contextDir);
107
+
108
+ assert.equal(state.delivery.status, "never_attempted");
109
+ assert.ok(fs.existsSync(path.join(contextDir, "workflow", "state.json")));
110
+ });
111
+
112
+ test("review trust uses the explicit active task instead of guessing from the newest agent run", () => {
113
+ const { root, contextDir } = makeProject();
114
+ const fakeHome = fs.mkdtempSync(path.join(os.tmpdir(), "cortex-review-home-"));
115
+ process.env.HOME = fakeHome;
116
+ try {
117
+ writeTaskState(root, "task-a");
118
+ writeTaskState(root, "task-b", "shadow-workflow");
119
+ const state = recordQueuedReviewTrustState(
120
+ {
121
+ contextDir,
122
+ projectRoot: root,
123
+ repo: "demo-repo",
124
+ instance_id: "abc123",
125
+ session_id: "session-1",
126
+ task_id: "task-a",
127
+ },
128
+ {
129
+ reviewedAt: "2026-05-17T10:00:00.000Z",
130
+ summary: {
131
+ total: 1,
132
+ passed: 1,
133
+ failed: 0,
134
+ warnings: 0,
135
+ skipped: 0,
136
+ },
137
+ skippedPolicies: [],
138
+ },
139
+ );
140
+
141
+ assert.equal(state.workflow.task_id, "task-a");
142
+ assert.equal(state.workflow.id, "secure-build");
143
+ } finally {
144
+ delete process.env.HOME;
145
+ }
146
+ });
147
+
148
+ test("review push marks delivery accepted on successful ingestion", async () => {
149
+ const { contextDir } = makeProject();
150
+ const originalFetch = globalThis.fetch;
151
+ globalThis.fetch = async () => ({ ok: true, status: 200 });
152
+
153
+ setReviewPushContext({
154
+ repo: "demo-repo",
155
+ instance_id: "abc123",
156
+ session_id: "session-accepted",
157
+ context_dir: contextDir,
158
+ });
159
+ queueOneReview();
160
+
161
+ try {
162
+ const result = await pushReviewResults("https://example.com", "ent_test");
163
+ assert.equal(result.success, true);
164
+ assert.equal(result.delivery_status, "accepted");
165
+ } finally {
166
+ globalThis.fetch = originalFetch;
167
+ }
168
+
169
+ const state = loadReviewTrustState(contextDir);
170
+ assert.equal(state.delivery.status, "accepted");
171
+ });
172
+
173
+ test("review push marks delivery failed on HTTP errors", async () => {
174
+ const { contextDir } = makeProject();
175
+ const originalFetch = globalThis.fetch;
176
+ globalThis.fetch = async () => ({ ok: false, status: 502 });
177
+
178
+ setReviewPushContext({
179
+ repo: "demo-repo",
180
+ instance_id: "abc123",
181
+ session_id: "session-http-fail",
182
+ context_dir: contextDir,
183
+ });
184
+ queueOneReview();
185
+
186
+ try {
187
+ const result = await pushReviewResults("https://example.com", "ent_test");
188
+ assert.equal(result.success, false);
189
+ assert.equal(result.delivery_status, "failed");
190
+ } finally {
191
+ globalThis.fetch = originalFetch;
192
+ }
193
+
194
+ const state = loadReviewTrustState(contextDir);
195
+ assert.equal(state.delivery.status, "failed");
196
+ assert.equal(state.delivery.last_error, "HTTP 502");
197
+ });
198
+
199
+ test("review push marks delivery failed on network errors", async () => {
200
+ const { contextDir } = makeProject();
201
+ const originalFetch = globalThis.fetch;
202
+ globalThis.fetch = async () => {
203
+ throw new Error("network down");
204
+ };
205
+
206
+ setReviewPushContext({
207
+ repo: "demo-repo",
208
+ instance_id: "abc123",
209
+ session_id: "session-network-fail",
210
+ context_dir: contextDir,
211
+ });
212
+ queueOneReview();
213
+
214
+ try {
215
+ const result = await pushReviewResults("https://example.com", "ent_test");
216
+ assert.equal(result.success, false);
217
+ assert.equal(result.delivery_status, "failed");
218
+ } finally {
219
+ globalThis.fetch = originalFetch;
220
+ }
221
+
222
+ const state = loadReviewTrustState(contextDir);
223
+ assert.equal(state.delivery.status, "failed");
224
+ assert.equal(state.delivery.last_error, "network down");
225
+ });
226
+
227
+ test("queuing a new review resets prior accepted delivery markers", async () => {
228
+ const { root, contextDir } = makeProject();
229
+ const originalFetch = globalThis.fetch;
230
+ globalThis.fetch = async () => ({ ok: true, status: 200 });
231
+
232
+ setReviewPushContext({
233
+ repo: "demo-repo",
234
+ instance_id: "abc123",
235
+ session_id: "session-accepted",
236
+ context_dir: contextDir,
237
+ });
238
+ queueOneReview("2026-05-17T10:00:00.000Z");
239
+
240
+ try {
241
+ const result = await pushReviewResults("https://example.com", "ent_test");
242
+ assert.equal(result.success, true);
243
+ } finally {
244
+ globalThis.fetch = originalFetch;
245
+ }
246
+
247
+ const accepted = loadReviewTrustState(contextDir);
248
+ assert.equal(accepted.delivery.status, "accepted");
249
+ assert.ok(accepted.delivery.last_accepted_at);
250
+
251
+ const queued = recordQueuedReviewTrustState(
252
+ {
253
+ contextDir,
254
+ projectRoot: root,
255
+ repo: "demo-repo",
256
+ instance_id: "abc123",
257
+ session_id: "session-next",
258
+ },
259
+ {
260
+ reviewedAt: "2026-05-17T11:00:00.000Z",
261
+ summary: {
262
+ total: 1,
263
+ passed: 1,
264
+ failed: 0,
265
+ warnings: 0,
266
+ skipped: 0,
267
+ },
268
+ skippedPolicies: [],
269
+ },
270
+ );
271
+
272
+ assert.equal(queued.delivery.status, "queued");
273
+ assert.equal(queued.delivery.last_attempted_at, null);
274
+ assert.equal(queued.delivery.last_pushed_at, null);
275
+ assert.equal(queued.delivery.last_accepted_at, null);
276
+ });
277
+
278
+ test("zero-result reviews stay never_attempted instead of looking queued", () => {
279
+ const { root, contextDir } = makeProject();
280
+ const state = recordQueuedReviewTrustState(
281
+ {
282
+ contextDir,
283
+ projectRoot: root,
284
+ repo: "demo-repo",
285
+ instance_id: "abc123",
286
+ session_id: "session-empty",
287
+ },
288
+ {
289
+ reviewedAt: "2026-05-17T11:00:00.000Z",
290
+ summary: {
291
+ total: 0,
292
+ passed: 0,
293
+ failed: 0,
294
+ warnings: 0,
295
+ skipped: 2,
296
+ },
297
+ skippedPolicies: [
298
+ {
299
+ policy_id: "require-code-review",
300
+ kind: "predefined",
301
+ type: null,
302
+ reason: "validate this policy from workflow state on the next run.",
303
+ },
304
+ {
305
+ policy_id: "custom.missing",
306
+ kind: "custom",
307
+ type: "regex-custom",
308
+ reason: 'No evaluator registered for type "regex-custom"',
309
+ },
310
+ ],
311
+ },
312
+ );
313
+
314
+ assert.equal(state.delivery.status, "never_attempted");
315
+ assert.equal(state.delivery.review_count, 0);
316
+ assert.equal(state.delivery.queued_at, null);
317
+ assert.equal(state.delivery.last_attempted_at, null);
318
+ });
@@ -0,0 +1,59 @@
1
+ {
2
+ "skills": [
3
+ {
4
+ "name": "alpha-codex",
5
+ "description": "Codex-first org skill",
6
+ "body": "# Alpha Codex\n\nUse for Codex review flows.",
7
+ "scope": "cli:codex",
8
+ "enabled": true,
9
+ "updated_at": "2026-05-19T09:00:00.000Z"
10
+ },
11
+ {
12
+ "name": "claude-playbook",
13
+ "description": "Claude-only org skill",
14
+ "body": "# Claude Playbook\n\nUse for Claude-only flows.",
15
+ "scope": "cli:claude",
16
+ "enabled": true,
17
+ "updated_at": "2026-05-19T08:45:00.000Z"
18
+ },
19
+ {
20
+ "name": "global-guard",
21
+ "description": "Shared org skill",
22
+ "body": "# Global Guard\n\nApply for both CLIs.",
23
+ "scope": "global",
24
+ "enabled": true,
25
+ "updated_at": "2026-05-19T08:30:00.000Z"
26
+ }
27
+ ],
28
+ "manifest": {
29
+ "codex": [
30
+ {
31
+ "name": "alpha-codex",
32
+ "scope": "cli:codex",
33
+ "updated_at": "2026-05-19T09:00:00.000Z"
34
+ },
35
+ {
36
+ "name": "global-guard",
37
+ "scope": "global",
38
+ "updated_at": "2026-05-19T08:30:00.000Z"
39
+ }
40
+ ],
41
+ "claude": [
42
+ {
43
+ "name": "claude-playbook",
44
+ "scope": "cli:claude",
45
+ "updated_at": "2026-05-19T08:45:00.000Z"
46
+ },
47
+ {
48
+ "name": "global-guard",
49
+ "scope": "global",
50
+ "updated_at": "2026-05-19T08:30:00.000Z"
51
+ }
52
+ ]
53
+ },
54
+ "markdown": {
55
+ "alpha-codex": "---\nname: alpha-codex\ndescription: \"Codex-first org skill\"\n---\n\n# Alpha Codex\n\nUse for Codex review flows.\n",
56
+ "claude-playbook": "---\nname: claude-playbook\ndescription: \"Claude-only org skill\"\n---\n\n# Claude Playbook\n\nUse for Claude-only flows.\n",
57
+ "global-guard": "---\nname: global-guard\ndescription: \"Shared org skill\"\n---\n\n# Global Guard\n\nApply for both CLIs.\n"
58
+ }
59
+ }
@@ -0,0 +1,111 @@
1
+ {
2
+ "accepted": {
3
+ "review_session": {
4
+ "sessionId": "session-accepted",
5
+ "repo": "demo-repo",
6
+ "instanceId": "abc123",
7
+ "reviewCount": 3,
8
+ "lastReviewedAt": "2026-05-19T10:00:00.000Z",
9
+ "lastReceivedAt": "2026-05-19T10:02:00.000Z"
10
+ },
11
+ "workflow_session": {
12
+ "sessionId": "session-accepted",
13
+ "repo": "demo-repo",
14
+ "instanceId": "abc123",
15
+ "phase": "reviewed",
16
+ "reviewStatus": "passed",
17
+ "approvalStatus": "ready",
18
+ "lastReceivedAt": "2026-05-19T10:02:00.000Z"
19
+ },
20
+ "workflow_snapshot": {
21
+ "sessionId": "session-accepted",
22
+ "repo": "demo-repo",
23
+ "instanceId": "abc123",
24
+ "phase": "reviewed",
25
+ "reviewStatus": "passed",
26
+ "approvalStatus": "ready",
27
+ "receivedAt": "2026-05-19T10:02:00.000Z",
28
+ "snapshot": {
29
+ "review_trust": {
30
+ "workflow": {
31
+ "id": "secure-build",
32
+ "source": "synced"
33
+ },
34
+ "last_review_at": "2026-05-19T10:00:00.000Z",
35
+ "skipped_policies": [
36
+ {
37
+ "policy_id": "require-code-review",
38
+ "kind": "predefined",
39
+ "type": null,
40
+ "reason": "validate this policy from workflow state on the next run."
41
+ }
42
+ ],
43
+ "delivery": {
44
+ "status": "accepted",
45
+ "review_count": 3,
46
+ "last_accepted_at": "2026-05-19T10:02:00.000Z",
47
+ "last_attempted_at": "2026-05-19T10:02:00.000Z",
48
+ "last_error": null
49
+ }
50
+ }
51
+ }
52
+ },
53
+ "expected": {
54
+ "trustHealth": "healthy",
55
+ "workflowSource": "synced",
56
+ "reviewCount": 3,
57
+ "skippedPolicyIds": [
58
+ "require-code-review"
59
+ ]
60
+ }
61
+ },
62
+ "failed": {
63
+ "review_session": null,
64
+ "workflow_session": {
65
+ "sessionId": "session-failed",
66
+ "repo": "demo-repo",
67
+ "instanceId": "abc123",
68
+ "phase": "reviewed",
69
+ "reviewStatus": "passed",
70
+ "approvalStatus": "ready",
71
+ "lastReceivedAt": "2026-05-19T11:02:00.000Z"
72
+ },
73
+ "workflow_snapshot": {
74
+ "sessionId": "session-failed",
75
+ "repo": "demo-repo",
76
+ "instanceId": "abc123",
77
+ "phase": "reviewed",
78
+ "reviewStatus": "passed",
79
+ "approvalStatus": "ready",
80
+ "receivedAt": "2026-05-19T11:02:00.000Z",
81
+ "snapshot": {
82
+ "review_trust": {
83
+ "workflow": {
84
+ "id": "secure-build",
85
+ "source": "synced"
86
+ },
87
+ "last_review_at": "2026-05-19T11:00:00.000Z",
88
+ "skipped_policies": [],
89
+ "delivery": {
90
+ "status": "failed",
91
+ "review_count": 2,
92
+ "last_accepted_at": null,
93
+ "last_attempted_at": "2026-05-19T11:02:00.000Z",
94
+ "last_error": "HTTP 502"
95
+ }
96
+ }
97
+ }
98
+ },
99
+ "expected": {
100
+ "trustHealth": "failed_delivery",
101
+ "workflowSource": "synced",
102
+ "reviewCount": 2,
103
+ "lastPushFailure": {
104
+ "at": "2026-05-19T11:02:00.000Z",
105
+ "error": "HTTP 502",
106
+ "sessionId": "session-failed",
107
+ "repo": "demo-repo"
108
+ }
109
+ }
110
+ }
111
+ }