@veraxhq/verax 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -20
- package/bin/verax.js +11 -18
- package/package.json +28 -7
- package/src/cli/commands/baseline.js +1 -2
- package/src/cli/commands/default.js +72 -81
- package/src/cli/commands/doctor.js +29 -0
- package/src/cli/commands/ga.js +3 -0
- package/src/cli/commands/gates.js +1 -1
- package/src/cli/commands/inspect.js +6 -133
- package/src/cli/commands/release-check.js +2 -0
- package/src/cli/commands/run.js +74 -246
- package/src/cli/commands/security-check.js +2 -1
- package/src/cli/commands/truth.js +0 -1
- package/src/cli/entry.js +82 -309
- package/src/cli/util/angular-component-extractor.js +2 -2
- package/src/cli/util/angular-navigation-detector.js +2 -2
- package/src/cli/util/ast-interactive-detector.js +4 -6
- package/src/cli/util/ast-network-detector.js +3 -3
- package/src/cli/util/ast-promise-extractor.js +581 -0
- package/src/cli/util/ast-usestate-detector.js +3 -3
- package/src/cli/util/atomic-write.js +12 -1
- package/src/cli/util/console-reporter.js +72 -0
- package/src/cli/util/detection-engine.js +105 -41
- package/src/cli/util/determinism-runner.js +2 -1
- package/src/cli/util/determinism-writer.js +1 -1
- package/src/cli/util/digest-engine.js +359 -0
- package/src/cli/util/dom-diff.js +226 -0
- package/src/cli/util/env-url.js +0 -4
- package/src/cli/util/evidence-engine.js +287 -0
- package/src/cli/util/expectation-extractor.js +217 -367
- package/src/cli/util/findings-writer.js +19 -126
- package/src/cli/util/framework-detector.js +572 -0
- package/src/cli/util/idgen.js +1 -1
- package/src/cli/util/interaction-planner.js +529 -0
- package/src/cli/util/learn-writer.js +2 -2
- package/src/cli/util/ledger-writer.js +110 -0
- package/src/cli/util/monorepo-resolver.js +162 -0
- package/src/cli/util/observation-engine.js +127 -278
- package/src/cli/util/observe-writer.js +2 -2
- package/src/cli/util/paths.js +12 -3
- package/src/cli/util/project-discovery.js +284 -3
- package/src/cli/util/project-writer.js +2 -2
- package/src/cli/util/run-id.js +23 -27
- package/src/cli/util/run-result.js +778 -0
- package/src/cli/util/selector-resolver.js +235 -0
- package/src/cli/util/summary-writer.js +2 -1
- package/src/cli/util/svelte-navigation-detector.js +3 -3
- package/src/cli/util/svelte-sfc-extractor.js +0 -1
- package/src/cli/util/svelte-state-detector.js +1 -2
- package/src/cli/util/trust-activation-integration.js +496 -0
- package/src/cli/util/trust-activation-wrapper.js +85 -0
- package/src/cli/util/trust-integration-hooks.js +164 -0
- package/src/cli/util/types.js +153 -0
- package/src/cli/util/url-validation.js +40 -0
- package/src/cli/util/vue-navigation-detector.js +4 -3
- package/src/cli/util/vue-sfc-extractor.js +1 -2
- package/src/cli/util/vue-state-detector.js +1 -1
- package/src/types/fs-augment.d.ts +23 -0
- package/src/types/global.d.ts +137 -0
- package/src/types/internal-types.d.ts +35 -0
- package/src/verax/cli/finding-explainer.js +3 -56
- package/src/verax/cli/init.js +4 -18
- package/src/verax/core/action-classifier.js +4 -3
- package/src/verax/core/artifacts/registry.js +0 -15
- package/src/verax/core/artifacts/verifier.js +18 -8
- package/src/verax/core/baseline/baseline.snapshot.js +2 -0
- package/src/verax/core/capabilities/gates.js +7 -1
- package/src/verax/core/confidence/confidence-compute.js +14 -7
- package/src/verax/core/confidence/confidence.loader.js +1 -0
- package/src/verax/core/confidence-engine-refactor.js +8 -3
- package/src/verax/core/confidence-engine.js +162 -23
- package/src/verax/core/contracts/types.js +1 -0
- package/src/verax/core/contracts/validators.js +79 -4
- package/src/verax/core/decision-snapshot.js +3 -30
- package/src/verax/core/decisions/decision.trace.js +2 -0
- package/src/verax/core/determinism/contract-writer.js +2 -2
- package/src/verax/core/determinism/contract.js +1 -1
- package/src/verax/core/determinism/diff.js +42 -1
- package/src/verax/core/determinism/engine.js +7 -6
- package/src/verax/core/determinism/finding-identity.js +3 -2
- package/src/verax/core/determinism/normalize.js +32 -4
- package/src/verax/core/determinism/report-writer.js +1 -0
- package/src/verax/core/determinism/run-fingerprint.js +7 -2
- package/src/verax/core/dynamic-route-intelligence.js +8 -7
- package/src/verax/core/evidence/evidence-capture-service.js +1 -0
- package/src/verax/core/evidence/evidence-intent-ledger.js +2 -1
- package/src/verax/core/evidence-builder.js +2 -2
- package/src/verax/core/execution-mode-context.js +1 -1
- package/src/verax/core/execution-mode-detector.js +5 -3
- package/src/verax/core/failures/exit-codes.js +39 -37
- package/src/verax/core/failures/failure-summary.js +1 -1
- package/src/verax/core/failures/failure.factory.js +3 -3
- package/src/verax/core/failures/failure.ledger.js +3 -2
- package/src/verax/core/ga/ga.artifact.js +1 -1
- package/src/verax/core/ga/ga.contract.js +3 -2
- package/src/verax/core/ga/ga.enforcer.js +1 -0
- package/src/verax/core/guardrails/policy.loader.js +1 -0
- package/src/verax/core/guardrails/truth-reconciliation.js +1 -1
- package/src/verax/core/guardrails-engine.js +2 -2
- package/src/verax/core/incremental-store.js +1 -0
- package/src/verax/core/integrity/budget.js +138 -0
- package/src/verax/core/integrity/determinism.js +342 -0
- package/src/verax/core/integrity/integrity.js +208 -0
- package/src/verax/core/integrity/poisoning.js +108 -0
- package/src/verax/core/integrity/transaction.js +140 -0
- package/src/verax/core/observe/run-timeline.js +2 -0
- package/src/verax/core/perf/perf.report.js +2 -0
- package/src/verax/core/pipeline-tracker.js +5 -0
- package/src/verax/core/release/provenance.builder.js +73 -214
- package/src/verax/core/release/release.enforcer.js +14 -9
- package/src/verax/core/release/reproducibility.check.js +1 -0
- package/src/verax/core/release/sbom.builder.js +32 -23
- package/src/verax/core/replay-validator.js +2 -0
- package/src/verax/core/replay.js +4 -0
- package/src/verax/core/report/cross-index.js +6 -3
- package/src/verax/core/report/human-summary.js +141 -1
- package/src/verax/core/route-intelligence.js +4 -3
- package/src/verax/core/run-id.js +6 -3
- package/src/verax/core/run-manifest.js +4 -3
- package/src/verax/core/security/secrets.scan.js +10 -7
- package/src/verax/core/security/security.enforcer.js +4 -0
- package/src/verax/core/security/supplychain.policy.js +9 -1
- package/src/verax/core/security/vuln.scan.js +2 -2
- package/src/verax/core/truth/truth.certificate.js +3 -1
- package/src/verax/core/ui-feedback-intelligence.js +12 -46
- package/src/verax/detect/conditional-ui-silent-failure.js +84 -0
- package/src/verax/detect/confidence-engine.js +100 -660
- package/src/verax/detect/confidence-helper.js +1 -0
- package/src/verax/detect/detection-engine.js +1 -18
- package/src/verax/detect/dynamic-route-findings.js +17 -14
- package/src/verax/detect/expectation-chain-detector.js +1 -1
- package/src/verax/detect/expectation-model.js +3 -5
- package/src/verax/detect/failure-cause-inference.js +293 -0
- package/src/verax/detect/findings-writer.js +126 -166
- package/src/verax/detect/flow-detector.js +2 -2
- package/src/verax/detect/form-silent-failure.js +98 -0
- package/src/verax/detect/index.js +51 -234
- package/src/verax/detect/invariants-enforcer.js +147 -0
- package/src/verax/detect/journey-stall-detector.js +4 -4
- package/src/verax/detect/navigation-silent-failure.js +82 -0
- package/src/verax/detect/problem-aggregator.js +361 -0
- package/src/verax/detect/route-findings.js +7 -6
- package/src/verax/detect/summary-writer.js +477 -0
- package/src/verax/detect/test-failure-cause-inference.js +314 -0
- package/src/verax/detect/ui-feedback-findings.js +18 -18
- package/src/verax/detect/verdict-engine.js +3 -57
- package/src/verax/detect/view-switch-correlator.js +2 -2
- package/src/verax/flow/flow-engine.js +2 -1
- package/src/verax/flow/flow-spec.js +0 -6
- package/src/verax/index.js +48 -412
- package/src/verax/intel/ts-program.js +1 -0
- package/src/verax/intel/vue-navigation-extractor.js +3 -0
- package/src/verax/learn/action-contract-extractor.js +67 -682
- package/src/verax/learn/ast-contract-extractor.js +1 -1
- package/src/verax/learn/flow-extractor.js +1 -0
- package/src/verax/learn/project-detector.js +5 -0
- package/src/verax/learn/react-router-extractor.js +2 -0
- package/src/verax/learn/route-validator.js +1 -4
- package/src/verax/learn/source-instrumenter.js +1 -0
- package/src/verax/learn/state-extractor.js +2 -1
- package/src/verax/learn/static-extractor.js +1 -0
- package/src/verax/observe/coverage-gaps.js +132 -0
- package/src/verax/observe/expectation-handler.js +126 -0
- package/src/verax/observe/incremental-skip.js +46 -0
- package/src/verax/observe/index.js +735 -84
- package/src/verax/observe/interaction-executor.js +192 -0
- package/src/verax/observe/interaction-runner.js +782 -530
- package/src/verax/observe/network-firewall.js +86 -0
- package/src/verax/observe/observation-builder.js +169 -0
- package/src/verax/observe/observe-context.js +1 -1
- package/src/verax/observe/observe-helpers.js +2 -1
- package/src/verax/observe/observe-runner.js +28 -24
- package/src/verax/observe/observers/budget-observer.js +3 -3
- package/src/verax/observe/observers/console-observer.js +4 -4
- package/src/verax/observe/observers/coverage-observer.js +4 -4
- package/src/verax/observe/observers/interaction-observer.js +3 -3
- package/src/verax/observe/observers/navigation-observer.js +4 -4
- package/src/verax/observe/observers/network-observer.js +4 -4
- package/src/verax/observe/observers/safety-observer.js +1 -1
- package/src/verax/observe/observers/ui-feedback-observer.js +4 -4
- package/src/verax/observe/page-traversal.js +138 -0
- package/src/verax/observe/snapshot-ops.js +94 -0
- package/src/verax/observe/ui-signal-sensor.js +2 -148
- package/src/verax/scan-summary-writer.js +10 -42
- package/src/verax/shared/artifact-manager.js +30 -13
- package/src/verax/shared/caching.js +1 -0
- package/src/verax/shared/expectation-tracker.js +1 -0
- package/src/verax/shared/zip-artifacts.js +6 -0
- package/src/verax/core/confidence-engine.js.backup +0 -471
- package/src/verax/shared/config-loader.js +0 -169
- /package/src/verax/shared/{expectation-proof.js → expectation-validation.js} +0 -0
|
@@ -42,7 +42,7 @@ function hasConsoleData(consoleSummary) {
|
|
|
42
42
|
|
|
43
43
|
// Check for any actual console activity
|
|
44
44
|
const hasMessages = (consoleSummary.totalMessages || 0) > 0;
|
|
45
|
-
const hasErrors = (consoleSummary.errors || 0) > 0;
|
|
45
|
+
const hasErrors = (consoleSummary.errors || 0) > 0 || (consoleSummary.pageErrorCount || 0) > 0;
|
|
46
46
|
const hasWarnings = (consoleSummary.warnings || 0) > 0;
|
|
47
47
|
const hasEntries = Array.isArray(consoleSummary.entries) && consoleSummary.entries.length > 0;
|
|
48
48
|
|
|
@@ -67,33 +67,9 @@ function hasUiData(uiSignals) {
|
|
|
67
67
|
const hasFocusChange = diff.focusChanged === true;
|
|
68
68
|
const hasTextChange = diff.textChanged === true;
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Check if UIFeedback sensor contains non-trivial data (GAP 5.2).
|
|
75
|
-
* STRICT: Must have meaningful feedback signals captured.
|
|
76
|
-
*/
|
|
77
|
-
function hasUiFeedbackData(uiFeedback) {
|
|
78
|
-
if (!uiFeedback || typeof uiFeedback !== 'object') return false;
|
|
79
|
-
|
|
80
|
-
// Check if overall score is present and non-zero
|
|
81
|
-
const hasScore = typeof uiFeedback.overallUiFeedbackScore === 'number' && uiFeedback.overallUiFeedbackScore > 0;
|
|
82
|
-
|
|
83
|
-
// Check if any signals are present
|
|
84
|
-
const signals = uiFeedback.signals || {};
|
|
85
|
-
const hasAnySignal = (
|
|
86
|
-
signals.domChange?.happened === true ||
|
|
87
|
-
signals.loading?.appeared === true ||
|
|
88
|
-
signals.loading?.disappeared === true ||
|
|
89
|
-
signals.buttonStateTransition?.happened === true ||
|
|
90
|
-
signals.notification?.happened === true ||
|
|
91
|
-
signals.navigation?.happened === true ||
|
|
92
|
-
signals.focusChange?.happened === true ||
|
|
93
|
-
signals.scrollChange?.happened === true
|
|
94
|
-
);
|
|
95
|
-
|
|
96
|
-
return hasScore || hasAnySignal;
|
|
70
|
+
// Also check for changes field being present (even if it says no changes)
|
|
71
|
+
const hasChangesField = uiSignals.changes && typeof uiSignals.changes === 'object';
|
|
72
|
+
return hasAnyDelta || hasDomChange || hasVisibleChange || hasAriaChange || hasFocusChange || hasTextChange || hasChangesField;
|
|
97
73
|
}
|
|
98
74
|
|
|
99
75
|
const BASE_SCORES = {
|
|
@@ -106,9 +82,7 @@ const BASE_SCORES = {
|
|
|
106
82
|
navigation_silent_failure: 75, // NAVIGATION INTELLIGENCE v2
|
|
107
83
|
partial_navigation_failure: 65, // NAVIGATION INTELLIGENCE v2
|
|
108
84
|
flow_silent_failure: 70, // FLOW INTELLIGENCE v1
|
|
109
|
-
observed_break: 50
|
|
110
|
-
'journey-stall-silent-failure': 72, // PHASE 11: Journey stalls have high base (pattern-based), can reach HIGH despite individual steps OK
|
|
111
|
-
'expectation-chain-break': 78 // PHASE 12: Expectation chains from proven source - high base, increases with chain depth and break position
|
|
85
|
+
observed_break: 50 // OBSERVED expectations (runtime-derived, lower confidence)
|
|
112
86
|
};
|
|
113
87
|
|
|
114
88
|
/**
|
|
@@ -129,22 +103,17 @@ function getBaseScoreFromExpectationStrength(expectationStrength) {
|
|
|
129
103
|
|
|
130
104
|
/**
|
|
131
105
|
* Main confidence computation function.
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
* @param {Object} params - { findingType, expectation, sensors, comparisons, attemptMeta, executionModeCeiling }
|
|
135
|
-
* @param {number} params.executionModeCeiling - Optional confidence ceiling (0..1). Defaults to 1.0 (no ceiling).
|
|
136
|
-
* @returns {Object} - { score, level, explain, factors, contradictions, executionMode }
|
|
106
|
+
* @param {Object} params - { findingType, expectation, sensors, comparisons, attemptMeta }
|
|
107
|
+
* @returns {Object} - { score, level, explain, factors }
|
|
137
108
|
*/
|
|
138
|
-
export function computeConfidence({ findingType, expectation, sensors = {}, comparisons = {}, attemptMeta = {}
|
|
109
|
+
export function computeConfidence({ findingType, expectation, sensors = {}, comparisons = {}, attemptMeta = {} }) {
|
|
139
110
|
const boosts = [];
|
|
140
111
|
const penalties = [];
|
|
141
|
-
const contradictions = []; // GAP 5.2: Track contradictions explicitly
|
|
142
112
|
|
|
143
113
|
// Extract sensor data (with defaults for missing sensors)
|
|
144
114
|
const networkSummary = sensors.network || {};
|
|
145
115
|
const consoleSummary = sensors.console || {};
|
|
146
116
|
const uiSignals = sensors.uiSignals || {};
|
|
147
|
-
const uiFeedback = sensors.uiFeedback || {}; // GAP 5.1: UI feedback signals
|
|
148
117
|
|
|
149
118
|
// === STEP 1: DETERMINE EXPECTATION STRENGTH ===
|
|
150
119
|
const expectationStrength = determineExpectationStrength(expectation);
|
|
@@ -162,29 +131,31 @@ export function computeConfidence({ findingType, expectation, sensors = {}, comp
|
|
|
162
131
|
networkSummary,
|
|
163
132
|
consoleSummary,
|
|
164
133
|
uiSignals,
|
|
165
|
-
comparisons
|
|
166
|
-
uiFeedback // GAP 5.2: Pass uiFeedback for signal extraction
|
|
134
|
+
comparisons
|
|
167
135
|
});
|
|
168
136
|
|
|
169
|
-
// === STEP 3: SENSOR PRESENCE CHECK (
|
|
170
|
-
// PHASE 3:
|
|
171
|
-
|
|
137
|
+
// === STEP 3: SENSOR PRESENCE CHECK (TWO-LEVEL) ===
|
|
138
|
+
// PHASE 3: First check if sensor objects were provided (sensor infrastructure present)
|
|
139
|
+
// Then check if those sensors contain non-trivial data
|
|
140
|
+
|
|
141
|
+
// Check if sensor objects were explicitly provided (not undefined in input)
|
|
142
|
+
const sensorObjectsProvided = {
|
|
143
|
+
network: sensors.network !== undefined,
|
|
144
|
+
console: sensors.console !== undefined,
|
|
145
|
+
ui: sensors.uiSignals !== undefined
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
// Check if those sensors contain non-trivial data
|
|
149
|
+
const sensorsWithData = {
|
|
172
150
|
network: hasNetworkData(networkSummary),
|
|
173
151
|
console: hasConsoleData(consoleSummary),
|
|
174
|
-
ui: hasUiData(uiSignals)
|
|
175
|
-
uiFeedback: hasUiFeedbackData(uiFeedback) // GAP 5.2: Check UIFeedback presence
|
|
152
|
+
ui: hasUiData(uiSignals)
|
|
176
153
|
};
|
|
177
154
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
evidenceSignals,
|
|
183
|
-
expectation,
|
|
184
|
-
findingType,
|
|
185
|
-
contradictions,
|
|
186
|
-
penalties
|
|
187
|
-
});
|
|
155
|
+
// For penalties: use "objects provided" (infrastructure present)
|
|
156
|
+
// For HIGH level: use "has data" (actual evidence)
|
|
157
|
+
const allSensorObjectsProvided = sensorObjectsProvided.network && sensorObjectsProvided.console && sensorObjectsProvided.ui;
|
|
158
|
+
const allSensorsWithData = sensorsWithData.network && sensorsWithData.console && sensorsWithData.ui;
|
|
188
159
|
|
|
189
160
|
// === STEP 4: COMPUTE BOOSTS AND PENALTIES (TYPE-SPECIFIC) ===
|
|
190
161
|
let totalBoosts = 0;
|
|
@@ -209,15 +180,14 @@ export function computeConfidence({ findingType, expectation, sensors = {}, comp
|
|
|
209
180
|
|
|
210
181
|
// === STEP 5: APPLY GLOBAL PENALTIES ===
|
|
211
182
|
|
|
212
|
-
// -
|
|
213
|
-
if (!
|
|
183
|
+
// -25 if sensor infrastructure missing (sensor objects not provided at all)
|
|
184
|
+
if (!allSensorObjectsProvided) {
|
|
214
185
|
const missingSensors = [];
|
|
215
|
-
if (!
|
|
216
|
-
if (!
|
|
217
|
-
if (!
|
|
218
|
-
if (!sensorsPresent.uiFeedback) missingSensors.push('uiFeedback'); // GAP 5.2
|
|
186
|
+
if (!sensorObjectsProvided.network) missingSensors.push('network');
|
|
187
|
+
if (!sensorObjectsProvided.console) missingSensors.push('console');
|
|
188
|
+
if (!sensorObjectsProvided.ui) missingSensors.push('ui');
|
|
219
189
|
|
|
220
|
-
const penalty =
|
|
190
|
+
const penalty = 25;
|
|
221
191
|
totalPenalties += penalty;
|
|
222
192
|
penalties.push(`Missing sensor data: ${missingSensors.join(', ')}`);
|
|
223
193
|
}
|
|
@@ -228,13 +198,6 @@ export function computeConfidence({ findingType, expectation, sensors = {}, comp
|
|
|
228
198
|
penalties.push(`Expectation strength is ${expectationStrength}, not PROVEN`);
|
|
229
199
|
}
|
|
230
200
|
|
|
231
|
-
// GAP 5.2: Apply contradiction penalties
|
|
232
|
-
if (contradictions.length > 0) {
|
|
233
|
-
const contradictionPenalty = contradictions.length * 12; // -12 per contradiction
|
|
234
|
-
totalPenalties += contradictionPenalty;
|
|
235
|
-
penalties.push(`Contradictions detected: ${contradictions.length}`);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
201
|
// === STEP 6: COMPUTE FINAL SCORE ===
|
|
239
202
|
let score = baseScore + totalBoosts - totalPenalties;
|
|
240
203
|
score = Math.max(0, Math.min(100, score)); // Clamp to [0, 100]
|
|
@@ -244,8 +207,8 @@ export function computeConfidence({ findingType, expectation, sensors = {}, comp
|
|
|
244
207
|
let boundaryExplanation = null; // Phase 3: Track near-threshold decisions
|
|
245
208
|
|
|
246
209
|
if (score >= 80) {
|
|
247
|
-
// HARD RULE: HIGH level requires PROVEN expectation AND all sensors
|
|
248
|
-
if (expectationStrength === 'PROVEN' &&
|
|
210
|
+
// HARD RULE: HIGH level requires PROVEN expectation AND all sensors with actual data
|
|
211
|
+
if (expectationStrength === 'PROVEN' && allSensorsWithData) {
|
|
249
212
|
level = 'HIGH';
|
|
250
213
|
|
|
251
214
|
// Phase 3: Near-threshold detection (within 2 points of boundary)
|
|
@@ -253,12 +216,25 @@ export function computeConfidence({ findingType, expectation, sensors = {}, comp
|
|
|
253
216
|
boundaryExplanation = `Near threshold: score ${score.toFixed(1)} >= 80 threshold, assigned HIGH (proven expectation + all sensors)`;
|
|
254
217
|
}
|
|
255
218
|
} else {
|
|
256
|
-
//
|
|
219
|
+
// Cannot achieve HIGH - assign MEDIUM
|
|
257
220
|
level = 'MEDIUM';
|
|
258
|
-
|
|
221
|
+
// If sensors are at least partially provided (not completely missing), cap the score
|
|
222
|
+
// to prevent the 80+ threshold from being crossed without HIGH achievement
|
|
223
|
+
if (allSensorObjectsProvided) {
|
|
224
|
+
score = Math.min(score, 79);
|
|
225
|
+
}
|
|
226
|
+
// Only cap if at least some sensors have data (otherwise we're showing the penalty)
|
|
227
|
+
const anySensorWithData = sensorsWithData.network || sensorsWithData.console || sensorsWithData.ui;
|
|
228
|
+
if (!anySensorWithData) {
|
|
229
|
+
score = Math.max(score, 76); // Ensure penalty is visible
|
|
230
|
+
}
|
|
259
231
|
|
|
260
|
-
// Phase 3: Boundary explanation
|
|
261
|
-
|
|
232
|
+
// Phase 3: Boundary explanation
|
|
233
|
+
if (expectationStrength !== 'PROVEN') {
|
|
234
|
+
boundaryExplanation = `Assigned MEDIUM: score ${score.toFixed(1)} >= 80 but expectation not proven`;
|
|
235
|
+
} else if (!allSensorsWithData) {
|
|
236
|
+
boundaryExplanation = `Assigned MEDIUM: score ${score.toFixed(1)} >= 80 but sensors lack data`;
|
|
237
|
+
}
|
|
262
238
|
}
|
|
263
239
|
} else if (score >= 55) {
|
|
264
240
|
level = 'MEDIUM';
|
|
@@ -300,55 +276,28 @@ export function computeConfidence({ findingType, expectation, sensors = {}, comp
|
|
|
300
276
|
level,
|
|
301
277
|
score: Math.round(score),
|
|
302
278
|
expectationStrength,
|
|
303
|
-
|
|
304
|
-
|
|
279
|
+
sensorsWithData,
|
|
280
|
+
allSensorsWithData,
|
|
305
281
|
evidenceSignals,
|
|
306
282
|
boosts,
|
|
307
283
|
penalties,
|
|
308
284
|
attemptMeta,
|
|
309
|
-
boundaryExplanation
|
|
310
|
-
contradictions // GAP 5.2: Include contradiction list
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
// === STEP 11: GENERATE CONFIDENCE FACTORS (GAP 5.2) ===
|
|
314
|
-
const factors = generateConfidenceFactors({
|
|
315
|
-
expectationStrength,
|
|
316
|
-
sensorsPresent,
|
|
317
|
-
evidenceSignals,
|
|
318
|
-
boosts,
|
|
319
|
-
penalties,
|
|
320
|
-
contradictions,
|
|
321
|
-
baseScore,
|
|
322
|
-
totalBoosts,
|
|
323
|
-
totalPenalties
|
|
285
|
+
boundaryExplanation // Phase 3: Include boundary reasoning
|
|
324
286
|
});
|
|
325
287
|
|
|
326
|
-
// === STEP 12: APPLY EXECUTION MODE CEILING ===
|
|
327
|
-
// If execution mode is WEB_SCAN_LIMITED, cap confidence at 0.45 (45%)
|
|
328
|
-
let computedScore = score / 100; // Convert from 0..100 to 0..1 (float)
|
|
329
|
-
const ceiledScore = Math.min(computedScore, executionModeCeiling);
|
|
330
|
-
|
|
331
|
-
// If ceiling was applied, adjust level accordingly
|
|
332
|
-
let ceiledLevel = level;
|
|
333
|
-
if (ceiledScore < computedScore) {
|
|
334
|
-
// Score was capped, so adjust level to match new ceiling
|
|
335
|
-
if (ceiledScore < 0.2) ceiledLevel = 'LOW';
|
|
336
|
-
else if (ceiledScore < 0.5) ceiledLevel = 'MEDIUM';
|
|
337
|
-
else ceiledLevel = 'HIGH';
|
|
338
|
-
}
|
|
339
|
-
|
|
340
288
|
return {
|
|
341
|
-
score:
|
|
342
|
-
|
|
343
|
-
level: ceiledLevel,
|
|
289
|
+
score: Math.round(score),
|
|
290
|
+
level,
|
|
344
291
|
explain: finalExplain,
|
|
345
|
-
factors:
|
|
346
|
-
|
|
292
|
+
factors: {
|
|
293
|
+
expectationStrength,
|
|
294
|
+
sensorsPresent: sensorsWithData,
|
|
295
|
+
evidenceSignals,
|
|
296
|
+
penalties,
|
|
297
|
+
boosts
|
|
298
|
+
},
|
|
347
299
|
confidenceExplanation,
|
|
348
|
-
boundaryExplanation
|
|
349
|
-
// Expose raw boosts/penalties for testing and debugging
|
|
350
|
-
boosts: boosts,
|
|
351
|
-
penalties: penalties
|
|
300
|
+
boundaryExplanation // Phase 3: Surface boundary reasoning in output
|
|
352
301
|
};
|
|
353
302
|
}
|
|
354
303
|
|
|
@@ -385,35 +334,16 @@ function determineExpectationStrength(expectation = {}) {
|
|
|
385
334
|
|
|
386
335
|
/**
|
|
387
336
|
* Extract deterministic evidence signals from runtime data.
|
|
388
|
-
* GAP 5.2: Integrates Gap 5.1 UI Feedback signals with existing sensor data.
|
|
389
337
|
*/
|
|
390
|
-
function extractEvidenceSignals({ networkSummary, consoleSummary, uiSignals, comparisons
|
|
391
|
-
// GAP 5.1: Extract UI feedback signals (6 types)
|
|
392
|
-
const uiFeedbackScore = uiFeedback?.overallUiFeedbackScore || 0;
|
|
393
|
-
const uiFeedbackSignals = uiFeedback?.signals || {};
|
|
394
|
-
|
|
338
|
+
function extractEvidenceSignals({ networkSummary, consoleSummary, uiSignals, comparisons }) {
|
|
395
339
|
const signals = {
|
|
396
340
|
urlChanged: comparisons?.hasUrlChange === true,
|
|
397
341
|
domChanged: comparisons?.hasDomChange === true,
|
|
398
342
|
screenshotChanged: comparisons?.hasVisibleChange === true,
|
|
399
343
|
networkFailed: (networkSummary?.failedRequests || 0) > 0,
|
|
400
|
-
networkSuccess: (networkSummary?.totalRequests || 0) > 0 && (networkSummary?.failedRequests || 0) === 0,
|
|
401
344
|
consoleErrors: (consoleSummary?.hasErrors === true),
|
|
402
345
|
uiFeedbackDetected: hasAnyFeedback(uiSignals),
|
|
403
|
-
slowRequests: (networkSummary?.slowRequestsCount || 0) > 0
|
|
404
|
-
|
|
405
|
-
// GAP 5.1: Runtime UI feedback signals
|
|
406
|
-
uiFeedbackScore: uiFeedbackScore, // 0..1 overall score
|
|
407
|
-
uiFeedbackDomChange: uiFeedbackSignals.domChange?.happened === true,
|
|
408
|
-
uiFeedbackLoading: uiFeedbackSignals.loading?.appeared === true || uiFeedbackSignals.loading?.disappeared === true,
|
|
409
|
-
uiFeedbackButtonState: uiFeedbackSignals.buttonStateTransition?.happened === true,
|
|
410
|
-
uiFeedbackNotification: uiFeedbackSignals.notification?.happened === true,
|
|
411
|
-
uiFeedbackNavigation: uiFeedbackSignals.navigation?.happened === true,
|
|
412
|
-
uiFeedbackFocusChange: uiFeedbackSignals.focusChange?.happened === true,
|
|
413
|
-
uiFeedbackScrollChange: uiFeedbackSignals.scrollChange?.happened === true,
|
|
414
|
-
|
|
415
|
-
// Derived: Strong UI feedback = any significant signal
|
|
416
|
-
strongUiFeedback: uiFeedbackScore > 0.5
|
|
346
|
+
slowRequests: (networkSummary?.slowRequestsCount || 0) > 0
|
|
417
347
|
};
|
|
418
348
|
|
|
419
349
|
return signals;
|
|
@@ -566,36 +496,6 @@ function scoreByFindingType({
|
|
|
566
496
|
penalties
|
|
567
497
|
});
|
|
568
498
|
break;
|
|
569
|
-
|
|
570
|
-
// PHASE 11: Journey stall detection
|
|
571
|
-
case 'journey-stall-silent-failure':
|
|
572
|
-
totalBoosts = scoreJourneyStall({
|
|
573
|
-
expectation,
|
|
574
|
-
evidenceSignals,
|
|
575
|
-
boosts,
|
|
576
|
-
penalties
|
|
577
|
-
});
|
|
578
|
-
totalPenalties = penalizeJourneyStall({
|
|
579
|
-
expectation,
|
|
580
|
-
evidenceSignals,
|
|
581
|
-
penalties
|
|
582
|
-
});
|
|
583
|
-
break;
|
|
584
|
-
|
|
585
|
-
// PHASE 12: Expectation chain breaks
|
|
586
|
-
case 'expectation-chain-break':
|
|
587
|
-
totalBoosts = scoreExpectationChainBreak({
|
|
588
|
-
expectation,
|
|
589
|
-
evidenceSignals,
|
|
590
|
-
boosts,
|
|
591
|
-
penalties
|
|
592
|
-
});
|
|
593
|
-
totalPenalties = penalizeExpectationChainBreak({
|
|
594
|
-
expectation,
|
|
595
|
-
evidenceSignals,
|
|
596
|
-
penalties
|
|
597
|
-
});
|
|
598
|
-
break;
|
|
599
499
|
}
|
|
600
500
|
|
|
601
501
|
return { totalBoosts, totalPenalties };
|
|
@@ -620,16 +520,10 @@ function scoreNetworkSilentFailure({ networkSummary: _networkSummary, consoleSum
|
|
|
620
520
|
boosts.push('Console errors present');
|
|
621
521
|
}
|
|
622
522
|
|
|
623
|
-
//
|
|
624
|
-
if (evidenceSignals.networkFailed && !evidenceSignals.
|
|
625
|
-
total +=
|
|
626
|
-
boosts.push(
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
// GAP 5.2: +8 if network failed + no notification signal
|
|
630
|
-
if (evidenceSignals.networkFailed && !evidenceSignals.uiFeedbackNotification) {
|
|
631
|
-
total += 8;
|
|
632
|
-
boosts.push('Network failed without error notification to user');
|
|
523
|
+
// +6 if network failed AND no UI feedback
|
|
524
|
+
if (evidenceSignals.networkFailed && !evidenceSignals.uiFeedbackDetected) {
|
|
525
|
+
total += 6;
|
|
526
|
+
boosts.push('Silent failure: no user feedback on network error');
|
|
633
527
|
}
|
|
634
528
|
|
|
635
529
|
return total;
|
|
@@ -638,22 +532,10 @@ function scoreNetworkSilentFailure({ networkSummary: _networkSummary, consoleSum
|
|
|
638
532
|
function penalizeNetworkSilentFailure({ evidenceSignals, penalties }) {
|
|
639
533
|
let total = 0;
|
|
640
534
|
|
|
641
|
-
//
|
|
642
|
-
if (evidenceSignals.
|
|
643
|
-
total += 15;
|
|
644
|
-
penalties.push(`Strong UI feedback detected (score: ${evidenceSignals.uiFeedbackScore.toFixed(2)}) - not silent`);
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
// GAP 5.2: -10 if notification shown
|
|
648
|
-
if (evidenceSignals.uiFeedbackNotification) {
|
|
535
|
+
// -10 if UI feedback present (shouldn't be silent failure)
|
|
536
|
+
if (evidenceSignals.uiFeedbackDetected) {
|
|
649
537
|
total += 10;
|
|
650
|
-
penalties.push('
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
// GAP 5.2: -8 if moderate UI feedback (0.3-0.5)
|
|
654
|
-
if (evidenceSignals.uiFeedbackScore >= 0.3 && evidenceSignals.uiFeedbackScore <= 0.5) {
|
|
655
|
-
total += 8;
|
|
656
|
-
penalties.push(`Moderate UI feedback detected (score: ${evidenceSignals.uiFeedbackScore.toFixed(2)})`);
|
|
538
|
+
penalties.push('UI feedback detected (suggests not silent)');
|
|
657
539
|
}
|
|
658
540
|
|
|
659
541
|
return total;
|
|
@@ -698,16 +580,10 @@ function scoreMissingFeedbackFailure({ networkSummary: _networkSummary, evidence
|
|
|
698
580
|
boosts.push('Slow requests detected');
|
|
699
581
|
}
|
|
700
582
|
|
|
701
|
-
//
|
|
702
|
-
if (evidenceSignals.
|
|
703
|
-
total +=
|
|
704
|
-
boosts.push('
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
// GAP 5.2: +10 if button state didn't change during async operation
|
|
708
|
-
if (evidenceSignals.networkSuccess && !evidenceSignals.uiFeedbackButtonState && evidenceSignals.slowRequests) {
|
|
709
|
-
total += 10;
|
|
710
|
-
boosts.push('Async operation without button state feedback (disabled/loading)');
|
|
583
|
+
// +8 if network activity without loading feedback
|
|
584
|
+
if (evidenceSignals.networkFailed && !evidenceSignals.uiFeedbackDetected) {
|
|
585
|
+
total += 8;
|
|
586
|
+
boosts.push('Network activity without user feedback');
|
|
711
587
|
}
|
|
712
588
|
|
|
713
589
|
return total;
|
|
@@ -716,18 +592,12 @@ function scoreMissingFeedbackFailure({ networkSummary: _networkSummary, evidence
|
|
|
716
592
|
function penalizeMissingFeedbackFailure({ evidenceSignals, penalties }) {
|
|
717
593
|
let total = 0;
|
|
718
594
|
|
|
719
|
-
//
|
|
720
|
-
if (evidenceSignals.
|
|
721
|
-
total +=
|
|
595
|
+
// -10 if loading feedback detected
|
|
596
|
+
if (evidenceSignals.uiFeedbackDetected) {
|
|
597
|
+
total += 10;
|
|
722
598
|
penalties.push('Loading indicator detected');
|
|
723
599
|
}
|
|
724
600
|
|
|
725
|
-
// GAP 5.2: -8 if button state changed
|
|
726
|
-
if (evidenceSignals.uiFeedbackButtonState) {
|
|
727
|
-
total += 8;
|
|
728
|
-
penalties.push('Button state transition detected');
|
|
729
|
-
}
|
|
730
|
-
|
|
731
601
|
return total;
|
|
732
602
|
}
|
|
733
603
|
|
|
@@ -875,13 +745,13 @@ function penalizeNavigationSilentFailure({ evidenceSignals, penalties }) {
|
|
|
875
745
|
|
|
876
746
|
// -10 if UI feedback present (shouldn't be silent failure)
|
|
877
747
|
if (evidenceSignals.uiFeedbackDetected) {
|
|
878
|
-
total
|
|
748
|
+
total += 10;
|
|
879
749
|
penalties.push('UI feedback detected (suggests navigation feedback provided)');
|
|
880
750
|
}
|
|
881
751
|
|
|
882
752
|
// -5 if URL changed (navigation might have succeeded)
|
|
883
753
|
if (evidenceSignals.urlChanged) {
|
|
884
|
-
total
|
|
754
|
+
total += 5;
|
|
885
755
|
penalties.push('URL changed (navigation may have succeeded)');
|
|
886
756
|
}
|
|
887
757
|
|
|
@@ -911,7 +781,7 @@ function penalizePartialNavigationFailure({ evidenceSignals, penalties }) {
|
|
|
911
781
|
|
|
912
782
|
// -10 if UI feedback present (shouldn't be partial failure)
|
|
913
783
|
if (evidenceSignals.uiFeedbackDetected) {
|
|
914
|
-
total
|
|
784
|
+
total += 10;
|
|
915
785
|
penalties.push('UI feedback detected (suggests navigation feedback provided)');
|
|
916
786
|
}
|
|
917
787
|
|
|
@@ -957,20 +827,18 @@ function generateExplanations(boosts, penalties, expectationStrength, _evidenceS
|
|
|
957
827
|
* Generate confidence explanation for Phase 9: Reality Confidence & Explanation Layer.
|
|
958
828
|
* Provides whyThisConfidence, whatWouldIncreaseConfidence, whatWouldReduceConfidence.
|
|
959
829
|
* Phase 3: Also includes boundaryExplanation for near-threshold decisions.
|
|
960
|
-
* GAP 5.2: Includes contradiction handling.
|
|
961
830
|
*/
|
|
962
831
|
function generateConfidenceExplanation({
|
|
963
832
|
level,
|
|
964
833
|
score: _score,
|
|
965
834
|
expectationStrength,
|
|
966
|
-
|
|
967
|
-
|
|
835
|
+
sensorsWithData,
|
|
836
|
+
allSensorsWithData,
|
|
968
837
|
evidenceSignals: _evidenceSignals,
|
|
969
838
|
boosts,
|
|
970
839
|
penalties,
|
|
971
840
|
attemptMeta,
|
|
972
|
-
boundaryExplanation = null
|
|
973
|
-
contradictions = [] // GAP 5.2: Contradiction list
|
|
841
|
+
boundaryExplanation = null // Phase 3: Optional boundary reasoning
|
|
974
842
|
}) {
|
|
975
843
|
const whyThisConfidence = [];
|
|
976
844
|
const whatWouldIncreaseConfidence = [];
|
|
@@ -981,27 +849,14 @@ function generateConfidenceExplanation({
|
|
|
981
849
|
whyThisConfidence.push(boundaryExplanation);
|
|
982
850
|
}
|
|
983
851
|
|
|
984
|
-
// GAP 5.2: If contradictions exist, mention them first
|
|
985
|
-
if (contradictions.length > 0) {
|
|
986
|
-
const criticalCount = contradictions.filter(c => c.severity === 'critical').length;
|
|
987
|
-
const majorCount = contradictions.filter(c => c.severity === 'major').length;
|
|
988
|
-
if (criticalCount > 0) {
|
|
989
|
-
whyThisConfidence.push(`${criticalCount} critical contradiction(s) detected - significantly reduces confidence`);
|
|
990
|
-
} else if (majorCount > 0) {
|
|
991
|
-
whyThisConfidence.push(`${majorCount} major contradiction(s) detected - reduces confidence`);
|
|
992
|
-
} else {
|
|
993
|
-
whyThisConfidence.push(`${contradictions.length} minor contradiction(s) detected - slightly reduces confidence`);
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
|
|
997
852
|
// WHY THIS CONFIDENCE: Explain current level
|
|
998
853
|
if (level === 'HIGH') {
|
|
999
854
|
whyThisConfidence.push('High confidence: expectation is proven and all sensors captured evidence');
|
|
1000
855
|
if (expectationStrength === 'PROVEN') {
|
|
1001
856
|
whyThisConfidence.push('Expectation is proven from source code');
|
|
1002
857
|
}
|
|
1003
|
-
if (
|
|
1004
|
-
whyThisConfidence.push('All sensors (network, console, UI
|
|
858
|
+
if (allSensorsWithData) {
|
|
859
|
+
whyThisConfidence.push('All sensors (network, console, UI) were active');
|
|
1005
860
|
}
|
|
1006
861
|
if (boosts.length > 0) {
|
|
1007
862
|
whyThisConfidence.push(`Strong evidence: ${boosts.length} positive signal(s)`);
|
|
@@ -1013,12 +868,11 @@ function generateConfidenceExplanation({
|
|
|
1013
868
|
} else {
|
|
1014
869
|
whyThisConfidence.push(`Expectation strength: ${expectationStrength} (not proven)`);
|
|
1015
870
|
}
|
|
1016
|
-
if (!
|
|
871
|
+
if (!allSensorsWithData) {
|
|
1017
872
|
const missing = [];
|
|
1018
|
-
if (!
|
|
1019
|
-
if (!
|
|
1020
|
-
if (!
|
|
1021
|
-
if (!sensorsPresent.uiFeedback) missing.push('UIFeedback');
|
|
873
|
+
if (!sensorsWithData.network) missing.push('network');
|
|
874
|
+
if (!sensorsWithData.console) missing.push('console');
|
|
875
|
+
if (!sensorsWithData.ui) missing.push('UI');
|
|
1022
876
|
whyThisConfidence.push(`Missing sensor data: ${missing.join(', ')}`);
|
|
1023
877
|
}
|
|
1024
878
|
if (penalties.length > 0) {
|
|
@@ -1029,7 +883,7 @@ function generateConfidenceExplanation({
|
|
|
1029
883
|
if (expectationStrength !== 'PROVEN') {
|
|
1030
884
|
whyThisConfidence.push(`Expectation strength: ${expectationStrength} (not proven from code)`);
|
|
1031
885
|
}
|
|
1032
|
-
if (!
|
|
886
|
+
if (!allSensorsWithData) {
|
|
1033
887
|
whyThisConfidence.push('Some sensors were not active, reducing confidence');
|
|
1034
888
|
}
|
|
1035
889
|
if (attemptMeta && !attemptMeta.repeated) {
|
|
@@ -1042,12 +896,11 @@ function generateConfidenceExplanation({
|
|
|
1042
896
|
if (expectationStrength !== 'PROVEN') {
|
|
1043
897
|
whatWouldIncreaseConfidence.push('Make the expectation proven by adding explicit code that promises the behavior');
|
|
1044
898
|
}
|
|
1045
|
-
if (!
|
|
899
|
+
if (!allSensorsWithData) {
|
|
1046
900
|
const missing = [];
|
|
1047
|
-
if (!
|
|
1048
|
-
if (!
|
|
1049
|
-
if (!
|
|
1050
|
-
if (!sensorsPresent.uiFeedback) missing.push('UI feedback detection');
|
|
901
|
+
if (!sensorsWithData.network) missing.push('network monitoring');
|
|
902
|
+
if (!sensorsWithData.console) missing.push('console error detection');
|
|
903
|
+
if (!sensorsWithData.ui) missing.push('UI change detection');
|
|
1051
904
|
whatWouldIncreaseConfidence.push(`Enable missing sensors: ${missing.join(', ')}`);
|
|
1052
905
|
}
|
|
1053
906
|
if (attemptMeta && !attemptMeta.repeated && level === 'LOW') {
|
|
@@ -1056,9 +909,6 @@ function generateConfidenceExplanation({
|
|
|
1056
909
|
if (boosts.length === 0) {
|
|
1057
910
|
whatWouldIncreaseConfidence.push('Add stronger evidence signals (network requests, console errors, UI changes)');
|
|
1058
911
|
}
|
|
1059
|
-
if (contradictions.length > 0) {
|
|
1060
|
-
whatWouldIncreaseConfidence.push('Resolve contradictions by clarifying expected behavior or fixing detection logic');
|
|
1061
|
-
}
|
|
1062
912
|
}
|
|
1063
913
|
|
|
1064
914
|
// WHAT WOULD REDUCE CONFIDENCE
|
|
@@ -1066,15 +916,12 @@ function generateConfidenceExplanation({
|
|
|
1066
916
|
if (expectationStrength === 'PROVEN') {
|
|
1067
917
|
whatWouldReduceConfidence.push('If expectation becomes unproven (code changes, expectation removed)');
|
|
1068
918
|
}
|
|
1069
|
-
if (
|
|
919
|
+
if (allSensorsWithData) {
|
|
1070
920
|
whatWouldReduceConfidence.push('If sensors become unavailable or disabled');
|
|
1071
921
|
}
|
|
1072
922
|
if (boosts.length > 0) {
|
|
1073
923
|
whatWouldReduceConfidence.push('If positive evidence signals disappear (network succeeds, UI feedback appears)');
|
|
1074
924
|
}
|
|
1075
|
-
if (contradictions.length === 0) {
|
|
1076
|
-
whatWouldReduceConfidence.push('If contradictory evidence appears (mixed signals, conflicting feedback)');
|
|
1077
|
-
}
|
|
1078
925
|
}
|
|
1079
926
|
if (penalties.length === 0 && level === 'HIGH') {
|
|
1080
927
|
whatWouldReduceConfidence.push('If uncertainty factors appear (URL changes, partial effects, missing data)');
|
|
@@ -1092,7 +939,7 @@ function generateConfidenceExplanation({
|
|
|
1092
939
|
// ============================================================
|
|
1093
940
|
|
|
1094
941
|
// PHASE 3: Export sensor validation functions for testing
|
|
1095
|
-
export { hasNetworkData, hasConsoleData, hasUiData
|
|
942
|
+
export { hasNetworkData, hasConsoleData, hasUiData };
|
|
1096
943
|
|
|
1097
944
|
// Detect error feedback (legacy helper)
|
|
1098
945
|
function _detectErrorFeedback(uiSignals) {
|
|
@@ -1112,410 +959,3 @@ function _detectStatusFeedback(uiSignals) {
|
|
|
1112
959
|
const after = uiSignals?.after || {};
|
|
1113
960
|
return after.hasStatusSignal || after.hasLiveRegion || after.hasDialog;
|
|
1114
961
|
}
|
|
1115
|
-
|
|
1116
|
-
// ============================================================
|
|
1117
|
-
// GAP 5.2: CONTRADICTION DETECTION
|
|
1118
|
-
// ============================================================
|
|
1119
|
-
|
|
1120
|
-
/**
|
|
1121
|
-
* Detect contradictions in evidence signals and populate contradictions array.
|
|
1122
|
-
* Contradictions reduce confidence by identifying conflicting signals.
|
|
1123
|
-
*/
|
|
1124
|
-
function detectContradictions({ evidenceSignals, expectation, findingType, contradictions, penalties }) {
|
|
1125
|
-
// Contradiction 1: Network success + no UI feedback + no navigation + no DOM change + claiming silent failure
|
|
1126
|
-
if (
|
|
1127
|
-
evidenceSignals.networkSuccess &&
|
|
1128
|
-
!evidenceSignals.strongUiFeedback &&
|
|
1129
|
-
!evidenceSignals.uiFeedbackNavigation &&
|
|
1130
|
-
!evidenceSignals.domChanged &&
|
|
1131
|
-
!evidenceSignals.urlChanged &&
|
|
1132
|
-
findingType?.includes('silent_failure')
|
|
1133
|
-
) {
|
|
1134
|
-
contradictions.push({
|
|
1135
|
-
type: 'network_success_no_feedback',
|
|
1136
|
-
details: 'Network succeeded but no UI feedback, navigation, or DOM change detected - possible silent success or deferred update',
|
|
1137
|
-
severity: 'major'
|
|
1138
|
-
});
|
|
1139
|
-
}
|
|
1140
|
-
|
|
1141
|
-
// Contradiction 2: UI feedback shows explicit error/notification but finding claims "silent"
|
|
1142
|
-
if (
|
|
1143
|
-
(evidenceSignals.uiFeedbackNotification || evidenceSignals.consoleErrors) &&
|
|
1144
|
-
!evidenceSignals.strongUiFeedback &&
|
|
1145
|
-
findingType?.includes('silent')
|
|
1146
|
-
) {
|
|
1147
|
-
contradictions.push({
|
|
1148
|
-
type: 'error_feedback_present',
|
|
1149
|
-
details: 'Error notifications or console errors present but UI feedback score is low - may not be truly "silent"',
|
|
1150
|
-
severity: 'minor'
|
|
1151
|
-
});
|
|
1152
|
-
}
|
|
1153
|
-
|
|
1154
|
-
// Contradiction 3: Strong UI feedback but claiming silent failure
|
|
1155
|
-
if (evidenceSignals.strongUiFeedback && findingType?.includes('silent_failure')) {
|
|
1156
|
-
contradictions.push({
|
|
1157
|
-
type: 'strong_feedback_silent_claim',
|
|
1158
|
-
details: `Strong UI feedback detected (score: ${evidenceSignals.uiFeedbackScore.toFixed(2)}) contradicts silent failure claim`,
|
|
1159
|
-
severity: 'critical'
|
|
1160
|
-
});
|
|
1161
|
-
}
|
|
1162
|
-
|
|
1163
|
-
// Contradiction 4: Navigation occurred but claiming missing action
|
|
1164
|
-
if (
|
|
1165
|
-
(evidenceSignals.urlChanged || evidenceSignals.uiFeedbackNavigation) &&
|
|
1166
|
-
(findingType === 'missing_network_action' || findingType === 'missing_state_action')
|
|
1167
|
-
) {
|
|
1168
|
-
contradictions.push({
|
|
1169
|
-
type: 'navigation_with_missing_action',
|
|
1170
|
-
details: 'Navigation detected but claiming missing action - action may have fired differently',
|
|
1171
|
-
severity: 'major'
|
|
1172
|
-
});
|
|
1173
|
-
}
|
|
1174
|
-
|
|
1175
|
-
// Contradiction 5: DOM changed significantly but UI feedback score is zero
|
|
1176
|
-
if (
|
|
1177
|
-
evidenceSignals.domChanged &&
|
|
1178
|
-
evidenceSignals.uiFeedbackScore === 0 &&
|
|
1179
|
-
(expectation?.promise?.kind === 'network' || expectation?.promise?.kind === 'state')
|
|
1180
|
-
) {
|
|
1181
|
-
contradictions.push({
|
|
1182
|
-
type: 'dom_change_no_ui_feedback',
|
|
1183
|
-
details: 'DOM changed but UI feedback detection missed it - detection may be too conservative',
|
|
1184
|
-
severity: 'minor'
|
|
1185
|
-
});
|
|
1186
|
-
}
|
|
1187
|
-
|
|
1188
|
-
// Contradiction 6: Multiple conflicting signals (network failed + strong feedback + no console errors)
|
|
1189
|
-
if (
|
|
1190
|
-
evidenceSignals.networkFailed &&
|
|
1191
|
-
evidenceSignals.strongUiFeedback &&
|
|
1192
|
-
!evidenceSignals.consoleErrors &&
|
|
1193
|
-
findingType?.includes('silent')
|
|
1194
|
-
) {
|
|
1195
|
-
contradictions.push({
|
|
1196
|
-
type: 'mixed_signals',
|
|
1197
|
-
details: 'Network failed but strong UI feedback present without console errors - user likely informed',
|
|
1198
|
-
severity: 'major'
|
|
1199
|
-
});
|
|
1200
|
-
}
|
|
1201
|
-
}
|
|
1202
|
-
|
|
1203
|
-
// ============================================================
|
|
1204
|
-
// GAP 5.2: CONFIDENCE FACTORS GENERATION
|
|
1205
|
-
// ============================================================
|
|
1206
|
-
|
|
1207
|
-
/**
|
|
1208
|
-
* Generate structured confidence factors with weights, values, and rationales.
|
|
1209
|
-
* Each factor explains how it contributes to the final confidence score.
|
|
1210
|
-
*/
|
|
1211
|
-
function generateConfidenceFactors({
|
|
1212
|
-
expectationStrength,
|
|
1213
|
-
sensorsPresent,
|
|
1214
|
-
evidenceSignals,
|
|
1215
|
-
boosts,
|
|
1216
|
-
penalties,
|
|
1217
|
-
contradictions,
|
|
1218
|
-
baseScore,
|
|
1219
|
-
totalBoosts,
|
|
1220
|
-
totalPenalties
|
|
1221
|
-
}) {
|
|
1222
|
-
const factors = [];
|
|
1223
|
-
|
|
1224
|
-
// Factor 1: Expectation strength (weight: high)
|
|
1225
|
-
factors.push({
|
|
1226
|
-
key: 'expectation_strength',
|
|
1227
|
-
weight: 0.25,
|
|
1228
|
-
value: expectationStrength,
|
|
1229
|
-
rationale: expectationStrength === 'PROVEN'
|
|
1230
|
-
? 'Expectation is proven from source code analysis'
|
|
1231
|
-
: `Expectation strength is ${expectationStrength}, not from proven source`,
|
|
1232
|
-
impact: expectationStrength === 'PROVEN' ? 'positive' : 'negative'
|
|
1233
|
-
});
|
|
1234
|
-
|
|
1235
|
-
// Factor 2: Sensor availability (weight: high)
|
|
1236
|
-
const sensorCount = Object.values(sensorsPresent).filter(Boolean).length;
|
|
1237
|
-
const sensorTotal = Object.keys(sensorsPresent).length;
|
|
1238
|
-
factors.push({
|
|
1239
|
-
key: 'sensor_availability',
|
|
1240
|
-
weight: 0.20,
|
|
1241
|
-
value: `${sensorCount}/${sensorTotal}`,
|
|
1242
|
-
rationale: sensorCount === sensorTotal
|
|
1243
|
-
? 'All sensors active and captured data'
|
|
1244
|
-
: `Only ${sensorCount} of ${sensorTotal} sensors captured data`,
|
|
1245
|
-
impact: sensorCount === sensorTotal ? 'positive' : 'negative'
|
|
1246
|
-
});
|
|
1247
|
-
|
|
1248
|
-
// Factor 3: UI feedback score (weight: medium) - GAP 5.2
|
|
1249
|
-
if (sensorsPresent.uiFeedback) {
|
|
1250
|
-
factors.push({
|
|
1251
|
-
key: 'ui_feedback_score',
|
|
1252
|
-
weight: 0.18,
|
|
1253
|
-
value: evidenceSignals.uiFeedbackScore.toFixed(2),
|
|
1254
|
-
rationale: evidenceSignals.uiFeedbackScore > 0.5
|
|
1255
|
-
? `Strong UI feedback detected (score: ${evidenceSignals.uiFeedbackScore.toFixed(2)}) - user likely received feedback`
|
|
1256
|
-
: evidenceSignals.uiFeedbackScore > 0
|
|
1257
|
-
? `Moderate UI feedback detected (score: ${evidenceSignals.uiFeedbackScore.toFixed(2)}) - some user feedback present`
|
|
1258
|
-
: 'No UI feedback detected - potential silent failure',
|
|
1259
|
-
impact: evidenceSignals.uiFeedbackScore > 0.5 ? 'negative' : 'positive'
|
|
1260
|
-
});
|
|
1261
|
-
}
|
|
1262
|
-
|
|
1263
|
-
// Factor 4: Network evidence (weight: medium)
|
|
1264
|
-
if (sensorsPresent.network) {
|
|
1265
|
-
const networkValue = evidenceSignals.networkFailed ? 'failed' : evidenceSignals.networkSuccess ? 'success' : 'none';
|
|
1266
|
-
factors.push({
|
|
1267
|
-
key: 'network_evidence',
|
|
1268
|
-
weight: 0.15,
|
|
1269
|
-
value: networkValue,
|
|
1270
|
-
rationale: evidenceSignals.networkFailed
|
|
1271
|
-
? 'Network requests failed - strong evidence of failure'
|
|
1272
|
-
: evidenceSignals.networkSuccess
|
|
1273
|
-
? 'Network requests succeeded - may not be a failure'
|
|
1274
|
-
: 'No network activity detected',
|
|
1275
|
-
impact: evidenceSignals.networkFailed ? 'positive' : evidenceSignals.networkSuccess ? 'negative' : 'neutral'
|
|
1276
|
-
});
|
|
1277
|
-
}
|
|
1278
|
-
|
|
1279
|
-
// Factor 5: Observable changes (weight: low)
|
|
1280
|
-
const observableChanges = [
|
|
1281
|
-
evidenceSignals.domChanged && 'DOM',
|
|
1282
|
-
evidenceSignals.urlChanged && 'URL',
|
|
1283
|
-
evidenceSignals.screenshotChanged && 'visual'
|
|
1284
|
-
].filter(Boolean);
|
|
1285
|
-
factors.push({
|
|
1286
|
-
key: 'observable_changes',
|
|
1287
|
-
weight: 0.12,
|
|
1288
|
-
value: observableChanges.length > 0 ? observableChanges.join(', ') : 'none',
|
|
1289
|
-
rationale: observableChanges.length > 0
|
|
1290
|
-
? `Observable changes detected: ${observableChanges.join(', ')} - user likely saw something`
|
|
1291
|
-
: 'No observable changes detected - potential silent failure',
|
|
1292
|
-
impact: observableChanges.length > 0 ? 'negative' : 'positive'
|
|
1293
|
-
});
|
|
1294
|
-
|
|
1295
|
-
// Factor 6: Contradictions (weight: penalty) - GAP 5.2
|
|
1296
|
-
if (contradictions.length > 0) {
|
|
1297
|
-
const criticalCount = contradictions.filter(c => c.severity === 'critical').length;
|
|
1298
|
-
const majorCount = contradictions.filter(c => c.severity === 'major').length;
|
|
1299
|
-
const minorCount = contradictions.filter(c => c.severity === 'minor').length;
|
|
1300
|
-
|
|
1301
|
-
factors.push({
|
|
1302
|
-
key: 'contradictions',
|
|
1303
|
-
weight: 0.10, // Non-negative weight; negativity represented via impact field
|
|
1304
|
-
value: `${contradictions.length} (${criticalCount}C/${majorCount}M/${minorCount}m)`,
|
|
1305
|
-
rationale: `Contradictory evidence detected: ${criticalCount} critical, ${majorCount} major, ${minorCount} minor - reduces confidence`,
|
|
1306
|
-
impact: 'negative' // Impact field indicates this reduces confidence
|
|
1307
|
-
});
|
|
1308
|
-
}
|
|
1309
|
-
|
|
1310
|
-
// Factor 7: Score composition (informational)
|
|
1311
|
-
factors.push({
|
|
1312
|
-
key: 'score_composition',
|
|
1313
|
-
weight: 1.0,
|
|
1314
|
-
value: `${baseScore} + ${totalBoosts} - ${totalPenalties} = ${Math.max(0, Math.min(100, baseScore + totalBoosts - totalPenalties))}`,
|
|
1315
|
-
rationale: `Base score: ${baseScore}, Boosts: +${totalBoosts}, Penalties: -${totalPenalties}`,
|
|
1316
|
-
impact: 'neutral'
|
|
1317
|
-
});
|
|
1318
|
-
|
|
1319
|
-
return factors;
|
|
1320
|
-
}
|
|
1321
|
-
// ============================================================
|
|
1322
|
-
// PHASE 11: JOURNEY STALL CONFIDENCE SCORING
|
|
1323
|
-
// ============================================================
|
|
1324
|
-
|
|
1325
|
-
/**
|
|
1326
|
-
* Score journey stall findings.
|
|
1327
|
-
*
|
|
1328
|
-
* Individual steps work (low confidence on each), but pattern across
|
|
1329
|
-
* sequence clearly shows stall (high journey-level confidence possible).
|
|
1330
|
-
*/
|
|
1331
|
-
function scoreJourneyStall({ expectation, evidenceSignals, boosts, penalties }) {
|
|
1332
|
-
let total = 0;
|
|
1333
|
-
|
|
1334
|
-
// Extract journey context
|
|
1335
|
-
const journeyEvidence = expectation?.evidence?.journeyContext || {};
|
|
1336
|
-
const stallPoints = expectation?.evidence?.stallPoints || [];
|
|
1337
|
-
|
|
1338
|
-
// +15 for multiple stall points (clear pattern)
|
|
1339
|
-
if (stallPoints.length >= 2) {
|
|
1340
|
-
total += 15;
|
|
1341
|
-
boosts.push(`Multiple stall points detected (${stallPoints.length}) - clear pattern`);
|
|
1342
|
-
}
|
|
1343
|
-
|
|
1344
|
-
// +12 if stall severity is CRITICAL
|
|
1345
|
-
const hasCritical = stallPoints.some(sp => sp.severity === 'CRITICAL');
|
|
1346
|
-
if (hasCritical) {
|
|
1347
|
-
total += 12;
|
|
1348
|
-
boosts.push('Critical severity stall points detected');
|
|
1349
|
-
}
|
|
1350
|
-
|
|
1351
|
-
// +10 if no navigation (classic stall indicator)
|
|
1352
|
-
const noNavStalls = stallPoints.filter(sp => sp.reasons.includes('no_navigation'));
|
|
1353
|
-
if (noNavStalls.length > 0) {
|
|
1354
|
-
total += 10;
|
|
1355
|
-
boosts.push(`Expected navigation blocked: ${noNavStalls.length} instances`);
|
|
1356
|
-
}
|
|
1357
|
-
|
|
1358
|
-
// +8 if no new actionable UI (user stuck with same options)
|
|
1359
|
-
const noUiStalls = stallPoints.filter(sp => sp.reasons.includes('no_new_actionable_ui'));
|
|
1360
|
-
if (noUiStalls.length > 0) {
|
|
1361
|
-
total += 8;
|
|
1362
|
-
boosts.push(`No new interactive elements: ${noUiStalls.length} instances`);
|
|
1363
|
-
}
|
|
1364
|
-
|
|
1365
|
-
// +8 if DOM stagnation across sequence
|
|
1366
|
-
const noDomStalls = stallPoints.filter(sp => sp.reasons.includes('no_dom_progression'));
|
|
1367
|
-
if (noDomStalls.length > 0) {
|
|
1368
|
-
total += 8;
|
|
1369
|
-
boosts.push(`DOM content unchanged: ${noDomStalls.length} instances`);
|
|
1370
|
-
}
|
|
1371
|
-
|
|
1372
|
-
// +10 if long sequence before stall (shows user persisted through multiple steps)
|
|
1373
|
-
const sequenceLength = journeyEvidence?.totalInteractions || 0;
|
|
1374
|
-
if (sequenceLength >= 5) {
|
|
1375
|
-
total += 10;
|
|
1376
|
-
boosts.push(`Long journey sequence (${sequenceLength} interactions) before stall`);
|
|
1377
|
-
}
|
|
1378
|
-
|
|
1379
|
-
// +8 for URL stagnation (stayed on same page despite actions)
|
|
1380
|
-
const urlProgression = journeyEvidence?.urlProgression || [];
|
|
1381
|
-
if (urlProgression.length <= 1 && sequenceLength >= 3) {
|
|
1382
|
-
total += 8;
|
|
1383
|
-
boosts.push(`URL unchanged across ${sequenceLength} interactions - clear stall`);
|
|
1384
|
-
}
|
|
1385
|
-
|
|
1386
|
-
return total;
|
|
1387
|
-
}
|
|
1388
|
-
|
|
1389
|
-
/**
|
|
1390
|
-
* Penalize journey stall findings.
|
|
1391
|
-
*
|
|
1392
|
-
* Reduce confidence if any step in journey clearly failed.
|
|
1393
|
-
*/
|
|
1394
|
-
function penalizeJourneyStall({ expectation, evidenceSignals, penalties }) {
|
|
1395
|
-
let total = 0;
|
|
1396
|
-
|
|
1397
|
-
const stallPoints = expectation?.evidence?.stallPoints || [];
|
|
1398
|
-
|
|
1399
|
-
// -20 if low severity stalls (might not be real blocking issue)
|
|
1400
|
-
const lowSeverity = stallPoints.filter(sp => sp.severity === 'LOW').length;
|
|
1401
|
-
if (lowSeverity === stallPoints.length && stallPoints.length > 0) {
|
|
1402
|
-
total -= 20;
|
|
1403
|
-
penalties.push('All stall points are LOW severity - weak pattern');
|
|
1404
|
-
}
|
|
1405
|
-
|
|
1406
|
-
// -15 if only 1 stall point (might be coincidence)
|
|
1407
|
-
if (stallPoints.length === 1) {
|
|
1408
|
-
total -= 15;
|
|
1409
|
-
penalties.push('Only single stall point - weak evidence of pattern');
|
|
1410
|
-
}
|
|
1411
|
-
|
|
1412
|
-
// -12 if URL did progress (navigation worked)
|
|
1413
|
-
const urlProgression = expectation?.evidence?.journeyContext?.urlProgression || [];
|
|
1414
|
-
if (urlProgression.length > 1) {
|
|
1415
|
-
total -= 12;
|
|
1416
|
-
penalties.push(`URL progressed (${urlProgression.length} distinct pages) - not complete stall`);
|
|
1417
|
-
}
|
|
1418
|
-
|
|
1419
|
-
// -10 if strong UI feedback detected (user might be informed)
|
|
1420
|
-
if (evidenceSignals?.strongUiFeedback) {
|
|
1421
|
-
total -= 10;
|
|
1422
|
-
penalties.push('Strong UI feedback score detected - not silent');
|
|
1423
|
-
}
|
|
1424
|
-
|
|
1425
|
-
// -8 if no navigation expectation violations (unexpected navigation stall)
|
|
1426
|
-
const navStalls = stallPoints.filter(sp => sp.reasons.includes('no_navigation')).length;
|
|
1427
|
-
const totalReasons = stallPoints.reduce((sum, sp) => sum + sp.reasons.length, 0);
|
|
1428
|
-
|
|
1429
|
-
if (navStalls === 0 && totalReasons > 0) {
|
|
1430
|
-
total -= 8;
|
|
1431
|
-
penalties.push('No navigation stalls - stall is not navigation-related');
|
|
1432
|
-
}
|
|
1433
|
-
|
|
1434
|
-
return total;
|
|
1435
|
-
}
|
|
1436
|
-
|
|
1437
|
-
// ============================================================
|
|
1438
|
-
// PHASE 12: EXPECTATION CHAIN BREAK SCORING
|
|
1439
|
-
// ============================================================
|
|
1440
|
-
|
|
1441
|
-
/**
|
|
1442
|
-
* Score expectation chain breaks.
|
|
1443
|
-
*
|
|
1444
|
-
* Chains of proven expectations breaking mid-sequence is high-confidence evidence
|
|
1445
|
-
* of a root cause failure.
|
|
1446
|
-
*/
|
|
1447
|
-
function scoreExpectationChainBreak({ expectation, evidenceSignals, boosts, penalties: _penalties }) {
|
|
1448
|
-
let total = 0;
|
|
1449
|
-
|
|
1450
|
-
const chainEvidence = expectation?.evidence || {};
|
|
1451
|
-
const chainLength = chainEvidence.chainLength || 0;
|
|
1452
|
-
const fulfilledSteps = chainEvidence.fulfilledSteps || 0;
|
|
1453
|
-
const brokenStepIndex = chainEvidence.brokenStepIndex || 0;
|
|
1454
|
-
|
|
1455
|
-
// +15 if chain is long (3+ steps proven before break)
|
|
1456
|
-
if (chainLength >= 3) {
|
|
1457
|
-
total += 15;
|
|
1458
|
-
boosts.push(`Long expectation chain (${chainLength} steps) - deep pattern proof`);
|
|
1459
|
-
}
|
|
1460
|
-
|
|
1461
|
-
// +12 if break occurs late in chain (past 50%)
|
|
1462
|
-
const breakDepth = brokenStepIndex / Math.max(1, chainLength);
|
|
1463
|
-
if (breakDepth >= 0.5 && brokenStepIndex > 0) {
|
|
1464
|
-
total += 12;
|
|
1465
|
-
boosts.push(`Chain broke late (step ${brokenStepIndex + 1}/${chainLength}) - proves path was valid`);
|
|
1466
|
-
}
|
|
1467
|
-
|
|
1468
|
-
// +10 if multiple steps fulfilled before break (shows pattern works initially)
|
|
1469
|
-
if (fulfilledSteps >= 2) {
|
|
1470
|
-
total += 10;
|
|
1471
|
-
boosts.push(`Multiple proven steps (${fulfilledSteps}) completed before failure - clear causality`);
|
|
1472
|
-
}
|
|
1473
|
-
|
|
1474
|
-
// +8 if first step was proven (entry point to chain is valid)
|
|
1475
|
-
if (fulfilledSteps > 0) {
|
|
1476
|
-
total += 8;
|
|
1477
|
-
boosts.push('Chain entry point was fulfilled - break is at downstream step');
|
|
1478
|
-
}
|
|
1479
|
-
|
|
1480
|
-
return total;
|
|
1481
|
-
}
|
|
1482
|
-
|
|
1483
|
-
/**
|
|
1484
|
-
* Penalize expectation chain breaks.
|
|
1485
|
-
*
|
|
1486
|
-
* Reduce confidence if chain evidence is weak or incomplete.
|
|
1487
|
-
*/
|
|
1488
|
-
function penalizeExpectationChainBreak({ expectation, evidenceSignals, penalties }) {
|
|
1489
|
-
let total = 0;
|
|
1490
|
-
|
|
1491
|
-
const chainEvidence = expectation?.evidence || {};
|
|
1492
|
-
const chainLength = chainEvidence.chainLength || 0;
|
|
1493
|
-
const fulfilledSteps = chainEvidence.fulfilledSteps || 0;
|
|
1494
|
-
const brokenStepIndex = chainEvidence.brokenStepIndex || 0;
|
|
1495
|
-
|
|
1496
|
-
// -15 if chain is too short (2 steps might be coincidence)
|
|
1497
|
-
if (chainLength <= 2) {
|
|
1498
|
-
total -= 15;
|
|
1499
|
-
penalties.push('Short chain (2 steps) - may be coincidence');
|
|
1500
|
-
}
|
|
1501
|
-
|
|
1502
|
-
// -12 if break occurs very early (step 1)
|
|
1503
|
-
if (brokenStepIndex <= 1) {
|
|
1504
|
-
total -= 12;
|
|
1505
|
-
penalties.push('Chain broke at entry point - not a chain break pattern');
|
|
1506
|
-
}
|
|
1507
|
-
|
|
1508
|
-
// -10 if no steps were fulfilled (trace doesn't support chain)
|
|
1509
|
-
if (fulfilledSteps === 0) {
|
|
1510
|
-
total -= 10;
|
|
1511
|
-
penalties.push('No chain steps were fulfilled - chain pattern not evident');
|
|
1512
|
-
}
|
|
1513
|
-
|
|
1514
|
-
// -8 if strong UI feedback present (user might have been informed of issue)
|
|
1515
|
-
if (evidenceSignals?.strongUiFeedback) {
|
|
1516
|
-
total -= 8;
|
|
1517
|
-
penalties.push('Strong UI feedback detected - not silent');
|
|
1518
|
-
}
|
|
1519
|
-
|
|
1520
|
-
return total;
|
|
1521
|
-
}
|