flakelab 0.1.0 → 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.
- package/README.md +225 -38
- package/dist/analysis/blob-report.d.ts +15 -0
- package/dist/analysis/blob-report.js +137 -0
- package/dist/analysis/blob-report.js.map +1 -0
- package/dist/analysis/cli.d.ts +7 -0
- package/dist/analysis/cli.js +28 -0
- package/dist/analysis/cli.js.map +1 -0
- package/dist/analysis/schema.d.ts +175 -0
- package/dist/analysis/schema.js +34 -0
- package/dist/analysis/schema.js.map +1 -0
- package/dist/analysis/zip-archive.d.ts +6 -0
- package/dist/analysis/zip-archive.js +193 -0
- package/dist/analysis/zip-archive.js.map +1 -0
- package/dist/artifacts/paths.d.ts +3 -0
- package/dist/artifacts/paths.js +34 -0
- package/dist/artifacts/paths.js.map +1 -0
- package/dist/artifacts/retention.d.ts +1 -0
- package/dist/artifacts/retention.js +80 -0
- package/dist/artifacts/retention.js.map +1 -0
- package/dist/bisect/engine.js +0 -1
- package/dist/bisect/engine.js.map +1 -1
- package/dist/bisect/schema.d.ts +5 -6
- package/dist/bisect/schema.js +1 -2
- package/dist/bisect/schema.js.map +1 -1
- package/dist/bisect/solari-evaluator.js +9 -1
- package/dist/bisect/solari-evaluator.js.map +1 -1
- package/dist/ci/job-summary.d.ts +2 -0
- package/dist/ci/job-summary.js +120 -2
- package/dist/ci/job-summary.js.map +1 -1
- package/dist/ci/select-command.js +1 -1
- package/dist/ci/select-command.js.map +1 -1
- package/dist/ci/summary-command.js +12 -7
- package/dist/ci/summary-command.js.map +1 -1
- package/dist/cli-arguments.d.ts +44 -0
- package/dist/cli-arguments.js +356 -0
- package/dist/cli-arguments.js.map +1 -0
- package/dist/cli-command-help.d.ts +11 -0
- package/dist/cli-command-help.js +211 -0
- package/dist/cli-command-help.js.map +1 -0
- package/dist/cli-help.d.ts +5 -2
- package/dist/cli-help.js +122 -45
- package/dist/cli-help.js.map +1 -1
- package/dist/cli-option-definitions.d.ts +202 -0
- package/dist/cli-option-definitions.js +59 -0
- package/dist/cli-option-definitions.js.map +1 -0
- package/dist/cli.js +100 -100
- package/dist/cli.js.map +1 -1
- package/dist/commands/analyze-summary.d.ts +5 -0
- package/dist/commands/analyze-summary.js +89 -0
- package/dist/commands/analyze-summary.js.map +1 -0
- package/dist/commands/analyze.d.ts +6 -0
- package/dist/commands/analyze.js +128 -0
- package/dist/commands/analyze.js.map +1 -0
- package/dist/commands/bisect.d.ts +2 -2
- package/dist/commands/bisect.js +32 -3
- package/dist/commands/bisect.js.map +1 -1
- package/dist/commands/diagnose.d.ts +3 -2
- package/dist/commands/diagnose.js +355 -23
- package/dist/commands/diagnose.js.map +1 -1
- package/dist/commands/discover.d.ts +18 -2
- package/dist/commands/discover.js +215 -25
- package/dist/commands/discover.js.map +1 -1
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.js +66 -25
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/investigate.d.ts +3 -2
- package/dist/commands/investigate.js +22 -3
- package/dist/commands/investigate.js.map +1 -1
- package/dist/commands/options.d.ts +123 -16
- package/dist/commands/options.js +24 -2
- package/dist/commands/options.js.map +1 -1
- package/dist/commands/prove.d.ts +2 -2
- package/dist/commands/prove.js +38 -1
- package/dist/commands/prove.js.map +1 -1
- package/dist/commands/repair.d.ts +8 -2
- package/dist/commands/repair.js +32 -9
- package/dist/commands/repair.js.map +1 -1
- package/dist/commands/replay.d.ts +2 -2
- package/dist/commands/replay.js +15 -2
- package/dist/commands/replay.js.map +1 -1
- package/dist/commands/report.d.ts +2 -2
- package/dist/commands/report.js +35 -10
- package/dist/commands/report.js.map +1 -1
- package/dist/commands/scan-summary.d.ts +7 -0
- package/dist/commands/scan-summary.js +175 -0
- package/dist/commands/scan-summary.js.map +1 -0
- package/dist/commands/scan.d.ts +9 -12
- package/dist/commands/scan.js +66 -62
- package/dist/commands/scan.js.map +1 -1
- package/dist/core/plan.js +1 -1
- package/dist/core/plan.js.map +1 -1
- package/dist/diagnosis/checkpoint.d.ts +6 -0
- package/dist/diagnosis/checkpoint.js +46 -0
- package/dist/diagnosis/checkpoint.js.map +1 -0
- package/dist/diagnosis/cli.d.ts +7 -0
- package/dist/diagnosis/cli.js +84 -0
- package/dist/diagnosis/cli.js.map +1 -0
- package/dist/diagnosis/recommendation.d.ts +13 -0
- package/dist/diagnosis/recommendation.js +95 -0
- package/dist/diagnosis/recommendation.js.map +1 -0
- package/dist/diagnosis/run-state.d.ts +52 -0
- package/dist/diagnosis/run-state.js +173 -0
- package/dist/diagnosis/run-state.js.map +1 -0
- package/dist/diagnosis/schema.d.ts +207 -0
- package/dist/diagnosis/schema.js +108 -0
- package/dist/diagnosis/schema.js.map +1 -0
- package/dist/diagnosis/solari-handoff.d.ts +9 -0
- package/dist/diagnosis/solari-handoff.js +40 -0
- package/dist/diagnosis/solari-handoff.js.map +1 -0
- package/dist/diagnosis/summary.d.ts +3 -0
- package/dist/diagnosis/summary.js +115 -0
- package/dist/diagnosis/summary.js.map +1 -0
- package/dist/discovery/auth-cookie.d.ts +19 -0
- package/dist/discovery/auth-cookie.js +26 -0
- package/dist/discovery/auth-cookie.js.map +1 -0
- package/dist/discovery/evaluate.d.ts +35 -2
- package/dist/discovery/evaluate.js +136 -30
- package/dist/discovery/evaluate.js.map +1 -1
- package/dist/discovery/event-loop.d.ts +25 -0
- package/dist/discovery/event-loop.js +84 -0
- package/dist/discovery/event-loop.js.map +1 -0
- package/dist/discovery/minimize.d.ts +61 -1
- package/dist/discovery/minimize.js +179 -7
- package/dist/discovery/minimize.js.map +1 -1
- package/dist/discovery/resource-loading.d.ts +25 -0
- package/dist/discovery/resource-loading.js +84 -0
- package/dist/discovery/resource-loading.js.map +1 -0
- package/dist/discovery/runner-environment.d.ts +26 -0
- package/dist/discovery/runner-environment.js +68 -0
- package/dist/discovery/runner-environment.js.map +1 -0
- package/dist/discovery/startup-event.d.ts +25 -0
- package/dist/discovery/startup-event.js +84 -0
- package/dist/discovery/startup-event.js.map +1 -0
- package/dist/discovery/storage-state.d.ts +26 -0
- package/dist/discovery/storage-state.js +86 -0
- package/dist/discovery/storage-state.js.map +1 -0
- package/dist/discovery/temporal-environment.d.ts +31 -0
- package/dist/discovery/temporal-environment.js +43 -0
- package/dist/discovery/temporal-environment.js.map +1 -0
- package/dist/discovery/visual-environment.d.ts +28 -0
- package/dist/discovery/visual-environment.js +42 -0
- package/dist/discovery/visual-environment.js.map +1 -0
- package/dist/domain/schema.d.ts +840 -20
- package/dist/domain/schema.js +216 -6
- package/dist/domain/schema.js.map +1 -1
- package/dist/faults/browser-context.d.ts +16 -0
- package/dist/faults/browser-context.js +60 -0
- package/dist/faults/browser-context.js.map +1 -0
- package/dist/faults/cookie-header.d.ts +5 -0
- package/dist/faults/cookie-header.js +25 -0
- package/dist/faults/cookie-header.js.map +1 -0
- package/dist/faults/document-bootstrap.d.ts +5 -0
- package/dist/faults/document-bootstrap.js +141 -0
- package/dist/faults/document-bootstrap.js.map +1 -0
- package/dist/faults/install.d.ts +1 -1
- package/dist/faults/install.js +199 -6
- package/dist/faults/install.js.map +1 -1
- package/dist/faults/pattern.d.ts +1 -0
- package/dist/faults/pattern.js +24 -0
- package/dist/faults/pattern.js.map +1 -0
- package/dist/investigator/agent.js +39 -17
- package/dist/investigator/agent.js.map +1 -1
- package/dist/investigator/ledger.d.ts +1 -1
- package/dist/investigator/ledger.js +2 -2
- package/dist/investigator/ledger.js.map +1 -1
- package/dist/investigator/safe-source.d.ts +1 -0
- package/dist/investigator/safe-source.js +12 -3
- package/dist/investigator/safe-source.js.map +1 -1
- package/dist/investigator/schema.d.ts +293 -2
- package/dist/investigator/schema.js +100 -2
- package/dist/investigator/schema.js.map +1 -1
- package/dist/proof/cli.d.ts +7 -0
- package/dist/proof/cli.js +108 -0
- package/dist/proof/cli.js.map +1 -0
- package/dist/proof/preflight.d.ts +4 -0
- package/dist/proof/preflight.js +9 -0
- package/dist/proof/preflight.js.map +1 -0
- package/dist/repair/generator.d.ts +12 -1
- package/dist/repair/generator.js +30 -6
- package/dist/repair/generator.js.map +1 -1
- package/dist/repair/remote-proof-runner.js +6 -10
- package/dist/repair/remote-proof-runner.js.map +1 -1
- package/dist/repair/schema.d.ts +77 -2
- package/dist/repair/schema.js +23 -2
- package/dist/repair/schema.js.map +1 -1
- package/dist/repair/solari-validator.d.ts +2 -0
- package/dist/repair/solari-validator.js +4 -6
- package/dist/repair/solari-validator.js.map +1 -1
- package/dist/repair/summary.d.ts +10 -0
- package/dist/repair/summary.js +58 -0
- package/dist/repair/summary.js.map +1 -0
- package/dist/repair/validator.d.ts +1 -0
- package/dist/repair/validator.js +53 -12
- package/dist/repair/validator.js.map +1 -1
- package/dist/report/bundle.js +16 -37
- package/dist/report/bundle.js.map +1 -1
- package/dist/report/model.js +131 -12
- package/dist/report/model.js.map +1 -1
- package/dist/report/open.d.ts +9 -0
- package/dist/report/open.js +23 -0
- package/dist/report/open.js.map +1 -1
- package/dist/report/report-client.css +2 -0
- package/dist/report/report-client.js +58 -0
- package/dist/report/schema.d.ts +115 -5
- package/dist/report/schema.js +24 -5
- package/dist/report/schema.js.map +1 -1
- package/dist/reproducer/schema.d.ts +89 -4
- package/dist/reproducer/schema.js +3 -4
- package/dist/reproducer/schema.js.map +1 -1
- package/dist/runner/execution-fault.d.ts +10 -0
- package/dist/runner/execution-fault.js +24 -0
- package/dist/runner/execution-fault.js.map +1 -0
- package/dist/runner/fault-proxy.d.ts +7 -0
- package/dist/runner/fault-proxy.js +366 -0
- package/dist/runner/fault-proxy.js.map +1 -0
- package/dist/runner/local.js +2 -2
- package/dist/runner/local.js.map +1 -1
- package/dist/runner/native-scan.d.ts +25 -0
- package/dist/runner/native-scan.js +306 -0
- package/dist/runner/native-scan.js.map +1 -0
- package/dist/runner/playwright-executor.d.ts +3 -0
- package/dist/runner/playwright-executor.js +125 -66
- package/dist/runner/playwright-executor.js.map +1 -1
- package/dist/runner/process-tree.d.ts +7 -0
- package/dist/runner/process-tree.js +62 -0
- package/dist/runner/process-tree.js.map +1 -0
- package/dist/runner/project-bridge.d.ts +7 -0
- package/dist/runner/project-bridge.js +83 -0
- package/dist/runner/project-bridge.js.map +1 -0
- package/dist/runner/trial-reporter.d.ts +7 -0
- package/dist/runner/trial-reporter.js +47 -0
- package/dist/runner/trial-reporter.js.map +1 -0
- package/dist/scan/failure-clusters.d.ts +24 -0
- package/dist/scan/failure-clusters.js +74 -0
- package/dist/scan/failure-clusters.js.map +1 -0
- package/dist/scan/schema.d.ts +170 -0
- package/dist/scan/schema.js +71 -0
- package/dist/scan/schema.js.map +1 -0
- package/dist/solari/executor.d.ts +5 -1
- package/dist/solari/executor.js +25 -17
- package/dist/solari/executor.js.map +1 -1
- package/dist/solari/run-demo.d.ts +13 -1
- package/dist/solari/run-demo.js +35 -16
- package/dist/solari/run-demo.js.map +1 -1
- package/dist/solari/usage.d.ts +8 -2
- package/dist/solari/usage.js +14 -4
- package/dist/solari/usage.js.map +1 -1
- package/dist/ui/boundary.d.ts +17 -0
- package/dist/ui/boundary.js +18 -0
- package/dist/ui/boundary.js.map +1 -0
- package/dist/ui/console.d.ts +4 -0
- package/dist/ui/console.js +11 -0
- package/dist/ui/console.js.map +1 -0
- package/dist/ui/document.d.ts +40 -0
- package/dist/ui/document.js +120 -0
- package/dist/ui/document.js.map +1 -0
- package/dist/ui/format.d.ts +8 -0
- package/dist/ui/format.js +32 -0
- package/dist/ui/format.js.map +1 -0
- package/dist/ui/progress.d.ts +17 -1
- package/dist/ui/progress.js +51 -8
- package/dist/ui/progress.js.map +1 -1
- package/dist/ui/status.d.ts +7 -0
- package/dist/ui/status.js +36 -0
- package/dist/ui/status.js.map +1 -0
- package/dist/ui/style.d.ts +8 -0
- package/dist/ui/style.js +22 -0
- package/dist/ui/style.js.map +1 -0
- package/dist/ui/text.d.ts +17 -0
- package/dist/ui/text.js +123 -0
- package/dist/ui/text.js.map +1 -0
- package/dist/ui/theme.d.ts +23 -0
- package/dist/ui/theme.js +77 -0
- package/dist/ui/theme.js.map +1 -0
- package/dist/ui/trial-progress.d.ts +13 -0
- package/dist/ui/trial-progress.js +42 -0
- package/dist/ui/trial-progress.js.map +1 -0
- package/package.json +14 -19
- package/dist/faults/network-delay.d.ts +0 -5
- package/dist/faults/network-delay.js +0 -34
- package/dist/faults/network-delay.js.map +0 -1
- package/dist/faults/request-failure.d.ts +0 -5
- package/dist/faults/request-failure.js +0 -24
- package/dist/faults/request-failure.js.map +0 -1
- package/dist/playwright.d.ts +0 -3
- package/dist/playwright.js +0 -21
- package/dist/playwright.js.map +0 -1
- package/dist/report/browser-entry.d.ts +0 -2
- package/dist/report/browser-entry.js +0 -15
- package/dist/report/browser-entry.js.map +0 -1
- package/dist/report/components/artifacts.d.ts +0 -4
- package/dist/report/components/artifacts.js +0 -6
- package/dist/report/components/artifacts.js.map +0 -1
- package/dist/report/components/experiments.d.ts +0 -4
- package/dist/report/components/experiments.js +0 -7
- package/dist/report/components/experiments.js.map +0 -1
- package/dist/report/components/hypotheses.d.ts +0 -4
- package/dist/report/components/hypotheses.js +0 -26
- package/dist/report/components/hypotheses.js.map +0 -1
- package/dist/report/components/indicators.d.ts +0 -32
- package/dist/report/components/indicators.js +0 -42
- package/dist/report/components/indicators.js.map +0 -1
- package/dist/report/components/layout.d.ts +0 -29
- package/dist/report/components/layout.js +0 -20
- package/dist/report/components/layout.js.map +0 -1
- package/dist/report/components/proof.d.ts +0 -4
- package/dist/report/components/proof.js +0 -34
- package/dist/report/components/proof.js.map +0 -1
- package/dist/report/components/reproduction.d.ts +0 -4
- package/dist/report/components/reproduction.js +0 -19
- package/dist/report/components/reproduction.js.map +0 -1
- package/dist/report/components/summary.d.ts +0 -4
- package/dist/report/components/summary.js +0 -12
- package/dist/report/components/summary.js.map +0 -1
- package/dist/report/components/verdict.d.ts +0 -4
- package/dist/report/components/verdict.js +0 -27
- package/dist/report/components/verdict.js.map +0 -1
- package/dist/report/report-app.d.ts +0 -6
- package/dist/report/report-app.js +0 -16
- package/dist/report/report-app.js.map +0 -1
- package/dist/report/report-details.css +0 -182
- package/dist/report/report.css +0 -404
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { createCausalEvaluator } from "./evaluate.js";
|
|
2
|
+
const MINIMUM_CONFIRMATION_TRIALS = 12;
|
|
3
|
+
async function confirmBoundary(experiments, minimumDurationMs, evaluateDuration, confirmationTrials) {
|
|
4
|
+
const candidates = [...new Set(experiments
|
|
5
|
+
.filter((entry) => entry.durationMs >= minimumDurationMs && entry.result.confirmed)
|
|
6
|
+
.map((entry) => entry.durationMs))]
|
|
7
|
+
.sort((left, right) => left - right);
|
|
8
|
+
for (const durationMs of candidates) {
|
|
9
|
+
const result = await evaluateDuration(durationMs, confirmationTrials);
|
|
10
|
+
if (result.confirmed) {
|
|
11
|
+
return { durationMs, result };
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
throw new Error("No event-loop stall reproduced the failure in two independent batches");
|
|
15
|
+
}
|
|
16
|
+
async function confirmStableTrigger(minimumDurationMs, maximumDurationMs, evaluateDuration, confirmationTrials) {
|
|
17
|
+
const durationMs = Math.ceil((minimumDurationMs + maximumDurationMs) / 2);
|
|
18
|
+
const result = await evaluateDuration(durationMs, confirmationTrials);
|
|
19
|
+
if (result.confirmed) {
|
|
20
|
+
return { durationMs, result };
|
|
21
|
+
}
|
|
22
|
+
if (durationMs === maximumDurationMs) {
|
|
23
|
+
throw new Error("No stable event-loop stall reproducer was found within the configured bound");
|
|
24
|
+
}
|
|
25
|
+
const maximumResult = await evaluateDuration(maximumDurationMs, confirmationTrials);
|
|
26
|
+
if (!maximumResult.confirmed) {
|
|
27
|
+
throw new Error("No stable event-loop stall reproducer was found within the configured bound");
|
|
28
|
+
}
|
|
29
|
+
return { durationMs: maximumDurationMs, result: maximumResult };
|
|
30
|
+
}
|
|
31
|
+
export async function discoverEventLoopStall(execute, options) {
|
|
32
|
+
const common = {
|
|
33
|
+
concurrency: options.concurrency,
|
|
34
|
+
minimumFailureRate: options.minimumFailureRate,
|
|
35
|
+
seed: options.seed,
|
|
36
|
+
signal: options.signal,
|
|
37
|
+
trials: options.trials,
|
|
38
|
+
};
|
|
39
|
+
const evaluator = createCausalEvaluator(execute, common);
|
|
40
|
+
const experiments = [];
|
|
41
|
+
const evaluateDuration = async (durationMs, trials = options.trials) => {
|
|
42
|
+
const fault = {
|
|
43
|
+
kind: "event-loop-stall",
|
|
44
|
+
durationMs,
|
|
45
|
+
pattern: options.pattern,
|
|
46
|
+
startAfterMs: options.startAfterMs,
|
|
47
|
+
};
|
|
48
|
+
const result = await evaluator.evaluate([fault], trials);
|
|
49
|
+
experiments.push({ durationMs, result });
|
|
50
|
+
return result;
|
|
51
|
+
};
|
|
52
|
+
const maximum = await evaluateDuration(options.maximumDurationMs);
|
|
53
|
+
if (!maximum.confirmed) {
|
|
54
|
+
throw new Error("Maximum event-loop stall did not reproduce the failure confidently");
|
|
55
|
+
}
|
|
56
|
+
let passingDurationMs = 0;
|
|
57
|
+
let failingDurationMs = options.maximumDurationMs;
|
|
58
|
+
while (failingDurationMs - passingDurationMs > 1) {
|
|
59
|
+
const candidate = Math.floor((passingDurationMs + failingDurationMs) / 2);
|
|
60
|
+
const result = await evaluateDuration(candidate);
|
|
61
|
+
if (result.confirmed) {
|
|
62
|
+
failingDurationMs = candidate;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
passingDurationMs = candidate;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const confirmationTrials = Math.max(options.trials, MINIMUM_CONFIRMATION_TRIALS);
|
|
69
|
+
const minimum = await confirmBoundary(experiments, failingDurationMs, evaluateDuration, confirmationTrials);
|
|
70
|
+
const stable = await confirmStableTrigger(minimum.durationMs, options.maximumDurationMs, evaluateDuration, confirmationTrials);
|
|
71
|
+
return {
|
|
72
|
+
baseline: evaluator.baseline(),
|
|
73
|
+
experiments,
|
|
74
|
+
minimumDurationMs: minimum.durationMs,
|
|
75
|
+
trigger: {
|
|
76
|
+
kind: "event-loop-stall",
|
|
77
|
+
durationMs: stable.durationMs,
|
|
78
|
+
pattern: options.pattern,
|
|
79
|
+
startAfterMs: options.startAfterMs,
|
|
80
|
+
},
|
|
81
|
+
triggerResult: stable.result,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=event-loop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-loop.js","sourceRoot":"","sources":["../../src/discovery/event-loop.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { NetworkDelayFault } from "../domain/schema.js";
|
|
1
|
+
import type { NetworkDelayFault, ResponseDuplicationFault, ResponseReorderingFault, ResponseTruncationFault } from "../domain/schema.js";
|
|
2
2
|
import type { TrialExecutor } from "../runner/playwright-executor.js";
|
|
3
3
|
import type { ExperimentResult } from "./evaluate.js";
|
|
4
4
|
export interface DelayDiscoveryOptions {
|
|
@@ -20,5 +20,65 @@ export interface DelayDiscoveryResult {
|
|
|
20
20
|
trigger: NetworkDelayFault;
|
|
21
21
|
triggerResult: ExperimentResult;
|
|
22
22
|
}
|
|
23
|
+
export interface TruncationDiscoveryOptions {
|
|
24
|
+
concurrency: number;
|
|
25
|
+
maximumRemoveBytes: number;
|
|
26
|
+
minimumFailureRate: number;
|
|
27
|
+
pattern: string;
|
|
28
|
+
seed: number;
|
|
29
|
+
signal?: AbortSignal;
|
|
30
|
+
trials: number;
|
|
31
|
+
}
|
|
32
|
+
export interface TruncationExperiment {
|
|
33
|
+
removeBytes: number;
|
|
34
|
+
result: ExperimentResult;
|
|
35
|
+
}
|
|
36
|
+
export interface TruncationDiscoveryResult {
|
|
37
|
+
baseline: ExperimentResult;
|
|
38
|
+
experiments: TruncationExperiment[];
|
|
39
|
+
trigger: ResponseTruncationFault;
|
|
40
|
+
triggerResult: ExperimentResult;
|
|
41
|
+
}
|
|
42
|
+
export interface DuplicationDiscoveryOptions {
|
|
43
|
+
concurrency: number;
|
|
44
|
+
maximumDuplicateBytes: number;
|
|
45
|
+
minimumFailureRate: number;
|
|
46
|
+
pattern: string;
|
|
47
|
+
seed: number;
|
|
48
|
+
signal?: AbortSignal;
|
|
49
|
+
trials: number;
|
|
50
|
+
}
|
|
51
|
+
export interface DuplicationExperiment {
|
|
52
|
+
duplicateBytes: number;
|
|
53
|
+
result: ExperimentResult;
|
|
54
|
+
}
|
|
55
|
+
export interface DuplicationDiscoveryResult {
|
|
56
|
+
baseline: ExperimentResult;
|
|
57
|
+
experiments: DuplicationExperiment[];
|
|
58
|
+
trigger: ResponseDuplicationFault;
|
|
59
|
+
triggerResult: ExperimentResult;
|
|
60
|
+
}
|
|
61
|
+
export interface ReorderingDiscoveryOptions {
|
|
62
|
+
concurrency: number;
|
|
63
|
+
maximumHoldMs: number;
|
|
64
|
+
minimumFailureRate: number;
|
|
65
|
+
pattern: string;
|
|
66
|
+
seed: number;
|
|
67
|
+
signal?: AbortSignal;
|
|
68
|
+
trials: number;
|
|
69
|
+
}
|
|
70
|
+
export interface ReorderingExperiment {
|
|
71
|
+
holdMs: number;
|
|
72
|
+
result: ExperimentResult;
|
|
73
|
+
}
|
|
74
|
+
export interface ReorderingDiscoveryResult {
|
|
75
|
+
baseline: ExperimentResult;
|
|
76
|
+
experiments: ReorderingExperiment[];
|
|
77
|
+
trigger: ResponseReorderingFault;
|
|
78
|
+
triggerResult: ExperimentResult;
|
|
79
|
+
}
|
|
23
80
|
export declare function minimizeItems<T>(values: readonly T[], reproduces: (candidate: readonly T[]) => Promise<boolean>): Promise<T[]>;
|
|
24
81
|
export declare function discoverNetworkDelay(execute: TrialExecutor, options: DelayDiscoveryOptions): Promise<DelayDiscoveryResult>;
|
|
82
|
+
export declare function discoverResponseTruncation(execute: TrialExecutor, options: TruncationDiscoveryOptions): Promise<TruncationDiscoveryResult>;
|
|
83
|
+
export declare function discoverResponseDuplication(execute: TrialExecutor, options: DuplicationDiscoveryOptions): Promise<DuplicationDiscoveryResult>;
|
|
84
|
+
export declare function discoverResponseReordering(execute: TrialExecutor, options: ReorderingDiscoveryOptions): Promise<ReorderingDiscoveryResult>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createCausalEvaluator } from "./evaluate.js";
|
|
2
2
|
const MINIMUM_CONFIRMATION_TRIALS = 12;
|
|
3
3
|
async function confirmStableDelay(experiments, minimumDelayMs, evaluateDelay, confirmationTrials) {
|
|
4
4
|
const candidates = [...new Set(experiments
|
|
@@ -35,14 +35,11 @@ export async function discoverNetworkDelay(execute, options) {
|
|
|
35
35
|
signal: options.signal,
|
|
36
36
|
trials: options.trials,
|
|
37
37
|
};
|
|
38
|
-
const
|
|
39
|
-
if (baseline.failureRate > 0) {
|
|
40
|
-
throw new Error("Baseline failures must be resolved before fault minimization");
|
|
41
|
-
}
|
|
38
|
+
const evaluator = createCausalEvaluator(execute, common);
|
|
42
39
|
const experiments = [];
|
|
43
40
|
const evaluateDelay = async (delayMs, trials = options.trials) => {
|
|
44
41
|
const fault = { kind: "network-delay", pattern: options.pattern, delayMs };
|
|
45
|
-
const result = await
|
|
42
|
+
const result = await evaluator.evaluate([fault], trials);
|
|
46
43
|
experiments.push({ delayMs, result });
|
|
47
44
|
return result;
|
|
48
45
|
};
|
|
@@ -64,10 +61,185 @@ export async function discoverNetworkDelay(execute, options) {
|
|
|
64
61
|
}
|
|
65
62
|
const stable = await confirmStableDelay(experiments, failingDelayMs, evaluateDelay, Math.max(options.trials, MINIMUM_CONFIRMATION_TRIALS));
|
|
66
63
|
return {
|
|
67
|
-
baseline,
|
|
64
|
+
baseline: evaluator.baseline(),
|
|
68
65
|
experiments,
|
|
69
66
|
trigger: { kind: "network-delay", pattern: options.pattern, delayMs: stable.delayMs },
|
|
70
67
|
triggerResult: stable.result,
|
|
71
68
|
};
|
|
72
69
|
}
|
|
70
|
+
async function confirmStableTruncation(experiments, minimumRemoveBytes, evaluateRemoval, confirmationTrials) {
|
|
71
|
+
const candidates = [...new Set(experiments
|
|
72
|
+
.filter((entry) => entry.removeBytes >= minimumRemoveBytes && entry.result.confirmed)
|
|
73
|
+
.map((entry) => entry.removeBytes))]
|
|
74
|
+
.sort((left, right) => left - right);
|
|
75
|
+
for (const removeBytes of candidates) {
|
|
76
|
+
const result = await evaluateRemoval(removeBytes, confirmationTrials);
|
|
77
|
+
if (result.confirmed) {
|
|
78
|
+
return { removeBytes, result };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
throw new Error("No response truncation reproduced the failure in two independent trial batches");
|
|
82
|
+
}
|
|
83
|
+
export async function discoverResponseTruncation(execute, options) {
|
|
84
|
+
const common = {
|
|
85
|
+
concurrency: options.concurrency,
|
|
86
|
+
minimumFailureRate: options.minimumFailureRate,
|
|
87
|
+
seed: options.seed,
|
|
88
|
+
signal: options.signal,
|
|
89
|
+
trials: options.trials,
|
|
90
|
+
};
|
|
91
|
+
const evaluator = createCausalEvaluator(execute, common);
|
|
92
|
+
const experiments = [];
|
|
93
|
+
const evaluateRemoval = async (removeBytes, trials = options.trials) => {
|
|
94
|
+
const fault = {
|
|
95
|
+
kind: "response-truncation",
|
|
96
|
+
pattern: options.pattern,
|
|
97
|
+
removeBytes,
|
|
98
|
+
};
|
|
99
|
+
const result = await evaluator.evaluate([fault], trials);
|
|
100
|
+
experiments.push({ removeBytes, result });
|
|
101
|
+
return result;
|
|
102
|
+
};
|
|
103
|
+
const maximum = await evaluateRemoval(options.maximumRemoveBytes);
|
|
104
|
+
if (!maximum.confirmed) {
|
|
105
|
+
throw new Error("Maximum response truncation did not reproduce the failure confidently");
|
|
106
|
+
}
|
|
107
|
+
let passingRemoveBytes = 0;
|
|
108
|
+
let failingRemoveBytes = options.maximumRemoveBytes;
|
|
109
|
+
while (failingRemoveBytes - passingRemoveBytes > 1) {
|
|
110
|
+
const candidate = Math.floor((passingRemoveBytes + failingRemoveBytes) / 2);
|
|
111
|
+
const result = await evaluateRemoval(candidate);
|
|
112
|
+
if (result.confirmed) {
|
|
113
|
+
failingRemoveBytes = candidate;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
passingRemoveBytes = candidate;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const stable = await confirmStableTruncation(experiments, failingRemoveBytes, evaluateRemoval, Math.max(options.trials, MINIMUM_CONFIRMATION_TRIALS));
|
|
120
|
+
return {
|
|
121
|
+
baseline: evaluator.baseline(),
|
|
122
|
+
experiments,
|
|
123
|
+
trigger: {
|
|
124
|
+
kind: "response-truncation",
|
|
125
|
+
pattern: options.pattern,
|
|
126
|
+
removeBytes: stable.removeBytes,
|
|
127
|
+
},
|
|
128
|
+
triggerResult: stable.result,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
async function confirmStableDuplication(experiments, minimumDuplicateBytes, evaluateDuplication, confirmationTrials) {
|
|
132
|
+
const candidates = [...new Set(experiments
|
|
133
|
+
.filter((entry) => entry.duplicateBytes >= minimumDuplicateBytes && entry.result.confirmed)
|
|
134
|
+
.map((entry) => entry.duplicateBytes))]
|
|
135
|
+
.sort((left, right) => left - right);
|
|
136
|
+
for (const duplicateBytes of candidates) {
|
|
137
|
+
const result = await evaluateDuplication(duplicateBytes, confirmationTrials);
|
|
138
|
+
if (result.confirmed) {
|
|
139
|
+
return { duplicateBytes, result };
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
throw new Error("No response duplication reproduced the failure in two independent trial batches");
|
|
143
|
+
}
|
|
144
|
+
export async function discoverResponseDuplication(execute, options) {
|
|
145
|
+
const common = {
|
|
146
|
+
concurrency: options.concurrency,
|
|
147
|
+
minimumFailureRate: options.minimumFailureRate,
|
|
148
|
+
seed: options.seed,
|
|
149
|
+
signal: options.signal,
|
|
150
|
+
trials: options.trials,
|
|
151
|
+
};
|
|
152
|
+
const evaluator = createCausalEvaluator(execute, common);
|
|
153
|
+
const experiments = [];
|
|
154
|
+
const evaluateDuplication = async (duplicateBytes, trials = options.trials) => {
|
|
155
|
+
const fault = {
|
|
156
|
+
kind: "response-duplication",
|
|
157
|
+
pattern: options.pattern,
|
|
158
|
+
duplicateBytes,
|
|
159
|
+
};
|
|
160
|
+
const result = await evaluator.evaluate([fault], trials);
|
|
161
|
+
experiments.push({ duplicateBytes, result });
|
|
162
|
+
return result;
|
|
163
|
+
};
|
|
164
|
+
const maximum = await evaluateDuplication(options.maximumDuplicateBytes);
|
|
165
|
+
if (!maximum.confirmed) {
|
|
166
|
+
throw new Error("Maximum response duplication did not reproduce the failure confidently");
|
|
167
|
+
}
|
|
168
|
+
let passingDuplicateBytes = 0;
|
|
169
|
+
let failingDuplicateBytes = options.maximumDuplicateBytes;
|
|
170
|
+
while (failingDuplicateBytes - passingDuplicateBytes > 1) {
|
|
171
|
+
const candidate = Math.floor((passingDuplicateBytes + failingDuplicateBytes) / 2);
|
|
172
|
+
const result = await evaluateDuplication(candidate);
|
|
173
|
+
if (result.confirmed) {
|
|
174
|
+
failingDuplicateBytes = candidate;
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
passingDuplicateBytes = candidate;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
const stable = await confirmStableDuplication(experiments, failingDuplicateBytes, evaluateDuplication, Math.max(options.trials, MINIMUM_CONFIRMATION_TRIALS));
|
|
181
|
+
return {
|
|
182
|
+
baseline: evaluator.baseline(),
|
|
183
|
+
experiments,
|
|
184
|
+
trigger: {
|
|
185
|
+
kind: "response-duplication",
|
|
186
|
+
pattern: options.pattern,
|
|
187
|
+
duplicateBytes: stable.duplicateBytes,
|
|
188
|
+
},
|
|
189
|
+
triggerResult: stable.result,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
async function confirmStableReordering(experiments, minimumHoldMs, evaluateHold, confirmationTrials) {
|
|
193
|
+
const candidates = [...new Set(experiments
|
|
194
|
+
.filter((entry) => entry.holdMs >= minimumHoldMs && entry.result.confirmed)
|
|
195
|
+
.map((entry) => entry.holdMs))]
|
|
196
|
+
.sort((left, right) => left - right);
|
|
197
|
+
for (const holdMs of candidates) {
|
|
198
|
+
const result = await evaluateHold(holdMs, confirmationTrials);
|
|
199
|
+
if (result.confirmed) {
|
|
200
|
+
return { holdMs, result };
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
throw new Error("No response reordering reproduced the failure in two independent trial batches");
|
|
204
|
+
}
|
|
205
|
+
export async function discoverResponseReordering(execute, options) {
|
|
206
|
+
const common = {
|
|
207
|
+
concurrency: options.concurrency,
|
|
208
|
+
minimumFailureRate: options.minimumFailureRate,
|
|
209
|
+
seed: options.seed,
|
|
210
|
+
signal: options.signal,
|
|
211
|
+
trials: options.trials,
|
|
212
|
+
};
|
|
213
|
+
const evaluator = createCausalEvaluator(execute, common);
|
|
214
|
+
const experiments = [];
|
|
215
|
+
const evaluateHold = async (holdMs, trials = options.trials) => {
|
|
216
|
+
const fault = { kind: "response-reordering", pattern: options.pattern, holdMs };
|
|
217
|
+
const result = await evaluator.evaluate([fault], trials);
|
|
218
|
+
experiments.push({ holdMs, result });
|
|
219
|
+
return result;
|
|
220
|
+
};
|
|
221
|
+
const maximum = await evaluateHold(options.maximumHoldMs);
|
|
222
|
+
if (!maximum.confirmed) {
|
|
223
|
+
throw new Error("Maximum response hold did not reproduce the failure confidently");
|
|
224
|
+
}
|
|
225
|
+
let passingHoldMs = 0;
|
|
226
|
+
let failingHoldMs = options.maximumHoldMs;
|
|
227
|
+
while (failingHoldMs - passingHoldMs > 1) {
|
|
228
|
+
const candidate = Math.floor((passingHoldMs + failingHoldMs) / 2);
|
|
229
|
+
const result = await evaluateHold(candidate);
|
|
230
|
+
if (result.confirmed) {
|
|
231
|
+
failingHoldMs = candidate;
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
passingHoldMs = candidate;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
const stable = await confirmStableReordering(experiments, failingHoldMs, evaluateHold, Math.max(options.trials, MINIMUM_CONFIRMATION_TRIALS));
|
|
238
|
+
return {
|
|
239
|
+
baseline: evaluator.baseline(),
|
|
240
|
+
experiments,
|
|
241
|
+
trigger: { kind: "response-reordering", pattern: options.pattern, holdMs: stable.holdMs },
|
|
242
|
+
triggerResult: stable.result,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
73
245
|
//# sourceMappingURL=minimize.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"minimize.js","sourceRoot":"","sources":["../../src/discovery/minimize.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"minimize.js","sourceRoot":"","sources":["../../src/discovery/minimize.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { LoadingResourceType, ResourceLoadingDelayFault } from "../domain/schema.js";
|
|
2
|
+
import type { TrialExecutor } from "../runner/playwright-executor.js";
|
|
3
|
+
import type { ExperimentResult } from "./evaluate.js";
|
|
4
|
+
export interface ResourceLoadingDiscoveryOptions {
|
|
5
|
+
concurrency: number;
|
|
6
|
+
maximumDelayMs: number;
|
|
7
|
+
minimumFailureRate: number;
|
|
8
|
+
pattern: string;
|
|
9
|
+
resourceType: LoadingResourceType;
|
|
10
|
+
seed: number;
|
|
11
|
+
signal?: AbortSignal;
|
|
12
|
+
trials: number;
|
|
13
|
+
}
|
|
14
|
+
export interface ResourceLoadingExperiment {
|
|
15
|
+
delayMs: number;
|
|
16
|
+
result: ExperimentResult;
|
|
17
|
+
}
|
|
18
|
+
export interface ResourceLoadingDiscoveryResult {
|
|
19
|
+
baseline: ExperimentResult;
|
|
20
|
+
experiments: ResourceLoadingExperiment[];
|
|
21
|
+
minimumDelayMs: number;
|
|
22
|
+
trigger: ResourceLoadingDelayFault;
|
|
23
|
+
triggerResult: ExperimentResult;
|
|
24
|
+
}
|
|
25
|
+
export declare function discoverResourceLoadingDelay(execute: TrialExecutor, options: ResourceLoadingDiscoveryOptions): Promise<ResourceLoadingDiscoveryResult>;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { createCausalEvaluator } from "./evaluate.js";
|
|
2
|
+
const MINIMUM_CONFIRMATION_TRIALS = 12;
|
|
3
|
+
async function confirmStableDelay(experiments, minimumDelayMs, evaluateDelay, confirmationTrials) {
|
|
4
|
+
const candidates = [...new Set(experiments
|
|
5
|
+
.filter((entry) => entry.delayMs >= minimumDelayMs && entry.result.confirmed)
|
|
6
|
+
.map((entry) => entry.delayMs))]
|
|
7
|
+
.sort((left, right) => left - right);
|
|
8
|
+
for (const delayMs of candidates) {
|
|
9
|
+
const result = await evaluateDelay(delayMs, confirmationTrials);
|
|
10
|
+
if (result.confirmed) {
|
|
11
|
+
return { delayMs, result };
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
throw new Error("No resource loading delay reproduced the failure in two independent batches");
|
|
15
|
+
}
|
|
16
|
+
async function confirmReproducerDelay(minimumDelayMs, maximumDelayMs, evaluateDelay, confirmationTrials) {
|
|
17
|
+
const delayMs = Math.ceil((minimumDelayMs + maximumDelayMs) / 2);
|
|
18
|
+
const result = await evaluateDelay(delayMs, confirmationTrials);
|
|
19
|
+
if (result.confirmed) {
|
|
20
|
+
return { delayMs, result };
|
|
21
|
+
}
|
|
22
|
+
if (delayMs === maximumDelayMs) {
|
|
23
|
+
throw new Error("No stable resource loading reproducer was found within the configured bound");
|
|
24
|
+
}
|
|
25
|
+
const maximumResult = await evaluateDelay(maximumDelayMs, confirmationTrials);
|
|
26
|
+
if (!maximumResult.confirmed) {
|
|
27
|
+
throw new Error("No stable resource loading reproducer was found within the configured bound");
|
|
28
|
+
}
|
|
29
|
+
return { delayMs: maximumDelayMs, result: maximumResult };
|
|
30
|
+
}
|
|
31
|
+
export async function discoverResourceLoadingDelay(execute, options) {
|
|
32
|
+
const common = {
|
|
33
|
+
concurrency: options.concurrency,
|
|
34
|
+
minimumFailureRate: options.minimumFailureRate,
|
|
35
|
+
seed: options.seed,
|
|
36
|
+
signal: options.signal,
|
|
37
|
+
trials: options.trials,
|
|
38
|
+
};
|
|
39
|
+
const evaluator = createCausalEvaluator(execute, common);
|
|
40
|
+
const experiments = [];
|
|
41
|
+
const evaluateDelay = async (delayMs, trials = options.trials) => {
|
|
42
|
+
const fault = {
|
|
43
|
+
kind: "resource-loading-delay",
|
|
44
|
+
delayMs,
|
|
45
|
+
pattern: options.pattern,
|
|
46
|
+
resourceType: options.resourceType,
|
|
47
|
+
};
|
|
48
|
+
const result = await evaluator.evaluate([fault], trials);
|
|
49
|
+
experiments.push({ delayMs, result });
|
|
50
|
+
return result;
|
|
51
|
+
};
|
|
52
|
+
const maximum = await evaluateDelay(options.maximumDelayMs);
|
|
53
|
+
if (!maximum.confirmed) {
|
|
54
|
+
throw new Error("Maximum resource loading delay did not reproduce the failure confidently");
|
|
55
|
+
}
|
|
56
|
+
let passingDelayMs = 0;
|
|
57
|
+
let failingDelayMs = options.maximumDelayMs;
|
|
58
|
+
while (failingDelayMs - passingDelayMs > 1) {
|
|
59
|
+
const candidate = Math.floor((passingDelayMs + failingDelayMs) / 2);
|
|
60
|
+
const result = await evaluateDelay(candidate);
|
|
61
|
+
if (result.confirmed) {
|
|
62
|
+
failingDelayMs = candidate;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
passingDelayMs = candidate;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const confirmationTrials = Math.max(options.trials, MINIMUM_CONFIRMATION_TRIALS);
|
|
69
|
+
const minimum = await confirmStableDelay(experiments, failingDelayMs, evaluateDelay, confirmationTrials);
|
|
70
|
+
const stable = await confirmReproducerDelay(minimum.delayMs, options.maximumDelayMs, evaluateDelay, confirmationTrials);
|
|
71
|
+
return {
|
|
72
|
+
baseline: evaluator.baseline(),
|
|
73
|
+
experiments,
|
|
74
|
+
minimumDelayMs: minimum.delayMs,
|
|
75
|
+
trigger: {
|
|
76
|
+
kind: "resource-loading-delay",
|
|
77
|
+
delayMs: stable.delayMs,
|
|
78
|
+
pattern: options.pattern,
|
|
79
|
+
resourceType: options.resourceType,
|
|
80
|
+
},
|
|
81
|
+
triggerResult: stable.result,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=resource-loading.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource-loading.js","sourceRoot":"","sources":["../../src/discovery/resource-loading.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAA;AAErD,MAAM,2BAA2B,GAAG,EAAE,CAAA;AA0BtC,KAAK,UAAU,kBAAkB,CAC/B,WAAwC,EACxC,cAAsB,EACtB,aAA8E,EAC9E,kBAA0B;IAE1B,MAAM,UAAU,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,WAAW;aACvC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,IAAI,cAAc,IAAI,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC;aAC5E,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;SAC/B,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,GAAG,KAAK,CAAC,CAAA;IACtC,KAAK,MAAM,OAAO,IAAI,UAAU,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAA;QAC/D,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACrB,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAA;QAC5B,CAAC;IACH,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,6EAA6E,CAAC,CAAA;AAChG,CAAC;AAED,KAAK,UAAU,sBAAsB,CACnC,cAAsB,EACtB,cAAsB,EACtB,aAA8E,EAC9E,kBAA0B;IAE1B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,cAAc,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,CAAA;IAChE,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAA;IAC/D,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;QACrB,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAA;IAC5B,CAAC;IACD,IAAI,OAAO,KAAK,cAAc,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,6EAA6E,CAAC,CAAA;IAChG,CAAC;IACD,MAAM,aAAa,GAAG,MAAM,aAAa,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAA;IAC7E,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,6EAA6E,CAAC,CAAA;IAChG,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,aAAa,EAAE,CAAA;AAC3D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,OAAsB,EACtB,OAAwC;IAExC,MAAM,MAAM,GAAG;QACb,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,kBAAkB,EAAE,OAAO,CAAC,kBAAkB;QAC9C,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAA;IACD,MAAM,SAAS,GAAG,qBAAqB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;IAExD,MAAM,WAAW,GAAgC,EAAE,CAAA;IACnD,MAAM,aAAa,GAAG,KAAK,EACzB,OAAe,EACf,MAAM,GAAG,OAAO,CAAC,MAAM,EACI,EAAE;QAC7B,MAAM,KAAK,GAAG;YACZ,IAAI,EAAE,wBAAiC;YACvC,OAAO;YACP,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,YAAY,EAAE,OAAO,CAAC,YAAY;SACnC,CAAA;QACD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,CAAA;QACxD,WAAW,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAA;QACrC,OAAO,MAAM,CAAA;IACf,CAAC,CAAA;IAED,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,OAAO,CAAC,cAAc,CAAC,CAAA;IAC3D,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,0EAA0E,CAAC,CAAA;IAC7F,CAAC;IAED,IAAI,cAAc,GAAG,CAAC,CAAA;IACtB,IAAI,cAAc,GAAG,OAAO,CAAC,cAAc,CAAA;IAC3C,OAAO,cAAc,GAAG,cAAc,GAAG,CAAC,EAAE,CAAC;QAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,cAAc,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,CAAA;QACnE,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,SAAS,CAAC,CAAA;QAC7C,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACrB,cAAc,GAAG,SAAS,CAAA;QAC5B,CAAC;aAAM,CAAC;YACN,cAAc,GAAG,SAAS,CAAA;QAC5B,CAAC;IACH,CAAC;IACD,MAAM,kBAAkB,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,2BAA2B,CAAC,CAAA;IAChF,MAAM,OAAO,GAAG,MAAM,kBAAkB,CACtC,WAAW,EACX,cAAc,EACd,aAAa,EACb,kBAAkB,CACnB,CAAA;IACD,MAAM,MAAM,GAAG,MAAM,sBAAsB,CACzC,OAAO,CAAC,OAAO,EACf,OAAO,CAAC,cAAc,EACtB,aAAa,EACb,kBAAkB,CACnB,CAAA;IACD,OAAO;QACL,QAAQ,EAAE,SAAS,CAAC,QAAQ,EAAE;QAC9B,WAAW;QACX,cAAc,EAAE,OAAO,CAAC,OAAO;QAC/B,OAAO,EAAE;YACP,IAAI,EAAE,wBAAwB;YAC9B,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,YAAY,EAAE,OAAO,CAAC,YAAY;SACnC;QACD,aAAa,EAAE,MAAM,CAAC,MAAM;KAC7B,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { SharedStateInterferenceFault, WorkerPressureFault } from "../domain/schema.js";
|
|
2
|
+
import type { TrialExecutor } from "../runner/playwright-executor.js";
|
|
3
|
+
import type { ExperimentResult } from "./evaluate.js";
|
|
4
|
+
interface RunnerDiscoveryOptions {
|
|
5
|
+
concurrency: number;
|
|
6
|
+
minimumFailureRate: number;
|
|
7
|
+
pattern: string;
|
|
8
|
+
seed: number;
|
|
9
|
+
signal?: AbortSignal;
|
|
10
|
+
trials: number;
|
|
11
|
+
}
|
|
12
|
+
export interface WorkerPressureDiscoveryOptions extends RunnerDiscoveryOptions {
|
|
13
|
+
maximumWorkers: number;
|
|
14
|
+
}
|
|
15
|
+
export interface SharedStateDiscoveryOptions extends RunnerDiscoveryOptions {
|
|
16
|
+
maximumCopies: number;
|
|
17
|
+
}
|
|
18
|
+
export interface RunnerDiscoveryResult<T extends WorkerPressureFault | SharedStateInterferenceFault> {
|
|
19
|
+
baseline: ExperimentResult;
|
|
20
|
+
experiments: ExperimentResult[];
|
|
21
|
+
trigger: T;
|
|
22
|
+
triggerResult: ExperimentResult;
|
|
23
|
+
}
|
|
24
|
+
export declare function discoverWorkerPressure(execute: TrialExecutor, options: WorkerPressureDiscoveryOptions): Promise<RunnerDiscoveryResult<WorkerPressureFault>>;
|
|
25
|
+
export declare function discoverSharedStateInterference(execute: TrialExecutor, options: SharedStateDiscoveryOptions): Promise<RunnerDiscoveryResult<SharedStateInterferenceFault>>;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { createCausalEvaluator } from "./evaluate.js";
|
|
2
|
+
const MINIMUM_CONFIRMATION_TRIALS = 12;
|
|
3
|
+
function validateMaximum(value, label) {
|
|
4
|
+
if (!Number.isInteger(value) || value < 2 || value > 16) {
|
|
5
|
+
throw new Error(`${label} must be an integer between 2 and 16`);
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
async function discoverMinimum(search) {
|
|
9
|
+
const common = {
|
|
10
|
+
concurrency: search.options.concurrency,
|
|
11
|
+
minimumFailureRate: search.options.minimumFailureRate,
|
|
12
|
+
seed: search.options.seed,
|
|
13
|
+
signal: search.options.signal,
|
|
14
|
+
};
|
|
15
|
+
const evaluator = createCausalEvaluator(search.execute, {
|
|
16
|
+
...common,
|
|
17
|
+
trials: search.options.trials,
|
|
18
|
+
});
|
|
19
|
+
const experiments = [];
|
|
20
|
+
let trigger;
|
|
21
|
+
for (let value = 2; value <= search.maximum; value += 1) {
|
|
22
|
+
const candidate = search.buildFault(value);
|
|
23
|
+
const result = await evaluator.evaluate([candidate]);
|
|
24
|
+
experiments.push(result);
|
|
25
|
+
if (result.confirmed) {
|
|
26
|
+
trigger = candidate;
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (!trigger) {
|
|
31
|
+
throw new Error(`${search.label} did not reproduce the failure confidently`);
|
|
32
|
+
}
|
|
33
|
+
const triggerResult = await evaluator.evaluate([trigger], Math.max(search.options.trials, MINIMUM_CONFIRMATION_TRIALS));
|
|
34
|
+
experiments.push(triggerResult);
|
|
35
|
+
if (!triggerResult.confirmed) {
|
|
36
|
+
throw new Error(`${search.label} did not reproduce in an independent confirmation batch`);
|
|
37
|
+
}
|
|
38
|
+
return { baseline: evaluator.baseline(), experiments, trigger, triggerResult };
|
|
39
|
+
}
|
|
40
|
+
export function discoverWorkerPressure(execute, options) {
|
|
41
|
+
validateMaximum(options.maximumWorkers, "max-workers");
|
|
42
|
+
return discoverMinimum({
|
|
43
|
+
buildFault: (workers) => ({
|
|
44
|
+
kind: "worker-pressure",
|
|
45
|
+
pattern: options.pattern,
|
|
46
|
+
workers,
|
|
47
|
+
}),
|
|
48
|
+
execute,
|
|
49
|
+
label: "Worker pressure",
|
|
50
|
+
maximum: options.maximumWorkers,
|
|
51
|
+
options,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
export function discoverSharedStateInterference(execute, options) {
|
|
55
|
+
validateMaximum(options.maximumCopies, "max-copies");
|
|
56
|
+
return discoverMinimum({
|
|
57
|
+
buildFault: (copies) => ({
|
|
58
|
+
copies,
|
|
59
|
+
kind: "shared-state-interference",
|
|
60
|
+
pattern: options.pattern,
|
|
61
|
+
}),
|
|
62
|
+
execute,
|
|
63
|
+
label: "Shared-state interference",
|
|
64
|
+
maximum: options.maximumCopies,
|
|
65
|
+
options,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=runner-environment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner-environment.js","sourceRoot":"","sources":["../../src/discovery/runner-environment.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { StartupEvent, StartupEventDelayFault } from "../domain/schema.js";
|
|
2
|
+
import type { TrialExecutor } from "../runner/playwright-executor.js";
|
|
3
|
+
import type { ExperimentResult } from "./evaluate.js";
|
|
4
|
+
export interface StartupEventDiscoveryOptions {
|
|
5
|
+
concurrency: number;
|
|
6
|
+
event: StartupEvent;
|
|
7
|
+
maximumDelayMs: number;
|
|
8
|
+
minimumFailureRate: number;
|
|
9
|
+
pattern: string;
|
|
10
|
+
seed: number;
|
|
11
|
+
signal?: AbortSignal;
|
|
12
|
+
trials: number;
|
|
13
|
+
}
|
|
14
|
+
export interface StartupEventExperiment {
|
|
15
|
+
delayMs: number;
|
|
16
|
+
result: ExperimentResult;
|
|
17
|
+
}
|
|
18
|
+
export interface StartupEventDiscoveryResult {
|
|
19
|
+
baseline: ExperimentResult;
|
|
20
|
+
experiments: StartupEventExperiment[];
|
|
21
|
+
minimumDelayMs: number;
|
|
22
|
+
trigger: StartupEventDelayFault;
|
|
23
|
+
triggerResult: ExperimentResult;
|
|
24
|
+
}
|
|
25
|
+
export declare function discoverStartupEventDelay(execute: TrialExecutor, options: StartupEventDiscoveryOptions): Promise<StartupEventDiscoveryResult>;
|