amsd-pipeline-shared 0.5.0 → 0.5.2
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/docs/gateway-baseline-2.0.80.md5 +47 -0
- package/docs/gateway-files.txt +47 -0
- package/orchestrations/config/repo-artifacts.json +23 -0
- package/orchestrations/config/resume-preserves.json +25 -0
- package/orchestrations/config/run-modes.json +47 -0
- package/orchestrations/scripts/lib/checkpoints.sh +175 -0
- package/orchestrations/scripts/lib/codeline-lanes.sh +1664 -0
- package/orchestrations/scripts/lib/codeline-packages.js +67 -0
- package/orchestrations/scripts/lib/codeline-write-perimeter.sh +318 -0
- package/orchestrations/scripts/lib/common.sh +66 -0
- package/orchestrations/scripts/lib/control-plane.sh +506 -0
- package/orchestrations/scripts/lib/ecosystem-registry.js +148 -0
- package/orchestrations/scripts/lib/engine-paths.sh +52 -0
- package/orchestrations/scripts/lib/flags.sh +38 -0
- package/orchestrations/scripts/lib/git-ops.sh +975 -0
- package/orchestrations/scripts/lib/halt-recovery.sh +56 -0
- package/orchestrations/scripts/lib/handlers/_read-input.js +88 -0
- package/orchestrations/scripts/lib/handlers/carry-plan.js +25 -0
- package/orchestrations/scripts/lib/handlers/cl-entries.js +10 -0
- package/orchestrations/scripts/lib/handlers/codeline-ecosystem.js +164 -0
- package/orchestrations/scripts/lib/handlers/codeline-manifests.js +148 -0
- package/orchestrations/scripts/lib/handlers/filtered-prd.js +85 -0
- package/orchestrations/scripts/lib/handlers/merge-lane-into-canonical.js +39 -0
- package/orchestrations/scripts/lib/handlers/package-engines-node.js +25 -0
- package/orchestrations/scripts/lib/handlers/prd-phases.js +46 -0
- package/orchestrations/scripts/lib/handlers/rebuild-cross-contract.js +7 -0
- package/orchestrations/scripts/lib/handlers/record-declared-pass.js +23 -0
- package/orchestrations/scripts/lib/handlers/release-line-prd.js +31 -0
- package/orchestrations/scripts/lib/handlers/release-lines.js +31 -0
- package/orchestrations/scripts/lib/handlers/repo-exclude-patterns.js +108 -0
- package/orchestrations/scripts/lib/handlers/resume-spec-output-present.js +16 -0
- package/orchestrations/scripts/lib/handlers/sibling-providers.js +43 -0
- package/orchestrations/scripts/lib/handlers/spanning-stories-incomplete.js +50 -0
- package/orchestrations/scripts/lib/handlers/spec-inputs-digest.js +48 -0
- package/orchestrations/scripts/lib/handlers/spec-predates-plan.js +40 -0
- package/orchestrations/scripts/lib/handlers/stories-lacking-spec.js +64 -0
- package/orchestrations/scripts/lib/handlers/write-missing-plans.js +92 -0
- package/orchestrations/scripts/lib/orchestration-resume.sh +74 -0
- package/orchestrations/scripts/lib/phase-exit.sh +90 -0
- package/orchestrations/scripts/lib/pipeline-commit.sh +19 -0
- package/orchestrations/scripts/lib/plan-hash.js +19 -0
- package/orchestrations/scripts/lib/plan-scope.js +73 -0
- package/orchestrations/scripts/lib/qa-gate-evidence.sh +235 -0
- package/orchestrations/scripts/lib/release-lines.sh +166 -0
- package/orchestrations/scripts/lib/resume-semantics.sh +31 -0
- package/orchestrations/scripts/lib/run-checkpoint.sh +842 -0
- package/orchestrations/scripts/lib/run-modes.sh +93 -0
- package/orchestrations/scripts/lib/story-outputs.sh +322 -0
- package/orchestrations/scripts/lib/story-retry-state.sh +355 -0
- package/package.json +1 -1
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# _run_release_lines <codeline> <lane-prd> <worktree> <lane-log-dir> <log-file> <phase-filter> <phase-runner>
|
|
3
|
+
#
|
|
4
|
+
# A SHARED CODELINE SHIPS ON EVERY RELEASE LINE ITS STORY'S PLAN NAMES. The lane has worked its stories on the
|
|
5
|
+
# codeline's own base; this works them once more per line the plan marks off that base (lib/handlers/release-lines.js)
|
|
6
|
+
# — that line's base (a branch or a release tag), its own story branch (EPAM_BRANCH_SUFFIX), its own logs, its own PRD
|
|
7
|
+
# copy with the stories pending again (lib/handlers/release-line-prd.js). The plan decides how many: 0, 1 or N.
|
|
8
|
+
#
|
|
9
|
+
# Operator, 2026-10-06 (AMSD-2974): "Why one? That does not work for brownfield for a shared repo", "You cannot hard
|
|
10
|
+
# code 1:1". The library had to ship on 8.x and as a back-port from v7.14.0 for two consumers locked to ^7.
|
|
11
|
+
#
|
|
12
|
+
# The phase runner is the lane's own (the orchestrator, "$0"), run exactly as the lane runs it. A line that fails
|
|
13
|
+
# fails the lane; no later line runs after it. Returns non-zero then.
|
|
14
|
+
# shellcheck source=resume-semantics.sh
|
|
15
|
+
. "$(dirname "${BASH_SOURCE[0]}")/resume-semantics.sh"
|
|
16
|
+
# shellcheck source=phase-exit.sh
|
|
17
|
+
declare -F phase_exit_is_retryable >/dev/null 2>&1 || . "$(dirname "${BASH_SOURCE[0]}")/phase-exit.sh"
|
|
18
|
+
|
|
19
|
+
_run_release_lines() {
|
|
20
|
+
# THE CODELINE IS LEFT ON THE BRANCH IT WAS ON. A line pass checks out the line's story branch; left there, the next
|
|
21
|
+
# launch's detective read cx-shared at 7.14.0 and planned its own line as 7.x (AMSD-2974, 2026-10-07).
|
|
22
|
+
# The branch is recorded in the codeline's git dir first: a run killed mid-line runs nothing after the pass, and
|
|
23
|
+
# the next launch returns the codeline from the record (_return_codelines_from_release_lines).
|
|
24
|
+
local _home _rc=0 _gd
|
|
25
|
+
_home=$(git -C "$3" symbolic-ref -q --short HEAD 2>/dev/null || true)
|
|
26
|
+
_gd=$(git -C "$3" rev-parse --absolute-git-dir 2>/dev/null || true)
|
|
27
|
+
[ -n "$_home" ] && [ -n "$_gd" ] && printf '%s\n' "$_home" > "$_gd/epam-release-home"
|
|
28
|
+
_run_release_lines_each "$@" || _rc=$?
|
|
29
|
+
_return_from_release_lines "$3" "$1"
|
|
30
|
+
return "$_rc"
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
# _return_from_release_lines <codeline-root> [name] — back on the branch the record names; the record is removed.
|
|
34
|
+
_return_from_release_lines() {
|
|
35
|
+
local _gd _home
|
|
36
|
+
_gd=$(git -C "$1" rev-parse --absolute-git-dir 2>/dev/null) || return 0
|
|
37
|
+
[ -f "$_gd/epam-release-home" ] || return 0
|
|
38
|
+
_home=$(cat "$_gd/epam-release-home")
|
|
39
|
+
if [ -n "$_home" ] && [ "$(git -C "$1" symbolic-ref -q --short HEAD 2>/dev/null)" != "$_home" ]; then
|
|
40
|
+
if git -C "$1" checkout -q "$_home" 2>/dev/null; then
|
|
41
|
+
log "[orch] Codeline '${2:-$1}': release lines done — back on ${_home}"
|
|
42
|
+
else
|
|
43
|
+
warning "[orch] Codeline '${2:-$1}': could not return to ${_home} after its release lines"
|
|
44
|
+
return 0
|
|
45
|
+
fi
|
|
46
|
+
fi
|
|
47
|
+
rm -f "$_gd/epam-release-home"
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# _return_codelines_from_release_lines <prd> — every codeline of the PRD a line pass left is put back before the
|
|
51
|
+
# launch plans the story (AMSD-2974 run 2, 2026-10-07: the detective read cx-shared on its 7.x line branch).
|
|
52
|
+
_return_codelines_from_release_lines() {
|
|
53
|
+
local _p
|
|
54
|
+
while IFS=$'\t' read -r _n _p; do
|
|
55
|
+
[ -n "$_p" ] && [ -d "$_p" ] && _return_from_release_lines "$_p" "$_n"
|
|
56
|
+
done < <(jq -r '.project.outputDirs[]? | [.codeline, .path] | @tsv' "$1" 2>/dev/null)
|
|
57
|
+
return 0
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
_run_release_lines_each() {
|
|
61
|
+
local _cl="$1" _cl_prd="$2" _wt="$3" _lane_log="$4" _log_file="${5:-/dev/null}" _phase_filter="${6:-}" _runner="$7" _canonical="${8:-}"
|
|
62
|
+
local _lines=()
|
|
63
|
+
mapfile -t _lines < <("$NODE_BIN" "$SCRIPT_DIR/lib/handlers/release-lines.js" "$_cl_prd" "$_cl" "$_canonical")
|
|
64
|
+
[ "${#_lines[@]}" -gt 0 ] || return 0
|
|
65
|
+
# THE CHANGE EVERY LINE PORTS: what the codeline's own line committed for this story — from the lane's phase baseline
|
|
66
|
+
# to the branch the codeline was on when the lines began (recorded by _run_release_lines). Given verbatim to each
|
|
67
|
+
# line's writer and diff reviewers (lib/producers/fix-plan.js, template release-line-port): AMSD-2974 run 9 gave
|
|
68
|
+
# them only the plan's summary, and a 7.x back-port carrying a fraction of the 8.x change was approved.
|
|
69
|
+
local _main_branch="" _main_base="" _main_change="${_lane_log}/main-line-change.diff" _gdir
|
|
70
|
+
_gdir=$(git -C "$_wt" rev-parse --absolute-git-dir 2>/dev/null || true)
|
|
71
|
+
[ -n "$_gdir" ] && [ -f "$_gdir/epam-release-home" ] && _main_branch=$(cat "$_gdir/epam-release-home")
|
|
72
|
+
_main_base=$(tr -d '[:space:]' < "${_lane_log}/phase-baseline-sha.txt" 2>/dev/null || true)
|
|
73
|
+
rm -f "$_main_change"
|
|
74
|
+
if [ -n "$_main_branch" ] && [ -n "$_main_base" ]; then
|
|
75
|
+
git -C "$_wt" diff "$_main_base" "$_main_branch" > "$_main_change" 2>/dev/null || rm -f "$_main_change"
|
|
76
|
+
fi
|
|
77
|
+
[ -s "$_main_change" ] || { rm -f "$_main_change"; _main_change=""; }
|
|
78
|
+
if [ -n "$_main_change" ]; then
|
|
79
|
+
log "[orch] Codeline '${_cl}': each release line ports ${_main_branch}'s change ($(grep -c '^diff --git' "$_main_change") file(s), from ${_main_base:0:9})"
|
|
80
|
+
else
|
|
81
|
+
warning "[orch] Codeline '${_cl}': no committed change on its own line to port — release lines are worked from the plan alone"
|
|
82
|
+
fi
|
|
83
|
+
local _entry _line _base _slug _line_log _line_prd _phase _pex _ledger
|
|
84
|
+
for _entry in "${_lines[@]}"; do
|
|
85
|
+
[ -n "$_entry" ] || continue
|
|
86
|
+
_line="${_entry%%$'\t'*}"; _base="${_entry#*$'\t'}"
|
|
87
|
+
_slug=$(printf '%s' "$_line" | tr -c 'A-Za-z0-9._-' '-')
|
|
88
|
+
_line_log="${_lane_log}/lines/${_slug}"
|
|
89
|
+
mkdir -p "$_line_log" 2>/dev/null || true
|
|
90
|
+
_line_prd="${_line_log}/prd.json"
|
|
91
|
+
# A LINE THIS RUN COMPLETED GOES BACK TO ITS REVIEWER ON RESUME — kept, not redone, not passed over by rule
|
|
92
|
+
# (operator, 2026-10-08: the 7.x back-port carried a third of the 8.x fix). Its PRD and story branch are kept;
|
|
93
|
+
# the phase runs without --reset, so Step 1 passes it as completed and the review → rework loop judges it
|
|
94
|
+
# against the story's plan as it stands.
|
|
95
|
+
local _rerun_args=(--reset) _line_branch
|
|
96
|
+
if resume_preserves completed-stories && [ -f "$_line_prd" ] \
|
|
97
|
+
&& jq -e '(.stories | length) > 0 and all(.stories[]; .status == "completed")' "$_line_prd" >/dev/null 2>&1 \
|
|
98
|
+
&& [ -z "$("$NODE_BIN" "$SCRIPT_DIR/lib/handlers/spec-predates-plan.js" "$_line_prd" "${_canonical:-$_cl_prd}" 2>/dev/null)" ]; then
|
|
99
|
+
_rerun_args=()
|
|
100
|
+
_line_branch="${EPAM_BRANCH_PREFIX:-}AI-$(jq -r '.stories[0].id' "$_line_prd")-${_slug}"
|
|
101
|
+
git -C "$_wt" checkout -q "$_line_branch" 2>/dev/null \
|
|
102
|
+
|| warning "[orch] Codeline '${_cl}': could not check out ${_line_branch} for its review"
|
|
103
|
+
# The story's plan as it stands — the kept line PRD holds the plan of the pass that completed it.
|
|
104
|
+
"$NODE_BIN" "$SCRIPT_DIR/lib/handlers/carry-plan.js" "$_line_prd" "${_canonical:-$_cl_prd}" || true
|
|
105
|
+
log "[orch] Codeline '${_cl}' — release line ${_line} completed in this run — its reviewer judges it again against the story's plan"
|
|
106
|
+
else
|
|
107
|
+
"$NODE_BIN" "$SCRIPT_DIR/lib/handlers/release-line-prd.js" "$_cl_prd" "$_line_prd" "$_cl" "$_line" "$_canonical" || {
|
|
108
|
+
error "[orch] Codeline '${_cl}': could not prepare release line ${_line}"; return 1; }
|
|
109
|
+
fi
|
|
110
|
+
log "[orch] Codeline '${_cl}' — release line ${_line}, from ${_base} (the story's plan)"
|
|
111
|
+
# A STEP NEVER RUNS TWICE: a story already specified for this codeline is not specified again on another line.
|
|
112
|
+
# The spec pass runs on the line only for a story that still lacks its spec (lib/handlers/stories-lacking-spec.js).
|
|
113
|
+
local _line_spec="${EPAM_SPEC_MODE:-}"
|
|
114
|
+
[ -z "$("$NODE_BIN" "$SCRIPT_DIR/lib/handlers/stories-lacking-spec.js" "$_line_prd" 2>/dev/null)" ] && _line_spec=0
|
|
115
|
+
local _phases=()
|
|
116
|
+
mapfile -t _phases < <("$NODE_BIN" "$SCRIPT_DIR/lib/handlers/prd-phases.js" "$_line_prd")
|
|
117
|
+
for _phase in "${_phases[@]}"; do
|
|
118
|
+
[ -n "$_phase" ] || continue
|
|
119
|
+
[ -n "$_phase_filter" ] && [ "$_phase" != "$_phase_filter" ] && continue
|
|
120
|
+
_line_phase() {
|
|
121
|
+
JIRA_CODELINE_RUN=1 \
|
|
122
|
+
EPAM_CODELINE="$_cl" \
|
|
123
|
+
EPAM_RELEASE_LINE="$_line" \
|
|
124
|
+
EPAM_MAIN_LINE_CHANGE="$_main_change" \
|
|
125
|
+
EPAM_MAIN_LINE_BRANCH="$_main_branch" \
|
|
126
|
+
EPAM_SPEC_MODE="$_line_spec" \
|
|
127
|
+
EPAM_BRANCH_SUFFIX="-${_slug}" \
|
|
128
|
+
JIRA_BASELINE_BRANCH="$_base" \
|
|
129
|
+
LOG_DIR="$_line_log" \
|
|
130
|
+
AGENT_IO_DIR="$_line_log/agent-io" \
|
|
131
|
+
PRD_FILE="$_line_prd" \
|
|
132
|
+
PROJECT_ROOT="$_wt" \
|
|
133
|
+
OUTPUT_DIR="$_wt" \
|
|
134
|
+
PHASE="$_phase" \
|
|
135
|
+
bash "$_runner" "$@" 2>&1 | tee -a "$_log_file"
|
|
136
|
+
return "${PIPESTATUS[0]}"
|
|
137
|
+
}
|
|
138
|
+
_pex=0; _line_phase "${_rerun_args[@]}" || _pex=$?
|
|
139
|
+
# A LINE RETRIES AS A LANE DOES (lib/phase-exit.sh): exit 2 is "the gates remediated the story — retry the
|
|
140
|
+
# phase"; once, with SKIP_GATE_REMEDIATION=1 (AMSD-2974 run 10: the line failed on it, the finding never
|
|
141
|
+
# reached its writer).
|
|
142
|
+
# WHILE THE GATES REMEDIATE, THE LINE'S PHASE IS RETRIED with remediation on (lib/codeline-lanes.sh, the same rule).
|
|
143
|
+
while phase_exit_is_retryable "$_pex"; do
|
|
144
|
+
log "[orch] '${_phase}' ('${_cl}' release line ${_line}): $(phase_exit_describe "$_pex") — retrying the phase"
|
|
145
|
+
local _rmark _rargs=(); _rmark=$(phase_retry_mark "$_wt")
|
|
146
|
+
mapfile -t _rargs < <(phase_exit_retry_args "$_pex")
|
|
147
|
+
_pex=0; _line_phase ${_rargs[@]+"${_rargs[@]}"} || _pex=$?
|
|
148
|
+
# THE PIPELINE NEVER LOOPS (lib/phase-exit.sh): a retry that changed nothing in the codeline is not repeated.
|
|
149
|
+
if phase_exit_is_retryable "$_pex" && ! phase_retry_progressed "$_wt" "$_rmark"; then
|
|
150
|
+
error "[orch] Phase '${_phase}' for '${_cl}' on release line ${_line}: the self-healing retry changed nothing in the codeline (still ${_rmark:0:9}) — not retrying again"
|
|
151
|
+
_pex=1
|
|
152
|
+
fi
|
|
153
|
+
done
|
|
154
|
+
if [ "$_pex" -ne 0 ]; then
|
|
155
|
+
error "[orch] Phase '${_phase}' for '${_cl}' on release line ${_line} failed (exit $_pex)"
|
|
156
|
+
return 1
|
|
157
|
+
fi
|
|
158
|
+
log "[orch] Phase '${_phase}' — '${_cl}' release line ${_line} done."
|
|
159
|
+
done
|
|
160
|
+
# The line's append-only ledgers back into the lane's, as a lane folds its own into the parent.
|
|
161
|
+
for _ledger in phase-cost.jsonl agent-activity.jsonl healing-events.jsonl; do
|
|
162
|
+
[ -s "${_line_log}/${_ledger}" ] && cat "${_line_log}/${_ledger}" >> "${_lane_log}/${_ledger}" 2>/dev/null || true
|
|
163
|
+
done
|
|
164
|
+
done
|
|
165
|
+
return 0
|
|
166
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# resume-semantics.sh — THE ONE ANSWER to "what does a resume keep?"
|
|
3
|
+
#
|
|
4
|
+
# Declared once in config/resume-preserves.json (see its $why for the five incidents that each
|
|
5
|
+
# taught one component separately). Consumers ask `resume_preserves <aspect>` and never test
|
|
6
|
+
# EPAM_RESUME_RUN themselves for these decisions. An aspect the declaration does not name is
|
|
7
|
+
# refused loudly (exit 2, message on stderr) — a consumer that asks about something undeclared
|
|
8
|
+
# has found a gap in the declaration, not a reason to guess.
|
|
9
|
+
#
|
|
10
|
+
# is_resume — exit 0 when EPAM_RESUME_RUN names a run
|
|
11
|
+
# resume_preserves <aspect> — exit 0 when this is a resume AND the aspect is declared kept;
|
|
12
|
+
# exit 1 on a fresh launch; exit 2 for an undeclared aspect.
|
|
13
|
+
|
|
14
|
+
_resume_preserves_file() {
|
|
15
|
+
local _here; _here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
16
|
+
echo "${EPAM_RESUME_PRESERVES_FILE:-$_here/../../config/resume-preserves.json}"
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
is_resume() {
|
|
20
|
+
[ -n "${EPAM_RESUME_RUN:-}" ]
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
resume_preserves() {
|
|
24
|
+
local _aspect="${1:-}"
|
|
25
|
+
local _file; _file="$(_resume_preserves_file)"
|
|
26
|
+
if [ -z "$_aspect" ] || ! jq -e --arg a "$_aspect" '.preserves[$a] // empty' "$_file" >/dev/null 2>&1; then
|
|
27
|
+
echo "[resume-semantics] aspect '${_aspect}' is not declared in ${_file} — nothing says whether a resume keeps it; declare it before asking" >&2
|
|
28
|
+
return 2
|
|
29
|
+
fi
|
|
30
|
+
is_resume
|
|
31
|
+
}
|