whitepaper: re-add 10 missing entries + 11 new defects this session, count 578→590; rebuild PDF

This commit is contained in:
russell@unturf.com 2026-03-27 22:18:31 -04:00
parent e4ee168b1e
commit 2e4f7807d5
401 changed files with 3914 additions and 114 deletions

View file

@ -0,0 +1,95 @@
package unit;
import java.util.*;
/**
* Standalone unit test for prometheus-0002: CWE-407.
*
* prometheus-0002: dependencyMap.dependencies() O(R²×D) in AnalyseRules
* slow() mirrors the defective pattern: for each of R rules, scan all R
* map entries doing a linear list-contains on the dependents slice.
* Cost per call: O(R × D); total for AnalyseRules: O(R² × D).
* fast() maintains an inverse map built once in O(R×D); each lookup O(1).
* Cost per call: O(1); total for AnalyseRules: O(R).
* Assert: slowOps > fastOps * 5x for R=200 rules with D=10 dependents each.
*/
public class Prometheus0002DependenciesTest {
/**
* Slow path dependencies(r): iterate entire forward map, slices.Contains per entry.
* forwardMap: ruleId list of ruleIds that depend on it (dependents).
*/
static long slowAnalyseRules(Map<Integer, List<Integer>> forwardMap, List<Integer> rules) {
long ops = 0;
for (int r : rules) {
// dependencies(r): scan all entries
for (Map.Entry<Integer, List<Integer>> e : forwardMap.entrySet()) {
// slices.Contains(dependents, r) O(D) linear scan
for (int dep : e.getValue()) {
ops++;
if (dep == r) break; // early exit on hit, worst case no hit
}
}
}
return ops;
}
/**
* Fast path precompute inverse map; dependencies(r) is O(1) lookup.
*/
static long fastAnalyseRules(Map<Integer, List<Integer>> forwardMap, List<Integer> rules) {
long ops = 0;
// Build inverse map once: O(R×D)
Map<Integer, List<Integer>> inverseMap = new HashMap<>();
for (Map.Entry<Integer, List<Integer>> e : forwardMap.entrySet()) {
int rule = e.getKey();
for (int dep : e.getValue()) {
ops++; // cost to build inverse
inverseMap.computeIfAbsent(dep, k -> new ArrayList<>()).add(rule);
}
}
// Now each dependencies(r) lookup is O(1)
for (int r : rules) {
ops++; // O(1) map lookup
List<Integer> deps = inverseMap.get(r);
// use deps (no scan needed)
if (deps != null) {
ops += deps.size(); // charge for reading results (same in both)
}
}
return ops;
}
static void testDependencies() {
int R = 200; // number of rules
int D = 10; // average dependents per rule (fan-out)
// Build a synthetic forward dependency map:
// rule i has dependents [i+1, i+2, ..., i+D] (mod R) so D deps each
List<Integer> rules = new ArrayList<>(R);
for (int i = 0; i < R; i++) rules.add(i);
Map<Integer, List<Integer>> forwardMap = new HashMap<>();
for (int i = 0; i < R; i++) {
List<Integer> dependents = new ArrayList<>(D);
for (int j = 1; j <= D; j++) {
dependents.add((i + j) % R);
}
forwardMap.put(i, dependents);
}
long sOps = slowAnalyseRules(forwardMap, rules);
long fOps = fastAnalyseRules(forwardMap, rules);
int minRatio = 5;
boolean pass = sOps > fOps * minRatio;
System.out.printf("prometheus-0002 [R=%d D=%d]: slow=%d fast=%d ratio=%.1fx — %s%n",
R, D, sOps, fOps, (double) sOps / fOps, pass ? "PASS" : "FAIL");
if (!pass) throw new AssertionError("prometheus-0002 FAIL: slow=" + sOps + " fast=" + fOps);
}
public static void main(String[] args) {
testDependencies();
System.out.println("1/1 PASS");
}
}