feat(#22): Gate B BDFT identity and rounding (TV-3, TV-10)

Pure units module: bdft = sqft × thickness_in (no /12), half-up
rounding for sqft/bdft/price, length to nearest 1/8". Property
checks for monotonicity in thickness and sqft.

TDD: red evidence in test-results/tv3-tv10-red.txt, then minimum impl.

Results:
TV-3 | pass | test-results/tv3-tv10-green.txt
TV-10 | pass | test-results/tv3-tv10-green.txt
This commit is contained in:
2026-09-07 06:02:08 +00:00
parent 3c2f8871a8
commit 55d66b9644
6 changed files with 181 additions and 0 deletions
+39
View File
@@ -0,0 +1,39 @@
import {
AREA_DECIMALS,
BDFT_DECIMALS,
INCH_STEP,
PRICE_DECIMALS,
} from "./constants.js";
/** Half-up at .5 (away from zero). */
export function roundHalfUp(value: number, decimals: number): number {
if (!Number.isFinite(value)) {
return value;
}
const factor = 10 ** decimals;
const scaled = Math.abs(value) * factor;
const rounded = Math.floor(scaled + 0.5) / factor;
return value < 0 ? -rounded : rounded;
}
/** Nearest INCH_STEP (1/8"). */
export function roundLengthIn(lengthIn: number): number {
return Math.round(lengthIn / INCH_STEP) * INCH_STEP;
}
export function roundSqft(sqft: number): number {
return roundHalfUp(sqft, AREA_DECIMALS);
}
export function roundBdft(bdft: number): number {
return roundHalfUp(bdft, BDFT_DECIMALS);
}
export function roundPrice(price: number): number {
return roundHalfUp(price, PRICE_DECIMALS);
}
/** bdft = sqft × thickness_in. No divide-by-12. */
export function computeBdft(sqft: number, thicknessIn: number): number {
return roundBdft(sqft * thicknessIn);
}