@martinloop/mcp 0.3.8 → 0.5.0

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 (161) hide show
  1. package/README.md +90 -106
  2. package/dist/discovery-metadata.d.ts +1 -1
  3. package/dist/discovery-metadata.js +1 -1
  4. package/dist/resources.d.ts +1 -2
  5. package/dist/resources.js +190 -238
  6. package/dist/server-validation.d.ts +1 -1
  7. package/dist/server-validation.js +16 -11
  8. package/dist/server.d.ts +23 -0
  9. package/dist/server.js +152 -7
  10. package/dist/tools/run-dossier.d.ts +3 -1
  11. package/dist/tools/run-dossier.js +40 -2
  12. package/dist/tools/run-loop.d.ts +1 -4
  13. package/dist/tools/run-loop.js +6 -15
  14. package/dist/tools/tool-support.d.ts +2 -1
  15. package/dist/tools/tool-support.js +1 -12
  16. package/dist/vendor/adapters/claude-cli.js +38 -35
  17. package/dist/vendor/adapters/cli-bridge.d.ts +9 -1
  18. package/dist/vendor/adapters/cli-bridge.js +54 -13
  19. package/dist/vendor/adapters/codex-launcher.d.ts +61 -1
  20. package/dist/vendor/adapters/codex-launcher.js +118 -19
  21. package/dist/vendor/adapters/index.d.ts +1 -3
  22. package/dist/vendor/adapters/index.js +1 -3
  23. package/dist/vendor/adapters/openai-compatible.js +57 -18
  24. package/dist/vendor/contracts/adapter-capabilities.d.ts +1 -1
  25. package/dist/vendor/contracts/context-handoff.d.ts +100 -0
  26. package/dist/vendor/contracts/context-handoff.js +11 -0
  27. package/dist/vendor/contracts/context-manifest.d.ts +195 -0
  28. package/dist/vendor/contracts/context-manifest.js +17 -0
  29. package/dist/vendor/contracts/context-shadow.d.ts +75 -0
  30. package/dist/vendor/contracts/context-shadow.js +8 -0
  31. package/dist/vendor/contracts/exits.d.ts +126 -0
  32. package/dist/vendor/contracts/exits.js +32 -0
  33. package/dist/vendor/contracts/index.d.ts +39 -2
  34. package/dist/vendor/contracts/index.js +22 -0
  35. package/dist/vendor/contracts/mission.d.ts +102 -0
  36. package/dist/vendor/contracts/mission.js +64 -0
  37. package/dist/vendor/contracts/operator.d.ts +3 -1
  38. package/dist/vendor/contracts/operator.js +2 -1
  39. package/dist/vendor/contracts/verified-handoff.d.ts +100 -0
  40. package/dist/vendor/contracts/verified-handoff.js +35 -0
  41. package/dist/vendor/core/context-chain-gate.d.ts +89 -0
  42. package/dist/vendor/core/context-chain-gate.js +173 -0
  43. package/dist/vendor/core/context-compiler.d.ts +53 -0
  44. package/dist/vendor/core/context-compiler.js +261 -0
  45. package/dist/vendor/core/context-handoff.d.ts +42 -0
  46. package/dist/vendor/core/context-handoff.js +167 -0
  47. package/dist/vendor/core/context-shadow.d.ts +39 -0
  48. package/dist/vendor/core/context-shadow.js +200 -0
  49. package/dist/vendor/core/exit-signal.d.ts +88 -0
  50. package/dist/vendor/core/exit-signal.js +339 -0
  51. package/dist/vendor/core/exits.d.ts +41 -0
  52. package/dist/vendor/core/exits.js +258 -0
  53. package/dist/vendor/core/index.d.ts +42 -1
  54. package/dist/vendor/core/index.js +1086 -662
  55. package/dist/vendor/core/mission/aggregate.d.ts +27 -0
  56. package/dist/vendor/core/mission/aggregate.js +42 -0
  57. package/dist/vendor/core/mission/index.d.ts +2 -0
  58. package/dist/vendor/core/mission/index.js +1 -0
  59. package/dist/vendor/core/persistence/compiler.d.ts +8 -0
  60. package/dist/vendor/core/persistence/compiler.js +156 -0
  61. package/dist/vendor/core/persistence/context-handoff-store.d.ts +68 -0
  62. package/dist/vendor/core/persistence/context-handoff-store.js +112 -0
  63. package/dist/vendor/core/persistence/index.d.ts +4 -0
  64. package/dist/vendor/core/persistence/index.js +2 -0
  65. package/dist/vendor/core/persistence/ledger.d.ts +1 -1
  66. package/dist/vendor/core/persistence/mission-store.d.ts +56 -0
  67. package/dist/vendor/core/persistence/mission-store.js +281 -0
  68. package/dist/vendor/core/policy.d.ts +2 -0
  69. package/dist/vendor/core/policy.js +5 -2
  70. package/dist/vendor/core/rollback.js +15 -1
  71. package/dist/vendor/core/savings.d.ts +13 -0
  72. package/dist/vendor/core/savings.js +22 -0
  73. package/dist/vendor/core/termination-store.d.ts +15 -0
  74. package/dist/vendor/core/termination-store.js +44 -0
  75. package/dist/vendor/core/verified-handoff.d.ts +67 -0
  76. package/dist/vendor/core/verified-handoff.js +210 -0
  77. package/package.json +76 -83
  78. package/server.json +21 -21
  79. package/LICENSE +0 -216
  80. package/dist/vendor/adapters/adapters/src/claude-cli.d.ts +0 -146
  81. package/dist/vendor/adapters/adapters/src/claude-cli.js +0 -1100
  82. package/dist/vendor/adapters/adapters/src/cli-bridge.d.ts +0 -103
  83. package/dist/vendor/adapters/adapters/src/cli-bridge.js +0 -569
  84. package/dist/vendor/adapters/adapters/src/codex-launcher.d.ts +0 -78
  85. package/dist/vendor/adapters/adapters/src/codex-launcher.js +0 -663
  86. package/dist/vendor/adapters/adapters/src/direct-provider.d.ts +0 -10
  87. package/dist/vendor/adapters/adapters/src/direct-provider.js +0 -40
  88. package/dist/vendor/adapters/adapters/src/index.d.ts +0 -8
  89. package/dist/vendor/adapters/adapters/src/index.js +0 -8
  90. package/dist/vendor/adapters/adapters/src/openai-compatible.d.ts +0 -62
  91. package/dist/vendor/adapters/adapters/src/openai-compatible.js +0 -306
  92. package/dist/vendor/adapters/adapters/src/runtime-support.d.ts +0 -17
  93. package/dist/vendor/adapters/adapters/src/runtime-support.js +0 -59
  94. package/dist/vendor/adapters/adapters/src/stub-agent-cli.d.ts +0 -8
  95. package/dist/vendor/adapters/adapters/src/stub-agent-cli.js +0 -40
  96. package/dist/vendor/adapters/adapters/src/stub-direct-provider.d.ts +0 -8
  97. package/dist/vendor/adapters/adapters/src/stub-direct-provider.js +0 -12
  98. package/dist/vendor/adapters/adapters/src/verifier-only.d.ts +0 -9
  99. package/dist/vendor/adapters/adapters/src/verifier-only.js +0 -63
  100. package/dist/vendor/adapters/contracts/src/context-graph.d.ts +0 -48
  101. package/dist/vendor/adapters/contracts/src/context-graph.js +0 -26
  102. package/dist/vendor/adapters/contracts/src/execution-policy.d.ts +0 -78
  103. package/dist/vendor/adapters/contracts/src/execution-policy.js +0 -43
  104. package/dist/vendor/adapters/contracts/src/governance.d.ts +0 -24
  105. package/dist/vendor/adapters/contracts/src/governance.js +0 -11
  106. package/dist/vendor/adapters/contracts/src/identity.d.ts +0 -29
  107. package/dist/vendor/adapters/contracts/src/identity.js +0 -30
  108. package/dist/vendor/adapters/contracts/src/index.d.ts +0 -412
  109. package/dist/vendor/adapters/contracts/src/index.js +0 -225
  110. package/dist/vendor/adapters/contracts/src/operator.d.ts +0 -19
  111. package/dist/vendor/adapters/contracts/src/operator.js +0 -11
  112. package/dist/vendor/adapters/contracts/src/trajectory.d.ts +0 -26
  113. package/dist/vendor/adapters/contracts/src/trajectory.js +0 -27
  114. package/dist/vendor/adapters/core/src/compiler.d.ts +0 -52
  115. package/dist/vendor/adapters/core/src/compiler.js +0 -52
  116. package/dist/vendor/adapters/core/src/context-graph.d.ts +0 -3
  117. package/dist/vendor/adapters/core/src/context-graph.js +0 -371
  118. package/dist/vendor/adapters/core/src/context-integrity.d.ts +0 -26
  119. package/dist/vendor/adapters/core/src/context-integrity.js +0 -80
  120. package/dist/vendor/adapters/core/src/grounding.d.ts +0 -38
  121. package/dist/vendor/adapters/core/src/grounding.js +0 -273
  122. package/dist/vendor/adapters/core/src/identity.d.ts +0 -20
  123. package/dist/vendor/adapters/core/src/identity.js +0 -86
  124. package/dist/vendor/adapters/core/src/index.d.ts +0 -186
  125. package/dist/vendor/adapters/core/src/index.js +0 -1495
  126. package/dist/vendor/adapters/core/src/leash.d.ts +0 -48
  127. package/dist/vendor/adapters/core/src/leash.js +0 -497
  128. package/dist/vendor/adapters/core/src/persistence/compiler.d.ts +0 -18
  129. package/dist/vendor/adapters/core/src/persistence/compiler.js +0 -34
  130. package/dist/vendor/adapters/core/src/persistence/index.d.ts +0 -10
  131. package/dist/vendor/adapters/core/src/persistence/index.js +0 -5
  132. package/dist/vendor/adapters/core/src/persistence/integrity.d.ts +0 -39
  133. package/dist/vendor/adapters/core/src/persistence/integrity.js +0 -252
  134. package/dist/vendor/adapters/core/src/persistence/ledger.d.ts +0 -23
  135. package/dist/vendor/adapters/core/src/persistence/ledger.js +0 -9
  136. package/dist/vendor/adapters/core/src/persistence/memory-store.d.ts +0 -63
  137. package/dist/vendor/adapters/core/src/persistence/memory-store.js +0 -115
  138. package/dist/vendor/adapters/core/src/persistence/runs-reader.d.ts +0 -66
  139. package/dist/vendor/adapters/core/src/persistence/runs-reader.js +0 -140
  140. package/dist/vendor/adapters/core/src/persistence/store.d.ts +0 -89
  141. package/dist/vendor/adapters/core/src/persistence/store.js +0 -125
  142. package/dist/vendor/adapters/core/src/persistence/trace-store.d.ts +0 -85
  143. package/dist/vendor/adapters/core/src/persistence/trace-store.js +0 -125
  144. package/dist/vendor/adapters/core/src/policy-compiler.d.ts +0 -2
  145. package/dist/vendor/adapters/core/src/policy-compiler.js +0 -195
  146. package/dist/vendor/adapters/core/src/policy.d.ts +0 -156
  147. package/dist/vendor/adapters/core/src/policy.js +0 -704
  148. package/dist/vendor/adapters/core/src/repo-analyzer.d.ts +0 -53
  149. package/dist/vendor/adapters/core/src/repo-analyzer.js +0 -263
  150. package/dist/vendor/adapters/core/src/rollback.d.ts +0 -15
  151. package/dist/vendor/adapters/core/src/rollback.js +0 -253
  152. package/dist/vendor/adapters/core/src/routing.d.ts +0 -82
  153. package/dist/vendor/adapters/core/src/routing.js +0 -336
  154. package/dist/vendor/adapters/core/src/test-integrity.d.ts +0 -64
  155. package/dist/vendor/adapters/core/src/test-integrity.js +0 -197
  156. package/dist/vendor/adapters/core/src/trajectory.d.ts +0 -18
  157. package/dist/vendor/adapters/core/src/trajectory.js +0 -295
  158. package/dist/vendor/adapters/stub-agent-cli.d.ts +0 -8
  159. package/dist/vendor/adapters/stub-agent-cli.js +0 -40
  160. package/dist/vendor/adapters/verifier-only.d.ts +0 -9
  161. package/dist/vendor/adapters/verifier-only.js +0 -63
@@ -1,3 +1,12 @@
1
+ /**
2
+ * Contracts for the Martin Loop agentic system.
3
+ *
4
+ * This module defines the core type contracts and data structures for autonomous agent loop management,
5
+ * including loop lifecycle states, task definitions, budget tracking, cost accounting, verification,
6
+ * patch decisions, telemetry, and governance policies. It provides the public API surface for
7
+ * creating and managing loop records, handling events, validating batches, and tracking
8
+ * portfolio snapshots and routing economics.
9
+ */
1
10
  export const FAILURE_CLASSES = [
2
11
  "logic_error",
3
12
  "hallucination",
@@ -53,6 +62,7 @@ export function createLoopRecord(draft, options = {}) {
53
62
  updatedAt: draft.updatedAt ?? now,
54
63
  ...(draft.receiptScope ? { receiptScope: draft.receiptScope } : {}),
55
64
  ...(draft.receiptIntegrity ? { receiptIntegrity: draft.receiptIntegrity } : {}),
65
+ ...(draft.terminationEnvelope ? { terminationEnvelope: draft.terminationEnvelope } : {}),
56
66
  ...(draft.teamId ? { teamId: draft.teamId } : {})
57
67
  };
58
68
  }
@@ -210,6 +220,8 @@ function nextStatus(current, eventType) {
210
220
  return "verifying";
211
221
  case "run.completed":
212
222
  return current === "failed" ? "failed" : "completed";
223
+ case "run.terminated":
224
+ return "exited";
213
225
  default:
214
226
  return current;
215
227
  }
@@ -223,5 +235,15 @@ export { DEFAULT_ROUTING_POLICY } from "./execution-policy.js";
223
235
  export { cloneContextGraphSnapshot } from "./context-graph.js";
224
236
  export { cloneIdentityAttestation, cloneIdentityClaims, cloneIdentityToken } from "./identity.js";
225
237
  export { cloneCircuitBreakDecision, cloneTrajectoryAssessment } from "./trajectory.js";
238
+ export { EXIT_KINDS, EXIT_POLICY_VERSION, EXIT_EVALUATION_VERSION, EXIT_SIGNAL_VERSION, TERMINATION_ENVELOPE_VERSION } from "./exits.js";
226
239
  // ─── R4 Delivery — M1 Contract ──────────────────────────────────────────────
227
240
  export { ALLOWED_ACTION_TYPES, DELIVERY_MESSAGE_SCHEMA_VERSION, DELIVERY_RECORD_SCHEMA_VERSION, MESSAGE_SELECTION_RESPONSE_SCHEMA_VERSION } from "./delivery.js";
241
+ // ─── Context Shadow — A-CTX-0 ────────────────────────────────────────────────
242
+ export { CONTEXT_SHADOW_MANIFEST_VERSION, CONTEXT_C5_VERSION } from "./context-shadow.js";
243
+ // ─── Context Runtime — A-CTX-1 ───────────────────────────────────────────────
244
+ export { CONTEXT_MANIFEST_VERSION, CONTEXT_LEDGER_VERSION } from "./context-manifest.js";
245
+ // ─── Track A — Verified Handoff ───────────────────────────────────────────────
246
+ export { EVIDENCE_STATUSES, TEST_INTEGRITY_STATUSES, TEST_INTEGRITY_VERDICTS, VERIFIED_HANDOFF_OUTCOMES, } from "./verified-handoff.js";
247
+ // ─── Context Handoff — A-CTX-2 ───────────────────────────────────────────────
248
+ export { HANDOFF_SCHEMA_VERSION } from "./context-handoff.js";
249
+ export { MISSION_SCHEMA_VERSION, MISSION_STATUSES, ALLOWED_MISSION_TRANSITIONS, createMissionRecord, isMissionTransitionAllowed } from './mission.js';
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Mission Governance contracts — C2
3
+ *
4
+ * A MissionRecord governs one software mission: intent → budget → runs →
5
+ * verification → decision → receipt. It never replaces LoopRecord; it
6
+ * aggregates above it.
7
+ *
8
+ * Invariants:
9
+ * - One accountable human owner per mission.
10
+ * - State transitions are append-only in the ledger.
11
+ * - Ledger is the authority; mission.json is a rebuildable cache.
12
+ * - A mission cannot become "verified" without verified run evidence.
13
+ * - A mission cannot become "shipped" without an explicit ship decision.
14
+ * - Unknown schema versions fail closed.
15
+ * - Budgets cannot be raised silently.
16
+ */
17
+ export declare const MISSION_SCHEMA_VERSION: "martin.mission.v1";
18
+ export declare const MISSION_STATUSES: readonly ["planned", "running", "blocked", "verified", "shipped", "rolled_back", "killed"];
19
+ export type MissionStatus = (typeof MISSION_STATUSES)[number];
20
+ export declare const ALLOWED_MISSION_TRANSITIONS: Record<MissionStatus, readonly MissionStatus[]>;
21
+ export type MissionDecision = "ship" | "retry" | "rollback" | "kill";
22
+ export interface MissionBudget {
23
+ maxUsd: number;
24
+ maxTokens: number;
25
+ maxRuns: number;
26
+ maxConcurrentRuns: number;
27
+ }
28
+ export interface MissionCost {
29
+ /** Sum of actualUsd across all linked runs. */
30
+ totalActualUsd: number;
31
+ /** Number of linked runs with status "completed" (verified outcome). */
32
+ verifiedOutcomeCount: number;
33
+ /** Number of linked runs regardless of outcome. */
34
+ totalRunCount: number;
35
+ }
36
+ export type MissionRunRole = "primary" | "experiment" | "validation";
37
+ export interface MissionRunLink {
38
+ loopId: string;
39
+ role: MissionRunRole;
40
+ attachedAt: string;
41
+ /** Set to true when the linked run completed with verification passed. */
42
+ verifiedOutcome?: boolean;
43
+ /** Actual cost of this run in USD. */
44
+ actualUsd?: number;
45
+ }
46
+ export interface MissionApproval {
47
+ approvalId: string;
48
+ kind: "ship" | "budget_increase" | "scope_change";
49
+ decision: "approved" | "denied";
50
+ approvedBy: string;
51
+ approvedAt: string;
52
+ note?: string;
53
+ }
54
+ export interface MissionOutcome {
55
+ decision: MissionDecision;
56
+ decidedAt: string;
57
+ decidedBy: string;
58
+ note?: string;
59
+ }
60
+ export type MissionEventKind = "mission.created" | "mission.status_changed" | "mission.run_attached" | "mission.run_verified" | "mission.approved" | "mission.closed" | "mission.collision_blocked";
61
+ export interface MissionEvent {
62
+ eventId: string;
63
+ kind: MissionEventKind;
64
+ missionId: string;
65
+ timestamp: string;
66
+ payload: Record<string, unknown>;
67
+ }
68
+ export interface MissionRecord {
69
+ schemaVersion: typeof MISSION_SCHEMA_VERSION;
70
+ missionId: string;
71
+ /** Monotonically increasing write counter. Used for CAS enforcement. */
72
+ revision: number;
73
+ title: string;
74
+ objective: string;
75
+ ownerId: string;
76
+ workspaceId: string;
77
+ projectId: string;
78
+ status: MissionStatus;
79
+ budget: MissionBudget;
80
+ cost: MissionCost;
81
+ runLinks: MissionRunLink[];
82
+ approvals: MissionApproval[];
83
+ outcome?: MissionOutcome;
84
+ acceptanceCriteria: string[];
85
+ createdAt: string;
86
+ updatedAt: string;
87
+ }
88
+ export interface MissionDraft {
89
+ missionId?: string;
90
+ title: string;
91
+ objective: string;
92
+ ownerId: string;
93
+ workspaceId: string;
94
+ projectId: string;
95
+ budget: MissionBudget;
96
+ acceptanceCriteria?: string[];
97
+ }
98
+ export declare function createMissionRecord(draft: MissionDraft, options?: {
99
+ now?: () => string;
100
+ idFactory?: (prefix: string) => string;
101
+ }): MissionRecord;
102
+ export declare function isMissionTransitionAllowed(from: MissionStatus, to: MissionStatus): boolean;
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Mission Governance contracts — C2
3
+ *
4
+ * A MissionRecord governs one software mission: intent → budget → runs →
5
+ * verification → decision → receipt. It never replaces LoopRecord; it
6
+ * aggregates above it.
7
+ *
8
+ * Invariants:
9
+ * - One accountable human owner per mission.
10
+ * - State transitions are append-only in the ledger.
11
+ * - Ledger is the authority; mission.json is a rebuildable cache.
12
+ * - A mission cannot become "verified" without verified run evidence.
13
+ * - A mission cannot become "shipped" without an explicit ship decision.
14
+ * - Unknown schema versions fail closed.
15
+ * - Budgets cannot be raised silently.
16
+ */
17
+ export const MISSION_SCHEMA_VERSION = "martin.mission.v1";
18
+ // ─── Status and transitions ───────────────────────────────────────────────────
19
+ export const MISSION_STATUSES = [
20
+ "planned",
21
+ "running",
22
+ "blocked",
23
+ "verified",
24
+ "shipped",
25
+ "rolled_back",
26
+ "killed"
27
+ ];
28
+ export const ALLOWED_MISSION_TRANSITIONS = {
29
+ planned: ["running", "killed"],
30
+ running: ["blocked", "verified", "rolled_back", "killed"],
31
+ blocked: ["running", "rolled_back", "killed"],
32
+ verified: ["shipped", "running", "rolled_back", "killed"],
33
+ shipped: [],
34
+ rolled_back: ["running", "killed"],
35
+ killed: []
36
+ };
37
+ // ─── Factory ──────────────────────────────────────────────────────────────────
38
+ export function createMissionRecord(draft, options = {}) {
39
+ const now = options.now ?? (() => new Date().toISOString());
40
+ const makeId = options.idFactory ?? ((prefix) => `${prefix}_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`);
41
+ const ts = now();
42
+ return {
43
+ schemaVersion: MISSION_SCHEMA_VERSION,
44
+ missionId: draft.missionId ?? makeId("mission"),
45
+ revision: 0,
46
+ title: draft.title,
47
+ objective: draft.objective,
48
+ ownerId: draft.ownerId,
49
+ workspaceId: draft.workspaceId,
50
+ projectId: draft.projectId,
51
+ status: "planned",
52
+ budget: { ...draft.budget },
53
+ cost: { totalActualUsd: 0, verifiedOutcomeCount: 0, totalRunCount: 0 },
54
+ runLinks: [],
55
+ approvals: [],
56
+ acceptanceCriteria: draft.acceptanceCriteria ?? [],
57
+ createdAt: ts,
58
+ updatedAt: ts
59
+ };
60
+ }
61
+ // ─── Transition guard ─────────────────────────────────────────────────────────
62
+ export function isMissionTransitionAllowed(from, to) {
63
+ return ALLOWED_MISSION_TRANSITIONS[from].includes(to);
64
+ }
@@ -1,8 +1,9 @@
1
- export declare const MARTIN_ERROR_CATEGORIES: readonly ["invalid_input", "environment", "auth", "not_found", "store_unreadable", "verification_failed", "policy_blocked", "budget_exit", "transient"];
1
+ export declare const MARTIN_ERROR_CATEGORIES: readonly ["invalid_input", "environment", "auth", "not_found", "store_unreadable", "verification_failed", "policy_blocked", "budget_exit", "transient", "install_failed"];
2
2
  export type MartinErrorCategory = (typeof MARTIN_ERROR_CATEGORIES)[number];
3
3
  export type MartinOutputMode = "human" | "json" | "quiet";
4
4
  export interface MartinRunSelector {
5
5
  runsDir?: string;
6
+ workspaceId?: string;
6
7
  file?: string;
7
8
  loopId?: string;
8
9
  latest?: boolean;
@@ -10,6 +11,7 @@ export interface MartinRunSelector {
10
11
  }
11
12
  export interface MartinRunListFilters {
12
13
  runsDir?: string;
14
+ workspaceId?: string;
13
15
  limit?: number;
14
16
  status?: string;
15
17
  lifecycleState?: string;
@@ -7,5 +7,6 @@ export const MARTIN_ERROR_CATEGORIES = [
7
7
  "verification_failed",
8
8
  "policy_blocked",
9
9
  "budget_exit",
10
- "transient"
10
+ "transient",
11
+ "install_failed"
11
12
  ];
@@ -0,0 +1,100 @@
1
+ import type { CostProvenance, LoopLifecycleState, LoopStatus, ReceiptIntegritySummary } from "./index.js";
2
+ export declare const VERIFIED_HANDOFF_OUTCOMES: readonly ["VERIFIED", "STOPPED", "NEEDS_REVIEW"];
3
+ export type VerifiedHandoffOutcome = (typeof VERIFIED_HANDOFF_OUTCOMES)[number];
4
+ export declare const EVIDENCE_STATUSES: readonly ["PASSED", "FAILED", "CONTRADICTED", "NOT_RUN", "NOT_EVALUATED"];
5
+ export type EvidenceStatus = (typeof EVIDENCE_STATUSES)[number];
6
+ /**
7
+ * Granular internal/runtime state. Retained for diagnosis, policy,
8
+ * receipts and engineering review.
9
+ */
10
+ export declare const TEST_INTEGRITY_STATUSES: readonly ["UNCHANGED", "AUTHORIZED_CHANGE", "PREVENTED", "DETECTED_AND_ROLLED_BACK", "DETECTED_NEEDS_REVIEW", "NOT_EVALUATED"];
11
+ export type TestIntegrityStatus = (typeof TEST_INTEGRITY_STATUSES)[number];
12
+ /**
13
+ * Stable public-facing verdict used by CLI, MCP, JSON/Markdown handoffs
14
+ * and the website. Do not make each renderer collapse states independently.
15
+ */
16
+ export declare const TEST_INTEGRITY_VERDICTS: readonly ["VERIFIED", "TAMPERING_DETECTED", "NOT_EVALUATED"];
17
+ export type TestIntegrityVerdict = (typeof TEST_INTEGRITY_VERDICTS)[number];
18
+ export interface VerifiedHandoffCheckV1 {
19
+ command: string;
20
+ status: EvidenceStatus;
21
+ exitCode?: number;
22
+ timedOut?: boolean;
23
+ detail?: string;
24
+ }
25
+ export interface VerifiedHandoffRequirementV1 {
26
+ requirement: string;
27
+ status: "PROVEN" | "FAILED" | "UNRESOLVED" | "NOT_EVALUATED";
28
+ evidence?: string[];
29
+ }
30
+ export interface VerifiedHandoffScopeV1 {
31
+ status: "WITHIN_SCOPE" | "VIOLATION_REJECTED" | "NEEDS_REVIEW" | "NOT_EVALUATED";
32
+ allowedPaths: string[];
33
+ deniedPaths: string[];
34
+ changedFiles: string[];
35
+ violations: string[];
36
+ }
37
+ export interface VerifiedHandoffTestIntegrityV1 {
38
+ /** Public rendering contract. */
39
+ verdict: TestIntegrityVerdict;
40
+ /** Granular runtime state for diagnosis and evidence. */
41
+ status: TestIntegrityStatus;
42
+ protectedPaths: string[];
43
+ changedProtectedPaths: string[];
44
+ findings: Array<{
45
+ filePath: string;
46
+ issue: string;
47
+ severity: "high" | "medium" | "low";
48
+ detail: string;
49
+ }>;
50
+ summary: string;
51
+ }
52
+ export interface VerifiedHandoffRecoveryV1 {
53
+ rollbackBoundaryAvailable: boolean;
54
+ rollbackAttempted: boolean;
55
+ rollbackSucceeded?: boolean;
56
+ isolatedRef?: string;
57
+ nextCommand?: string;
58
+ summary: string;
59
+ }
60
+ export interface VerifiedHandoffV1 {
61
+ schemaVersion: "1.0.0";
62
+ handoffId: string;
63
+ loopId: string;
64
+ generatedAt: string;
65
+ task: {
66
+ title: string;
67
+ objective: string;
68
+ };
69
+ definitionOfDone: {
70
+ acceptanceCriteria: string[];
71
+ verificationPlan: string[];
72
+ };
73
+ outcome: VerifiedHandoffOutcome;
74
+ sourceStatus: {
75
+ status: LoopStatus;
76
+ lifecycleState: LoopLifecycleState;
77
+ };
78
+ verification: {
79
+ status: EvidenceStatus;
80
+ summary: string;
81
+ checks: VerifiedHandoffCheckV1[];
82
+ warnings: string[];
83
+ };
84
+ requirements: VerifiedHandoffRequirementV1[];
85
+ scope: VerifiedHandoffScopeV1;
86
+ testIntegrity: VerifiedHandoffTestIntegrityV1;
87
+ unresolvedWork: string[];
88
+ stopReason?: string;
89
+ recovery: VerifiedHandoffRecoveryV1;
90
+ usage: {
91
+ attempts: number;
92
+ actualUsd: number;
93
+ estimatedUsd?: number;
94
+ tokensIn: number;
95
+ tokensOut: number;
96
+ costProvenance: CostProvenance;
97
+ };
98
+ receiptIntegrity: ReceiptIntegritySummary;
99
+ nextAction: string;
100
+ }
@@ -0,0 +1,35 @@
1
+ // SPDX-FileCopyrightText: MartinLoop contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ export const VERIFIED_HANDOFF_OUTCOMES = [
4
+ "VERIFIED",
5
+ "STOPPED",
6
+ "NEEDS_REVIEW",
7
+ ];
8
+ export const EVIDENCE_STATUSES = [
9
+ "PASSED",
10
+ "FAILED",
11
+ "CONTRADICTED",
12
+ "NOT_RUN",
13
+ "NOT_EVALUATED",
14
+ ];
15
+ /**
16
+ * Granular internal/runtime state. Retained for diagnosis, policy,
17
+ * receipts and engineering review.
18
+ */
19
+ export const TEST_INTEGRITY_STATUSES = [
20
+ "UNCHANGED",
21
+ "AUTHORIZED_CHANGE",
22
+ "PREVENTED",
23
+ "DETECTED_AND_ROLLED_BACK",
24
+ "DETECTED_NEEDS_REVIEW",
25
+ "NOT_EVALUATED",
26
+ ];
27
+ /**
28
+ * Stable public-facing verdict used by CLI, MCP, JSON/Markdown handoffs
29
+ * and the website. Do not make each renderer collapse states independently.
30
+ */
31
+ export const TEST_INTEGRITY_VERDICTS = [
32
+ "VERIFIED",
33
+ "TAMPERING_DETECTED",
34
+ "NOT_EVALUATED",
35
+ ];
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Context Chain Gate — C1
3
+ *
4
+ * Converts chain verification evidence into a merge-gate decision and
5
+ * a PR comment (Infracost-style). Two things hard-fail. Everything else
6
+ * is configurable or comment-only.
7
+ *
8
+ * Hard failures (always block merge):
9
+ * 1. no_governance_receipt — no receipt at all
10
+ * 2. tamper_detected — receipt hash does not match producer run
11
+ *
12
+ * Configurable gate (team decides; default: warn only):
13
+ * 3. verifier_failed — unverified claims, incomplete integrity,
14
+ * missing artifacts, unresolved assumptions
15
+ *
16
+ * Comment-only (never block, always visible):
17
+ * - Cost: actual vs budget — money is already spent, blocking adds friction
18
+ * - Chain lineage: chainId, producerRunId, consumerRunId
19
+ * - Integrity state
20
+ *
21
+ * Standing rules:
22
+ * - Pure functions, no side effects.
23
+ * - evaluateChainGate never reads environment variables or config files.
24
+ * - renderGatePrComment produces valid GitHub-flavored markdown.
25
+ * - No fake data, no placeholder behaviour.
26
+ */
27
+ import type { ContextHandoffReceipt } from "../contracts/index.js";
28
+ import type { ChainIntegrityState, ContextHandoffVerification } from "../contracts/index.js";
29
+ export interface ChainGateConfig {
30
+ /**
31
+ * When true, a failed verifier (unverified claims, incomplete integrity,
32
+ * missing artifacts, unresolved assumptions) blocks the merge.
33
+ * Default: false — warn in PR comment, do not block.
34
+ */
35
+ blockOnVerifierFailure: boolean;
36
+ }
37
+ export interface ChainGateCost {
38
+ actualUsd: number;
39
+ budgetUsd: number;
40
+ }
41
+ export interface ChainGateInput {
42
+ /** null means no receipt was provided — triggers the hard no_governance_receipt failure. */
43
+ receipt: ContextHandoffReceipt | null;
44
+ /** null when receipt is null. Must be provided when receipt is non-null. */
45
+ verification: ContextHandoffVerification | null;
46
+ cost?: ChainGateCost;
47
+ config?: Partial<ChainGateConfig>;
48
+ }
49
+ export type ChainGateConclusion = "failure" | "neutral" | "success";
50
+ export interface ChainGateResult {
51
+ noGovernance: boolean;
52
+ tamperDetected: boolean;
53
+ verifierFailed: boolean;
54
+ shouldBlock: boolean;
55
+ conclusion: ChainGateConclusion;
56
+ failureReasonCode?: string;
57
+ failureMessage?: string;
58
+ cost?: ChainGateCost & {
59
+ exceeded: boolean;
60
+ };
61
+ integrity: ChainIntegrityState | "absent";
62
+ }
63
+ /**
64
+ * Evaluates whether the chain gate should block merge, and assembles
65
+ * the data needed for the PR comment.
66
+ *
67
+ * Call order:
68
+ * 1. Check for missing receipt (hard fail).
69
+ * 2. Check for tamper_detected integrity (hard fail).
70
+ * 3. Check verifier result against config (configurable gate).
71
+ * 4. Return success / neutral with full comment data.
72
+ */
73
+ export declare function evaluateChainGate(input: ChainGateInput): ChainGateResult;
74
+ export interface GatePrCommentOptions {
75
+ runId?: string;
76
+ chainId?: string;
77
+ handoffId?: string;
78
+ producerRunId?: string;
79
+ prNumber?: number;
80
+ headSha?: string;
81
+ }
82
+ /**
83
+ * Renders an Infracost-style GitHub PR comment summarising the gate result.
84
+ *
85
+ * Hard failures and cost overruns are shown prominently.
86
+ * Cost is always present when provided — never omitted, never a blocking signal.
87
+ * Lineage fields (chainId, producerRunId, runId) provide audit trail links.
88
+ */
89
+ export declare function renderGatePrComment(result: ChainGateResult, options?: GatePrCommentOptions): string;
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Context Chain Gate — C1
3
+ *
4
+ * Converts chain verification evidence into a merge-gate decision and
5
+ * a PR comment (Infracost-style). Two things hard-fail. Everything else
6
+ * is configurable or comment-only.
7
+ *
8
+ * Hard failures (always block merge):
9
+ * 1. no_governance_receipt — no receipt at all
10
+ * 2. tamper_detected — receipt hash does not match producer run
11
+ *
12
+ * Configurable gate (team decides; default: warn only):
13
+ * 3. verifier_failed — unverified claims, incomplete integrity,
14
+ * missing artifacts, unresolved assumptions
15
+ *
16
+ * Comment-only (never block, always visible):
17
+ * - Cost: actual vs budget — money is already spent, blocking adds friction
18
+ * - Chain lineage: chainId, producerRunId, consumerRunId
19
+ * - Integrity state
20
+ *
21
+ * Standing rules:
22
+ * - Pure functions, no side effects.
23
+ * - evaluateChainGate never reads environment variables or config files.
24
+ * - renderGatePrComment produces valid GitHub-flavored markdown.
25
+ * - No fake data, no placeholder behaviour.
26
+ */
27
+ const DEFAULT_CONFIG = {
28
+ blockOnVerifierFailure: false
29
+ };
30
+ // ─── Gate evaluation ─────────────────────────────────────────────────────────
31
+ /**
32
+ * Evaluates whether the chain gate should block merge, and assembles
33
+ * the data needed for the PR comment.
34
+ *
35
+ * Call order:
36
+ * 1. Check for missing receipt (hard fail).
37
+ * 2. Check for tamper_detected integrity (hard fail).
38
+ * 3. Check verifier result against config (configurable gate).
39
+ * 4. Return success / neutral with full comment data.
40
+ */
41
+ export function evaluateChainGate(input) {
42
+ const config = { ...DEFAULT_CONFIG, ...input.config };
43
+ const costResult = input.cost !== undefined
44
+ ? { ...input.cost, exceeded: input.cost.actualUsd > input.cost.budgetUsd }
45
+ : undefined;
46
+ // ── Hard fail 1: no governance receipt ───────────────────────────────────
47
+ if (input.receipt === null || input.verification === null) {
48
+ return {
49
+ noGovernance: true,
50
+ tamperDetected: false,
51
+ verifierFailed: false,
52
+ shouldBlock: true,
53
+ conclusion: "failure",
54
+ failureReasonCode: "no_governance_receipt",
55
+ failureMessage: "No MartinLoop governance receipt was found for this run. " +
56
+ "Every AI-authored PR must carry a verified governance receipt.",
57
+ integrity: "absent",
58
+ ...(costResult !== undefined ? { cost: costResult } : {})
59
+ };
60
+ }
61
+ const integrity = input.verification.integrity;
62
+ // ── Hard fail 2: tampered receipt ─────────────────────────────────────────
63
+ if (integrity === "tamper_detected") {
64
+ return {
65
+ noGovernance: false,
66
+ tamperDetected: true,
67
+ verifierFailed: false,
68
+ shouldBlock: true,
69
+ conclusion: "failure",
70
+ failureReasonCode: "tamper_detected",
71
+ failureMessage: "Governance receipt integrity check failed: tamper detected. " +
72
+ "The receipt hash does not match the producer run record.",
73
+ integrity,
74
+ ...(costResult !== undefined ? { cost: costResult } : {})
75
+ };
76
+ }
77
+ // ── Configurable gate: verifier failed ───────────────────────────────────
78
+ const verifierFailed = !input.verification.ok;
79
+ const blockOnVerifier = verifierFailed && config.blockOnVerifierFailure;
80
+ if (blockOnVerifier) {
81
+ const first = input.verification.reasons[0];
82
+ return {
83
+ noGovernance: false,
84
+ tamperDetected: false,
85
+ verifierFailed: true,
86
+ shouldBlock: true,
87
+ conclusion: "failure",
88
+ failureReasonCode: first?.code ?? "verifier_failed",
89
+ failureMessage: first?.message ?? "Context chain verification failed.",
90
+ integrity,
91
+ ...(costResult !== undefined ? { cost: costResult } : {})
92
+ };
93
+ }
94
+ // ── Pass (or warn-only verifier failure) ──────────────────────────────────
95
+ return {
96
+ noGovernance: false,
97
+ tamperDetected: false,
98
+ verifierFailed,
99
+ shouldBlock: false,
100
+ conclusion: verifierFailed ? "neutral" : "success",
101
+ integrity,
102
+ ...(costResult !== undefined ? { cost: costResult } : {})
103
+ };
104
+ }
105
+ /**
106
+ * Renders an Infracost-style GitHub PR comment summarising the gate result.
107
+ *
108
+ * Hard failures and cost overruns are shown prominently.
109
+ * Cost is always present when provided — never omitted, never a blocking signal.
110
+ * Lineage fields (chainId, producerRunId, runId) provide audit trail links.
111
+ */
112
+ export function renderGatePrComment(result, options = {}) {
113
+ const lines = [];
114
+ lines.push("## MartinLoop Governance");
115
+ lines.push("");
116
+ // Status headline
117
+ if (result.noGovernance) {
118
+ lines.push("🚫 **No governance receipt** — merge is blocked.");
119
+ }
120
+ else if (result.tamperDetected) {
121
+ lines.push("🚫 **Tampered receipt** — merge is blocked.");
122
+ }
123
+ else if (result.verifierFailed && result.shouldBlock) {
124
+ lines.push("⚠️ **Verifier failed** — merge is blocked (configured as required).");
125
+ }
126
+ else if (result.verifierFailed) {
127
+ lines.push("⚠️ **Verifier warnings** — merge is permitted, review recommended.");
128
+ }
129
+ else {
130
+ lines.push("✅ **Governance verified** — chain integrity confirmed.");
131
+ }
132
+ lines.push("");
133
+ lines.push("| Signal | Value | Status |");
134
+ lines.push("|--------|-------|--------|");
135
+ // Chain integrity
136
+ const integrityIcon = result.integrity === "verified"
137
+ ? "✅"
138
+ : result.integrity === "absent" || result.integrity === "tamper_detected"
139
+ ? "🚫"
140
+ : "⚠️";
141
+ lines.push(`| Chain integrity | \`${result.integrity}\` | ${integrityIcon} |`);
142
+ // Cost — always comment-only, never a block signal
143
+ if (result.cost !== undefined) {
144
+ const { actualUsd, budgetUsd, exceeded } = result.cost;
145
+ const costIcon = exceeded ? "⚠️" : "✅";
146
+ const delta = actualUsd - budgetUsd;
147
+ const costNote = exceeded
148
+ ? `over budget (+$${delta.toFixed(4)})`
149
+ : "within budget";
150
+ lines.push(`| Cost | \`$${actualUsd.toFixed(4)}\` / \`$${budgetUsd.toFixed(4)}\` | ${costIcon} ${costNote} |`);
151
+ }
152
+ // Lineage (audit trail, never a block signal)
153
+ if (options.chainId) {
154
+ lines.push(`| Chain ID | \`${options.chainId}\` | ℹ️ |`);
155
+ }
156
+ if (options.handoffId) {
157
+ lines.push(`| Handoff ID | \`${options.handoffId}\` | ℹ️ |`);
158
+ }
159
+ if (options.producerRunId) {
160
+ lines.push(`| Producer run | \`${options.producerRunId}\` | ℹ️ |`);
161
+ }
162
+ if (options.runId) {
163
+ lines.push(`| Consumer run | \`${options.runId}\` | ℹ️ |`);
164
+ }
165
+ // Failure detail
166
+ if (result.failureMessage) {
167
+ lines.push("");
168
+ lines.push(`> **Failure:** ${result.failureMessage}`);
169
+ }
170
+ lines.push("");
171
+ lines.push("_Powered by [MartinLoop](https://github.com/Keesan12/martin-loop) governance gate_");
172
+ return lines.join("\n");
173
+ }