fix: the detail verdict never actually asked the sharpness question
dpVerdict gated on structure >= 0.85 and returned "the shot moved"
otherwise — so `detail` and `edge_aligned` were never consulted. The
block-repeat sweep's best row was structure 0.831, which means all 19
comparisons short-circuited and the "sharper" branch was unreachable for
the entire experiment. Reporting that as "not one row read sharper" was
true and misleading: sharpness was never evaluated at all.
The threshold was also wrong on its own terms. Blocks 10/15/44/45 were
judged indistinguishable from plain by eye and measured 0.73-0.83, so
the cliff was rejecting pairs a person calls the same shot.
Now: how far the shot moved is a PREFIX, not a verdict, and the detail
half is always reported alongside it ("shot moved 17% · detail
unchanged"), which is strictly more than either half alone. Only below
0.35 — where the two runs share almost nothing — is a detail comparison
refused outright.
Tested against the sweep's real rows, including a hypothetical genuine
sharpen to prove the branch is now reachable.
This commit is contained in:
@@ -28,6 +28,34 @@ test("every branch runs without throwing", () => {
|
||||
cases.forEach((r) => [null, 0.1].forEach((f) => assert.equal(typeof dpVerdict(r, f), "string")));
|
||||
});
|
||||
|
||||
test("a moved shot still gets a detail verdict — the old 0.85 cliff hid it", () => {
|
||||
// The block-repeat sweep's best row was structure 0.831, so a >=0.85 gate returned "the
|
||||
// shot moved" for all 19 comparisons and never once evaluated sharpness. Both halves get
|
||||
// reported now: how much the shot moved AND what happened to the detail.
|
||||
const v = dpVerdict(row({ structure: 0.831, detail: 0.99,
|
||||
changed: { h3_block_repeat: ["", "40"] } }), 0);
|
||||
assert.match(v, /shot moved 17%/);
|
||||
assert.match(v, /detail unchanged/);
|
||||
});
|
||||
|
||||
test("sharper is reachable when all three numbers agree", () => {
|
||||
const v = dpVerdict(row({ structure: 0.95, detail: 1.3, edge_aligned: 0.7,
|
||||
changed: { h3_block_repeat: ["", "40"] } }), 0);
|
||||
assert.match(v, /SHARPER/);
|
||||
});
|
||||
|
||||
test("more detail spread evenly is grain, not sharpening", () => {
|
||||
const v = dpVerdict(row({ structure: 0.95, detail: 1.3, edge_aligned: 0.05,
|
||||
changed: { h3_block_repeat: ["", "40"] } }), 0);
|
||||
assert.match(v, /grain, not sharpening/);
|
||||
});
|
||||
|
||||
test("two nearly unrelated pictures refuse a detail verdict", () => {
|
||||
const v = dpVerdict(row({ structure: 0.09, detail: 1.25,
|
||||
changed: { h3_block_repeat: ["", "40"] } }), 0);
|
||||
assert.match(v, /detail cannot be compared/);
|
||||
});
|
||||
|
||||
test("a pair with nothing changed reports the noise floor", () => {
|
||||
const v = dpVerdict(row({ structure: 0.9 }), 0.1);
|
||||
assert.match(v, /noise floor: two identical runs differ by 10%/);
|
||||
@@ -36,6 +64,7 @@ test("a pair with nothing changed reports the noise floor", () => {
|
||||
test("movement is expressed against the measured floor", () => {
|
||||
const v = dpVerdict(row({ structure: 0.42, changed: { h3_repr_steering: [true, false] } }), 0.1);
|
||||
assert.match(v, /5\.8x your noise floor/);
|
||||
assert.match(v, /detail unchanged/); // and the detail half survives the prefix
|
||||
});
|
||||
|
||||
test("a real prompt change voids the comparison, a small drift does not", () => {
|
||||
@@ -43,7 +72,7 @@ test("a real prompt change voids the comparison, a small drift does not", () =>
|
||||
/prompt or scenes changed/);
|
||||
const drift = dpVerdict(row({ changed: { conditioning: [null, 0.02] }, cond_shift: 0.02,
|
||||
structure: 0.95, detail: 1.3, edge_aligned: 0.7 }), 0.1);
|
||||
assert.match(drift, /sharper/);
|
||||
assert.match(drift, /SHARPER/i);
|
||||
});
|
||||
|
||||
test("the floor is the median of the quiet pairs, so one outlier cannot set it", () => {
|
||||
|
||||
@@ -443,20 +443,29 @@
|
||||
return `noise floor: two identical runs differ by ${(moved * 100).toFixed(0)}% `
|
||||
+ `(detail x${r.detail.toFixed(2)}). Anything smaller than this is not a result.`;
|
||||
}
|
||||
if (r.structure < 0.85) {
|
||||
return r.same_seed
|
||||
? `the shot moved ${(moved * 100).toFixed(0)}%${vsFloor} — this changed the picture, `
|
||||
+ "not just its detail"
|
||||
: "different seed — two separate generations, so detail cannot be compared. Rerun "
|
||||
+ "the same seed with the change off, then on.";
|
||||
if (r.same_seed === false) {
|
||||
return "different seed — two separate generations, so detail cannot be compared. Rerun "
|
||||
+ "the same seed with the change off, then on.";
|
||||
}
|
||||
// Below this the two runs share almost nothing and the detail ratio compares unrelated
|
||||
// pictures. Everything above it still gets a detail verdict, because "the shot moved AND
|
||||
// the detail did not" is strictly more informative than either half alone — and the old
|
||||
// 0.85 cliff swallowed the whole block-repeat sweep, whose best row was 0.831, so the
|
||||
// sharpness question was never actually asked. The user's own eyes put the threshold of
|
||||
// VISIBLE change near 30% moved, well past where the cliff sat.
|
||||
if (r.structure < 0.35) {
|
||||
return `the shot moved ${(moved * 100).toFixed(0)}%${vsFloor} — barely the same `
|
||||
+ "generation, so detail cannot be compared";
|
||||
}
|
||||
const gain = (r.detail - 1) * 100;
|
||||
const caveat = r.same_seed === false ? " (different seed — treat as indicative only)" : "";
|
||||
if (Math.abs(gain) < 2) return "no real change in detail" + caveat;
|
||||
if (gain < 0) return `detail DOWN ${Math.abs(gain).toFixed(0)}% — softer, not sharper` + caveat;
|
||||
return (r.edge_aligned > 0.35
|
||||
? `sharper — +${gain.toFixed(0)}% detail, landing on existing edges`
|
||||
: `+${gain.toFixed(0)}% detail but spread evenly — reads as grain, not sharpening`) + caveat;
|
||||
// How much the shot moved is a PREFIX, not a verdict: it says how much of the change is
|
||||
// "a different shot" so the detail half can be read for what it is.
|
||||
const shot = moved > 0.05 ? `shot moved ${(moved * 100).toFixed(0)}%${vsFloor} · ` : "";
|
||||
if (Math.abs(gain) < 2) return shot + "detail unchanged";
|
||||
if (gain < 0) return shot + `detail DOWN ${Math.abs(gain).toFixed(0)}% — softer`;
|
||||
return shot + (r.edge_aligned > 0.35
|
||||
? `SHARPER — +${gain.toFixed(0)}% detail, landing on existing edges`
|
||||
: `+${gain.toFixed(0)}% detail but spread evenly — grain, not sharpening`);
|
||||
}
|
||||
|
||||
// What this pair actually was. The probe cannot know which knob you consider the
|
||||
|
||||
Reference in New Issue
Block a user