Files
rods/gui-ts/src/state/engineeringChecks.ts
Conner Majic 64e9d31373 feat: gate heavy solver JSON, field traceability API, GUI rod/export depth
- C: emit profiles/diagnostics/fourier only when enable flags are set; null otherwise
- API: fieldTraceability on case parse/default and solve; fix GET /solve/default options
- Tests: golden fingerprint, quality gates, C diagnostics invariants; cardQa mean empty guard
- Makefile: test-solver-sanitize ASan/UBSan target; README and COMPUTE_PLAN updates
- GUI: taper weight/MTS/guides/sinker round-trip, rod catalog, solver output toggles,
  results (profiles/diagnostics/Fourier/traceability), engineering checks and tabs
- Restore canonical WellName in base-case for regression; trace TaperGuidesCountArray

Made-with: Cursor
2026-04-16 23:19:00 -06:00

71 lines
2.0 KiB
TypeScript

import type { CaseState } from "./caseModel";
export const PUMP_ROD_MISMATCH_M = 15;
export type EngineeringIssue = {
severity: "warning" | "error";
code: string;
message: string;
};
export type EngineeringChecks = {
issues: EngineeringIssue[];
hasBlockingError: boolean;
};
export function runEngineeringChecks(state: CaseState): EngineeringChecks {
const issues: EngineeringIssue[] = [];
const activeTaper = state.taper.filter((t) => Number.isFinite(t.length) && t.length > 0);
const rodTotal = activeTaper.reduce((acc, t) => acc + t.length, 0);
const pumpDepth = state.pumpDepth;
if (rodTotal > 0 && pumpDepth > 0) {
const diff = Math.abs(pumpDepth - rodTotal);
if (diff > PUMP_ROD_MISMATCH_M) {
issues.push({
severity: "error",
code: "PUMP_ROD_MISMATCH_15M",
message: `Pump depth (${pumpDepth.toFixed(1)}) and total rod length (${rodTotal.toFixed(
1
)}) differ by ${diff.toFixed(1)} m (> ${PUMP_ROD_MISMATCH_M} m limit).`
});
}
}
if (state.survey.length < 2) {
issues.push({
severity: "error",
code: "SURVEY_TOO_SHORT",
message: "Trajectory needs at least 2 survey stations."
});
} else {
let nonMonotonic = false;
for (let i = 1; i < state.survey.length; i += 1) {
if (state.survey[i].md <= state.survey[i - 1].md) nonMonotonic = true;
}
if (nonMonotonic) {
issues.push({
severity: "error",
code: "SURVEY_MD_NON_MONOTONIC",
message: "Measured depth must strictly increase between survey stations."
});
}
const maxMd = state.survey[state.survey.length - 1].md;
if (pumpDepth > 0 && maxMd > 0 && maxMd < pumpDepth - 10) {
issues.push({
severity: "warning",
code: "SURVEY_BELOW_PUMP_MISSING",
message: `Trajectory ends at MD ${maxMd.toFixed(
1
)}, shallower than pump depth ${pumpDepth.toFixed(1)}.`
});
}
}
return {
issues,
hasBlockingError: issues.some((issue) => issue.severity === "error")
};
}