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.
Files changed (50) hide show
  1. package/docs/gateway-baseline-2.0.80.md5 +47 -0
  2. package/docs/gateway-files.txt +47 -0
  3. package/orchestrations/config/repo-artifacts.json +23 -0
  4. package/orchestrations/config/resume-preserves.json +25 -0
  5. package/orchestrations/config/run-modes.json +47 -0
  6. package/orchestrations/scripts/lib/checkpoints.sh +175 -0
  7. package/orchestrations/scripts/lib/codeline-lanes.sh +1664 -0
  8. package/orchestrations/scripts/lib/codeline-packages.js +67 -0
  9. package/orchestrations/scripts/lib/codeline-write-perimeter.sh +318 -0
  10. package/orchestrations/scripts/lib/common.sh +66 -0
  11. package/orchestrations/scripts/lib/control-plane.sh +506 -0
  12. package/orchestrations/scripts/lib/ecosystem-registry.js +148 -0
  13. package/orchestrations/scripts/lib/engine-paths.sh +52 -0
  14. package/orchestrations/scripts/lib/flags.sh +38 -0
  15. package/orchestrations/scripts/lib/git-ops.sh +975 -0
  16. package/orchestrations/scripts/lib/halt-recovery.sh +56 -0
  17. package/orchestrations/scripts/lib/handlers/_read-input.js +88 -0
  18. package/orchestrations/scripts/lib/handlers/carry-plan.js +25 -0
  19. package/orchestrations/scripts/lib/handlers/cl-entries.js +10 -0
  20. package/orchestrations/scripts/lib/handlers/codeline-ecosystem.js +164 -0
  21. package/orchestrations/scripts/lib/handlers/codeline-manifests.js +148 -0
  22. package/orchestrations/scripts/lib/handlers/filtered-prd.js +85 -0
  23. package/orchestrations/scripts/lib/handlers/merge-lane-into-canonical.js +39 -0
  24. package/orchestrations/scripts/lib/handlers/package-engines-node.js +25 -0
  25. package/orchestrations/scripts/lib/handlers/prd-phases.js +46 -0
  26. package/orchestrations/scripts/lib/handlers/rebuild-cross-contract.js +7 -0
  27. package/orchestrations/scripts/lib/handlers/record-declared-pass.js +23 -0
  28. package/orchestrations/scripts/lib/handlers/release-line-prd.js +31 -0
  29. package/orchestrations/scripts/lib/handlers/release-lines.js +31 -0
  30. package/orchestrations/scripts/lib/handlers/repo-exclude-patterns.js +108 -0
  31. package/orchestrations/scripts/lib/handlers/resume-spec-output-present.js +16 -0
  32. package/orchestrations/scripts/lib/handlers/sibling-providers.js +43 -0
  33. package/orchestrations/scripts/lib/handlers/spanning-stories-incomplete.js +50 -0
  34. package/orchestrations/scripts/lib/handlers/spec-inputs-digest.js +48 -0
  35. package/orchestrations/scripts/lib/handlers/spec-predates-plan.js +40 -0
  36. package/orchestrations/scripts/lib/handlers/stories-lacking-spec.js +64 -0
  37. package/orchestrations/scripts/lib/handlers/write-missing-plans.js +92 -0
  38. package/orchestrations/scripts/lib/orchestration-resume.sh +74 -0
  39. package/orchestrations/scripts/lib/phase-exit.sh +90 -0
  40. package/orchestrations/scripts/lib/pipeline-commit.sh +19 -0
  41. package/orchestrations/scripts/lib/plan-hash.js +19 -0
  42. package/orchestrations/scripts/lib/plan-scope.js +73 -0
  43. package/orchestrations/scripts/lib/qa-gate-evidence.sh +235 -0
  44. package/orchestrations/scripts/lib/release-lines.sh +166 -0
  45. package/orchestrations/scripts/lib/resume-semantics.sh +31 -0
  46. package/orchestrations/scripts/lib/run-checkpoint.sh +842 -0
  47. package/orchestrations/scripts/lib/run-modes.sh +93 -0
  48. package/orchestrations/scripts/lib/story-outputs.sh +322 -0
  49. package/orchestrations/scripts/lib/story-retry-state.sh +355 -0
  50. package/package.json +1 -1
@@ -41,3 +41,50 @@ bc5acdb9260923082e05ef3b67304028 scripts/preflight-static.sh
41
41
  f206025f304e8320b8417a6dd6606044 scripts/spec-mode-runner.js
42
42
  dfa070b168a7c01fab8aab5a46d16192 scripts/team-lead-review.sh
43
43
  40c65de8360d5a9f59902fca26d1d7a8 scripts/update-monitor.sh
44
+ 7ab104b57abcbc8cb3cd890c753d5d67 config/resume-preserves.json
45
+ be822cc2faec79be223cf2cc1766ec4b scripts/lib/checkpoints.sh
46
+ 448c8118bdab3697022e2f68f3a99801 scripts/lib/codeline-lanes.sh
47
+ 8ef595221a8fb9d4a60f531d302c33bd scripts/lib/codeline-write-perimeter.sh
48
+ a945f1483df090d9b053e1ea883fdb4c scripts/lib/common.sh
49
+ 1fae91a1cd6b7304f23ba87ba88a7019 scripts/lib/control-plane.sh
50
+ 800e750c30be013c620ac76f28d41c20 scripts/lib/flags.sh
51
+ 3fd6c829074f18a67bf08b9d05a0256d scripts/lib/git-ops.sh
52
+ bbcb3501aa61f196ccb170a6166fde65 scripts/lib/halt-recovery.sh
53
+ 175d82c1706b45866ac6b1d0e6ddb9f5 scripts/lib/orchestration-resume.sh
54
+ 779412cd9db1a61deb307a9bcf6804f3 scripts/lib/phase-exit.sh
55
+ a38009bef2909c164a449b2192bf4c75 scripts/lib/qa-gate-evidence.sh
56
+ f64fdd6bc6df7e13d742e9e53a470be4 scripts/lib/release-lines.sh
57
+ 9768775dcd035b39932f3ebce243857e scripts/lib/resume-semantics.sh
58
+ 9216939efdf63c244d42d91ba6fb466c scripts/lib/run-checkpoint.sh
59
+ 886860d643c5db8fb3bfcf5bd3efaf9d scripts/lib/run-modes.sh
60
+ 156cf302dcedf423dea01ccb11fe305d scripts/lib/story-outputs.sh
61
+ 8e4481cc43b5efe2d7c032e8d2eb2f66 scripts/lib/story-retry-state.sh
62
+ f2cf5c1489ba9cd3fde4522b8c249b8b scripts/lib/handlers/_read-input.js
63
+ 38b31e37abb0fb6b9021673d22bd4d59 scripts/lib/handlers/carry-plan.js
64
+ 5d0397d7da5537c75fc0bc8b2bd7e9b9 scripts/lib/handlers/cl-entries.js
65
+ 35339f54cb483bbb79ff18100366b1d1 scripts/lib/handlers/codeline-ecosystem.js
66
+ a2e6097447d4b4a2ee7bdcd5df42267a scripts/lib/handlers/codeline-manifests.js
67
+ a8ce1f16d6a7acc79cabbe1e8aa2523c scripts/lib/handlers/filtered-prd.js
68
+ b15485e34a3db5e860609b9685b36211 scripts/lib/handlers/merge-lane-into-canonical.js
69
+ 3d40afd95026d86ca6ff3cc4f6d11a10 scripts/lib/handlers/package-engines-node.js
70
+ 41d04505e7688043f0bdfc2ef41537b2 scripts/lib/handlers/prd-phases.js
71
+ 3d17d52aa9d40a73240108e66f022cca scripts/lib/handlers/rebuild-cross-contract.js
72
+ 7dd7fadbb2e98fee9646cc3206a55744 scripts/lib/handlers/record-declared-pass.js
73
+ fa0fb7977606fdb98777288e613b2666 scripts/lib/handlers/release-line-prd.js
74
+ 3cc434c139dbba56aed51c7485a53d27 scripts/lib/handlers/release-lines.js
75
+ 4e2a0f8465afb1d58664e3474d1e99f3 scripts/lib/handlers/repo-exclude-patterns.js
76
+ fd4a27b6fb02b2d5dcb3e610ae126ec3 scripts/lib/handlers/resume-spec-output-present.js
77
+ b3015f602e1cb07887b7c94954a0886e scripts/lib/handlers/sibling-providers.js
78
+ 2a53c1cc2abab67f4a35504f8b70c2b9 scripts/lib/handlers/spanning-stories-incomplete.js
79
+ 8f796a4c6976cf334ba281017d0eac64 scripts/lib/handlers/spec-inputs-digest.js
80
+ 9daeb255ff23b1b7831806200d2d5e4c scripts/lib/handlers/spec-predates-plan.js
81
+ ee73864570c04d3c420b824b700e9b7c scripts/lib/handlers/stories-lacking-spec.js
82
+ ac166207d8a1d93a4c50a88568ef6e5c scripts/lib/handlers/write-missing-plans.js
83
+ 9038bc6d4e70462f757ee5e544df9c78 scripts/lib/codeline-packages.js
84
+ 3fedc22f90f05ca8740686295bb79d07 scripts/lib/ecosystem-registry.js
85
+ 9c0c8864b3cd98826fd930fdc5193d01 scripts/lib/plan-hash.js
86
+ 8a1bb4df2d1b6e7fd135f757423fb2f2 config/repo-artifacts.json
87
+ 91cec3c50040ebc9050c3d95f037bce2 config/run-modes.json
88
+ ee4366721c38cbc8cd72ee0f779d22a8 scripts/lib/plan-scope.js
89
+ aab7063cf68a9ecd54f6ef735adf895e scripts/lib/engine-paths.sh
90
+ 1d0346da09c13150e511809034396949 scripts/lib/pipeline-commit.sh
@@ -1,6 +1,9 @@
1
1
  config/doctor-heavy-jobs.json
2
2
  config/doctor-signatures.json
3
3
  config/model-pricing.json
4
+ config/repo-artifacts.json
5
+ config/resume-preserves.json
6
+ config/run-modes.json
4
7
  prompts/doctor-repair.md
5
8
  prompts/templates/codeline-discovery.json
6
9
  scripts/agent-attempt-analyst.sh
@@ -8,9 +11,15 @@ scripts/lib/agent-contract.js
8
11
  scripts/lib/agent-ladder.sh
9
12
  scripts/lib/agent-messages.js
10
13
  scripts/lib/agent-si.js
14
+ scripts/lib/checkpoints.sh
15
+ scripts/lib/codeline-lanes.sh
16
+ scripts/lib/codeline-packages.js
17
+ scripts/lib/codeline-write-perimeter.sh
18
+ scripts/lib/common.sh
11
19
  scripts/lib/constraint-compiler.js
12
20
  scripts/lib/constraint-sanity.js
13
21
  scripts/lib/content-retry.js
22
+ scripts/lib/control-plane.sh
14
23
  scripts/lib/cost-emitter.js
15
24
  scripts/lib/cost-record.sh
16
25
  scripts/lib/doctor/agent.js
@@ -22,11 +31,37 @@ scripts/lib/doctor/profile.js
22
31
  scripts/lib/doctor/repair.js
23
32
  scripts/lib/doctor/restarter.js
24
33
  scripts/lib/doctor/state.js
34
+ scripts/lib/ecosystem-registry.js
35
+ scripts/lib/engine-paths.sh
25
36
  scripts/lib/engine-prompt.js
26
37
  scripts/lib/env-file.sh
27
38
  scripts/lib/evidence-windows.js
28
39
  scripts/lib/failure-signature.js
40
+ scripts/lib/flags.sh
41
+ scripts/lib/git-ops.sh
42
+ scripts/lib/halt-recovery.sh
43
+ scripts/lib/handlers/_read-input.js
44
+ scripts/lib/handlers/carry-plan.js
45
+ scripts/lib/handlers/cl-entries.js
46
+ scripts/lib/handlers/codeline-ecosystem.js
47
+ scripts/lib/handlers/codeline-manifests.js
29
48
  scripts/lib/handlers/emit-cost.js
49
+ scripts/lib/handlers/filtered-prd.js
50
+ scripts/lib/handlers/merge-lane-into-canonical.js
51
+ scripts/lib/handlers/package-engines-node.js
52
+ scripts/lib/handlers/prd-phases.js
53
+ scripts/lib/handlers/rebuild-cross-contract.js
54
+ scripts/lib/handlers/record-declared-pass.js
55
+ scripts/lib/handlers/release-line-prd.js
56
+ scripts/lib/handlers/release-lines.js
57
+ scripts/lib/handlers/repo-exclude-patterns.js
58
+ scripts/lib/handlers/resume-spec-output-present.js
59
+ scripts/lib/handlers/sibling-providers.js
60
+ scripts/lib/handlers/spanning-stories-incomplete.js
61
+ scripts/lib/handlers/spec-inputs-digest.js
62
+ scripts/lib/handlers/spec-predates-plan.js
63
+ scripts/lib/handlers/stories-lacking-spec.js
64
+ scripts/lib/handlers/write-missing-plans.js
30
65
  scripts/lib/jq-vals.sh
31
66
  scripts/lib/kb-apply.sh
32
67
  scripts/lib/kb-arbitration.js
@@ -37,15 +72,27 @@ scripts/lib/langfuse-emit.js
37
72
  scripts/lib/llm-settings-resolve.js
38
73
  scripts/lib/model-ladder.sh
39
74
  scripts/lib/model-ladders.sh
75
+ scripts/lib/orchestration-resume.sh
76
+ scripts/lib/phase-exit.sh
77
+ scripts/lib/pipeline-commit.sh
40
78
  scripts/lib/pipeline-tools.js
79
+ scripts/lib/plan-hash.js
80
+ scripts/lib/plan-scope.js
41
81
  scripts/lib/preflight.sh
42
82
  scripts/lib/prelaunch.js
83
+ scripts/lib/qa-gate-evidence.sh
43
84
  scripts/lib/relative-paths.js
85
+ scripts/lib/release-lines.sh
44
86
  scripts/lib/render-prompt-section.js
87
+ scripts/lib/resume-semantics.sh
88
+ scripts/lib/run-checkpoint.sh
89
+ scripts/lib/run-modes.sh
45
90
  scripts/lib/seam-invocation.js
46
91
  scripts/lib/seam-ladder.sh
47
92
  scripts/lib/self-heal.js
48
93
  scripts/lib/stage-coverage-gate.sh
94
+ scripts/lib/story-outputs.sh
95
+ scripts/lib/story-retry-state.sh
49
96
  scripts/lib/tool-timeouts.js
50
97
  scripts/lib/transcript-tool-calls.js
51
98
  scripts/llm-handler.sh
@@ -0,0 +1,23 @@
1
+ {
2
+ "$comment": "Directories and files that are never agent output, and are not facts of any ecosystem. Ecosystem artefacts (node_modules, target, __pycache__, .venv …) live in scripts/lib/ecosystem-registry.js beside the ecosystem that produces them; these are editor and operating-system droppings, and engine state that must never reach a client repository. Extracted 2026-08-16 from two hand-written lists — one in worktree-health-check.sh and one in lib/git-ops.sh — that had drifted apart and between them named only node_modules, build and .next.",
3
+
4
+ "$biasComment": "The bias here is deliberate and one-directional. A directory wrongly EXCLUDED loses real agent work silently; one wrongly INCLUDED appears in a diff where a human sees it. So this list stays short and holds only what can never be source. Anything ambiguous belongs in the repository's own .gitignore, which is the customer's decision to make, not the engine's.",
5
+
6
+ "dirs": [
7
+ ".idea",
8
+ ".vscode",
9
+ ".dart_tool"
10
+ ],
11
+
12
+ "files": [
13
+ ".DS_Store",
14
+ "Thumbs.db"
15
+ ],
16
+
17
+ "$engineComment": "Engine state, matched as path prefixes. The write perimeter in lib/engine-paths.sh is the authority and is applied separately; these are the belt-and-braces entries the untracked report also needs, so an engine file never shows up as the agent's uncommitted work.",
18
+ "enginePaths": [
19
+ "orchestrations/logs/*",
20
+ "orchestrations/prd.json.lock",
21
+ "orchestrations/prd.json.backup"
22
+ ]
23
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "$why": [
3
+ "Between 2026-09-15 and 2026-09-20 five components each had to be taught 'this is a resume'",
4
+ "separately, one live failure at a time: the launcher tore the codeline down, the lifecycle",
5
+ "passed --reset, pre-run-reset archived the run's ledgers, pre-flight refused the run's own",
6
+ "spec blocks and healing ledger, and the remediation reset 14 completed stories ($20). Each",
7
+ "read EPAM_RESUME_RUN on its own and decided on its own what that meant. This file is the",
8
+ "one statement of what a resume keeps; lib/resume-semantics.sh (and its Python twin) answers",
9
+ "resume_preserves <aspect> from it; every consumer asks. An aspect not listed here is refused",
10
+ "loudly by the reader — never guessed."
11
+ ],
12
+ "preserves": {
13
+ "prd-state": "The PRD on disk is the run's own working copy — never restored from the authored canonical (tier3-run 2026-09-16, pre-flight 2026-09-15).",
14
+ "codeline": "The output directory holds the run's committed work; it is not torn down or reinitialised (tier3-run 2026-09-16).",
15
+ "ledgers": "phase-gates, phase-cost, healing-events, run-guidance, code-reviews and the other JSONL ledgers under LOG_DIR, and the per-story writer-rung (story-rung/) and ladder-state (story-retry-state/) records, are this run's record — not archived or cleared (pre-run-reset 2026-09-18 and 2026-09-21, pre-flight 2026-09-19).",
16
+ "roster": "The roster and agent profiles this run minted and reviewed are reused byte-for-byte; the specialiser is not called again (pre-run-reset 2026-09-19). Also across an engine release between pause and resume: an entry whose canonical ancestor changed is kept as reviewed and a canonical agent the release added is adopted verbatim, both recorded in logs/roster-release-drift.json — the roster is never re-derived (lib/project-roster.js keptAcrossRelease, 2026-09-25).",
17
+ "prompts": "The prompt set built for this run's codeline is reused, not rebuilt (2026-09-19) — except that when its inputs changed since, each kept generated prompt is judged again by the current reviewer and only one the reviewer rejects is regenerated (operator, 2026-10-06).",
18
+ "fetched-documents": "Referenced documents and the estate survey fetched for this run are kept (pre-run-reset 2026-09-18).",
19
+ "phase-gates": "A phase whose gate already decided GO is recognised as completed and not run again (greenfield-lifecycle 2026-09-16).",
20
+ "completed-stories": "A story marked completed keeps its status and record; only failed, blocked or in-progress stories are re-queued; the orchestrator runs without --reset (greenfield-lifecycle 2026-09-16, prd-remediate 2026-09-20).",
21
+ "spec-blocks": "Specification blocks on pending stories are this run's own spec pass, not prior-run contamination (prd-remediate and pre-flight 2026-09-15).",
22
+ "checkpoint": "The run's checkpoint (roster, prompts, PRD, briefs) is restored and owned by this run; a later launch may displace, never overwrite (run-checkpoint 2026-09-19).",
23
+ "review-findings": "The reviewer's per-story findings (review-feedback-<story>.json) are this run's own evidence; the story a resume re-runs is the one they reject, and the writer is re-invoked with them (pre-run-reset 2026-09-22)."
24
+ }
25
+ }
@@ -0,0 +1,47 @@
1
+ {
2
+ "_what": "Named run modes. A mode is a stated INTENT — 'resume the writer' — and the set of steps that intent turns off.",
3
+ "_why": [
4
+ "On 2026-08-13 an operator asked for a writer resume. It was launched with three environment",
5
+ "variables and needed six, so the CPA pre-pass, the pre-phase skill assessment and the",
6
+ "regression guard all ran anyway — each is a separate default-ACTIVE step, and nothing tied",
7
+ "any of them to the stated intent. The operator had to notice it mid-run.",
8
+ "",
9
+ "The intent already existed in run-checkpoint.sh's pre-writer stage, reachable only through a",
10
+ "checkpoint, and even that list omitted the regression guard. Two half-definitions of one idea.",
11
+ "",
12
+ "Declared here, the engine reads a mode and never knows one. Adding a mode is an edit to this",
13
+ "file. Nobody assembles a mode by hand, so no mode can be half-applied."
14
+ ],
15
+ "modes": {
16
+ "writer-only": {
17
+ "_what": "Resume at the writer. The spec pass, roster mint, Jira ingest, CPA pre-pass, pre-phase skill assessment and regression baseline have all already run, or are not wanted for this attempt.",
18
+ "_cost": "Skipping the regression baseline means later test gates judge the codeline's CURRENT state, so pre-existing failures can be attributed to this change. Right for testing a writer; wrong for a run you intend to merge.",
19
+ "skips": [
20
+ "EPAM_SPEC_MODE=0",
21
+ "EPAM_SKIP_AGENT_MINT=1",
22
+ "EPAM_SKIP_JIRA_INGEST=1",
23
+ "SKIP_CPA=1",
24
+ "SKIP_SKILL_ASSESSMENT=1",
25
+ "SKIP_REGRESSION_GUARD=true"
26
+ ],
27
+ "_why_no_mint": "The mint does NOT run. A writer re-run uses the roster that was already minted and reviewed; re-minting proposes against an existing roster and the merge is additive, so it accumulates near-duplicate roles and changes the agents under a story mid-stream."
28
+ },
29
+ "post-spec": {
30
+ "_what": "The spec pass and the roster are done and on disk; everything from the CPA pre-pass onward still runs.",
31
+ "skips": [
32
+ "EPAM_SPEC_MODE=0",
33
+ "EPAM_SKIP_JIRA_INGEST=1",
34
+ "EPAM_SKIP_AGENT_MINT=1"
35
+ ],
36
+ "_why_mint": "Skips the mint because this mode describes a RESUME of a run whose roster is already on disk — pre-run-reset preserves the registries when EPAM_RESUME_RUN is set. A fresh launch has no such protection, which is why writer-only does not skip it."
37
+ },
38
+ "post-roster": {
39
+ "_what": "The roster is minted and assignments are written; the spec pass still runs.",
40
+ "skips": [
41
+ "EPAM_SKIP_JIRA_INGEST=1",
42
+ "EPAM_SKIP_AGENT_MINT=1"
43
+ ],
44
+ "_why_mint": "Skips the mint because this mode describes a RESUME of a run whose roster is already on disk — pre-run-reset preserves the registries when EPAM_RESUME_RUN is set. A fresh launch has no such protection, which is why writer-only does not skip it."
45
+ }
46
+ }
47
+ }
@@ -0,0 +1,175 @@
1
+ #!/usr/bin/env bash
2
+ # checkpoints.sh — moved verbatim out of run-agent-orchestration.sh by tools/split-main-into-modules.py
3
+ # (6 functions). Sourced by run-agent-orchestration.sh; SCRIPT_DIR and the globals it sets
4
+ # are in scope exactly as they were. A move, not an edit: every body is byte-identical to
5
+ # the golden recorded at the move (see the identity test).
6
+
7
+ # ── GAP-P13 checkpoint helpers ──────────────────────────────────────────────
8
+ # Write a completed checkpoint entry for a story.
9
+ checkpoint_complete() {
10
+ local story_id="$1"
11
+ local idem_key="${ORCH_RUN_ID}:${PHASE:-main}:${story_id}"
12
+ jq -cn \
13
+ --arg key "$idem_key" \
14
+ --arg sid "$story_id" \
15
+ --arg phase "${PHASE:-main}" \
16
+ --arg runId "$ORCH_RUN_ID" \
17
+ '{idempotencyKey:$key, storyId:$sid, phase:$phase, runId:$runId,
18
+ status:"completed", completedAt:(now|todate)}' \
19
+ >> "$CHECKPOINT_FILE" 2>/dev/null || true
20
+ }
21
+
22
+ # Returns 0 (true) if the story already has a completed checkpoint in this run.
23
+ # Used to skip stories that finished before a crash/restart.
24
+ checkpoint_already_done() {
25
+ local story_id="$1"
26
+ [ ! -f "$CHECKPOINT_FILE" ] && return 1
27
+ local idem_key="${ORCH_RUN_ID}:${PHASE:-main}:${story_id}"
28
+ grep -q "\"idempotencyKey\":\"${idem_key}\"" "$CHECKPOINT_FILE" 2>/dev/null
29
+ }
30
+
31
+ # Clear checkpoints for this phase+run (called when RESET_STORIES=true).
32
+ checkpoint_clear() {
33
+ rm -f "$CHECKPOINT_FILE" 2>/dev/null || true
34
+ }
35
+
36
+ # RESUME IS DECIDED BEFORE ANY WORK, NOT AFTER IT.
37
+ #
38
+ # EPAM_RESUME_RUN restores what a previous run persisted and skips exactly what that
39
+ # checkpoint already paid for — derived from the stage it was taken at, never assumed.
40
+ #
41
+ # This block used to sit past the entry-point dispatch below, and a Jira run calls
42
+ # _run_jira_pipeline and EXITS there, so on that shape it was never reached. The checkpoint was
43
+ # never restored and the skip env was computed for a branch that never ran. Every "resume" was
44
+ # therefore a fresh run: it re-ingested, re-minted, and discarded the roster the operator had
45
+ # just reviewed at the pause — which made the roster pause ceremonial, since you reviewed one
46
+ # roster and ran a different one.
47
+ #
48
+ # A resume that cannot be honoured HALTS. Continuing would silently run against whatever stale
49
+ # state happened to be on disk, which is the failure this exists to prevent.
50
+ #
51
+ # Top level only: lanes re-invoke this script and would each restore the checkpoint over their
52
+ # own state. The parent decides what to resume; the lanes inherit the result.
53
+ # resume_spec_output_present <prd_file>
54
+ # Did the spec pass leave anything behind in this PRD?
55
+ #
56
+ # A resume exports EPAM_SPEC_MODE=0 to mean "the spec pass already ran, skip it". That is a
57
+ # statement about HISTORY, and history stops being a safe proxy the moment something overwrites
58
+ # the PRD in between. Live 2026-08-10: a fresh (non-resume) launch re-ingested Jira over the
59
+ # same file, emptying fixSiteAnalysis (13->0), verificationCriteria (14->0) and the declared
60
+ # file list (13->0). The next resume skipped the spec pass exactly as instructed and handed the
61
+ # writer a story with nothing to aim at — 23 invocations, 10 watchdog kills, $11.76, no code.
62
+ #
63
+ # PRESENCE, not content: any one of the spec pass's own output fields being non-empty proves it
64
+ # ran and survived. Nothing here names a story, a file, a codeline or a project, so a PRD from
65
+ # any project passes the moment its spec pass has left something behind.
66
+ #
67
+ # Fails CLOSED — unreadable, absent or malformed all count as "not present". A guard against
68
+ # missing state must not treat "I could not tell" as "fine".
69
+ resume_spec_output_present() {
70
+ local _prd="${1:-}"
71
+ [ -n "$_prd" ] && [ -f "$_prd" ] || return 1
72
+ "${NODE_BIN:-node}" "$SCRIPT_DIR/lib/handlers/resume-spec-output-present.js" "$_prd" 2>/dev/null
73
+ }
74
+
75
+ # _clear_suite_state_for_phase <prd_file> <phase>
76
+ # WHATEVER SETS THE FLAG CAN UNSET IT.
77
+ #
78
+ # Step 3.545 stamps suiteState=red when it cannot reconcile a failing test, and Step 3.55
79
+ # blocks on that flag. Nothing ever cleared it, so it was a latch: a run that recovered was
80
+ # still failed by its own history.
81
+ #
82
+ # Live, run 20260815T142007Z (metrolinx, AMSD-2041): pass 1's generated spec mocked a module
83
+ # the SDK does not use, the suite went red, and 3.545 stamped it. The retry fixed the code —
84
+ # tsc passed, external verification passed, the story completed and committed. At 16:03
85
+ # update-invalidated-tests re-checked and reported "suite already green — nothing to do",
86
+ # and seconds later Step 3.55 failed the phase on the stale flag, asserting "Step 3.545
87
+ # could not reconcile it" about a step that had just reported the opposite. The suite was
88
+ # green: 1203/1203 under the project's declared TZ.
89
+ #
90
+ # This ONLY clears. Step 3.55 is untouched, so a suite that never recovered still blocks —
91
+ # that is the behaviour the flag exists to provide.
92
+ _clear_suite_state_for_phase() {
93
+ local _prd="${1:-}" _phase="${2:-}"
94
+ [ -f "$_prd" ] || return 0
95
+ local _ids
96
+ _ids=$(jq -r --arg phase "$_phase" '(.implementationOrder[$phase] // [])[]?' "$_prd" 2>/dev/null)
97
+ [ -n "$_ids" ] || return 0
98
+ local _sid
99
+ while IFS= read -r _sid; do
100
+ [ -n "$_sid" ] || continue
101
+ jq -e --arg id "$_sid" '.stories[] | select(.id == $id) | has("suiteState")' "$_prd" >/dev/null 2>&1 || continue
102
+ local _tmp
103
+ _tmp="$(mktemp)"
104
+ # Staged through a temp file and moved: a truncated PRD is worse than a stale flag.
105
+ if jq --arg id "$_sid" \
106
+ '(.stories[] | select(.id == $id)) |= (del(.suiteState) | del(.suiteStateStep))' \
107
+ "$_prd" > "$_tmp" 2>/dev/null; then
108
+ mv "$_tmp" "$_prd"
109
+ info "Step 3.545: suite recovered — cleared suiteState on $_sid"
110
+ else
111
+ rm -f "$_tmp"
112
+ fi
113
+ done <<< "$_ids"
114
+ return 0
115
+ }
116
+
117
+ # ──────────────────────────────────────────────
118
+ # run_interstitial_e2e_phase <phase_id>
119
+ # Step 5.5: After phase gate passes, check for a <phase_id>_e2e phase
120
+ # in implementationOrder and run it. Blocks next phase if E2E fails.
121
+ # ──────────────────────────────────────────────
122
+ run_interstitial_e2e_phase() {
123
+ local phase_id="$1"
124
+ local e2e_phase="${phase_id}_e2e"
125
+
126
+ local has_e2e_phase
127
+ has_e2e_phase=$(jq -r --arg p "$e2e_phase" \
128
+ 'if .implementationOrder[$p] then "yes" else "no" end' \
129
+ "$PRD_FILE" 2>/dev/null || echo "no")
130
+
131
+ if [ "$has_e2e_phase" = "no" ]; then
132
+ info "Step 5.5: No interstitial E2E phase for '$phase_id' — skipping"
133
+ return 0
134
+ fi
135
+
136
+ log "Step 5.5: Running interstitial E2E phase '$e2e_phase'..."
137
+ "$SCRIPT_DIR/update-monitor.sh" event "e2e_gate_start" \
138
+ "Starting E2E phase $e2e_phase" "" "main" "qa-engineer" 2>/dev/null || true
139
+
140
+ local e2e_log="$LOG_DIR/e2e-phase-${e2e_phase}.log"
141
+ # PIPESTATUS[0], NOT THE `if`. Without pipefail -- and this script sets none -- `if cmd | tee`
142
+ # tests TEE's status, which is always 0. So this phase reported PASSED unconditionally and the
143
+ # else branch below, which fails the run, was unreachable. Same defect as the phase gate.
144
+ bash "$0" --phase "$e2e_phase" 2>&1 | tee "$e2e_log"
145
+ local _e2e_rc=${PIPESTATUS[0]}
146
+ if [ "$_e2e_rc" -eq 0 ]; then
147
+ success "Interstitial E2E phase '$e2e_phase' PASSED"
148
+ "$SCRIPT_DIR/update-monitor.sh" event "e2e_gate_pass" \
149
+ "E2E phase $e2e_phase passed" "" "main" "qa-engineer" 2>/dev/null || true
150
+ else
151
+ local e2e_exit=$_e2e_rc
152
+ error "Interstitial E2E phase '$e2e_phase' FAILED (exit $e2e_exit)"
153
+ error "Fix E2E failures then re-run: $0 --phase $e2e_phase"
154
+ error "Log: $e2e_log"
155
+ "$SCRIPT_DIR/update-monitor.sh" event "e2e_gate_fail" \
156
+ "E2E phase $e2e_phase FAILED" "" "main" "qa-engineer" 2>/dev/null || true
157
+ return 1
158
+ fi
159
+ }
160
+
161
+ # record_run_pause <stage>
162
+ # THE PAUSE, ON DISK, FOR THE LAUNCHER. A pause exits 0 — it is not a failure — and the greenfield
163
+ # phase loop read that 0 as "phase completed", started the next phase, minted a second run id and
164
+ # reported the project done (run 20260916T200051Z → 200108Z). The launcher cannot tell a pause
165
+ # from a completion by exit code alone, so the pause says so here: run id, stage and phase, in
166
+ # the run's log dir, where the loop looks after every phase.
167
+ record_run_pause() {
168
+ local _stage="${1:?stage}"
169
+ local _dir="${EPAM_PROJECT_OUTPUT_DIR:-${LOG_DIR:-}}"
170
+ [ -n "$_dir" ] || return 0
171
+ mkdir -p "$_dir" 2>/dev/null || return 0
172
+ jq -n --arg runId "${ORCH_RUN_ID:-}" --arg stage "$_stage" --arg phase "${PHASE:-}" --arg at "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
173
+ '{runId:$runId, stage:$stage, phase:$phase, pausedAt:$at}' > "$_dir/paused-run.json" 2>/dev/null || true
174
+ }
175
+