amsd-pipeline-shared 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/amsd-pipeline-shared.js +3 -0
- package/docs/gateway-baseline-2.0.80.md5 +4 -0
- package/docs/gateway-files.txt +5 -0
- package/orchestrations/scripts/lib/preflight.sh +65 -0
- package/orchestrations/scripts/lib/prelaunch.js +294 -0
- package/orchestrations/scripts/preflight-check.sh +696 -0
- package/orchestrations/scripts/preflight-prd-integrity.sh +36 -0
- package/orchestrations/scripts/preflight-static.sh +251 -0
- package/package.json +1 -1
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# preflight-prd-integrity.sh — exhaustive PRD integrity gate.
|
|
3
|
+
#
|
|
4
|
+
# Catches every category of PRD drift that has caused run failures:
|
|
5
|
+
# - Stale runtime artifacts (BUG- stories, numbered bug-fix split suffixes)
|
|
6
|
+
# - Provider/model misalignment
|
|
7
|
+
# - Phase structure corruption
|
|
8
|
+
# - Dirty pre-run state (non-pending active stories)
|
|
9
|
+
# - Path drift (outputDir mismatch, /tmp/ stragglers)
|
|
10
|
+
# - AC quality issues (phantom imports, oversized)
|
|
11
|
+
#
|
|
12
|
+
# Usage:
|
|
13
|
+
# bash orchestrations/scripts/preflight-prd-integrity.sh --prd <path>
|
|
14
|
+
#
|
|
15
|
+
# Exit 0 = all checks passed. Exit 1 = one or more HARD failures.
|
|
16
|
+
# Warnings (⚠) are printed but do not fail the gate.
|
|
17
|
+
|
|
18
|
+
set -euo pipefail
|
|
19
|
+
|
|
20
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
21
|
+
|
|
22
|
+
PRD_FILE=""
|
|
23
|
+
PHASE_ARG=""
|
|
24
|
+
while [[ $# -gt 0 ]]; do
|
|
25
|
+
case $1 in
|
|
26
|
+
--prd) PRD_FILE="$2"; shift 2 ;;
|
|
27
|
+
--phase) PHASE_ARG="$2"; shift 2 ;;
|
|
28
|
+
*) echo "Unknown arg: $1" >&2; exit 1 ;;
|
|
29
|
+
esac
|
|
30
|
+
done
|
|
31
|
+
|
|
32
|
+
if [[ -z "$PRD_FILE" || ! -f "$PRD_FILE" ]]; then
|
|
33
|
+
echo " ✗ PRD file not found: $PRD_FILE" >&2; exit 1
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
python3 "$SCRIPT_DIR/lib/handlers/prd-integrity-audit.py" "$PHASE_ARG" "$PRD_FILE" "$SCRIPT_DIR/../config/providers.json"
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# PRE-FLIGHT — everything that can be known without spending a run.
|
|
3
|
+
#
|
|
4
|
+
# Every live failure on 2026-08-19/20 was catchable offline in under a minute. None needed a model
|
|
5
|
+
# call, a codeline, or a dollar. This runs the checks that would have caught them.
|
|
6
|
+
#
|
|
7
|
+
# Exit 0 = safe to launch. Non-zero = a defect that WILL surface in a run.
|
|
8
|
+
|
|
9
|
+
# THE COVERAGE GATE IS NOT HERE. This file is a STATIC SOURCE AUDIT — it reads code and reports
|
|
10
|
+
# findings, and it is run at a desk as often as in a pipeline. Halting it on a coverage measurement
|
|
11
|
+
# meant it printed nothing at all whenever coverage was stale, so every check it performs vanished
|
|
12
|
+
# and the operator saw an empty report rather than a reason.
|
|
13
|
+
#
|
|
14
|
+
# The whole-map gate belongs where money moves: the tier3 launchers call require_all_stage_coverage
|
|
15
|
+
# before they spend, which is also what marks the run gated for the per-stage gates.
|
|
16
|
+
|
|
17
|
+
set -uo pipefail
|
|
18
|
+
# NEITHER OF THESE IS WRITTEN DOWN.
|
|
19
|
+
#
|
|
20
|
+
# This defaulted to one developer's absolute home path, and pinned node to one nvm install of
|
|
21
|
+
# one version. On any other machine — CI, a second checkout, a colleague — the default ROOT
|
|
22
|
+
# pointed at a directory that does not exist, and $NODE at an interpreter that does not exist,
|
|
23
|
+
# so a pre-flight whose entire purpose is "catch it before spending a run" could not run at all.
|
|
24
|
+
#
|
|
25
|
+
# The repo root is where this script lives, two levels up. The interpreter is resolved by
|
|
26
|
+
# lib/node-bin.sh, which reads the requirement from package.json engines.node and finds an
|
|
27
|
+
# interpreter that satisfies it — the library that exists for exactly this, and that ten other
|
|
28
|
+
# sites already use.
|
|
29
|
+
_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
30
|
+
ROOT="${1:-$(cd "$_SCRIPT_DIR/../.." && pwd)}"
|
|
31
|
+
# shellcheck source=lib/node-bin.sh
|
|
32
|
+
. "$_SCRIPT_DIR/lib/node-bin.sh"
|
|
33
|
+
NODE="$(resolve_node_bin "$ROOT")" || { echo "[preflight] no usable node interpreter" >&2; exit 2; }
|
|
34
|
+
cd "$ROOT" || exit 2
|
|
35
|
+
FAILED=0
|
|
36
|
+
report() { printf '%-34s %s\n' "$1" "$2"; }
|
|
37
|
+
fail() { FAILED=$((FAILED+1)); report "$1" "FAIL $2"; }
|
|
38
|
+
pass() { report "$1" "ok $2"; }
|
|
39
|
+
|
|
40
|
+
# ── 1. SHELL SCOPE/RUNTIME ERRORS ────────────────────────────────────────────
|
|
41
|
+
# bash -n is a SYNTAX check and cannot see `local` outside a function. That one word broke the only
|
|
42
|
+
# reviewer the pipeline runs, produced NO VERDICT eight times, and cost a whole run.
|
|
43
|
+
n=0
|
|
44
|
+
while read -r f; do
|
|
45
|
+
out=$(shellcheck -S error "$f" 2>/dev/null | grep -c 'SC[0-9]* (error)' || true)
|
|
46
|
+
[ "${out:-0}" -gt 0 ] && { n=$((n+out)); echo " $f"; shellcheck -S error "$f" 2>/dev/null | grep 'SC[0-9]* (error)' | sed 's/^/ /'; }
|
|
47
|
+
done < <(ls orchestrations/scripts/*.sh orchestrations/scripts/lib/*.sh 2>/dev/null)
|
|
48
|
+
[ "$n" -eq 0 ] && pass "shell runtime errors" "0" || fail "shell runtime errors" "$n found"
|
|
49
|
+
|
|
50
|
+
# ── 1b. WHAT ACTUALLY RUNS IS CURRENT WITH ITS SOURCE ────────────────────────
|
|
51
|
+
# Every check in this file reads SOURCE. `epam` runs dist/epam.js. A change written, tested and
|
|
52
|
+
# never built passes everything here and reaches a run as the old behaviour — 2026-08-09 (tool-use
|
|
53
|
+
# logging, nine passing tests, zero events) and 2026-08-20 (plugin strictness, caught only by one
|
|
54
|
+
# launcher's own gate). Shared with the launchers: lib/build-freshness.sh.
|
|
55
|
+
# shellcheck source=lib/build-freshness.sh
|
|
56
|
+
source "$ROOT/orchestrations/scripts/lib/build-freshness.sh" 2>/dev/null || true
|
|
57
|
+
if command -v build_is_current >/dev/null 2>&1; then
|
|
58
|
+
_bf=$(build_is_current "$ROOT" 2>&1) && pass "build current with src" "ok" \
|
|
59
|
+
|| { fail "build current with src" "stale"; echo "$_bf" | sed 's/^/ /'; }
|
|
60
|
+
else
|
|
61
|
+
fail "build current with src" "lib/build-freshness.sh did not load"
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
# ── 2. JS / PYTHON PARSE ─────────────────────────────────────────────────────
|
|
65
|
+
n=0
|
|
66
|
+
while read -r f; do "$NODE" --check "$f" >/dev/null 2>&1 || { n=$((n+1)); echo " $f"; }; done \
|
|
67
|
+
< <(ls orchestrations/scripts/*.js orchestrations/scripts/lib/*.js orchestrations/plugins/*.js 2>/dev/null)
|
|
68
|
+
[ "$n" -eq 0 ] && pass "js parse" "0" || fail "js parse" "$n"
|
|
69
|
+
n=0
|
|
70
|
+
while read -r f; do python3 -c "import ast,sys;ast.parse(open(sys.argv[1]).read())" "$f" >/dev/null 2>&1 || { n=$((n+1)); echo " $f"; }; done \
|
|
71
|
+
< <(ls orchestrations/scripts/lib/handlers/*.py orchestrations/scripts/lib/*.py 2>/dev/null)
|
|
72
|
+
[ "$n" -eq 0 ] && pass "python parse" "0" || fail "python parse" "$n"
|
|
73
|
+
|
|
74
|
+
# ── 3. PROVISIONED PLUGINS ACTUALLY LOAD ─────────────────────────────────────
|
|
75
|
+
# verification-plugin.js is provisioned by the codeline and rejected at load for a missing `name`.
|
|
76
|
+
# A warning, so nothing ever surfaced it: the tools simply never reached the agent.
|
|
77
|
+
out=$("$NODE" -e '
|
|
78
|
+
const fs=require("fs"),path=require("path");
|
|
79
|
+
// THE REAL CONTRACT: src/tools/PluginLoader.ts:79-80 requires name AND execute on each TOOL.
|
|
80
|
+
// A first version of this check tested the MODULE for .name and flagged all six plugins — a false
|
|
81
|
+
// positive rate of 5/6. Verified against the loader before being trusted.
|
|
82
|
+
let bad=[];
|
|
83
|
+
for (const f of fs.readdirSync("orchestrations/plugins").filter(x=>x.endsWith(".js"))) {
|
|
84
|
+
let m; try { m=require(path.resolve("orchestrations/plugins",f)); }
|
|
85
|
+
catch(e){ bad.push(f+" (load error: "+e.message.slice(0,50)+")"); continue; }
|
|
86
|
+
if (!Array.isArray(m.tools)) continue; // not a tool plugin
|
|
87
|
+
m.tools.forEach((t,i)=>{
|
|
88
|
+
if (!t || !t.name) bad.push(f+" tool["+i+"] missing required field: name");
|
|
89
|
+
else if (typeof t.execute !== "function") bad.push(f+" tool["+i+"] ("+t.name+") missing execute");
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
console.log(bad.join("\n"));' 2>&1)
|
|
93
|
+
[ -z "$out" ] && pass "plugins load" "all" || { fail "plugins load" "$(echo "$out"|wc -l) rejected"; echo "$out" | sed 's/^/ /'; }
|
|
94
|
+
|
|
95
|
+
# ── 4. EVERY TEMPLATE'S PLACEHOLDERS ARE SUPPLIED ────────────────────────────
|
|
96
|
+
# A producer that omits a declared value makes the renderer throw AT RUN TIME. Two of these fired
|
|
97
|
+
# live on consecutive runs (skill-assessment-postphase, plan-corrective).
|
|
98
|
+
out=$("$NODE" -e '
|
|
99
|
+
const fs=require("fs"),path=require("path");
|
|
100
|
+
const SH=["orchestrations/scripts","orchestrations/scripts/lib"].flatMap(d=>fs.readdirSync(d).filter(f=>f.endsWith(".sh")).map(f=>path.join(d,f)));
|
|
101
|
+
const T={};for(const f of fs.readdirSync("orchestrations/prompts/templates").filter(f=>f.endsWith(".json"))){const j=JSON.parse(fs.readFileSync(path.join("orchestrations/prompts/templates",f),"utf8"));T[j.id||f.replace(/\.json$/,"")]=j;}
|
|
102
|
+
// THE RENDERER RULE, not a second copy of it. NO APOSTROPHES IN THIS BLOCK: it is single-quoted
|
|
103
|
+
// shell. This line had its own regex, anchored so that __A____B__ read as ONE placeholder, while
|
|
104
|
+
// engine-prompt.js matches non-greedily precisely because templates put placeholders ADJACENT.
|
|
105
|
+
// The tc-writer body opens __CORRECTIVE_NOTE____TC_WRITER_PROFILE__, renders correctly, and
|
|
106
|
+
// failed pre-flight as MISSING a placeholder that does not exist.
|
|
107
|
+
const {placeholdersIn:ph}=require(path.resolve("orchestrations/scripts/lib/engine-prompt.js"));
|
|
108
|
+
const bad=[];
|
|
109
|
+
for(const f of SH){const L=fs.readFileSync(f,"utf8").split("\n");
|
|
110
|
+
for(let i=0;i<L.length;i++){const m=/render_(?:engine_prompt|or_keep)\s+([a-z0-9-]+)\s+"?\$?\{?([A-Za-z_]*)\}?"?\s*("?([a-z_]+)"?)?/.exec(L[i]);
|
|
111
|
+
if(!m)continue;const j=T[m[1]];if(!j)continue;const key=m[4];let body;
|
|
112
|
+
if(j.bodies){body=key&&j.bodies[key]!==undefined?j.bodies[key]:null;if(body===null)continue;}else body=j.body||"";
|
|
113
|
+
// Values arrive two ways: named in the jq_vals block, or supplied by THE RENDERER. A checker
|
|
114
|
+
// that modelled only the first would report a site as broken while it works — silencing it by
|
|
115
|
+
// "fixing" working code is worse than the miss.
|
|
116
|
+
//
|
|
117
|
+
// The renderer is the supplier now, unconditionally. engine-prompt.js adds exactly the stack
|
|
118
|
+
// placeholders a template DECLARES (`stackDeclared`). This used to credit merge_stack_facts
|
|
119
|
+
// instead, and only when that call appeared near the jq_vals block — a second implementation
|
|
120
|
+
// of the same idea that merged ALL SEVEN keys, so the renderer threw "was given values it does
|
|
121
|
+
// not use" on every template declaring fewer, and four seams could not render at all.
|
|
122
|
+
const STACK_FACT_KEYS=["__STACK__","__MANIFEST_FILE__","__TEST_COMMAND__","__TEST_FILE_CONVENTIONS__","__PROTECTED_FILES__","__IMPL_ROLE__","__TEST_ROLE__"];
|
|
123
|
+
let sup=null;for(let k=i;k>=0&&k>i-30;k--){if(/jq_vals|jq -n/.test(L[k])){sup=ph(L.slice(k,i).join("\n"));
|
|
124
|
+
sup=sup.concat(STACK_FACT_KEYS);
|
|
125
|
+
break;}}
|
|
126
|
+
if(!sup)continue;const miss=ph(body).filter(p=>!sup.includes(p));
|
|
127
|
+
if(miss.length)bad.push(f.replace("orchestrations/scripts/","")+":"+(i+1)+" "+m[1]+" MISSING "+miss.join(", "));}}
|
|
128
|
+
console.log(bad.join("\n"));' 2>&1)
|
|
129
|
+
[ -z "$out" ] && pass "template values supplied" "all" || { fail "template values supplied" "$(echo "$out"|wc -l) mismatched"; echo "$out" | sed 's/^/ /'; }
|
|
130
|
+
|
|
131
|
+
# ── 5. HANDLERS PRODUCE OUTPUT FOR THE REAL STORY ────────────────────────────
|
|
132
|
+
# tc-story-context.py returned EMPTY for a brownfield story, so the TC writer was invoked three
|
|
133
|
+
# times per run with an empty brief and wrote nothing — while its gate reported PASSED.
|
|
134
|
+
#
|
|
135
|
+
# THE CHECK ITSELF HAD THE SAME DEFECT IT WAS WRITTEN TO CATCH. It took stories[0], ran the handler
|
|
136
|
+
# and called an empty answer a failure. But the handler SKIPS a story that already has
|
|
137
|
+
# testCriteria.facts — correctly, there is nothing to brief — so once AMSD-2041 had its 21 facts
|
|
138
|
+
# the check failed on the handler doing exactly the right thing. A check whose scope does not match
|
|
139
|
+
# its claim reports the wrong thing in both directions.
|
|
140
|
+
#
|
|
141
|
+
# It now asks the handler about a story that ACTUALLY needs context, and says so when none does.
|
|
142
|
+
# shellcheck source=lib/project-config.sh
|
|
143
|
+
. "$ROOT/orchestrations/scripts/lib/project-config.sh"
|
|
144
|
+
PRD=$(ls -t "$(projects_root "$ROOT")"/*/runs/*/work/*-prd.json 2>/dev/null | head -1)
|
|
145
|
+
if [ -n "$PRD" ]; then
|
|
146
|
+
# The selector is a handler, not an inline program, so the same question this check asks can be
|
|
147
|
+
# asked by a test — a check that can only ever be exercised by running the whole pre-flight
|
|
148
|
+
# against whatever PRD happens to be on disk is a check nobody can prove.
|
|
149
|
+
SID=$("$NODE" "orchestrations/scripts/lib/handlers/tc-story-needing-context.js" "$PRD" core 2>/dev/null || echo "")
|
|
150
|
+
OUT_DIR=$(dirname "$(dirname "$PRD")")
|
|
151
|
+
if [ -z "$SID" ]; then
|
|
152
|
+
report "tc story context" "skip (no story in this PRD needs criteria — nothing to brief)"
|
|
153
|
+
else
|
|
154
|
+
ctx=$(python3 orchestrations/scripts/lib/handlers/tc-story-context.py "$OUT_DIR" "$PRD" core "$SID" 2>/dev/null | wc -c)
|
|
155
|
+
[ "${ctx:-0}" -gt 20 ] && pass "tc story context ($SID)" "${ctx} bytes" \
|
|
156
|
+
|| fail "tc story context ($SID)" "EMPTY — the TC writer would be given nothing"
|
|
157
|
+
fi
|
|
158
|
+
else
|
|
159
|
+
report "tc story context" "skip (no run PRD on disk)"
|
|
160
|
+
fi
|
|
161
|
+
|
|
162
|
+
# ── 6. DETERMINISTIC CHECKS ARE READ, NOT CALLED BARE ────────────────────────
|
|
163
|
+
# A check whose exit status is discarded is not a gate. lockfile-sync blocked four times live and
|
|
164
|
+
# the story completed anyway.
|
|
165
|
+
out=$("$NODE" -e '
|
|
166
|
+
const fs=require("fs");const s=fs.readFileSync("orchestrations/scripts/claude.sh","utf8");
|
|
167
|
+
const f=s.slice(s.indexOf("run_external_verification() {"));const b=f.slice(0,f.indexOf("\n}\n"));
|
|
168
|
+
const bare=b.split("\n").map(l=>l.trim()).filter(l=>/^run_[a-z_]+_check "/.test(l)).filter(l=>!/^if ! /.test(l)&&!/\|\||&&/.test(l));
|
|
169
|
+
console.log(bare.join("\n"));' 2>&1)
|
|
170
|
+
[ -z "$out" ] && pass "gate verdicts read" "all" || { fail "gate verdicts read" "$(echo "$out"|wc -l) bare"; echo "$out" | sed 's/^/ /'; }
|
|
171
|
+
|
|
172
|
+
# ── 7. RATCHETS — THE DEBT MAY ONLY SHRINK ───────────────────────────────────
|
|
173
|
+
# Eight of the ten defects confirmed on 2026-08-20 were hardcoding, and every one of them was
|
|
174
|
+
# added by a change that passed every check above. Counting is not a fix; it is the only thing
|
|
175
|
+
# that stops the number growing while the fixes are worked through one at a time.
|
|
176
|
+
#
|
|
177
|
+
# A count BELOW its baseline lowers the baseline in place — today's number becomes tomorrow's
|
|
178
|
+
# ceiling. A count ABOVE it fails. Raising a baseline by hand is an operator decision.
|
|
179
|
+
BASELINES="orchestrations/config/preflight-baselines.json"
|
|
180
|
+
ratchet() {
|
|
181
|
+
local _label="$1" _key="$2" _scanner="$3"
|
|
182
|
+
local _out _n _base _rc
|
|
183
|
+
# An empty scan is not automatically a pass: a scanner that cannot run reports nothing, which
|
|
184
|
+
# is the exact shape of every defect this file exists to catch. rc is captured on the SAME
|
|
185
|
+
# logical step as the call — a check that reads $? a line later reads whatever ran in between.
|
|
186
|
+
_out=$("$NODE" "orchestrations/scripts/lib/handlers/$_scanner" "$ROOT" 2>&1); _rc=$?
|
|
187
|
+
if [ "$_rc" -ne 0 ]; then fail "$_label" "scanner did not run"; printf '%s\n' "$_out" | sed 's/^/ /'; return; fi
|
|
188
|
+
_n=$(printf '%s' "$_out" | grep -c . || true)
|
|
189
|
+
_base=$("$NODE" -e 'try{const j=require(process.argv[1]);const v=j[process.argv[2]];console.log(Number.isFinite(v)?v:"")}catch{console.log("")}' \
|
|
190
|
+
"$ROOT/$BASELINES" "$_key" 2>/dev/null)
|
|
191
|
+
if [ -z "$_base" ]; then fail "$_label" "no baseline for $_key in $BASELINES"; return; fi
|
|
192
|
+
if [ "$_n" -gt "$_base" ]; then
|
|
193
|
+
fail "$_label" "$_n > baseline $_base — $(($_n - _base)) new"
|
|
194
|
+
printf '%s\n' "$_out" | sed 's/^/ /'
|
|
195
|
+
elif [ "$_n" -lt "$_base" ]; then
|
|
196
|
+
"$NODE" -e '
|
|
197
|
+
const fs=require("fs");const p=process.argv[1];const j=JSON.parse(fs.readFileSync(p,"utf8"));
|
|
198
|
+
j[process.argv[2]]=Number(process.argv[3]);fs.writeFileSync(p,JSON.stringify(j,null,2)+"\n");' \
|
|
199
|
+
"$ROOT/$BASELINES" "$_key" "$_n" 2>/dev/null
|
|
200
|
+
pass "$_label" "$_n (improved from $_base — baseline tightened)"
|
|
201
|
+
else
|
|
202
|
+
pass "$_label" "$_n (at baseline)"
|
|
203
|
+
fi
|
|
204
|
+
}
|
|
205
|
+
ratchet "literal ratchet" "duplicatedLiterals" "scan-duplicated-literals.js"
|
|
206
|
+
ratchet "guard calibration" "uncalibratedGuards" "scan-uncalibrated-guards.js"
|
|
207
|
+
# THE SHELL ITSELF, READ STATICALLY. Coverage says how much of the engine a test has executed;
|
|
208
|
+
# this says how much of it is wrong on its face, across every .sh file, needing no test written
|
|
209
|
+
# first. The classes it counts have each already cost a run: an export masking a command status,
|
|
210
|
+
# `A && B || C` read as if-then-else, a redirection with no command, a subshell losing an assignment.
|
|
211
|
+
ratchet "shell defects" "shellDefects" "scan-shell-defects.js"
|
|
212
|
+
|
|
213
|
+
# ── THE HARDCODING AUDIT CAN STILL SEE ───────────────────────────────────────
|
|
214
|
+
# Not its count — that is a research number nobody should gate on, and the file says so itself.
|
|
215
|
+
# This asks the prior question: does each category still detect the defect it claims to cover?
|
|
216
|
+
#
|
|
217
|
+
# Every hardcoding defect found on 2026-08-23 was invisible to that audit — it scanned .sh/.js/.ts
|
|
218
|
+
# and declared config exempt, so RELOCATING a literal into orchestrations/config counted as
|
|
219
|
+
# repair; its numeric category needed a named knob, so topN = 8 matched nothing. And nothing ran
|
|
220
|
+
# it, so the blindness was never observed. --calibrate runs every pattern against a fixture of
|
|
221
|
+
# known-bad lines and fails on any that has gone blind. It found a real gap on its first run: the
|
|
222
|
+
# branch pattern required a character AFTER the branch name, so `git checkout develop` at the end
|
|
223
|
+
# of a line matched nothing.
|
|
224
|
+
_hc_out=$(bash orchestrations/scripts/hardcoding-audit.sh --calibrate 2>&1); _hc_rc=$?
|
|
225
|
+
if [ "$_hc_rc" -eq 0 ]; then
|
|
226
|
+
pass "hardcoding audit sees" "$(printf '%s' "$_hc_out" | grep -c 'sees its example') categories"
|
|
227
|
+
else
|
|
228
|
+
fail "hardcoding audit sees" "a category has gone BLIND"
|
|
229
|
+
printf '%s\n' "$_hc_out" | grep -E 'BLIND' | sed 's/^/ /'
|
|
230
|
+
fi
|
|
231
|
+
|
|
232
|
+
# ── 8. THE OPERATOR'S OWN DECISIONS ──────────────────────────────────────────
|
|
233
|
+
# orchestrations/config/remediation-register.json is DATA the operator owns: literals that must be
|
|
234
|
+
# gone, and guards judged useless. Marking one enforce:true makes it fatal here — no code change,
|
|
235
|
+
# no negotiation with this file. An unreadable register FAILS rather than reporting nothing.
|
|
236
|
+
out=$("$NODE" "orchestrations/scripts/lib/handlers/check-remediation-register.js" "$ROOT" 2>&1)
|
|
237
|
+
rc=$?
|
|
238
|
+
if [ "$rc" -eq 2 ]; then
|
|
239
|
+
fail "remediation register" "unreadable — decisions cannot be enforced"
|
|
240
|
+
echo "$out" | sed 's/^/ /'
|
|
241
|
+
elif [ "$rc" -ne 0 ]; then
|
|
242
|
+
fail "remediation register" "$(printf '%s' "$out" | grep -c . || true) enforced item(s) still present"
|
|
243
|
+
echo "$out" | sed 's/^/ /'
|
|
244
|
+
else
|
|
245
|
+
pass "remediation register" "no enforced violations"
|
|
246
|
+
fi
|
|
247
|
+
|
|
248
|
+
echo
|
|
249
|
+
[ "$FAILED" -eq 0 ] && echo "PRE-FLIGHT PASS — nothing here will surface in a run" \
|
|
250
|
+
|| echo "PRE-FLIGHT FAIL — $FAILED check(s); each one WILL surface in a run"
|
|
251
|
+
exit "$FAILED"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "amsd-pipeline-shared",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "The AMSD pipeline's shared components, one source for the bash pipeline and its Claude workflows: the model-call gateway (llm-handler.sh — retry, ladder, self-heal, cost) and the libraries it runs.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"bin": {
|