Deploy to Staging / Build Images (push) Successful in 5m32s
Deploy to Staging / Deploy to Staging (push) Successful in 44s
Deploy to Staging / Verify Staging (push) Successful in 5s
Deploy to Staging / Notify Staging Ready (push) Successful in 4s
Deploy to Staging / Notify Staging Failure (push) Has been skipped
Removes the old planner/decision-critic/role-agents/domain-agents system (step-injector scripts, stale scopes, sprint-era workflow) and replaces it with 16 ground-truth-verified skills under .claude/skills/: change control, debugging playbook, failure archaeology, architecture contract, domain reference, OCR/Gemini pipeline, config and secrets, build and env, run and operate, diagnostics (with tested scripts), validation and QA, docs and writing, launch readiness, deploy-safety campaign, proof and analysis toolkit, and research frontier. RULE 0/1/2, the temporal-contamination rule, and the decision stress-test protocol are carried forward into the new skills; the retired content remains in git history. Co-Authored-By: Claude Fable 5 <[email protected]>
78 lines
3.4 KiB
Bash
Executable File
78 lines
3.4 KiB
Bash
Executable File
#!/bin/bash
|
|
# check-numeric-coercion.sh - Find NUMERIC/DECIMAL columns returned from
|
|
# repositories without Number()/parseFloat() coercion.
|
|
#
|
|
# Why: node-postgres returns NUMERIC/DECIMAL (OID 1700) as *strings*.
|
|
# backend/src/core/config/database.ts overrides only the DATE parser, so
|
|
# every repository mapper must coerce manually. Missed coercion is this
|
|
# project's #1 recurring bug class (issues #239, #241, #244).
|
|
#
|
|
# Usage: ./check-numeric-coercion.sh (read-only; run from anywhere in repo)
|
|
# Exit: 0 = no suspects, 1 = suspects found, 2 = setup error
|
|
set -u
|
|
|
|
ROOT="$(git rev-parse --show-toplevel 2>/dev/null)"
|
|
[ -z "$ROOT" ] && { echo "ERROR: not inside a git repo" >&2; exit 2; }
|
|
SRC="$ROOT/backend/src"
|
|
[ -d "$SRC" ] && cd "$ROOT" || { echo "ERROR: $SRC missing" >&2; exit 2; }
|
|
|
|
# 1. Collect numeric/decimal column names from all migration SQL.
|
|
# Three shapes: column definition lines, ADD COLUMN, ALTER COLUMN ... TYPE.
|
|
COLS=$(
|
|
{
|
|
grep -rhiE '^[[:space:]]*"?[a-z_]+"?[[:space:]]+(numeric|decimal)[[:space:](]' \
|
|
--include='*.sql' "$SRC" | awk '{gsub(/"/,""); print tolower($1)}'
|
|
grep -rhioE 'add column (if not exists )?"?[a-z_]+"? +(numeric|decimal)' \
|
|
--include='*.sql' "$SRC" | awk '{gsub(/"/,""); print tolower($(NF-1))}'
|
|
grep -rhioE 'alter column "?[a-z_]+"? type +(numeric|decimal)' \
|
|
--include='*.sql' "$SRC" | awk '{gsub(/"/,""); print tolower($(NF-2))}'
|
|
} | sort -u
|
|
)
|
|
[ -z "$COLS" ] && { echo "ERROR: no numeric columns found (wrong dir?)" >&2; exit 2; }
|
|
|
|
echo "Numeric/decimal columns found in migrations:"
|
|
echo "$COLS" | tr '\n' ' '; echo; echo
|
|
|
|
# 2. In every repository file, flag lines that read row.<col> without
|
|
# Number( or parseFloat( on the same line.
|
|
SUSPECTS=0
|
|
for col in $COLS; do
|
|
HITS=$(find "$SRC" -name '*.repository.ts' -exec \
|
|
grep -nE "row\.${col}([^a-zA-Z0-9_]|\$)" {} + 2>/dev/null |
|
|
grep -v 'parseFloat(' | grep -v 'Number(')
|
|
if [ -n "$HITS" ]; then
|
|
echo "SUSPECT column '$col' (string from pg, no coercion on line):"
|
|
echo "$HITS" | sed "s|$ROOT/||; s/^/ /"
|
|
SUSPECTS=$((SUSPECTS + $(echo "$HITS" | wc -l | tr -d ' ')))
|
|
fi
|
|
done
|
|
|
|
# 3. Flag raw-row returns (the actual shape of bug #244: "return res.rows[0]"
|
|
# bypasses the mapper entirely) in features whose migrations define
|
|
# numeric columns. Scalar returns (.count/.exists/.length) are filtered.
|
|
for repo in $(find "$SRC/features" -name '*.repository.ts'); do
|
|
feat=$(echo "$repo" | sed "s|$SRC/features/||; s|/.*||")
|
|
featcols=$(grep -rhiE "(numeric|decimal)" --include='*.sql' \
|
|
"$SRC/features/$feat/migrations" 2>/dev/null | head -1)
|
|
[ -z "$featcols" ] && continue
|
|
RAW=$(grep -nE 'return (res|result)\.rows' "$repo" |
|
|
grep -vE 'map[A-Za-z]*\(|\.map\(|\?\.|\.length|\.count|\.exists')
|
|
if [ -n "$RAW" ]; then
|
|
echo "SUSPECT raw-row return in numeric-bearing feature '$feat':"
|
|
echo "$RAW" | sed "s|^| ${repo#"$ROOT"/}:|"
|
|
SUSPECTS=$((SUSPECTS + $(echo "$RAW" | wc -l | tr -d ' ')))
|
|
fi
|
|
done
|
|
|
|
echo
|
|
if [ "$SUSPECTS" -eq 0 ]; then
|
|
echo "PASS: no uncoerced numeric column reads or raw-row returns found."
|
|
exit 0
|
|
else
|
|
echo "FAIL: $SUSPECTS suspect line(s). Each must wrap the value in Number()"
|
|
echo "or parseFloat() (nullable: 'row.x != null ? parseFloat(row.x) : null')."
|
|
echo "Limitations: same-line heuristic; coercion done on a different line or"
|
|
echo "in the service layer will still be flagged - verify before fixing."
|
|
exit 1
|
|
fi
|