opencode-wait-a-minute 0.0.0-stage → 1.1.0-rc.8

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 (207) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +318 -2
  3. package/index.js +1836 -0
  4. package/package.json +70 -4
  5. package/skills/codebase-design/SKILL.md +114 -0
  6. package/skills/design-contract/SKILL.md +27 -0
  7. package/skills/design-critique/SKILL.md +19 -0
  8. package/skills/design-system/SKILL.md +17 -0
  9. package/skills/design-system/references/image-analysis.md +14 -0
  10. package/skills/design-system/references/tokens.md +32 -0
  11. package/skills/design-system/references/ui-rules.md +14 -0
  12. package/skills/diagnosing-bugs/SKILL.md +138 -0
  13. package/skills/frontend-design/SKILL.md +36 -0
  14. package/skills/handoff/SKILL.md +16 -0
  15. package/skills/improve-codebase-architecture/SKILL.md +71 -0
  16. package/skills/linter-negative/SKILL.md +74 -0
  17. package/skills/no-slop-ui/SKILL.md +26 -0
  18. package/skills/prototype/SKILL.md +26 -0
  19. package/skills/registry.json +44087 -0
  20. package/skills/tastemaker/SKILL.md +8 -0
  21. package/skills/tastemaker/references/tastemaker.md +14 -0
  22. package/skills/tdd/SKILL.md +38 -0
  23. package/skills/visual-review/SKILL.md +103 -0
  24. package/skills/visual-review/references/review-gates.md +42 -0
  25. package/skills/visual-review/references/surface-archetypes.md +37 -0
  26. package/skills/wizard/SKILL.md +44 -0
  27. package/skills/writing-for-agents/SKILL.md +81 -0
  28. package/src/cognition/cognition-store.js +251 -0
  29. package/src/cognition/cognitive-state.js +126 -0
  30. package/src/cognition/hypothesis-manager.js +113 -0
  31. package/src/cognition/observation-engine.js +112 -0
  32. package/src/cognition/observation-provenance.js +268 -0
  33. package/src/context/active-context-boundary.js +68 -0
  34. package/src/context/assembly.js +494 -0
  35. package/src/context/assessment-rules.js +55 -0
  36. package/src/context/capsule-staleness.js +267 -0
  37. package/src/context/capsules.js +2 -0
  38. package/src/context/compare-array.js +98 -0
  39. package/src/context/compare-object.js +89 -0
  40. package/src/context/compare-values.js +42 -0
  41. package/src/context/context-assembly-contract.js +71 -0
  42. package/src/context/context-budget-manager.js +232 -0
  43. package/src/context/context-builder.js +49 -0
  44. package/src/context/context-cache.js +55 -0
  45. package/src/context/context-capture.js +243 -0
  46. package/src/context/context-classification.js +199 -0
  47. package/src/context/context-compaction.js +179 -0
  48. package/src/context/context-decision-audit.js +267 -0
  49. package/src/context/context-demotion.js +173 -0
  50. package/src/context/context-dictionary.js +106 -0
  51. package/src/context/context-drift-detection.js +225 -0
  52. package/src/context/context-evaluation.js +374 -0
  53. package/src/context/context-event-ingress.js +100 -0
  54. package/src/context/context-event-normalization.js +224 -0
  55. package/src/context/context-feedback-loop.js +216 -0
  56. package/src/context/context-freshness.js +21 -0
  57. package/src/context/context-graph-builder.js +71 -0
  58. package/src/context/context-graph.js +451 -0
  59. package/src/context/context-history-relevance.js +321 -0
  60. package/src/context/context-interception.js +145 -0
  61. package/src/context/context-invalidation-events.js +154 -0
  62. package/src/context/context-lifecycle.js +170 -0
  63. package/src/context/context-loop-prevention.js +347 -0
  64. package/src/context/context-manager.js +340 -0
  65. package/src/context/context-memory-layers.js +265 -0
  66. package/src/context/context-minimality.js +166 -0
  67. package/src/context/context-normalization.js +130 -0
  68. package/src/context/context-optimization-metrics.js +434 -0
  69. package/src/context/context-output-policy.js +135 -0
  70. package/src/context/context-pack-authority.js +157 -0
  71. package/src/context/context-promotion.js +172 -0
  72. package/src/context/context-query-contract.js +101 -0
  73. package/src/context/context-ranking.js +164 -0
  74. package/src/context/context-rate-distortion.js +261 -0
  75. package/src/context/context-recovery.js +209 -0
  76. package/src/context/context-retrieval-integration.js +60 -0
  77. package/src/context/context-retrieval.js +93 -0
  78. package/src/context/context-router.js +457 -0
  79. package/src/context/context-routing-evaluation.js +331 -0
  80. package/src/context/context-routing-observability.js +296 -0
  81. package/src/context/context-routing-shadow.js +237 -0
  82. package/src/context/context-scope.js +181 -0
  83. package/src/context/context-snapshot.js +226 -0
  84. package/src/context/context-source-registry.js +95 -0
  85. package/src/context/context-sufficiency-gate.js +120 -0
  86. package/src/context/context-sufficiency-oracle.js +167 -0
  87. package/src/context/context-telemetry.js +176 -0
  88. package/src/context/context.js +633 -0
  89. package/src/context/dependency-closure.js +246 -0
  90. package/src/context/page-fault-tracker.js +275 -0
  91. package/src/context/prompt-engine.js +74 -0
  92. package/src/context/runtime-context-graph.js +260 -0
  93. package/src/context/selection.js +2 -0
  94. package/src/context/session.js +2 -0
  95. package/src/context/sufficiency-contract.js +300 -0
  96. package/src/context/tokenizer.js +17 -0
  97. package/src/context-benchmark-router.mjs +125 -0
  98. package/src/evidence/evidence-engine.js +161 -0
  99. package/src/evidence/evidence-factory.js +3 -0
  100. package/src/evidence/evidence-freshness.js +463 -0
  101. package/src/evidence/evidence-gap.js +76 -0
  102. package/src/evidence/evidence-lineage.js +525 -0
  103. package/src/evidence/evidence.js +136 -0
  104. package/src/evidence/freshness-validation.js +187 -0
  105. package/src/evidence/lineage.js +4 -0
  106. package/src/execution/action-evaluation.js +179 -0
  107. package/src/execution/circuit-breaker.js +70 -0
  108. package/src/execution/claim-interception.js +63 -0
  109. package/src/execution/execution-engine.js +258 -0
  110. package/src/execution/execution-intent.js +69 -0
  111. package/src/execution/execution-state.js +89 -0
  112. package/src/execution/formatting.js +60 -0
  113. package/src/execution/l1-sanitize.js +16 -0
  114. package/src/execution/l2-resource-guards.js +19 -0
  115. package/src/execution/l3-invariant-checker.js +5 -0
  116. package/src/execution/l4-containment.js +6 -0
  117. package/src/execution/runtime-guards.js +106 -0
  118. package/src/execution/strategy-identity.js +162 -0
  119. package/src/execution/tool-interceptor.js +7 -0
  120. package/src/execution/tool-result-classifier.js +63 -0
  121. package/src/integration/canary-deploy.js +143 -0
  122. package/src/integration/collector.js +59 -0
  123. package/src/integration/error-recovery.js +6 -0
  124. package/src/integration/event-bus.js +66 -0
  125. package/src/integration/health-checker.js +57 -0
  126. package/src/integration/logger.js +39 -0
  127. package/src/integration/message-handler.js +611 -0
  128. package/src/integration/opencode-db.js +153 -0
  129. package/src/integration/orchestration.js +419 -0
  130. package/src/integration/part-provenance.js +65 -0
  131. package/src/integration/rate-limiter.js +55 -0
  132. package/src/integration/release-gate.js +336 -0
  133. package/src/integration/rollback-manager.js +164 -0
  134. package/src/integration/router-adapter.js +269 -0
  135. package/src/integration/telemetry.js +45 -0
  136. package/src/integration/update-checker.js +10 -0
  137. package/src/persistence/event-sourcing.js +75 -0
  138. package/src/persistence/memory.js +501 -0
  139. package/src/persistence/migration-runner.js +16 -0
  140. package/src/persistence/persistence-manager.js +39 -0
  141. package/src/persistence/transaction-log.js +157 -0
  142. package/src/policy/action-capabilities.js +116 -0
  143. package/src/policy/action-policy.js +4 -0
  144. package/src/policy/assessment-engine.js +104 -0
  145. package/src/policy/assumption-tracking.js +66 -0
  146. package/src/policy/budget-enforcer.js +7 -0
  147. package/src/policy/config-validator.js +102 -0
  148. package/src/policy/execution-assessment.js +142 -0
  149. package/src/policy/failure-classification.js +5 -0
  150. package/src/policy/feature-flags.js +65 -0
  151. package/src/policy/governance-enforcement.js +118 -0
  152. package/src/policy/locale.js +15 -0
  153. package/src/policy/multi-signer.js +151 -0
  154. package/src/policy/policy-state-machine.js +97 -0
  155. package/src/policy/ponytail-constraint.js +38 -0
  156. package/src/policy/project-inspector.js +93 -0
  157. package/src/policy/query-builder.js +14 -0
  158. package/src/policy/request-classifier.js +79 -0
  159. package/src/policy/risk-engine.js +266 -0
  160. package/src/policy/scope-enforcement.js +140 -0
  161. package/src/policy/secret-scanner.js +68 -0
  162. package/src/policy/skill-routing.js +104 -0
  163. package/src/policy/strategy-capabilities.js +211 -0
  164. package/src/policy/strategy.js +6 -0
  165. package/src/policy/uncertainty.js +117 -0
  166. package/src/shared/container.js +44 -0
  167. package/src/shared/decision-types.js +24 -0
  168. package/src/shared/simple-test.js +160 -0
  169. package/src/shared/wam-events.js +52 -0
  170. package/src/skills/engine.js +1705 -0
  171. package/src/skills/skill-registry.js +19 -0
  172. package/src/skills/skill-routing.js +340 -0
  173. package/src/state/lifecycle-manager.js +113 -0
  174. package/src/state/operational-state.js +198 -0
  175. package/src/state/projections.js +47 -0
  176. package/src/state/replay-engine.js +5 -0
  177. package/src/state/requirement-ownership.js +20 -0
  178. package/src/state/requirement-state.js +152 -0
  179. package/src/state/run-event-identity.js +172 -0
  180. package/src/state/state-engine.js +19 -0
  181. package/src/state/state-machine.js +119 -0
  182. package/src/state/state-schema.js +318 -0
  183. package/src/state/state-store.js +335 -0
  184. package/src/state/state-transition.js +84 -0
  185. package/src/state/task-dependencies.js +287 -0
  186. package/src/state/task-execution.js +217 -0
  187. package/src/state/task-lifecycle.js +59 -0
  188. package/src/state/task-runs.js +361 -0
  189. package/src/state/task-state-file.js +86 -0
  190. package/src/state/task-state.js +41 -0
  191. package/src/state/task-status.js +54 -0
  192. package/src/state/task-store.js +48 -0
  193. package/src/state/wam-state.js +148 -0
  194. package/src/verification/completion-gate-simple.js +8 -0
  195. package/src/verification/completion-gate.js +183 -0
  196. package/src/verification/contract.js +9 -0
  197. package/src/verification/contradiction-resolution.js +255 -0
  198. package/src/verification/diagnostic-engine.js +659 -0
  199. package/src/verification/false-completion-prevention.js +100 -0
  200. package/src/verification/hook-validator.js +6 -0
  201. package/src/verification/requirements.js +6 -0
  202. package/src/verification/verification-context.js +162 -0
  203. package/src/verification/verification-lifecycle.js +66 -0
  204. package/src/verification/verification-model.js +89 -0
  205. package/src/verification/verification-persistence.js +129 -0
  206. package/src/verification/verification-policy.js +127 -0
  207. package/src/verification/verification.js +415 -0
@@ -0,0 +1,5 @@
1
+ export function replayEvents(events, initialState) {
2
+ return events.reduce((state, event) => {
3
+ return { ...state, ...event };
4
+ }, initialState);
5
+ }
@@ -0,0 +1,20 @@
1
+ // Requirement ownership: verify who can validate a requirement
2
+ export function verifyRequirementOwnership(task, owner) {
3
+ if (!task || !owner) return { owned: false, reason: "missing-input" };
4
+ const taskOwner = task.owner || task.assignedTo || null;
5
+ if (taskOwner === owner) return { owned: true, owner: taskOwner };
6
+ if (task.verifiers && Array.isArray(task.verifiers) && task.verifiers.includes(owner)) {
7
+ return { owned: true, owner: taskOwner };
8
+ }
9
+ return { owned: false, reason: "not-owner", owner: taskOwner };
10
+ }
11
+
12
+ // Assert that a task can be verified given its state and ownership
13
+ export function assertCanVerify(task, verifier) {
14
+ if (!task) return { canVerify: false, reason: "missing-task" };
15
+ if (task.status === "VERIFIED") return { canVerify: false, reason: "already-verified" };
16
+ if (task.status === "BLOCKED") return { canVerify: false, reason: "blocked" };
17
+ const ownership = verifyRequirementOwnership(task, verifier);
18
+ if (!ownership.owned) return { canVerify: false, reason: "no-ownership", ...ownership };
19
+ return { canVerify: true, verifier };
20
+ }
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Requirement State Machine
3
+ *
4
+ * Formalizes the lifecycle states of a requirement and the legal transitions
5
+ * between them. Used by completion-gate to determine whether a requirement can
6
+ * be considered complete.
7
+ *
8
+ * States:
9
+ * - PENDING : requirement identified but not started
10
+ * - IN_PROGRESS : work is being done; some evidence may exist
11
+ * - VERIFIED : sufficient verified evidence exists; gates can pass
12
+ * - INVALIDATED : existing evidence was invalidated (stale, contradicted, etc.)
13
+ * - BLOCKED : cannot proceed (dependency, missing info, external blocker)
14
+ * - NEEDS_REPLAN : current approach cannot satisfy the requirement
15
+ *
16
+ * Transition table is the source of truth. Any transition not listed is
17
+ * considered illegal and will return { allowed: false } from canTransition().
18
+ */
19
+
20
+ export const REQUIREMENT_STATES = Object.freeze({
21
+ PENDING: "PENDING",
22
+ IN_PROGRESS: "IN_PROGRESS",
23
+ VERIFIED: "VERIFIED",
24
+ INVALIDATED: "INVALIDATED",
25
+ BLOCKED: "BLOCKED",
26
+ NEEDS_REPLAN: "NEEDS_REPLAN",
27
+ });
28
+
29
+ export const TERMINAL_STATES = new Set([
30
+ REQUIREMENT_STATES.VERIFIED,
31
+ ]);
32
+
33
+ /**
34
+ * Allowed transitions: from -> Set(to).
35
+ * VERIFIED is intentionally reachable from a small set of states to avoid
36
+ * silently promoting blocked/needs-replan requirements.
37
+ */
38
+ export const TRANSITIONS = Object.freeze({
39
+ [REQUIREMENT_STATES.PENDING]: new Set([
40
+ REQUIREMENT_STATES.IN_PROGRESS,
41
+ REQUIREMENT_STATES.BLOCKED,
42
+ ]),
43
+ [REQUIREMENT_STATES.IN_PROGRESS]: new Set([
44
+ REQUIREMENT_STATES.VERIFIED,
45
+ REQUIREMENT_STATES.INVALIDATED,
46
+ REQUIREMENT_STATES.BLOCKED,
47
+ REQUIREMENT_STATES.NEEDS_REPLAN,
48
+ REQUIREMENT_STATES.PENDING,
49
+ ]),
50
+ [REQUIREMENT_STATES.VERIFIED]: new Set([
51
+ // Once verified, it can be invalidated if evidence is later contradicted.
52
+ REQUIREMENT_STATES.INVALIDATED,
53
+ ]),
54
+ [REQUIREMENT_STATES.INVALIDATED]: new Set([
55
+ REQUIREMENT_STATES.IN_PROGRESS,
56
+ REQUIREMENT_STATES.NEEDS_REPLAN,
57
+ REQUIREMENT_STATES.PENDING,
58
+ ]),
59
+ [REQUIREMENT_STATES.BLOCKED]: new Set([
60
+ REQUIREMENT_STATES.IN_PROGRESS,
61
+ REQUIREMENT_STATES.PENDING,
62
+ REQUIREMENT_STATES.NEEDS_REPLAN,
63
+ ]),
64
+ [REQUIREMENT_STATES.NEEDS_REPLAN]: new Set([
65
+ REQUIREMENT_STATES.PENDING,
66
+ REQUIREMENT_STATES.IN_PROGRESS,
67
+ ]),
68
+ });
69
+
70
+ /**
71
+ * Returns whether `to` is a legal next state from `from`.
72
+ */
73
+ export function canTransition(from, to) {
74
+ if (!Object.values(REQUIREMENT_STATES).includes(to)) {
75
+ return { allowed: false, reason: `unknown target state: ${to}` };
76
+ }
77
+ const allowed = TRANSITIONS[from];
78
+ if (!allowed) {
79
+ return { allowed: false, reason: `unknown source state: ${from}` };
80
+ }
81
+ if (!allowed.has(to)) {
82
+ return {
83
+ allowed: false,
84
+ reason: `illegal transition ${from} -> ${to}`,
85
+ };
86
+ }
87
+ return { allowed: true };
88
+ }
89
+
90
+ /**
91
+ * Executes a transition. Returns a new state object (immutable update) or
92
+ * an { error } object if the transition is illegal.
93
+ */
94
+ export function transition(requirement, to) {
95
+ if (!requirement || typeof requirement !== "object") {
96
+ return { error: "requirement must be an object" };
97
+ }
98
+ const from = requirement.status || REQUIREMENT_STATES.PENDING;
99
+ const check = canTransition(from, to);
100
+ if (!check.allowed) {
101
+ return { error: check.reason, from, to };
102
+ }
103
+ return {
104
+ ...requirement,
105
+ status: to,
106
+ lastTransitionAt: new Date().toISOString(),
107
+ lastTransitionFrom: from,
108
+ };
109
+ }
110
+
111
+ /**
112
+ * Pure decision: is this requirement eligible for completion?
113
+ * Only VERIFIED requirements are complete.
114
+ */
115
+ export function isRequirementComplete(requirement) {
116
+ return Boolean(
117
+ requirement &&
118
+ typeof requirement === "object" &&
119
+ requirement.status === REQUIREMENT_STATES.VERIFIED
120
+ );
121
+ }
122
+
123
+ /**
124
+ * Aggregates a list of requirements into an overall verdict.
125
+ * Returns { allComplete, blocked, incomplete, summary }.
126
+ */
127
+ export function summarizeRequirements(requirements = []) {
128
+ const incomplete = [];
129
+ const blocked = [];
130
+ for (const req of requirements) {
131
+ if (!isRequirementComplete(req)) {
132
+ incomplete.push(req);
133
+ if (
134
+ req.status === REQUIREMENT_STATES.BLOCKED ||
135
+ req.status === REQUIREMENT_STATES.NEEDS_REPLAN
136
+ ) {
137
+ blocked.push(req);
138
+ }
139
+ }
140
+ }
141
+ return {
142
+ allComplete: incomplete.length === 0,
143
+ incomplete,
144
+ blocked,
145
+ summary: {
146
+ total: requirements.length,
147
+ complete: requirements.length - incomplete.length,
148
+ incomplete: incomplete.length,
149
+ blocked: blocked.length,
150
+ },
151
+ };
152
+ }
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Run Event Identity — scoped, stable event IDs.
3
+ *
4
+ * Events use composite IDs: <runId>:<type>:<sequence>
5
+ *
6
+ * Format:
7
+ * run-003:act:001
8
+ * run-003:obs:004
9
+ * run-003:dec:002
10
+ * run-003:ev:003
11
+ *
12
+ * Benefits:
13
+ * - Unique within task (different runs have different prefixes)
14
+ * - Readable and debuggable
15
+ * - Legacy IDs still supported for backward compatibility
16
+ */
17
+
18
+ import fs from "node:fs";
19
+ import path from "node:path";
20
+
21
+ /**
22
+ * @typedef {"act" | "obs" | "dec" | "ev"} EventType
23
+ */
24
+
25
+ /**
26
+ * Generate a scoped event ID.
27
+ *
28
+ * @param {string} runId - Run ID (e.g., "run-003")
29
+ * @param {EventType} type - Event type
30
+ * @param {number} sequence - Sequence number
31
+ * @returns {string} Scoped event ID (e.g., "run-003:act:001")
32
+ */
33
+ export function generateEventId(runId, type, sequence) {
34
+ const seq = String(sequence).padStart(3, "0");
35
+ return `${runId}:${type}:${seq}`;
36
+ }
37
+
38
+ /**
39
+ * Parse a scoped event ID into components.
40
+ *
41
+ * @param {string} eventId - Scoped event ID
42
+ * @returns {{ runId: string, type: EventType, sequence: number } | null}
43
+ */
44
+ export function parseEventId(eventId) {
45
+ if (!eventId || typeof eventId !== "string") return null;
46
+
47
+ const parts = eventId.split(":");
48
+ if (parts.length !== 3) return null;
49
+
50
+ const [runId, type, seqStr] = parts;
51
+ const sequence = parseInt(seqStr, 10);
52
+
53
+ if (isNaN(sequence)) return null;
54
+ if (!["act", "obs", "dec", "ev"].includes(type)) return null;
55
+
56
+ return { runId, type: /** @type {EventType} */ (type), sequence };
57
+ }
58
+
59
+ /**
60
+ * Check if an ID is a scoped event ID (vs legacy).
61
+ *
62
+ * @param {string} id
63
+ * @returns {boolean}
64
+ */
65
+ export function isScopedEventId(id) {
66
+ return parseEventId(id) !== null;
67
+ }
68
+
69
+ /**
70
+ * Get the next sequence number for an event type in a run.
71
+ *
72
+ * @param {Object} run - Run object
73
+ * @param {EventType} type - Event type
74
+ * @returns {number} Next sequence number
75
+ */
76
+ export function getNextSequence(run, type) {
77
+ const fieldMap = {
78
+ act: "actions",
79
+ obs: "observations",
80
+ dec: "decisions",
81
+ ev: "evidence",
82
+ };
83
+
84
+ const field = fieldMap[type];
85
+ if (!field || !run[field]) return 1;
86
+
87
+ // Count existing scoped IDs for this type
88
+ let maxSeq = 0;
89
+ for (const event of run[field]) {
90
+ if (event.id && isScopedEventId(event.id)) {
91
+ const parsed = parseEventId(event.id);
92
+ if (parsed && parsed.type === type && parsed.sequence > maxSeq) {
93
+ maxSeq = parsed.sequence;
94
+ }
95
+ }
96
+ }
97
+
98
+ return maxSeq + 1;
99
+ }
100
+
101
+ /**
102
+ * Create a scoped event within a run.
103
+ *
104
+ * @param {Object} run - Run object
105
+ * @param {EventType} type - Event type
106
+ * @param {Object} data - Event data
107
+ * @returns {Object} Created event with scoped ID
108
+ */
109
+ export function createScopedEvent(run, type, data) {
110
+ const sequence = getNextSequence(run, type);
111
+ const id = generateEventId(run.id, type, sequence);
112
+
113
+ return {
114
+ id,
115
+ ...data,
116
+ timestamp: Date.now(),
117
+ };
118
+ }
119
+
120
+ /**
121
+ * Migrate legacy event IDs to scoped format.
122
+ *
123
+ * @param {Object} run - Run object
124
+ * @returns {Object} Run with migrated IDs
125
+ */
126
+ export function migrateRunEventIds(run) {
127
+ if (!run) return run;
128
+
129
+ const fieldMap = {
130
+ actions: "act",
131
+ observations: "obs",
132
+ decisions: "dec",
133
+ evidence: "ev",
134
+ };
135
+
136
+ for (const [field, type] of Object.entries(fieldMap)) {
137
+ if (!run[field]) continue;
138
+
139
+ for (let i = 0; i < run[field].length; i++) {
140
+ const event = run[field][i];
141
+ // Only migrate legacy IDs (not already scoped)
142
+ if (event.id && !isScopedEventId(event.id)) {
143
+ const sequence = i + 1;
144
+ event.id = generateEventId(run.id, type, sequence);
145
+ }
146
+ }
147
+ }
148
+
149
+ return run;
150
+ }
151
+
152
+ /**
153
+ * Get event type from scoped ID.
154
+ *
155
+ * @param {string} eventId
156
+ * @returns {EventType | null}
157
+ */
158
+ export function getEventType(eventId) {
159
+ const parsed = parseEventId(eventId);
160
+ return parsed ? parsed.type : null;
161
+ }
162
+
163
+ /**
164
+ * Get run ID from scoped event ID.
165
+ *
166
+ * @param {string} eventId
167
+ * @returns {string | null}
168
+ */
169
+ export function getRunIdFromEvent(eventId) {
170
+ const parsed = parseEventId(eventId);
171
+ return parsed ? parsed.runId : null;
172
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Formal Execution State — WAM 1.2
3
+ *
4
+ * Implementa el lifecycle formal de la tarea.
5
+ */
6
+ export const STATE = {
7
+ INITIALIZING: "INITIALIZING",
8
+ INVESTIGATING: "INVESTIGATING",
9
+ EXECUTING: "EXECUTING",
10
+ VERIFYING: "VERIFYING",
11
+ COMPLETED: "COMPLETED",
12
+ BLOCKED: "BLOCKED",
13
+ WAITING_AUTHORIZATION: "WAITING_AUTHORIZATION",
14
+ FAILED: "FAILED",
15
+ };
16
+
17
+ export function getPhaseLabel(phase) {
18
+ return phase || STATE.INITIALIZING;
19
+ }
@@ -0,0 +1,119 @@
1
+ /**
2
+ * State Machine — centralized transitions for hypothesis / experiment /
3
+ * evidence events during the execution loop.
4
+ *
5
+ * Pure functions: given an assessment (and optional supporting context),
6
+ * return the next status and any side-effect descriptors. No I/O.
7
+ *
8
+ * Decouples decision logic from execution-engine.js so status transitions
9
+ * become testable in isolation and reusable across noteSuccess / noteFailure /
10
+ * handleContradiction callers.
11
+ */
12
+
13
+ import { AssessmentResult } from "../policy/assessment-engine.js";
14
+ import { HYPOTHESIS_STATUS, EXPERIMENT_STATUS } from "../cognition/cognition-store.js";
15
+
16
+ export { HYPOTHESIS_STATUS, EXPERIMENT_STATUS };
17
+
18
+ /**
19
+ * Contradiction severity classification. Higher severity → faster replan.
20
+ */
21
+ export const SEVERITY = Object.freeze({
22
+ HIGH: "high",
23
+ LOW: "low",
24
+ NONE: null,
25
+ });
26
+
27
+ /**
28
+ * Derive the next hypothesis status from an assessment verdict.
29
+ * Returns { status, severity } so callers can branch on both.
30
+ *
31
+ * Rules (M2 execution-loop contract):
32
+ * - SUPPORTED → SUPPORTED, no severity
33
+ * - CONTRADICTED → REJECTED (high) when contradicted > supported; else TESTING (low)
34
+ * - INCONCLUSIVE → TESTING, no severity
35
+ *
36
+ * @param {object} assessment - { result, summary: { contradicted, supported } }
37
+ * @returns {{status: string, severity: string|null}}
38
+ */
39
+ export function deriveHypothesisStatus(assessment) {
40
+ if (!assessment || typeof assessment !== "object") {
41
+ return { status: HYPOTHESIS_STATUS.TESTING, severity: SEVERITY.NONE };
42
+ }
43
+ if (assessment.result === AssessmentResult.SUPPORTED) {
44
+ return { status: HYPOTHESIS_STATUS.SUPPORTED, severity: SEVERITY.NONE };
45
+ }
46
+ if (assessment.result === AssessmentResult.CONTRADICTED) {
47
+ const { summary = {} } = assessment;
48
+ const contradicted = summary.contradicted || 0;
49
+ const supported = summary.supported || 0;
50
+ if (contradicted > supported && contradicted > 0) {
51
+ return { status: HYPOTHESIS_STATUS.REJECTED, severity: SEVERITY.HIGH };
52
+ }
53
+ return { status: HYPOTHESIS_STATUS.TESTING, severity: SEVERITY.LOW };
54
+ }
55
+ return { status: HYPOTHESIS_STATUS.TESTING, severity: SEVERITY.NONE };
56
+ }
57
+
58
+ /**
59
+ * Decide whether the current outcome should trigger a replan.
60
+ * A replan is warranted when:
61
+ * - assessment is CONTRADICTED AND
62
+ * - hypothesis has moved to REJECTED (high severity contradiction), OR
63
+ * - hypothesis remains TESTING but contradicted (caller may want to re-explore)
64
+ *
65
+ * @param {object} args
66
+ * @param {object} args.assessment
67
+ * @param {string} args.hypothesisStatus
68
+ * @returns {boolean}
69
+ */
70
+ export function shouldReplan({ assessment, hypothesisStatus }) {
71
+ if (!assessment || assessment.result !== AssessmentResult.CONTRADICTED) return false;
72
+ if (hypothesisStatus === HYPOTHESIS_STATUS.REJECTED) return true;
73
+ return false;
74
+ }
75
+
76
+ /**
77
+ * Decide whether the contradiction should be noted as a learning event
78
+ * (without forcing a full replan).
79
+ *
80
+ * @param {object} args
81
+ * @param {object} args.assessment
82
+ * @param {string} args.hypothesisStatus
83
+ * @returns {boolean}
84
+ */
85
+ export function shouldNoteContradiction({ assessment, hypothesisStatus }) {
86
+ if (!assessment || assessment.result !== AssessmentResult.CONTRADICTED) return false;
87
+ // When REJECTED, the caller may already replan; still useful to note it.
88
+ return hypothesisStatus !== HYPOTHESIS_STATUS.SUPPORTED;
89
+ }
90
+
91
+ /**
92
+ * Pick the experiment terminal status for an outcome.
93
+ *
94
+ * @param {string} outcome - "success" | "failure"
95
+ * @returns {string}
96
+ */
97
+ export function deriveExperimentStatus(outcome) {
98
+ return outcome === "failure"
99
+ ? EXPERIMENT_STATUS.FAILED
100
+ : EXPERIMENT_STATUS.COMPLETED;
101
+ }
102
+
103
+ /**
104
+ * Contradiction-handling transition: given a contradicted experiment,
105
+ * compute the next hypothesis status + replan trigger descriptor.
106
+ *
107
+ * @param {object} args
108
+ * @param {string} args.outcome - "success" | "failure" | "contradicted"
109
+ * @param {object} args.assessment
110
+ * @returns {{status: string, replan: boolean, severity: string|null}}
111
+ */
112
+ export function transitionAfterOutcome({ outcome, assessment }) {
113
+ const derived = deriveHypothesisStatus(assessment);
114
+ const replan = shouldReplan({
115
+ assessment,
116
+ hypothesisStatus: derived.status,
117
+ });
118
+ return { ...derived, replan };
119
+ }