Back to home page

EIC code displayed by LXR

 
 

    


Warning, /swf-monitor/docs/ERROR_ATTRIBUTION.md is written in an unsupported language. File is not indexed.

0001 # Error Attribution and Correction
0002 
0003 Unreliable PanDA job error labels are corrected at a single service
0004 root through which every error-presentation surface reads. This is a
0005 design document; the sections below are the agreed plan of record for
0006 implementation. It extends the error machinery of
0007 [SNAPPER_ERRORS.md](SNAPPER_ERRORS.md) — in particular its
0008 progressive-refinement and knowledge-base tiers — with the concrete
0009 correction mechanism, the evidence model behind it, and the payload
0010 and pilot channels that feed it.
0011 
0012 ## Problem
0013 
0014 PanDA job error labels come from the pilot's error extraction, which
0015 can misattribute failures. Confirmed case: 42,870 NERSC jobs over four
0016 days in August 2026 recorded as pilot error 1305 ("bind mounting
0017 /global", a stale apptainer stderr line) that had run reconstruction
0018 for ~2 hours and failed at Rucio registration — payload exit 78,
0019 confirmed against the payload log of a representative job (2584600)
0020 and self-contradicted by the pilot's own timing fields (`pilottiming`
0021 exe = 5450 s under a "launch failure" label).
0022 
0023 Error labels feed many presentation surfaces: the error summary
0024 (`/panda/errors/` and the `panda_error_summary` MCP tool), job study,
0025 the Snapper errors view, system status, daily reports, assessments,
0026 and Capcom notices. A correction applied inside any one aggregation
0027 leaves the others wrong. Correction therefore applies at one root
0028 through which every surface reads.
0029 
0030 ## The correction service
0031 
0032 A single module and rules store in swf-monitor; every
0033 error-presentation path is a client.
0034 
0035 - **Read-time application.** Corrections arrive after the fact, so
0036   recorded history (job records, Snapper snaps) stays raw as reported;
0037   every read path applies corrections on the way out. A rule added
0038   today corrects last week's presentation everywhere.
0039 - **Provenance always.** The corrected reading leads; the original
0040   label stays visible ("reported as pilot:1305"); every verdict
0041   carries its evidence link, scope, author, and date.
0042 - **REST face** on the same root, so out-of-process consumers
0043   (assessment harness, swf-remote face, standalone tools) apply the
0044   identical corrections without importing Django.
0045 - **Fast action.** A management page for rule entry: one row added at
0046   diagnosis time corrects every surface at the next page load.
0047 
0048 ## Rules — two kinds, two lifetimes
0049 
0050 - **Label-reliability rules** (durable): "this label is untrustworthy
0051   in this scope" — a fact about the producing extractor, standing
0052   until the extractor is fixed. Match on component × code × diagnostic
0053   substring, scoped by queue/site.
0054 - **Cause verdicts** (episode-scoped): what the unreliable label
0055   currently masks. Never cached against the signature alone — a
0056   signature can mask different causes in different months. Verdicts
0057   attach to episodes; the storm detector planned in
0058   [SNAPPER_ERRORS.md](SNAPPER_ERRORS.md) provides episode boundaries
0059   (start, escalation, end). Episode end retires the verdict into the
0060   knowledge base as history; a new flood of the same signature opens a
0061   new episode and earns a fresh verdict.
0062 
0063 ## Evidence ladder — witness grades
0064 
0065 Every corrected reading carries the grade of its evidence, best first:
0066 
0067 1. **Directed canary probe** — ground truth about a claimed site
0068    condition (site-canary increment 8): a passing container/storage
0069    probe refutes a claimed mount or storage failure.
0070 2. **Payload log** — the payload's own full record; fetched per
0071    representative job (Rucio + xrootd, cached per job); the
0072    calibration standard.
0073 3. **Payload self-report** — `jobReport.json` written by the payload
0074    on failure. It travels in the job's log tarball, and the epic pilot
0075    plugin lifts its exitCode/exitMsg into the stored
0076    `exeErrorCode`/`exeErrorDiag` job fields
0077    ([pilot3 PR #212](https://github.com/PanDAWMS/pilot3/pull/212),
0078    merged and deployed on the ePIC pilot 2026-08-25).
0079 4. **Pilot mechanical fields** — `transexitcode`, `pilottiming`,
0080    `cpuconsumptiontime`: measurements, population-wide, SQL-joinable,
0081    and self-cross-checking (a "launch" label on a job whose own timing
0082    shows hours of execution is refuted from within the pilot's
0083    report). Cross-field contradiction is an automatic label-unreliable
0084    trigger.
0085 5. **Pilot-extracted label** — the lowest grade; the input being
0086    corrected.
0087 
0088 The server's metatable stores pilot-shipped metadata for finished jobs
0089 only (`addMetadata` discards failed-job metadata by policy), so it is
0090 not a failure channel; the failed-job record path is the exeError
0091 fields via the pilot lift.
0092 
0093 ## Representative-job digs
0094 
0095 The dig unit is the pattern signature within an episode, never the
0096 job. A bounded sample (5–10 jobs, covering each exit-code mode
0097 present) is fetched and diagnosed through the existing payload-log
0098 machinery; the verdict is joined at read time by all jobs matching the
0099 signature, scope, and cheap-field profile. Jobs that fail the profile
0100 check present as unverified and count toward a re-dig. Long-lived
0101 episodes re-earn their verdict by trickle re-sampling (order one dig
0102 per day). Cost scales with the number of distinct failure modes, not
0103 with job count.
0104 
0105 ### Dig triggers
0106 
0107 Digs are never routine. A dig runs on three triggers only: a storm
0108 start from the error-stream detector (SNAPPER_ERRORS.md, storm
0109 detection), a platform alarm detection whose detail concentrates at a
0110 site — heartbeat staleness or yield at one site, or a node list from
0111 the node health map (SNAPPER_PLATFORM.md) — and an operator request
0112 from the job page. Each trigger opens one bounded dig: one
0113 representative job per distinct pattern signature in the episode, and
0114 for a lost-heartbeat episode one job per top silent node, chosen as
0115 the job whose silence began first there. For those jobs the dig
0116 reads every file at the site's published location (the NERSC portal
0117 directory holds, per PanDA id, the Slurm output and error files, the
0118 pilot log `pilotlog-task<N>.txt`, and the payload stdout and stderr),
0119 in that order: the batch system's own verdict first, the pilot's
0120 account second, the payload's last. The 2026-08-25 lost-heartbeat
0121 storm is the reference case: the pilot log showed a 229-minute hole
0122 and was read as a node-side I/O stall; the Slurm record, unread, said
0123 the node had run out of memory — 128 single-core pilots at 5.7 GB
0124 resident against a 476 GB node.
0125 
0126 Before a dig names any node-side cause, it computes the node budget
0127 from the job records: jobs per node (`modificationhost`) times their
0128 resident memory (`maxrss`) against the node's memory from the queue
0129 definition, and the equivalent for cores. A budget over the node is
0130 the finding; a stall, a hole in a log, or a missing heartbeat is the
0131 symptom.
0132 
0133 A dig's findings enter the action stream and the alarm event's detail,
0134 and the verdict attaches to the episode as above; a further dig in the
0135 same episode runs only on escalation or on the daily trickle.
0136 
0137 ## Population-wide channels
0138 
0139 - **Exit-code vocabulary.** The payload communicates its failure mode
0140   through coded exits, stored on every failed job as `transexitcode`.
0141   The hepmc3 campaign `run.sh` already codes 78 (Rucio registration
0142   failure) and 65 (validation failure); the vocabulary is completed so
0143   every distinct failure path has a documented code, kept in a
0144   registry in the production documentation.
0145 - **Failure report.** On failure the payload writes `jobReport.json`
0146   (`exitCode`, `exitMsg`; extra fields welcome). In the PCS path the
0147   in-job dispatcher shipped in every task sandbox writes it, wrapping
0148   the unmodified campaign `run.sh`; direct submissions add the same
0149   via a small insert in `run.sh` (helper + ERR trap + explicit calls
0150   at coded exits, since bash suppresses the ERR trap in `||`
0151   branches).
0152 
0153 ## Canary roles
0154 
0155 - **Consumer first**: the site-canary commissioning gate names failure
0156   attribution as a blocker — site health verdicts must not classify a
0157   site unhealthy on task-caused failures. Canary consumes corrected
0158   categories, never raw pilot labels; the duration and error-class
0159   recording the gate plans supplies the same cheap consistency fields
0160   the correction service uses.
0161 - **Witness at increment 8**: directed probes test claimed site
0162   conditions during an episode, entering the dossier at the top
0163   evidence grade.
0164 - **Transport later**: the rider collection ladder
0165   (heartbeat-attached packets, direct REST, staged files) is the
0166   designed channel for richer job-internal reporting beyond the
0167   final-update path.
0168 
0169 ## Implementation
0170 
0171 - **swf-monitor**: rules model + `error_corrections` module (pure
0172   application API with batch form, rules cached); clients wired at the
0173   readers — `error_summary`, `study_job`/`diagnose_jobs`, Snapper
0174   errors providers, system status, inventory; REST endpoints;
0175   management page; witness grade shown in every rendering.
0176 - **swf-epicprod**: dispatcher report writer for the PCS path; the
0177   exit-code registry; the `run.sh` insert for direct submissions.
0178 - **Upstream, parallel and non-blocking**:
0179   [pilot3 PR #212](https://github.com/PanDAWMS/pilot3/pull/212)
0180   (merged and deployed on the ePIC pilot 2026-08-25); optionally a
0181   server-side lift of the failed-job metadata discard.