@fairfox/polly 0.1.1 → 0.1.2

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 (39) hide show
  1. package/cli/polly.ts +9 -3
  2. package/package.json +2 -2
  3. package/vendor/analysis/src/extract/adr.ts +212 -0
  4. package/vendor/analysis/src/extract/architecture.ts +160 -0
  5. package/vendor/analysis/src/extract/contexts.ts +298 -0
  6. package/vendor/analysis/src/extract/flows.ts +309 -0
  7. package/vendor/analysis/src/extract/handlers.ts +321 -0
  8. package/vendor/analysis/src/extract/index.ts +9 -0
  9. package/vendor/analysis/src/extract/integrations.ts +329 -0
  10. package/vendor/analysis/src/extract/manifest.ts +298 -0
  11. package/vendor/analysis/src/extract/types.ts +389 -0
  12. package/vendor/analysis/src/index.ts +7 -0
  13. package/vendor/analysis/src/types/adr.ts +53 -0
  14. package/vendor/analysis/src/types/architecture.ts +245 -0
  15. package/vendor/analysis/src/types/core.ts +210 -0
  16. package/vendor/analysis/src/types/index.ts +18 -0
  17. package/vendor/verify/src/adapters/base.ts +164 -0
  18. package/vendor/verify/src/adapters/detection.ts +281 -0
  19. package/vendor/verify/src/adapters/event-bus/index.ts +480 -0
  20. package/vendor/verify/src/adapters/web-extension/index.ts +508 -0
  21. package/vendor/verify/src/adapters/websocket/index.ts +486 -0
  22. package/vendor/verify/src/cli.ts +430 -0
  23. package/vendor/verify/src/codegen/config.ts +354 -0
  24. package/vendor/verify/src/codegen/tla.ts +719 -0
  25. package/vendor/verify/src/config/parser.ts +303 -0
  26. package/vendor/verify/src/config/types.ts +113 -0
  27. package/vendor/verify/src/core/model.ts +267 -0
  28. package/vendor/verify/src/core/primitives.ts +106 -0
  29. package/vendor/verify/src/extract/handlers.ts +2 -0
  30. package/vendor/verify/src/extract/types.ts +2 -0
  31. package/vendor/verify/src/index.ts +150 -0
  32. package/vendor/verify/src/primitives/index.ts +102 -0
  33. package/vendor/verify/src/runner/docker.ts +283 -0
  34. package/vendor/verify/src/types.ts +51 -0
  35. package/vendor/visualize/src/cli.ts +365 -0
  36. package/vendor/visualize/src/codegen/structurizr.ts +770 -0
  37. package/vendor/visualize/src/index.ts +13 -0
  38. package/vendor/visualize/src/runner/export.ts +235 -0
  39. package/vendor/visualize/src/viewer/server.ts +485 -0
@@ -0,0 +1,303 @@
1
+ // Configuration validator - detects incomplete configuration
2
+
3
+ import type { ValidationResult, ConfigIssue, VerificationConfig } from "../types";
4
+ import * as fs from "node:fs";
5
+ import * as path from "node:path";
6
+
7
+ export class ConfigValidator {
8
+ private issues: ConfigIssue[] = [];
9
+
10
+ validate(configPath: string): ValidationResult {
11
+ this.issues = [];
12
+
13
+ if (!fs.existsSync(configPath)) {
14
+ this.issues.push({
15
+ type: "incomplete",
16
+ severity: "error",
17
+ message: "Configuration file does not exist",
18
+ suggestion: "Run 'bun verify --setup' to generate configuration",
19
+ });
20
+
21
+ return {
22
+ valid: false,
23
+ issues: this.issues,
24
+ };
25
+ }
26
+
27
+ // Read the source file
28
+ const configSource = fs.readFileSync(configPath, "utf-8");
29
+
30
+ // Check for CONFIGURE markers
31
+ this.checkConfigureMarkers(configSource);
32
+
33
+ // Check for REVIEW markers (warnings only)
34
+ this.checkReviewMarkers(configSource);
35
+
36
+ // Load and validate the actual config
37
+ try {
38
+ const config = this.loadConfig(configPath);
39
+ this.validateConfig(config);
40
+ } catch (error) {
41
+ this.issues.push({
42
+ type: "invalid_value",
43
+ severity: "error",
44
+ message: `Failed to load configuration: ${error instanceof Error ? error.message : String(error)}`,
45
+ suggestion: "Check for syntax errors in the configuration file",
46
+ });
47
+ }
48
+
49
+ const hasErrors = this.issues.some((i) => i.severity === "error");
50
+
51
+ return {
52
+ valid: !hasErrors,
53
+ issues: this.issues,
54
+ };
55
+ }
56
+
57
+ private checkConfigureMarkers(source: string): void {
58
+ const configureRegex = /\/\*\s*CONFIGURE\s*\*\//g;
59
+ const matches = [...source.matchAll(configureRegex)];
60
+
61
+ if (matches.length > 0) {
62
+ // Find line numbers for each match
63
+ const lines = source.split("\n");
64
+ const locations: Array<{ line: number; column: number; context: string }> = [];
65
+
66
+ for (const match of matches) {
67
+ const position = match.index!;
68
+ const lineNumber = source.substring(0, position).split("\n").length;
69
+ const line = lines[lineNumber - 1];
70
+
71
+ // Extract field name from context
72
+ const fieldMatch = line.match(/"([^"]+)":\s*{/);
73
+ const fieldName = fieldMatch ? fieldMatch[1] : "unknown";
74
+
75
+ locations.push({
76
+ line: lineNumber,
77
+ column: match.index! - source.lastIndexOf("\n", position),
78
+ context: fieldName,
79
+ });
80
+ }
81
+
82
+ this.issues.push({
83
+ type: "incomplete",
84
+ severity: "error",
85
+ message: `Found ${matches.length} incomplete configuration marker(s)`,
86
+ suggestion: "Replace all /* CONFIGURE */ markers with actual values",
87
+ });
88
+
89
+ // Add individual issues for each marker
90
+ for (const loc of locations) {
91
+ this.issues.push({
92
+ type: "incomplete",
93
+ severity: "error",
94
+ field: loc.context,
95
+ location: { line: loc.line, column: loc.column },
96
+ message: `Incomplete configuration at line ${loc.line}`,
97
+ suggestion: `Fill in value for "${loc.context}"`,
98
+ });
99
+ }
100
+ }
101
+ }
102
+
103
+ private checkReviewMarkers(source: string): void {
104
+ const reviewRegex = /\/\*\s*REVIEW\s*\*\//g;
105
+ const matches = [...source.matchAll(reviewRegex)];
106
+
107
+ if (matches.length > 0) {
108
+ this.issues.push({
109
+ type: "incomplete",
110
+ severity: "warning",
111
+ message: `Found ${matches.length} value(s) that should be reviewed`,
112
+ suggestion: "Review auto-generated values marked with /* REVIEW */",
113
+ });
114
+ }
115
+ }
116
+
117
+ private loadConfig(configPath: string): VerificationConfig {
118
+ // Dynamic import of the config file
119
+ // Note: In production, this would use proper module loading
120
+ delete require.cache[require.resolve(path.resolve(configPath))];
121
+ const module = require(path.resolve(configPath));
122
+ return module.default || module;
123
+ }
124
+
125
+ private validateConfig(config: VerificationConfig): void {
126
+ // Check for null values
127
+ this.findNullPlaceholders(config.state, "state");
128
+ this.findNullPlaceholders(config.messages, "messages");
129
+
130
+ // Validate bounds
131
+ this.validateBounds(config);
132
+ }
133
+
134
+ private findNullPlaceholders(obj: any, path: string): void {
135
+ if (obj === null || obj === undefined) {
136
+ this.issues.push({
137
+ type: "null_placeholder",
138
+ severity: "error",
139
+ field: path,
140
+ message: `Configuration incomplete: ${path}`,
141
+ suggestion: "Replace null with a concrete value",
142
+ });
143
+ return;
144
+ }
145
+
146
+ if (typeof obj !== "object") {
147
+ return;
148
+ }
149
+
150
+ for (const [key, value] of Object.entries(obj)) {
151
+ const fullPath = `${path}.${key}`;
152
+
153
+ if (value === null) {
154
+ this.issues.push({
155
+ type: "null_placeholder",
156
+ severity: "error",
157
+ field: fullPath,
158
+ message: `Configuration incomplete: ${fullPath}`,
159
+ suggestion: "Replace null with a concrete value",
160
+ });
161
+ } else if (typeof value === "object" && value !== null && !Array.isArray(value)) {
162
+ this.findNullPlaceholders(value, fullPath);
163
+ }
164
+ }
165
+ }
166
+
167
+ private validateBounds(config: VerificationConfig): void {
168
+ // Check messages config
169
+ if (config.messages.maxInFlight !== null) {
170
+ if (config.messages.maxInFlight < 1) {
171
+ this.issues.push({
172
+ type: "invalid_value",
173
+ severity: "error",
174
+ field: "messages.maxInFlight",
175
+ message: "maxInFlight must be at least 1",
176
+ suggestion: "Use a value between 4-10 for most cases",
177
+ });
178
+ }
179
+
180
+ if (config.messages.maxInFlight > 20) {
181
+ this.issues.push({
182
+ type: "unrealistic_bound",
183
+ severity: "warning",
184
+ field: "messages.maxInFlight",
185
+ message: "Very high maxInFlight (>20) will slow verification significantly",
186
+ suggestion: "Use 4-10 for development, up to 20 for thorough verification",
187
+ });
188
+ }
189
+ }
190
+
191
+ if (config.messages.maxTabs !== null) {
192
+ if (config.messages.maxTabs < 1) {
193
+ this.issues.push({
194
+ type: "invalid_value",
195
+ severity: "error",
196
+ field: "messages.maxTabs",
197
+ message: "maxTabs must be at least 1",
198
+ suggestion: "Use 2-3 for most cases",
199
+ });
200
+ }
201
+
202
+ if (config.messages.maxTabs > 10) {
203
+ this.issues.push({
204
+ type: "unrealistic_bound",
205
+ severity: "warning",
206
+ field: "messages.maxTabs",
207
+ message: "Very high maxTabs (>10) will slow verification significantly",
208
+ suggestion: "Use 2-3 for most cases",
209
+ });
210
+ }
211
+ }
212
+
213
+ // Check state field bounds
214
+ for (const [fieldName, fieldConfig] of Object.entries(config.state)) {
215
+ if (typeof fieldConfig !== "object" || fieldConfig === null) {
216
+ continue;
217
+ }
218
+
219
+ // Array bounds
220
+ if ("maxLength" in fieldConfig) {
221
+ const maxLength = (fieldConfig as any).maxLength;
222
+ if (maxLength !== null) {
223
+ if (maxLength < 0) {
224
+ this.issues.push({
225
+ type: "invalid_value",
226
+ severity: "error",
227
+ field: `state.${fieldName}.maxLength`,
228
+ message: "maxLength cannot be negative",
229
+ suggestion: "Use a positive number",
230
+ });
231
+ }
232
+
233
+ if (maxLength > 50) {
234
+ this.issues.push({
235
+ type: "unrealistic_bound",
236
+ severity: "warning",
237
+ field: `state.${fieldName}.maxLength`,
238
+ message: `Very large maxLength (${maxLength}) will slow verification`,
239
+ suggestion: "Use 10-20 for most cases",
240
+ });
241
+ }
242
+ }
243
+ }
244
+
245
+ // Number bounds
246
+ if ("min" in fieldConfig && "max" in fieldConfig) {
247
+ const min = (fieldConfig as any).min;
248
+ const max = (fieldConfig as any).max;
249
+
250
+ if (min !== null && max !== null && min > max) {
251
+ this.issues.push({
252
+ type: "invalid_value",
253
+ severity: "error",
254
+ field: `state.${fieldName}`,
255
+ message: `Invalid range: min (${min}) > max (${max})`,
256
+ suggestion: "Ensure min is less than or equal to max",
257
+ });
258
+ }
259
+
260
+ if (min !== null && max !== null && max - min > 1000) {
261
+ this.issues.push({
262
+ type: "unrealistic_bound",
263
+ severity: "warning",
264
+ field: `state.${fieldName}`,
265
+ message: `Very large number range (${max - min}) will slow verification`,
266
+ suggestion: "Use smaller ranges when possible",
267
+ });
268
+ }
269
+ }
270
+
271
+ // Map/Set bounds
272
+ if ("maxSize" in fieldConfig) {
273
+ const maxSize = (fieldConfig as any).maxSize;
274
+ if (maxSize !== null) {
275
+ if (maxSize < 0) {
276
+ this.issues.push({
277
+ type: "invalid_value",
278
+ severity: "error",
279
+ field: `state.${fieldName}.maxSize`,
280
+ message: "maxSize cannot be negative",
281
+ suggestion: "Use a positive number",
282
+ });
283
+ }
284
+
285
+ if (maxSize > 20) {
286
+ this.issues.push({
287
+ type: "unrealistic_bound",
288
+ severity: "warning",
289
+ field: `state.${fieldName}.maxSize`,
290
+ message: `Very large maxSize (${maxSize}) will slow verification`,
291
+ suggestion: "Use 3-5 for most cases",
292
+ });
293
+ }
294
+ }
295
+ }
296
+ }
297
+ }
298
+ }
299
+
300
+ export function validateConfig(configPath: string): ValidationResult {
301
+ const validator = new ConfigValidator();
302
+ return validator.validate(configPath);
303
+ }
@@ -0,0 +1,113 @@
1
+ // ═══════════════════════════════════════════════════════════════
2
+ // Configuration Types for Adapter-Based Verification
3
+ // ═══════════════════════════════════════════════════════════════
4
+
5
+ import type { RoutingAdapter } from "../adapters/base";
6
+ import type { StateSchema } from "../core/model";
7
+
8
+ // ─────────────────────────────────────────────────────────────────
9
+ // New Adapter-Based Configuration
10
+ // ─────────────────────────────────────────────────────────────────
11
+
12
+ /**
13
+ * Adapter-based verification configuration (new format)
14
+ */
15
+ export interface AdapterVerificationConfig {
16
+ /** The routing adapter to use */
17
+ adapter: RoutingAdapter;
18
+
19
+ /** State bounds (domain-agnostic) */
20
+ state: StateSchema;
21
+
22
+ /** Concurrency bounds */
23
+ bounds?: {
24
+ maxInFlight?: number;
25
+ [key: string]: unknown;
26
+ };
27
+
28
+ /** Verification behavior on build */
29
+ onBuild?: "warn" | "error" | "off";
30
+
31
+ /** Verification behavior on release */
32
+ onRelease?: "warn" | "error" | "off";
33
+
34
+ /** Optional: Custom invariants */
35
+ invariants?: Array<{
36
+ name: string;
37
+ expression: string;
38
+ description?: string;
39
+ }>;
40
+ }
41
+
42
+ // ─────────────────────────────────────────────────────────────────
43
+ // Legacy Configuration (Backward Compatibility)
44
+ // ─────────────────────────────────────────────────────────────────
45
+
46
+ /**
47
+ * Legacy verification configuration (backward compatible)
48
+ */
49
+ export interface LegacyVerificationConfig {
50
+ /** State configuration (old format) */
51
+ state: Record<string, any>;
52
+
53
+ /** Message configuration (old format) */
54
+ messages: {
55
+ maxInFlight: number | null;
56
+ maxTabs: number | null;
57
+ };
58
+
59
+ /** Verification behavior on build */
60
+ onBuild: "warn" | "error" | "off";
61
+
62
+ /** Verification behavior on release */
63
+ onRelease: "warn" | "error" | "off";
64
+
65
+ /** Optional preset */
66
+ preset?: "quick" | "balanced" | "thorough";
67
+ }
68
+
69
+ // ─────────────────────────────────────────────────────────────────
70
+ // Unified Configuration Type
71
+ // ─────────────────────────────────────────────────────────────────
72
+
73
+ /**
74
+ * Union of new and legacy configuration formats
75
+ */
76
+ export type UnifiedVerificationConfig = AdapterVerificationConfig | LegacyVerificationConfig;
77
+
78
+ /**
79
+ * Type guard to check if config is adapter-based (new format)
80
+ */
81
+ export function isAdapterConfig(
82
+ config: UnifiedVerificationConfig
83
+ ): config is AdapterVerificationConfig {
84
+ return "adapter" in config;
85
+ }
86
+
87
+ /**
88
+ * Type guard to check if config is legacy format
89
+ */
90
+ export function isLegacyConfig(
91
+ config: UnifiedVerificationConfig
92
+ ): config is LegacyVerificationConfig {
93
+ return "messages" in config && !("adapter" in config);
94
+ }
95
+
96
+ // ─────────────────────────────────────────────────────────────────
97
+ // Configuration Validation
98
+ // ─────────────────────────────────────────────────────────────────
99
+
100
+ export interface ConfigIssue {
101
+ type: "incomplete" | "null_placeholder" | "unrealistic_bound" | "invalid_value";
102
+ severity: "error" | "warning";
103
+ field?: string;
104
+ location?: { line: number; column: number };
105
+ message: string;
106
+ suggestion: string;
107
+ }
108
+
109
+ export interface ValidationResult {
110
+ valid: boolean;
111
+ issues: ConfigIssue[];
112
+ configType?: "adapter" | "legacy";
113
+ }
@@ -0,0 +1,267 @@
1
+ // ═══════════════════════════════════════════════════════════════
2
+ // Core Verification Model (Domain-Agnostic)
3
+ // ═══════════════════════════════════════════════════════════════
4
+ //
5
+ // This module defines abstract types for any message-passing system.
6
+ // These types are independent of the specific domain (web extensions,
7
+ // actors, event buses, etc.).
8
+ //
9
+ // Adapters translate domain-specific code into this universal model.
10
+
11
+ // ─────────────────────────────────────────────────────────────────
12
+ // Type System (Universal)
13
+ // ─────────────────────────────────────────────────────────────────
14
+
15
+ export type TypeKind =
16
+ | "boolean"
17
+ | "string"
18
+ | "number"
19
+ | "enum"
20
+ | "array"
21
+ | "object"
22
+ | "map"
23
+ | "set"
24
+ | "union"
25
+ | "null"
26
+ | "unknown";
27
+
28
+ export type TypeInfo = {
29
+ name: string;
30
+ kind: TypeKind;
31
+ nullable: boolean;
32
+ elementType?: TypeInfo; // For arrays, sets
33
+ valueType?: TypeInfo; // For maps
34
+ properties?: Record<string, TypeInfo>; // For objects
35
+ enumValues?: string[]; // For enums
36
+ unionTypes?: TypeInfo[]; // For unions
37
+ };
38
+
39
+ // ─────────────────────────────────────────────────────────────────
40
+ // Node System (Abstract)
41
+ // ─────────────────────────────────────────────────────────────────
42
+
43
+ /**
44
+ * A node represents an entity in the system that can send/receive messages.
45
+ *
46
+ * Examples:
47
+ * - Web extension: "background", "content", "popup"
48
+ * - Actor system: Individual actor instances
49
+ * - Event bus: Emitters/listeners
50
+ * - Worker threads: Main thread + worker instances
51
+ */
52
+ export type NodeDefinition = {
53
+ /** Unique identifier for this node */
54
+ id: string;
55
+
56
+ /** Type of node (adapter-specific) */
57
+ type: string;
58
+
59
+ /** Which nodes can this send messages to? */
60
+ canSendTo: string[];
61
+
62
+ /** Which nodes can send messages to this? */
63
+ canReceiveFrom: string[];
64
+
65
+ /** Optional: Additional metadata */
66
+ metadata?: Record<string, unknown>;
67
+ };
68
+
69
+ // ─────────────────────────────────────────────────────────────────
70
+ // Message Types (Abstract)
71
+ // ─────────────────────────────────────────────────────────────────
72
+
73
+ /**
74
+ * Defines a type of message that flows through the system
75
+ */
76
+ export type MessageType = {
77
+ /** Name/identifier of the message type */
78
+ name: string;
79
+
80
+ /** Schema of the message payload */
81
+ payload: TypeInfo;
82
+
83
+ /** Routing constraints */
84
+ routing: {
85
+ /** Which node types can send this message? */
86
+ from: string[];
87
+
88
+ /** Which node types can receive this message? */
89
+ to: string[];
90
+ };
91
+
92
+ /** Optional: Expected response type */
93
+ response?: TypeInfo;
94
+ };
95
+
96
+ // ─────────────────────────────────────────────────────────────────
97
+ // Routing Rules (Abstract)
98
+ // ─────────────────────────────────────────────────────────────────
99
+
100
+ export type RoutingPattern =
101
+ | "direct" // Point-to-point (actor.send)
102
+ | "broadcast" // One-to-many (event bus)
103
+ | "request-reply" // Request-response (extension messaging)
104
+ | "publish-subscribe" // Pub/sub pattern
105
+ | "custom"; // Adapter-defined
106
+
107
+ export type RoutingRule = {
108
+ /** Type of routing pattern */
109
+ pattern: RoutingPattern;
110
+
111
+ /** Which message types use this routing? */
112
+ messageTypes: string[];
113
+
114
+ /** Optional: Custom routing logic description */
115
+ description?: string;
116
+ };
117
+
118
+ // ─────────────────────────────────────────────────────────────────
119
+ // State Schema (Abstract)
120
+ // ─────────────────────────────────────────────────────────────────
121
+
122
+ /**
123
+ * Configuration for a state field
124
+ */
125
+ export type FieldConfig =
126
+ | { maxLength: number | null }
127
+ | { min: number | null; max: number | null }
128
+ | { type: "enum"; values: string[] }
129
+ | { values: string[] | null; abstract?: boolean }
130
+ | { maxSize: number | null; valueType?: unknown }
131
+ | { abstract: boolean };
132
+
133
+ export type StateSchema = Record<string, FieldConfig>;
134
+
135
+ // ─────────────────────────────────────────────────────────────────
136
+ // State Mutations (Abstract)
137
+ // ─────────────────────────────────────────────────────────────────
138
+
139
+ /**
140
+ * Represents an assignment to a state field
141
+ */
142
+ export type StateAssignment = {
143
+ /** Field path (e.g., "user.loggedIn") */
144
+ field: string;
145
+
146
+ /** The assigned value */
147
+ value: string | boolean | number | null;
148
+
149
+ /** Optional condition guard */
150
+ conditional?: string;
151
+ };
152
+
153
+ // ─────────────────────────────────────────────────────────────────
154
+ // Verification Conditions (Abstract)
155
+ // ─────────────────────────────────────────────────────────────────
156
+
157
+ /**
158
+ * A verification condition (precondition or postcondition)
159
+ */
160
+ export type VerificationCondition = {
161
+ /** The condition expression as a string */
162
+ expression: string;
163
+
164
+ /** Optional error message */
165
+ message?: string;
166
+
167
+ /** Source location */
168
+ location: {
169
+ line: number;
170
+ column: number;
171
+ };
172
+ };
173
+
174
+ // ─────────────────────────────────────────────────────────────────
175
+ // Message Handler (Abstract)
176
+ // ─────────────────────────────────────────────────────────────────
177
+
178
+ /**
179
+ * Represents a message handler extracted from code
180
+ */
181
+ export type MessageHandler = {
182
+ /** Which message type does this handle? */
183
+ messageType: string;
184
+
185
+ /** Which node handles this message? */
186
+ node: string;
187
+
188
+ /** State assignments made by this handler */
189
+ assignments: StateAssignment[];
190
+
191
+ /** Preconditions (requires() calls) */
192
+ preconditions: VerificationCondition[];
193
+
194
+ /** Postconditions (ensures() calls) */
195
+ postconditions: VerificationCondition[];
196
+
197
+ /** Source location */
198
+ location: {
199
+ file: string;
200
+ line: number;
201
+ };
202
+ };
203
+
204
+ // ─────────────────────────────────────────────────────────────────
205
+ // Complete Verification Model (Abstract)
206
+ // ─────────────────────────────────────────────────────────────────
207
+
208
+ /**
209
+ * The complete abstract model that the core verification engine operates on.
210
+ * This is what adapters produce from domain-specific code.
211
+ */
212
+ export type CoreVerificationModel = {
213
+ /** All nodes in the system */
214
+ nodes: NodeDefinition[];
215
+
216
+ /** All message types that flow between nodes */
217
+ messageTypes: MessageType[];
218
+
219
+ /** Routing rules that govern message delivery */
220
+ routingRules: RoutingRule[];
221
+
222
+ /** State schema with bounds */
223
+ state: StateSchema;
224
+
225
+ /** All message handlers extracted from code */
226
+ handlers: MessageHandler[];
227
+
228
+ /** Concurrency bounds for model checking */
229
+ bounds: {
230
+ /** Maximum concurrent messages in flight */
231
+ maxConcurrentMessages: number;
232
+
233
+ /** Maximum number of nodes (for bounded model checking) */
234
+ maxNodes: number;
235
+
236
+ /** Optional: Adapter-specific bounds */
237
+ custom?: Record<string, number>;
238
+ };
239
+ };
240
+
241
+ // ─────────────────────────────────────────────────────────────────
242
+ // Confidence Levels (Universal)
243
+ // ─────────────────────────────────────────────────────────────────
244
+
245
+ export type Confidence = "high" | "medium" | "low";
246
+
247
+ export type FieldAnalysis = {
248
+ path: string;
249
+ type: TypeInfo;
250
+ confidence: Confidence;
251
+ evidence: string[];
252
+ suggestions: string[];
253
+ bounds?: {
254
+ min?: number;
255
+ max?: number;
256
+ maxLength?: number;
257
+ maxSize?: number;
258
+ values?: string[];
259
+ };
260
+ };
261
+
262
+ export type CodebaseAnalysis = {
263
+ stateType: TypeInfo | null;
264
+ messageTypes: string[];
265
+ fields: FieldAnalysis[];
266
+ handlers: MessageHandler[];
267
+ };