Repository navigation
fix: classifyWorkflowStatus case labels never matched real status values - #25
Conversation
classifyWorkflowStatus() switched on uppercase literals ("COMPLETED",
"PAUSED", "FAILED", "ABORTED"), but RunStatus's actual values
(src/factory/base.mjs) are lowercase ("completed", "paused", "failed",
"aborted"). Every real terminal status silently fell through to the
`default` case, returning exitCode 1 unconditionally — confirmed
empirically: classifyWorkflowStatus("completed") returned 1, not 0.
This breaks the documented Argo lane contract in workflow.mjs
(`asInt(lastRetry.exitCode) != 10 && != 3`, meant to exclude PAUSED/
FAILED from retries) for every outcome, not just the ones tikalk#19 already
covered — COMPLETED runs were being treated identically to FAILED/
ABORTED ones at the exit-code layer, even though `workflow run`/
`workflow resume` always computed the correct in-memory RunStatus and
printed the correct "Status: completed" to stdout.
Fix: match on the actual (lowercase) values. Deliberately did not add
a RunStatus import, preserving this file's "no imports" header
contract — added a comment explaining why the casing must be
hand-kept in sync instead.
Verified live with real runs (local + cluster), before marking readyPatched the actually-running `adlc-cli` binary (not just the source checkout) in both a local sandbox and a real `adlc-mission-runner` cluster pod, and ran real missions end-to-end against real GitLab issues. `PAUSED` → exit 3 (confirmed twice):
`COMPLETED` → exit 0 (confirmed):
This is the exact scenario from the original report — a run that finishes every step including `sweep`, prints `Status: completed`, and previously still exited 1. With this fix it correctly exits 0. |
|
factory-review self-heal: fixed the blocking finding, PR is merge-ready pending human approval (I never approve or merge). What was wrong: the case-fix was correct, but Fix pushed as a259dc0 (new head): 4 test input strings → lowercase, src/ untouched. Converge check on the new head: fix commit touches only that test file, cases match real Advisory nits left for you (non-blocking): the test file's header comment (lines 13-16) and test titles (lines 99/104/109/114) still say COMPLETED/PAUSED/FAILED/ABORTED in uppercase while inputs are now lowercase — worth a consistency touch. Open question from review (unchanged): the PR body mentions one pre-existing failing test, but the tree is fully green here — which test did you mean? |
Problem
Every `adlc-cli workflow run`/`workflow resume` invocation exits 1 regardless of the actual terminal status — `COMPLETED`, `PAUSED`, and `FAILED` all collapse to the same exit code. Confirmed live, in a real mission pod: a run that finished all 7 factory steps including the final `sweep`, printed `Status: completed`, had already posted real completion comments to the tracker — still exited 1.
Root cause
`classifyWorkflowStatus()` (`src/exit-codes.mjs`) switches on the uppercase enum key names (`"COMPLETED"`, `"PAUSED"`, `"FAILED"`, `"ABORTED"`), but `RunStatus`'s actual values (`src/factory/base.mjs:13-20`) are lowercase:
```js
export const RunStatus = Object.freeze({
CREATED: "created", RUNNING: "running", PAUSED: "paused",
COMPLETED: "completed", FAILED: "failed", ABORTED: "aborted",
});
```
`workflow.mjs` calls `classifyWorkflowStatus(state.status)` with the real (lowercase) value every time — so every `case` label in the switch silently never matches, and every call falls through to `default: return { exitCode: 1 }`.
Verified empirically against the unpatched function:
```
Impact
This isn't cosmetic. `workflow.mjs`'s own comment documents the contract this exit code exists for: the Argo retry-gate expression `asInt(lastRetry.exitCode) != 10 && asInt(lastRetry.exitCode) != 3`, meant to exclude `PAUSED`/`FAILED` runs from infra-level retries. Since every real status currently returns 1 (never 10, never 3), that expression is always true — the retry gate cannot distinguish a successfully-completed run from a failed or paused one at all. A completed mission pod gets the exact same exit code as a failed one.
`#19` (closed) covered a related but narrower gap (FAILED/PAUSED/ABORTED all collapsing together); this is the same symptom but for every status including `COMPLETED`, and the actual bug is a plain casing mismatch, not a missing case.
Fix
Match on the actual (lowercase) `RunStatus` values. Deliberately did not add a `RunStatus` import — this file's header explicitly says "Pure classifiers — no side effects, no imports," so instead added a comment explaining why the casing has to be hand-kept in sync, to stop this regressing silently again.
Verification