Repository navigation
Description
describe-batch.mjs has no way to give up on a domain that is failing systematically. A bad describeCommand, a wrong idField, or an expired token makes every describe in the domain fail — and the loop works through the entire asset list anyway. On a large domain that is well over a thousand pointless CLI spawns before anything reports a problem.
There is already a stop rule, and it doesn't cover this
skills/setup/SKILL.md:529:
Stop rule for persistent failures: if a re-invocation documents 0 assets and its
failureslist names the same NON-EMPTY set of keys as the run before it, stop re-invoking — those failures are deterministic; report the failed keys with their recorded errors instead of looping. A run that documents 0 with an EMPTYfailureslist andbudgetExhausted: true… is progress — so re-invoke.
That rule is correct, but it operates between invocations and it is prose the model executes — it requires holding two consecutive run summaries and diffing them. It protects against re-invoking a doomed domain forever. It cannot stop a single long run that is already doomed, because it can only fire once that run has ended.
The case it misses is the common one: a token that dies mid-run. The CLI's token stops working at roughly half its printed lifetime (skills/setup/SKILL.md Phase 1 token pre-flight), so on a long domain this is routine rather than exceptional. Every describe after that moment fails identically, and the run keeps spawning.
The change
Abort the current domain after 5 consecutive retryable failures, and say so in the summary.
The existing failure taxonomy already decides what counts:
- Retryable failures (timeout, transport, unexpected output — the classes
describe-batch.mjsalready marksfailed) count toward the limit. A success resets the counter to zero. - PERMANENT gaps — a field the CLI refuses under every spelling — do not count. They are recorded on the item, never retried, and explicitly non-blocking; the entry is still marked documented.
- Budget exhaustion is not a failure. It is progress, and the existing rule already says so.
Five is chosen to be high enough that a handful of genuinely broken assets in an otherwise healthy domain doesn't abort the run, and low enough that a systemic failure costs seconds instead of tens of minutes.
On abort: stop the domain loop, leave everything already marked exactly as it is (the per-asset durability guarantee is unchanged), and report the abort distinctly in the run summary so the caller can tell it apart from normal completion. Nothing about resumption changes — the next invocation picks up where it stopped, as it does after budget exhaustion.
Where
plugins/gs-superadmin/scripts/describe-batch.mjs— the per-asset loop and the summary it emits.plugins/gs-superadmin/skills/setup/SKILL.md— the stop-rule paragraph should note that the script now enforces a within-run limit, so the model-side rule is about re-invocation only.
Testing
A fixture where every describe fails should abort after exactly 5 attempts rather than walking the full asset list, and the summary should name the abort. A fixture with 4 failures followed by a success should run to completion — that's the boundary worth pinning, since an off-by-one here either aborts healthy runs or never fires.
Worth confirming that an aborted run and a budget-exhausted run remain distinguishable in the summary, since the skill's existing logic branches on exactly that difference.
Activity
bus: Issues hint — add #13, compact the round's issue list [skip ci]
BradleyDB commentedon Sep 11, 2026
A measured incident supporting this, from a live production deep ingest.
A batch was sized from a 25-asset sample rate and ran past the token deadline. 17 consecutive describes failed with
Token expired and silent refresh failed, and the loop kept spawning through every one of them. All 17 were markedfailedin the manifest; all 17 described fine on retry.That is exactly the shape this issue proposes to stop. With "abort after 5 consecutive retryable failures" the run would have ended after 5 instead of 17, and the 12 assets never attempted would have kept their prior status rather than acquiring a wrong one.
It also validates the choice to count consecutive rather than total failures. These were strictly consecutive from the moment the token died, which is the signature of a systemic cause — a handful of genuinely broken assets scattered through a domain would not have produced a run of 17, and would not have tripped the limit.
Worth noting the two problems are related: a run that aborts early also writes fewer wrong
failedmarks, so this change shrinks the blast radius of a deadline death even without addressing how such a death is recorded.BradleyDB commentedon Sep 15, 2026
Fixed on
devby #19 (merge d23f890, 2026-09-14) as part of plugin 0.39.0, which is staged on dev and reachesmainat the next release. Verified live by the tester round @ hb-20260914-01 (dev/FEEDBACK.md on dev): a mismatched describe over a 19-entry domain stopped after exactly 5 spawns with aborted.reason consecutive-failures and the remaining entries untouched; a token death past the half-life aborted on first sighting with nothing marked (F-458, same change). The limit is a constant of 5; the summary field aborted { reason, after, lastError } is additive.bus: Session B round closed out — PR #19 merged (d23f890), F-456/F-45…
describe loop and its fences: within-run abort, actionKey read gate, …
bus: Issues hint — #28 closed by #31 (7a75662, plugin 0.43.1); #10 and …