Commit 6edca7c6 authored by Andrey Filippov's avatar Andrey Filippov

CLAUDE: B3 oracle order-independent by packed index + FAIL-safe + profile attribution

The 07/16 22:09 B3 gate run FALSE-FAILed the one-shot oracle: the naive
POSITIONAL compare ignored that correlate2D_inter assigns corr rows via
atomicAdd - row ORDER is legitimately nondeterministic between runs (the
rung-1 'order-independent corr compare by packed index' rule); all 497
poses stayed BYTE-IDENTICAL to the B4 record while the run was driven by
batched cycles, proving the chain end-to-end. Fixes:
- oracle compares per packed corr index (HashMap row lookup): index SETS
  must match and every index-matched 8-float peak row must be bit-exact;
- REAL oracle FAIL now disables the batched path for the run (fail-safe:
  a divergence must never drive production);
- B3_CHAIN profile stage attributed from the pre-gpuTaskBuild timestamp
  (was a fresh start AFTER the chain -> recorded ~0 and leaked ~2 ms/
  cycle into 'leanMeasure other') and printed in the profile summary
  (printSummary never printed the new stage).

mvn PASS. Oracle PASS line expected on the next routine run.
Co-Authored-By: 's avatarClaude Fable 5 <noreply@anthropic.com>
parent 88468d62
......@@ -353,6 +353,7 @@ public class CuasPoseRT {
printStage(REPORT_QC, postSum);
printDerived(" post other", postSum - sum(MOTION_BLUR) - sum(LEAN_FIT) - sum(REPORT_QC), postSum);
printStage(MEASURE_TOTAL, postSum);
printStage(B3_CHAIN, postSum); // rung B3: batched cycles (replaces stages 6-13) // By Claude on 07/16/2026
for (int stage = GRID_TRANSFORM; stage <= MEASURE_OTHER; stage++) printStage(stage, postSum);
printStage(LMA_PREPARE, postSum);
for (int stage = PREP_SETUP; stage <= PREP_FX2; stage++) printStage(stage, postSum); // By Claude on 07/17/2026
......@@ -613,7 +614,7 @@ public class CuasPoseRT {
// first cycle); debug-fetch cycles and armed pose_corr captures stay
// granular (they read mid-chain state). By Claude on 07/16/2026.
final boolean b3_try = gpuQuad.supportsPoseMeasureCycle() &&
!PoseCorrExport.isArmed() &&
!PoseCorrExport.isArmed() && !b3_oracle_failed &&
(corr_pd_out == null) && (img_out == null) &&
((clt_parameters.curt.pose_lma_debug < 1) || b3_oracle_reported);
if (b3_try) b3_stats = new int [3];
......@@ -624,6 +625,13 @@ public class CuasPoseRT {
}
final boolean b1_built = (b1_tasks != null);
final boolean b3_ran = (b3_stats != null); // By Claude on 07/16/2026
// rung B3 profile: the batched chain ran INSIDE gpuTaskBuild - attribute it
// from the pre-build timestamp (the 22:09 gate run took a fresh start below
// and recorded ~0, leaking ~2 ms/cycle into "leanMeasure other").
// By Claude on 07/16/2026.
if (b3_ran && (rtProfile != null)) {
measureAccounted += rtProfile.addElapsed(RtPoseProfile.B3_CHAIN, profileStart);
}
// 1. scene grid at the current pose estimate (average-camera coordinates) -
// LEGACY CPU front end only (B1 projects on-device) // By Claude on 07/16/2026
final double [][] scene_pXpYD = b1_built ? null : OpticalFlow.transformToScenePxPyD(
......@@ -662,11 +670,11 @@ public class CuasPoseRT {
if (b3_ran) {
// 3-B rung B3: the whole GPU measure chain (task_update -> geometry/
// convert x2 -> consolidate -> inter-corr -> normalize -> peak) already
// ran as ONE JNA call inside gpuTaskBuild - only the corr-index/peak
// D2H and the Java unpack remain below. By Claude on 07/16/2026.
// ran as ONE JNA call inside gpuTaskBuild (attributed to B3_CHAIN above) -
// only the corr-index/peak D2H and the Java unpack remain below.
// By Claude on 07/16/2026.
cons_tasks = b1_tasks;
resident_tasks = true;
if (rtProfile != null) measureAccounted += rtProfile.addElapsed(RtPoseProfile.B3_CHAIN, profileStart);
} else if (b1_built) {
// 3-B rung B1: tasks are already GPU-built in the resident slots. The
// Java-side skeleton only carries count/txy/task_size for consolidation
......@@ -935,21 +943,40 @@ public class CuasPoseRT {
}
// 3-B rung B3 one-shot oracle: the batched chain ran FIRST this cycle (inside
// gpuTaskBuild) and captured its indices+peaks; the granular chain just re-ran
// the identical sequence - the two must match BIT-EXACT (any diff = a real
// enqueue-order/argument bug, the DP-spike precedent). By Claude on 07/16/2026.
// the identical sequence - every (tile,pair) row must match BIT-EXACT.
// ORDER-INDEPENDENT by packed corr index (the rung-1 rule): correlate2D_inter
// assigns rows via atomicAdd, so the ROW ORDER is legitimately nondeterministic
// between runs - only the per-index content is contractual (all consumers map
// rows through corr_indices). The 07/16 22:09 gate run FALSE-FAILed on a naive
// positional compare while all 497 poses stayed byte-identical - fixed here.
// By Claude on 07/16/2026.
if ((b3_oracle_peaks != null) && !b3_oracle_reported) {
final boolean idx_ok = Arrays.equals(corr_indices, b3_oracle_indices);
long mism = 0;
if (gpu_peaks.length != b3_oracle_peaks.length) mism = -1;
else for (int i = 0; i < gpu_peaks.length; i++) {
if (Float.floatToRawIntBits(gpu_peaks[i]) != Float.floatToRawIntBits(b3_oracle_peaks[i])) mism++;
final java.util.HashMap<Integer, Integer> oracle_rows = new java.util.HashMap<>();
for (int n = 0; n < b3_oracle_indices.length; n++) oracle_rows.put(b3_oracle_indices[n], n);
int missing = 0; // granular rows whose packed index the batched run never emitted
long mism = 0; // bit-mismatched floats among index-matched rows
final int row_floats = GpuQuad.PEAK_ROW_FLOATS;
for (int n = 0; n < corr_indices.length; n++) {
final Integer on = oracle_rows.remove(corr_indices[n]);
if (on == null) { missing++; continue; }
for (int k = 0; k < row_floats; k++) {
if (Float.floatToRawIntBits(gpu_peaks[n * row_floats + k]) !=
Float.floatToRawIntBits(b3_oracle_peaks[on * row_floats + k])) mism++;
}
}
final int extra = oracle_rows.size(); // batched-only indices left unmatched
final boolean oracle_pass = (missing == 0) && (extra == 0) && (mism == 0);
System.out.println(String.format(
"CuasPoseRT B3 batched-vs-granular oracle (one-shot): %d corr tiles, indices %s,"+
" peak bit-mismatches=%d, consolidation stats=(%d, %d, %d) -> %s",
corr_indices.length, idx_ok ? "IDENTICAL" : "DIFFER", mism,
"CuasPoseRT B3 batched-vs-granular oracle (one-shot, order-independent by packed index):"+
" %d corr rows, unmatched granular=%d batched=%d, peak bit-mismatches=%d,"+
" consolidation stats=(%d, %d, %d) -> %s",
corr_indices.length, missing, extra, mism,
b3_oracle_stats[0], b3_oracle_stats[1], b3_oracle_stats[2],
(idx_ok && (mism == 0)) ? "PASS" : "FAIL"));
oracle_pass ? "PASS" : "FAIL"));
if (!oracle_pass) { // fail-safe: a REAL divergence must never drive production
b3_oracle_failed = true;
System.out.println("CuasPoseRT: B3 batched chain DISABLED for this run (oracle FAIL) - staying granular");
}
b3_oracle_reported = true;
b3_oracle_indices = null; b3_oracle_peaks = null; b3_oracle_stats = null;
}
......@@ -1043,6 +1070,7 @@ public class CuasPoseRT {
// < 1). By Claude on 07/16/2026.
private static boolean b3_path_reported = false; // once-per-program "path active" note
private static boolean b3_oracle_reported = false; // one-shot batched-vs-granular bit compare
private static boolean b3_oracle_failed = false; // fail-safe: FAIL keeps the run granular // By Claude on 07/16/2026
private static int [] b3_oracle_indices = null; // oracle captures (arm cycle only)
private static float [] b3_oracle_peaks = null;
private static int [] b3_oracle_stats = null;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment