|
| 1 | +--- |
| 2 | +description: Recover a failed main-branch sweep ingest from validated PR artifacts without rerunning GPU benchmarks |
| 3 | +argument-hint: <failed-run-or-job-url> [source-run-id] |
| 4 | +--- |
| 5 | + |
| 6 | +Recover the official database ingest for a failed InferenceX push-to-main `Run Sweep` |
| 7 | +workflow by reusing artifacts from the corresponding PR sweep. Execute the diagnosis, |
| 8 | +recovery PR, dispatch, and downstream verification end to end. |
| 9 | + |
| 10 | +Inputs from `$ARGUMENTS`: |
| 11 | + |
| 12 | +- `failed-run-or-job-url` is required. A run-only URL is accepted only when it has exactly |
| 13 | + one completed failed job; otherwise require a `/job/<job-id>` URL. |
| 14 | +- `source-run-id` is optional and is only a candidate until every source and artifact check |
| 15 | + passes. |
| 16 | + |
| 17 | +## Safety rules |
| 18 | + |
| 19 | +- Never rerun the failed target workflow or job. |
| 20 | +- The target must be a completed failed `push` run of |
| 21 | + `.github/workflows/run-sweep.yml` on `main`. |
| 22 | +- Reuse only a completed PR run of that workflow whose head SHA remains in the merged PR. |
| 23 | + Unpinned runs must be successful. A specifically supplied failed run is allowed only when |
| 24 | + exact artifact validation proves the target matrix is complete. |
| 25 | +- Stop if execution-relevant files changed between the source SHA and final PR head. |
| 26 | +- The recovery workflow must contain one `ubuntu-latest` job, only |
| 27 | + `workflow_dispatch`, and an exact confirmation input. It must not call benchmark reusable |
| 28 | + workflows or use a matrix. Its GitHub token permissions must be explicitly read-only. |
| 29 | +- Preserve historical `perf-changelog.yaml` bytes. Reconstruct only the target PR's appended |
| 30 | + entries, with canonical links to that PR. |
| 31 | +- Use a detached temporary worktree for reconstruction. Every `git add`, `write-tree`, and |
| 32 | + processor command must run through `git -C "$WORKTREE"` or the recovery helper. |
| 33 | +- Never bypass failing or pending checks. Use admin merge only when all checks passed and |
| 34 | + repository policy is the sole blocker. |
| 35 | +- Put `[skip-sweep]` in the recovery commit and merge subject. |
| 36 | +- Do not add co-author lines, generated-by text, bot branding, or author attribution. |
| 37 | + |
| 38 | +## 1. Inspect the exact target |
| 39 | + |
| 40 | +Install local helper dependencies, then let the tested helper parse the URL, resolve an |
| 41 | +omitted job ID only when unambiguous, validate target invariants, and resolve the merged PR: |
| 42 | + |
| 43 | +```bash |
| 44 | +python -m pip install pydantic pyyaml |
| 45 | +python utils/recover_failed_ingest.py inspect-target \ |
| 46 | + "$FAILED_RUN_OR_JOB_URL" \ |
| 47 | + --output /tmp/infx-recovery-target.json |
| 48 | + |
| 49 | +TARGET_RUN_ID=$(jq -r .run_id /tmp/infx-recovery-target.json) |
| 50 | +TARGET_JOB_ID=$(jq -r .job_id /tmp/infx-recovery-target.json) |
| 51 | +PR=$(jq -r .pr_number /tmp/infx-recovery-target.json) |
| 52 | +ORIGINAL_MERGE_SHA=$(jq -r .merge_sha /tmp/infx-recovery-target.json) |
| 53 | + |
| 54 | +gh run view "$TARGET_RUN_ID" \ |
| 55 | + --repo SemiAnalysisAI/InferenceX \ |
| 56 | + --job "$TARGET_JOB_ID" --log \ |
| 57 | + > "/tmp/infx-target-$TARGET_RUN_ID.log" |
| 58 | +``` |
| 59 | + |
| 60 | +Fetch history and require the merge's first parent: |
| 61 | + |
| 62 | +```bash |
| 63 | +git fetch origin main |
| 64 | +git cat-file -e "${ORIGINAL_MERGE_SHA}^{commit}" |
| 65 | +ORIGINAL_BASE_SHA=$(git rev-parse "${ORIGINAL_MERGE_SHA}^") |
| 66 | +python utils/recover_failed_ingest.py audit-changelog \ |
| 67 | + --ref "$ORIGINAL_MERGE_SHA" |
| 68 | +git diff --check "$ORIGINAL_BASE_SHA" "$ORIGINAL_MERGE_SHA" \ |
| 69 | + -- perf-changelog.yaml |
| 70 | +``` |
| 71 | + |
| 72 | +The audit reads `perf-changelog.yaml` from `ORIGINAL_MERGE_SHA`, never from the current |
| 73 | +checkout. Its `errors` list records repairable historical defects such as a missing final |
| 74 | +newline; duplicate keys or an unparseable schema still abort. Record the failed job's root |
| 75 | +cause and stop unless it is an ingest/reuse failure that can be repaired without GPU work. |
| 76 | + |
| 77 | +## 2. Select the source PR sweep |
| 78 | + |
| 79 | +Enumerate every current PR commit and every `run-sweep.yml` PR run for those SHAs. Validate |
| 80 | +the candidate through GitHub's API: |
| 81 | + |
| 82 | +- workflow path, event, status, conclusion, attempt, and source head SHA; |
| 83 | +- source-head membership in the PR commit list; |
| 84 | +- all retained artifacts are unexpired; |
| 85 | +- the candidate produced `results_bmk`, `eval_results_all`, or at least one |
| 86 | + `bmk_agentic_*` point artifact. |
| 87 | + |
| 88 | +Do not require `results_bmk` or `run-stats` for eval-only or agentic-only matrices. The exact |
| 89 | +matrix validator in step 4 decides which aggregates and point artifacts are required. |
| 90 | + |
| 91 | +Compare the source SHA through the final PR head. Any target-specific config, image, model, |
| 92 | +runner, launcher, benchmark script, or matrix change disqualifies the source. |
| 93 | + |
| 94 | +## 3. Reconstruct in a detached worktree |
| 95 | + |
| 96 | +Read the two prior examples, inspect the historical diff, and create a worktree at the exact |
| 97 | +failed merge: |
| 98 | + |
| 99 | +```bash |
| 100 | +sed -n '1,260p' .github/workflows/recover-pr-1767-ingest.yml |
| 101 | +sed -n '1,280p' .github/workflows/recover-pr-1798-ingest.yml |
| 102 | +git diff "$ORIGINAL_BASE_SHA" "$ORIGINAL_MERGE_SHA" -- perf-changelog.yaml |
| 103 | + |
| 104 | +WORKTREE=$(mktemp -d /tmp/infx-recovery-worktree.XXXXXX) |
| 105 | +rmdir "$WORKTREE" |
| 106 | +python utils/recover_failed_ingest.py create-worktree \ |
| 107 | + --ref "$ORIGINAL_MERGE_SHA" \ |
| 108 | + --directory "$WORKTREE" |
| 109 | +``` |
| 110 | + |
| 111 | +Edit only `$WORKTREE/perf-changelog.yaml`. Repair malformed target entries and reverse any |
| 112 | +unrelated historical repair so the resulting file is exactly the base bytes followed by the |
| 113 | +target PR's intended entries. Do not autoformat or deduplicate. |
| 114 | + |
| 115 | +Build the synthetic commit and config through the helper. It stages only inside the detached |
| 116 | +worktree, rejects unrelated changes, enforces exact historical bytes and canonical PR links, |
| 117 | +and verifies that the synthetic commit changes only `perf-changelog.yaml`: |
| 118 | + |
| 119 | +```bash |
| 120 | +python utils/recover_failed_ingest.py build-config \ |
| 121 | + --worktree "$WORKTREE" \ |
| 122 | + --base-ref "$ORIGINAL_BASE_SHA" \ |
| 123 | + --merge-ref "$ORIGINAL_MERGE_SHA" \ |
| 124 | + --pr-number "$PR" \ |
| 125 | + --config-output /tmp/full-config.json \ |
| 126 | + --metadata-output /tmp/changelog-metadata/changelog_metadata.json |
| 127 | +``` |
| 128 | + |
| 129 | +Inspect the reported fixed-sequence, agentic, and eval counts before continuing. |
| 130 | + |
| 131 | +## 4. Download and validate exact artifacts |
| 132 | + |
| 133 | +Download the selected source run to a fresh directory. Remove its changelog metadata and |
| 134 | +retain only ingest-relevant classes: |
| 135 | + |
| 136 | +```text |
| 137 | +results_bmk |
| 138 | +eval_results_all |
| 139 | +run-stats |
| 140 | +bmk_* |
| 141 | +eval_* |
| 142 | +agentic_* |
| 143 | +server_logs_* |
| 144 | +multinode_server_logs_* |
| 145 | +agentic_aggregated |
| 146 | +``` |
| 147 | + |
| 148 | +Run the authoritative exact validator: |
| 149 | + |
| 150 | +```bash |
| 151 | +python utils/validate_reusable_sweep_artifacts.py \ |
| 152 | + --config-json /tmp/full-config.json \ |
| 153 | + --artifacts-dir /tmp/source-artifacts |
| 154 | +``` |
| 155 | + |
| 156 | +It requires equality for fixed-sequence identities, agentic point/raw/aggregate identities, |
| 157 | +and eval-only raw identities. It also rejects unexpected rows and requires `run-stats` only |
| 158 | +when fixed-sequence collection should have produced it. Stop on any mismatch. |
| 159 | + |
| 160 | +## 5. Create the guarded recovery workflow |
| 161 | + |
| 162 | +Create `workflow/recover-pr-<PR>-ingest` from current `origin/main` and add |
| 163 | +`.github/workflows/recover-pr-<PR>-ingest.yml`, based on the closest prior example. |
| 164 | +Hard-code the validated source run/attempt/SHA, target run/job, PR, original base, and merge |
| 165 | +SHAs. Revalidate those values in the workflow before downloading artifacts. |
| 166 | + |
| 167 | +The workflow must reproduce the locally tested reconstruction, upload |
| 168 | +`reused-ingest-artifacts` and corrected `changelog-metadata`, then dispatch |
| 169 | +`ingest-results` to `SemiAnalysisAI/InferenceX-app`. |
| 170 | + |
| 171 | +Validate it before committing: |
| 172 | + |
| 173 | +```bash |
| 174 | +python utils/recover_failed_ingest.py validate-workflow \ |
| 175 | + ".github/workflows/recover-pr-$PR-ingest.yml" \ |
| 176 | + --pr-number "$PR" |
| 177 | +actionlint ".github/workflows/recover-pr-$PR-ingest.yml" |
| 178 | +yq eval '.' ".github/workflows/recover-pr-$PR-ingest.yml" >/dev/null |
| 179 | +git diff --check |
| 180 | +``` |
| 181 | + |
| 182 | +Commit as `fix: recover PR <PR> ingest [skip-sweep]`, push, and open a PR. The body and a PR |
| 183 | +comment must record the failed target/job, root cause, source run/attempt/SHA, exact counts, |
| 184 | +and CPU-only safeguards. Do not add attribution. |
| 185 | + |
| 186 | +Wait for all checks, then merge with a `[skip-sweep]` subject. Use admin merge only for the |
| 187 | +policy-only case described above. |
| 188 | + |
| 189 | +## 6. Dispatch and verify |
| 190 | + |
| 191 | +Dispatch from `main` with the exact confirmation string: |
| 192 | + |
| 193 | +```bash |
| 194 | +gh workflow run "recover-pr-$PR-ingest.yml" \ |
| 195 | + --repo SemiAnalysisAI/InferenceX \ |
| 196 | + --ref main \ |
| 197 | + -f confirm="recover-pr-$PR" |
| 198 | +``` |
| 199 | + |
| 200 | +Require the carrier workflow to succeed and confirm it created no GPU or benchmark jobs. |
| 201 | +Then locate the resulting `repository_dispatch` run in `SemiAnalysisAI/InferenceX-app`. |
| 202 | +Require successful artifact download/flattening, database ingest, run overrides, database |
| 203 | +verification, cache invalidation, and unmapped-entity checks. |
| 204 | + |
| 205 | +Post a final recovery PR comment with carrier and downstream run links plus exact counts. |
| 206 | +Remove the temporary worktree with `git worktree remove "$WORKTREE"` and report the recovery |
| 207 | +PR, merge SHA, source attempt, carrier run, downstream run, row counts, and verification |
| 208 | +outcome. |
0 commit comments