opencode-wait-a-minute 0.0.0-stage → 1.1.0-rc.10
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.
- package/LICENSE +21 -0
- package/README.md +318 -2
- package/index.js +1836 -0
- package/package.json +70 -4
- package/skills/codebase-design/SKILL.md +114 -0
- package/skills/design-contract/SKILL.md +27 -0
- package/skills/design-critique/SKILL.md +19 -0
- package/skills/design-system/SKILL.md +17 -0
- package/skills/design-system/references/image-analysis.md +14 -0
- package/skills/design-system/references/tokens.md +32 -0
- package/skills/design-system/references/ui-rules.md +14 -0
- package/skills/diagnosing-bugs/SKILL.md +138 -0
- package/skills/frontend-design/SKILL.md +36 -0
- package/skills/handoff/SKILL.md +16 -0
- package/skills/improve-codebase-architecture/SKILL.md +71 -0
- package/skills/linter-negative/SKILL.md +74 -0
- package/skills/no-slop-ui/SKILL.md +26 -0
- package/skills/prototype/SKILL.md +26 -0
- package/skills/registry.json +44087 -0
- package/skills/tastemaker/SKILL.md +8 -0
- package/skills/tastemaker/references/tastemaker.md +14 -0
- package/skills/tdd/SKILL.md +38 -0
- package/skills/visual-review/SKILL.md +103 -0
- package/skills/visual-review/references/review-gates.md +42 -0
- package/skills/visual-review/references/surface-archetypes.md +37 -0
- package/skills/wizard/SKILL.md +44 -0
- package/skills/writing-for-agents/SKILL.md +81 -0
- package/src/cognition/cognition-store.js +251 -0
- package/src/cognition/cognitive-state.js +126 -0
- package/src/cognition/hypothesis-manager.js +113 -0
- package/src/cognition/observation-engine.js +112 -0
- package/src/cognition/observation-provenance.js +268 -0
- package/src/context/active-context-boundary.js +68 -0
- package/src/context/assembly.js +494 -0
- package/src/context/assessment-rules.js +55 -0
- package/src/context/capsule-staleness.js +267 -0
- package/src/context/capsules.js +2 -0
- package/src/context/compare-array.js +98 -0
- package/src/context/compare-object.js +89 -0
- package/src/context/compare-values.js +42 -0
- package/src/context/context-assembly-contract.js +71 -0
- package/src/context/context-budget-manager.js +232 -0
- package/src/context/context-builder.js +49 -0
- package/src/context/context-cache.js +55 -0
- package/src/context/context-capture.js +243 -0
- package/src/context/context-classification.js +199 -0
- package/src/context/context-compaction.js +179 -0
- package/src/context/context-decision-audit.js +267 -0
- package/src/context/context-demotion.js +173 -0
- package/src/context/context-dictionary.js +106 -0
- package/src/context/context-drift-detection.js +225 -0
- package/src/context/context-evaluation.js +374 -0
- package/src/context/context-event-ingress.js +100 -0
- package/src/context/context-event-normalization.js +224 -0
- package/src/context/context-feedback-loop.js +216 -0
- package/src/context/context-freshness.js +21 -0
- package/src/context/context-graph-builder.js +71 -0
- package/src/context/context-graph.js +451 -0
- package/src/context/context-history-relevance.js +321 -0
- package/src/context/context-interception.js +145 -0
- package/src/context/context-invalidation-events.js +154 -0
- package/src/context/context-lifecycle.js +170 -0
- package/src/context/context-loop-prevention.js +347 -0
- package/src/context/context-manager.js +340 -0
- package/src/context/context-memory-layers.js +265 -0
- package/src/context/context-minimality.js +166 -0
- package/src/context/context-normalization.js +130 -0
- package/src/context/context-optimization-metrics.js +434 -0
- package/src/context/context-output-policy.js +135 -0
- package/src/context/context-pack-authority.js +157 -0
- package/src/context/context-promotion.js +172 -0
- package/src/context/context-query-contract.js +101 -0
- package/src/context/context-ranking.js +164 -0
- package/src/context/context-rate-distortion.js +261 -0
- package/src/context/context-recovery.js +209 -0
- package/src/context/context-retrieval-integration.js +60 -0
- package/src/context/context-retrieval.js +93 -0
- package/src/context/context-router.js +457 -0
- package/src/context/context-routing-evaluation.js +331 -0
- package/src/context/context-routing-observability.js +296 -0
- package/src/context/context-routing-shadow.js +237 -0
- package/src/context/context-scope.js +181 -0
- package/src/context/context-snapshot.js +226 -0
- package/src/context/context-source-registry.js +95 -0
- package/src/context/context-sufficiency-gate.js +120 -0
- package/src/context/context-sufficiency-oracle.js +167 -0
- package/src/context/context-telemetry.js +176 -0
- package/src/context/context.js +633 -0
- package/src/context/dependency-closure.js +246 -0
- package/src/context/page-fault-tracker.js +275 -0
- package/src/context/prompt-engine.js +74 -0
- package/src/context/runtime-context-graph.js +260 -0
- package/src/context/selection.js +2 -0
- package/src/context/session.js +2 -0
- package/src/context/sufficiency-contract.js +300 -0
- package/src/context/tokenizer.js +17 -0
- package/src/context-benchmark-router.mjs +125 -0
- package/src/evidence/evidence-engine.js +161 -0
- package/src/evidence/evidence-factory.js +3 -0
- package/src/evidence/evidence-freshness.js +463 -0
- package/src/evidence/evidence-gap.js +76 -0
- package/src/evidence/evidence-lineage.js +525 -0
- package/src/evidence/evidence.js +136 -0
- package/src/evidence/freshness-validation.js +187 -0
- package/src/evidence/lineage.js +4 -0
- package/src/execution/action-evaluation.js +179 -0
- package/src/execution/circuit-breaker.js +70 -0
- package/src/execution/claim-interception.js +63 -0
- package/src/execution/execution-engine.js +258 -0
- package/src/execution/execution-intent.js +69 -0
- package/src/execution/execution-state.js +89 -0
- package/src/execution/formatting.js +60 -0
- package/src/execution/l1-sanitize.js +16 -0
- package/src/execution/l2-resource-guards.js +19 -0
- package/src/execution/l3-invariant-checker.js +5 -0
- package/src/execution/l4-containment.js +6 -0
- package/src/execution/runtime-guards.js +106 -0
- package/src/execution/strategy-identity.js +162 -0
- package/src/execution/tool-interceptor.js +7 -0
- package/src/execution/tool-result-classifier.js +63 -0
- package/src/integration/canary-deploy.js +143 -0
- package/src/integration/collector.js +59 -0
- package/src/integration/error-recovery.js +6 -0
- package/src/integration/event-bus.js +66 -0
- package/src/integration/health-checker.js +57 -0
- package/src/integration/logger.js +39 -0
- package/src/integration/message-handler.js +611 -0
- package/src/integration/opencode-db.js +153 -0
- package/src/integration/orchestration.js +419 -0
- package/src/integration/part-provenance.js +65 -0
- package/src/integration/rate-limiter.js +55 -0
- package/src/integration/release-gate.js +336 -0
- package/src/integration/rollback-manager.js +164 -0
- package/src/integration/router-adapter.js +269 -0
- package/src/integration/telemetry.js +45 -0
- package/src/integration/update-checker.js +10 -0
- package/src/persistence/event-sourcing.js +75 -0
- package/src/persistence/memory.js +501 -0
- package/src/persistence/migration-runner.js +16 -0
- package/src/persistence/persistence-manager.js +39 -0
- package/src/persistence/transaction-log.js +157 -0
- package/src/policy/action-capabilities.js +116 -0
- package/src/policy/action-policy.js +4 -0
- package/src/policy/assessment-engine.js +104 -0
- package/src/policy/assumption-tracking.js +66 -0
- package/src/policy/budget-enforcer.js +7 -0
- package/src/policy/config-validator.js +102 -0
- package/src/policy/execution-assessment.js +142 -0
- package/src/policy/failure-classification.js +5 -0
- package/src/policy/feature-flags.js +65 -0
- package/src/policy/governance-enforcement.js +118 -0
- package/src/policy/locale.js +15 -0
- package/src/policy/multi-signer.js +151 -0
- package/src/policy/policy-state-machine.js +97 -0
- package/src/policy/ponytail-constraint.js +38 -0
- package/src/policy/project-inspector.js +93 -0
- package/src/policy/query-builder.js +14 -0
- package/src/policy/request-classifier.js +79 -0
- package/src/policy/risk-engine.js +266 -0
- package/src/policy/scope-enforcement.js +140 -0
- package/src/policy/secret-scanner.js +68 -0
- package/src/policy/skill-routing.js +104 -0
- package/src/policy/strategy-capabilities.js +211 -0
- package/src/policy/strategy.js +6 -0
- package/src/policy/uncertainty.js +117 -0
- package/src/shared/container.js +44 -0
- package/src/shared/decision-types.js +24 -0
- package/src/shared/simple-test.js +160 -0
- package/src/shared/wam-events.js +52 -0
- package/src/skills/engine.js +1705 -0
- package/src/skills/skill-registry.js +19 -0
- package/src/skills/skill-routing.js +340 -0
- package/src/state/lifecycle-manager.js +113 -0
- package/src/state/operational-state.js +198 -0
- package/src/state/projections.js +47 -0
- package/src/state/replay-engine.js +5 -0
- package/src/state/requirement-ownership.js +20 -0
- package/src/state/requirement-state.js +152 -0
- package/src/state/run-event-identity.js +172 -0
- package/src/state/state-engine.js +19 -0
- package/src/state/state-machine.js +119 -0
- package/src/state/state-schema.js +318 -0
- package/src/state/state-store.js +335 -0
- package/src/state/state-transition.js +84 -0
- package/src/state/task-dependencies.js +287 -0
- package/src/state/task-execution.js +217 -0
- package/src/state/task-lifecycle.js +59 -0
- package/src/state/task-runs.js +361 -0
- package/src/state/task-state-file.js +86 -0
- package/src/state/task-state.js +41 -0
- package/src/state/task-status.js +54 -0
- package/src/state/task-store.js +48 -0
- package/src/state/wam-state.js +148 -0
- package/src/verification/completion-gate-simple.js +8 -0
- package/src/verification/completion-gate.js +183 -0
- package/src/verification/contract.js +9 -0
- package/src/verification/contradiction-resolution.js +255 -0
- package/src/verification/diagnostic-engine.js +659 -0
- package/src/verification/false-completion-prevention.js +100 -0
- package/src/verification/hook-validator.js +6 -0
- package/src/verification/requirements.js +6 -0
- package/src/verification/verification-context.js +162 -0
- package/src/verification/verification-lifecycle.js +66 -0
- package/src/verification/verification-model.js +89 -0
- package/src/verification/verification-persistence.js +129 -0
- package/src/verification/verification-policy.js +127 -0
- package/src/verification/verification.js +415 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context Freshness Validation — derives verification from evidence lineage.
|
|
3
|
+
*
|
|
4
|
+
* The Context Graph should NOT be a second source of truth for
|
|
5
|
+
* epistemological state. It should derive it from Evidence Lineage.
|
|
6
|
+
*
|
|
7
|
+
* Rule: `verified` on a ContextNode cannot survive invalidated
|
|
8
|
+
* supporting evidence. Validity must be resolved from lineage/provenance.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {Object} FreshnessResult
|
|
13
|
+
* @property {string} nodeId
|
|
14
|
+
* @property {boolean} effectiveVerified
|
|
15
|
+
* @property {string} reason
|
|
16
|
+
* @property {string} derivedFrom
|
|
17
|
+
* @property {number} derivedAt
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @typedef {Object} EvidenceStatus
|
|
22
|
+
* @property {string} id
|
|
23
|
+
* @property {string} status - "valid" | "superseded" | "invalidated" | "unverified"
|
|
24
|
+
* @property {number} updatedAt
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Derive effective verification status for a node.
|
|
29
|
+
*
|
|
30
|
+
* A node is effectively verified only if:
|
|
31
|
+
* 1. It is marked as verified in the graph
|
|
32
|
+
* 2. ALL supporting evidence is valid (not invalidated)
|
|
33
|
+
*
|
|
34
|
+
* @param {Object} node - Context node
|
|
35
|
+
* @param {EvidenceStatus[]} supportingEvidence - Evidence that supports this node
|
|
36
|
+
* @returns {FreshnessResult}
|
|
37
|
+
*/
|
|
38
|
+
export function deriveVerification(node, supportingEvidence = []) {
|
|
39
|
+
if (!node) {
|
|
40
|
+
return {
|
|
41
|
+
nodeId: null,
|
|
42
|
+
effectiveVerified: false,
|
|
43
|
+
reason: "node not found",
|
|
44
|
+
derivedFrom: "none",
|
|
45
|
+
derivedAt: Date.now(),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// If node is not verified, it's not verified
|
|
50
|
+
if (!node.verified) {
|
|
51
|
+
return {
|
|
52
|
+
nodeId: node.id,
|
|
53
|
+
effectiveVerified: false,
|
|
54
|
+
reason: "node not verified in graph",
|
|
55
|
+
derivedFrom: "graph",
|
|
56
|
+
derivedAt: Date.now(),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Check if any supporting evidence is invalidated
|
|
61
|
+
const invalidated = supportingEvidence.filter((e) => e.status === "invalidated");
|
|
62
|
+
if (invalidated.length > 0) {
|
|
63
|
+
return {
|
|
64
|
+
nodeId: node.id,
|
|
65
|
+
effectiveVerified: false,
|
|
66
|
+
reason: `${invalidated.length} supporting evidence invalidated`,
|
|
67
|
+
derivedFrom: "evidence-lineage",
|
|
68
|
+
derivedAt: Date.now(),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Check if all supporting evidence is superseded
|
|
73
|
+
const superseded = supportingEvidence.filter((e) => e.status === "superseded");
|
|
74
|
+
if (superseded.length > 0 && superseded.length === supportingEvidence.length) {
|
|
75
|
+
return {
|
|
76
|
+
nodeId: node.id,
|
|
77
|
+
effectiveVerified: false,
|
|
78
|
+
reason: "all supporting evidence superseded",
|
|
79
|
+
derivedFrom: "evidence-lineage",
|
|
80
|
+
derivedAt: Date.now(),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Check if there's any valid evidence
|
|
85
|
+
const valid = supportingEvidence.filter((e) => e.status === "valid");
|
|
86
|
+
if (supportingEvidence.length > 0 && valid.length === 0) {
|
|
87
|
+
return {
|
|
88
|
+
nodeId: node.id,
|
|
89
|
+
effectiveVerified: false,
|
|
90
|
+
reason: "no valid supporting evidence",
|
|
91
|
+
derivedFrom: "evidence-lineage",
|
|
92
|
+
derivedAt: Date.now(),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Node is verified and has valid supporting evidence
|
|
97
|
+
return {
|
|
98
|
+
nodeId: node.id,
|
|
99
|
+
effectiveVerified: true,
|
|
100
|
+
reason: "verified with valid supporting evidence",
|
|
101
|
+
derivedFrom: "combined",
|
|
102
|
+
derivedAt: Date.now(),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Check if evidence invalidation affects graph nodes.
|
|
108
|
+
*
|
|
109
|
+
* @param {string} evidenceId - Invalidated evidence ID
|
|
110
|
+
* @param {Object} graph - Context graph
|
|
111
|
+
* @returns {string[]} Affected node IDs
|
|
112
|
+
*/
|
|
113
|
+
export function findAffectedNodes(evidenceId, graph) {
|
|
114
|
+
const affected = [];
|
|
115
|
+
|
|
116
|
+
// Find all nodes that depend on this evidence
|
|
117
|
+
const edges = graph.getEdgesToByType
|
|
118
|
+
? graph.getEdgesToByType(evidenceId, "supports")
|
|
119
|
+
: [];
|
|
120
|
+
|
|
121
|
+
for (const edge of edges) {
|
|
122
|
+
const node = graph.getNode(edge.from);
|
|
123
|
+
if (node && node.verified) {
|
|
124
|
+
affected.push(node.id);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return affected;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Mark graph nodes as stale when evidence is invalidated.
|
|
133
|
+
*
|
|
134
|
+
* @param {string} evidenceId - Invalidated evidence ID
|
|
135
|
+
* @param {Object} graph - Context graph
|
|
136
|
+
* @returns {string[]} Nodes that were marked stale
|
|
137
|
+
*/
|
|
138
|
+
export function markStaleOnInvalidation(evidenceId, graph) {
|
|
139
|
+
const affected = findAffectedNodes(evidenceId, graph);
|
|
140
|
+
|
|
141
|
+
for (const nodeId of affected) {
|
|
142
|
+
const node = graph.getNode(nodeId);
|
|
143
|
+
if (node) {
|
|
144
|
+
node.verified = false;
|
|
145
|
+
node.metadata = node.metadata || {};
|
|
146
|
+
node.metadata.staleReason = `evidence ${evidenceId} invalidated`;
|
|
147
|
+
node.metadata.staleAt = Date.now();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return affected;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Generate freshness report for a set of nodes.
|
|
156
|
+
*
|
|
157
|
+
* @param {Object[]} nodes
|
|
158
|
+
* @param {Object} evidenceStore - Evidence lookup function
|
|
159
|
+
* @returns {Object} Freshness report
|
|
160
|
+
*/
|
|
161
|
+
export function generateFreshnessReport(nodes, evidenceStore) {
|
|
162
|
+
const results = [];
|
|
163
|
+
let verified = 0;
|
|
164
|
+
let stale = 0;
|
|
165
|
+
|
|
166
|
+
for (const node of nodes) {
|
|
167
|
+
const evidence = evidenceStore?.getSupportingEvidence?.(node.id) || [];
|
|
168
|
+
const result = deriveVerification(node, evidence);
|
|
169
|
+
results.push(result);
|
|
170
|
+
|
|
171
|
+
if (result.effectiveVerified) {
|
|
172
|
+
verified++;
|
|
173
|
+
} else if (node.verified && !result.effectiveVerified) {
|
|
174
|
+
stale++;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
total: nodes.length,
|
|
180
|
+
verified,
|
|
181
|
+
stale,
|
|
182
|
+
unverified: nodes.length - verified - stale,
|
|
183
|
+
results,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export default deriveVerification;
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Action Evaluation — Separation of action results, observations,
|
|
3
|
+
* requirement evaluation, and task verification.
|
|
4
|
+
*
|
|
5
|
+
* Core insight: ActionResult ≠ Observation ≠ RequirementEvaluation ≠ TaskVerification
|
|
6
|
+
* A tool succeeding does NOT mean its requirement is satisfied.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// -- ActionResult: directly from tool execution --
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {Object} ActionResult
|
|
13
|
+
* @property {string} actionId
|
|
14
|
+
* @property {boolean} success
|
|
15
|
+
* @property {number} exitCode
|
|
16
|
+
* @property {string} output
|
|
17
|
+
* @property {number} durationMs
|
|
18
|
+
* @property {number} timestamp
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Creates an ActionResult directly from tool execution metadata.
|
|
23
|
+
*/
|
|
24
|
+
export function createActionResult({
|
|
25
|
+
actionId,
|
|
26
|
+
success,
|
|
27
|
+
exitCode,
|
|
28
|
+
output,
|
|
29
|
+
durationMs,
|
|
30
|
+
timestamp = Date.now(),
|
|
31
|
+
}) {
|
|
32
|
+
return { actionId, success, exitCode, output, durationMs, timestamp };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// -- Observation: interpretation of action result --
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @typedef {Object} Observation
|
|
39
|
+
* @property {string} id
|
|
40
|
+
* @property {string} actionId
|
|
41
|
+
* @property {string} requirementId
|
|
42
|
+
* @property {string} observation
|
|
43
|
+
* @property {"direct" | "derived" | "inferred"} relevance
|
|
44
|
+
* @property {number} timestamp
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Creates an Observation — an interpretation of what happened during execution.
|
|
49
|
+
*/
|
|
50
|
+
export function createObservation({
|
|
51
|
+
actionId,
|
|
52
|
+
requirementId,
|
|
53
|
+
observation,
|
|
54
|
+
relevance = "direct",
|
|
55
|
+
}) {
|
|
56
|
+
return {
|
|
57
|
+
id: `obs-${actionId}-${Date.now().toString(36)}`,
|
|
58
|
+
actionId,
|
|
59
|
+
requirementId,
|
|
60
|
+
observation,
|
|
61
|
+
relevance,
|
|
62
|
+
timestamp: Date.now(),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// -- Requirement evaluation: mapping observation to requirement --
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @typedef {Object} RequirementEvaluation
|
|
70
|
+
* @property {string} requirementId
|
|
71
|
+
* @property {string} observationId
|
|
72
|
+
* @property {"unknown" | "supports" | "contradicts" | "neutral"} evaluation
|
|
73
|
+
* @property {string} reason
|
|
74
|
+
* @property {number} timestamp
|
|
75
|
+
*/
|
|
76
|
+
|
|
77
|
+
import { assessObservation, AssessmentResult } from "../policy/assessment-engine.js";
|
|
78
|
+
const EVALUATION_BY_RESULT = { [AssessmentResult.SUPPORTED]: "supports", [AssessmentResult.CONTRADICTED]: "contradicts", [AssessmentResult.INCONCLUSIVE]: "unknown" };
|
|
79
|
+
/**
|
|
80
|
+
* Evaluates an observation against a requirement.
|
|
81
|
+
* Returns an evaluation, NOT a status change. Delegates to assessment-engine.
|
|
82
|
+
*/
|
|
83
|
+
export function evaluateObservationAgainst(observation, requirement) {
|
|
84
|
+
const expected = (requirement && (requirement.expectedObservation ?? requirement.description)) ?? undefined;
|
|
85
|
+
const actual = (observation && (observation.observation ?? observation.actual)) ?? undefined;
|
|
86
|
+
const assessment = assessObservation({ expectedObservation: expected }, actual);
|
|
87
|
+
const evaluation = EVALUATION_BY_RESULT[assessment.result] || "unknown";
|
|
88
|
+
const isNoExpected = assessment.reasoning === "No expectedObservation defined for this experiment.";
|
|
89
|
+
return { requirementId: observation.requirementId, observationId: observation.id, evaluation, reason: isNoExpected ? "" : assessment.reasoning || "", timestamp: Date.now(), assessment };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// -- Task verification: final result --
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @typedef {Object} TaskVerification
|
|
96
|
+
* @property {string} taskId
|
|
97
|
+
* @property {boolean} verified
|
|
98
|
+
* @property {RequirementEvaluation[]} evaluations
|
|
99
|
+
* @property {string} summary
|
|
100
|
+
* @property {number} timestamp
|
|
101
|
+
*/
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Verifies a task by aggregating all requirement evaluations.
|
|
105
|
+
*/
|
|
106
|
+
export function verifyTask({ taskId, evaluations, summary }) {
|
|
107
|
+
const verified =
|
|
108
|
+
evaluations.length > 0 &&
|
|
109
|
+
evaluations.every((e) => e.evaluation === "supports");
|
|
110
|
+
return {
|
|
111
|
+
taskId,
|
|
112
|
+
verified,
|
|
113
|
+
evaluations,
|
|
114
|
+
summary,
|
|
115
|
+
timestamp: Date.now(),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// -- Classic bug demonstrations --
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Bug demo #1: Command succeeded ≠ Requirement satisfied.
|
|
123
|
+
* A command exiting with 0 does not prove the underlying requirement is met.
|
|
124
|
+
*/
|
|
125
|
+
export function demoCommandSucceedsNotRequirementSatisfied() {
|
|
126
|
+
const actionResult = createActionResult({
|
|
127
|
+
actionId: "act-1",
|
|
128
|
+
success: true,
|
|
129
|
+
exitCode: 0,
|
|
130
|
+
output: "Chromium executable exists at /usr/bin/chromium",
|
|
131
|
+
durationMs: 12,
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
const observation = createObservation({
|
|
135
|
+
actionId: actionResult.actionId,
|
|
136
|
+
requirementId: "req-playwright-chromium",
|
|
137
|
+
observation: "Chromium executable exists",
|
|
138
|
+
relevance: "direct",
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
const requirement = {
|
|
142
|
+
id: "req-playwright-chromium",
|
|
143
|
+
description: "Playwright can launch required Chromium",
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const evaluation = evaluateObservationAgainst(observation, requirement);
|
|
147
|
+
|
|
148
|
+
return { actionResult, observation, requirement, evaluation };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Bug demo #2: Tool output exists ≠ Requirement verified.
|
|
153
|
+
* Having output does not mean the requirement is actually satisfied.
|
|
154
|
+
*/
|
|
155
|
+
export function demoToolOutputExistsNotRequirementVerified() {
|
|
156
|
+
const actionResult = createActionResult({
|
|
157
|
+
actionId: "act-2",
|
|
158
|
+
success: true,
|
|
159
|
+
exitCode: 0,
|
|
160
|
+
output: "npm install completed with 0 warnings",
|
|
161
|
+
durationMs: 4500,
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
const observation = createObservation({
|
|
165
|
+
actionId: actionResult.actionId,
|
|
166
|
+
requirementId: "req-deps-installed",
|
|
167
|
+
observation: "npm install completed",
|
|
168
|
+
relevance: "derived",
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
const requirement = {
|
|
172
|
+
id: "req-deps-installed",
|
|
173
|
+
description: "All runtime dependencies are installed and importable",
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const evaluation = evaluateObservationAgainst(observation, requirement);
|
|
177
|
+
|
|
178
|
+
return { actionResult, observation, requirement, evaluation };
|
|
179
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Circuit Breaker — fail-fast pattern for unreliable calls.
|
|
3
|
+
*
|
|
4
|
+
* States: "closed" (allow), "open" (reject fast), "half-open" (probe).
|
|
5
|
+
* After `threshold` consecutive failures the breaker opens; after
|
|
6
|
+
* `timeout` ms it transitions to half-open to allow one probe.
|
|
7
|
+
*
|
|
8
|
+
* Production hardening (M5-53).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {"closed"|"open"|"half-open"} BreakerState
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @typedef {Object} CircuitBreaker
|
|
17
|
+
* @property {() => BreakerState} getState
|
|
18
|
+
* @property {<T>(fn: () => Promise<T>) => Promise<T>} execute
|
|
19
|
+
* @property {() => void} reset
|
|
20
|
+
* @property {() => number} failures
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param {{threshold?: number, timeout?: number}} opts
|
|
25
|
+
* @returns {CircuitBreaker}
|
|
26
|
+
*/
|
|
27
|
+
export function createCircuitBreaker(opts = {}) {
|
|
28
|
+
const threshold = opts.threshold ?? 3;
|
|
29
|
+
const timeout = opts.timeout ?? 1000;
|
|
30
|
+
/** @type {BreakerState} */
|
|
31
|
+
let state = "closed";
|
|
32
|
+
let failures = 0;
|
|
33
|
+
let openedAt = 0;
|
|
34
|
+
|
|
35
|
+
function getState() {
|
|
36
|
+
if (state === "open" && Date.now() - openedAt >= timeout) {
|
|
37
|
+
state = "half-open";
|
|
38
|
+
}
|
|
39
|
+
return state;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function execute(fn) {
|
|
43
|
+
const cur = getState();
|
|
44
|
+
if (cur === "open") {
|
|
45
|
+
throw new Error("circuit breaker is OPEN");
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
const result = await fn();
|
|
49
|
+
// success: close if half-open, reset counter
|
|
50
|
+
state = "closed";
|
|
51
|
+
failures = 0;
|
|
52
|
+
return result;
|
|
53
|
+
} catch (err) {
|
|
54
|
+
failures++;
|
|
55
|
+
if (failures >= threshold || state === "half-open") {
|
|
56
|
+
state = "open";
|
|
57
|
+
openedAt = Date.now();
|
|
58
|
+
}
|
|
59
|
+
throw err;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function reset() {
|
|
64
|
+
state = "closed";
|
|
65
|
+
failures = 0;
|
|
66
|
+
openedAt = 0;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return { getState, execute, reset, failures: () => failures };
|
|
70
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { classifyClaim } from "../verification/false-completion-prevention.js";
|
|
2
|
+
|
|
3
|
+
export function interceptAgentClaim(message) {
|
|
4
|
+
const claimPatterns = {
|
|
5
|
+
FACT: /\b(is|exists|present|available|installed|configured|has|have)\b/i,
|
|
6
|
+
HYPOTHESIS: /\b(think|believe|probably|might|could be|suspect)\b/i,
|
|
7
|
+
OBSERVATION: /\b(see|observe|notice|found|detected)\b/i,
|
|
8
|
+
INTENT: /\b(will|going to|plan|should|need to|want to)\b/i,
|
|
9
|
+
CONCLUSION: /\b(therefore|so|thus|conclude)\b/i,
|
|
10
|
+
COMPLETION: /\b(done|fixed|working|solved|completed|implemented|resolved|ready)\b/i
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const claims = [];
|
|
14
|
+
|
|
15
|
+
for (const [type, pattern] of Object.entries(claimPatterns)) {
|
|
16
|
+
const match = message.match(pattern);
|
|
17
|
+
if (match) {
|
|
18
|
+
claims.push({
|
|
19
|
+
type,
|
|
20
|
+
text: match[0],
|
|
21
|
+
position: match.index,
|
|
22
|
+
context: message.slice(Math.max(0, match.index - 20), match.index + 20)
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return claims;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function createClaim(text, type, source = "agent") {
|
|
31
|
+
return {
|
|
32
|
+
id: `claim-${Date.now().toString(36)}`,
|
|
33
|
+
text,
|
|
34
|
+
type,
|
|
35
|
+
source,
|
|
36
|
+
timestamp: Date.now(),
|
|
37
|
+
validated: false
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function validateClaim(claim, taskState) {
|
|
42
|
+
const result = {
|
|
43
|
+
claimId: claim.id,
|
|
44
|
+
valid: false,
|
|
45
|
+
requiresVerification: false,
|
|
46
|
+
reason: ""
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
if (claim.type === "COMPLETION") {
|
|
50
|
+
result.requiresVerification = true;
|
|
51
|
+
result.reason = "Completion claim requires verification";
|
|
52
|
+
} else if (claim.type === "HYPOTHESIS") {
|
|
53
|
+
result.reason = "Hypothesis requires validation";
|
|
54
|
+
} else if (claim.type === "FACT") {
|
|
55
|
+
result.requiresVerification = true;
|
|
56
|
+
result.reason = "Fact claims should be verified";
|
|
57
|
+
} else {
|
|
58
|
+
result.valid = true;
|
|
59
|
+
result.reason = "Observation or intent does not require verification";
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return result;
|
|
63
|
+
}
|