Skip to content

Attribute mid-stream repetition aborts to model and detector (CL-6775) - #580

Merged
TheGreatAxios merged 1 commit into
mainfrom
cl-6775-track-mid-stream-degenerate-repetition-aborts-per-model-and
Aug 23, 2026
Merged

Attribute mid-stream repetition aborts to model and detector (CL-6775)#580
TheGreatAxios merged 1 commit into
mainfrom
cl-6775-track-mid-stream-degenerate-repetition-aborts-per-model-and

Conversation

@TheGreatAxios

Copy link
Copy Markdown
Collaborator

Closes CL-6775.

What's recorded

src/subagent/repetition.ts aborts a run for one of three reasons: a raw-text periodicity hit, a digit-folded thinking-stream hit, or the contentless/zero-width growth guard. Until now every abort landed in the intervention log (CL-6938) under one generic id: "repetition", and the contentless-growth path logged no measurement at all.

This PR keeps writing into the existing interventions.jsonl sink and:

  • Folds the detector into the id instead of adding a new field: repetition-raw-text-periodicity, repetition-digit-folded-thinking, repetition-contentless-growth. Model, provider, and family are already carried on every record by the log's per-run context (CL-6938), so this alone gives per-model, per-detector attribution.
  • Records a measurement for every abort: { metric: "repeats", value, threshold } for the two periodicity detectors, { metric: "visibleChars", value, threshold } for the contentless guard (previously missing).
  • Keeps detail (both in the log and the parent-facing "Stopped:" line) content-free: repetitionStopDetail now reports period <n>ch × <repeats> (threshold <t>) instead of a slice of the looped text, and the new contentlessGrowthDetail reports raw/visible char counts instead of stream content. The looped-window sample the parent needs to judge the abort still travels separately via partial (the Findings section of the salvage report), capped as before — that path is unchanged.

Reuse vs. new file

Reused src/subagent/intervention-log.ts rather than adding a new logging mechanism. The record shape (InterventionRecord) didn't need to change at all — model/provider/family/measurement/state were already there from CL-6938 for stop events; the only gap was that the repetition abort site collapsed three distinct detectors into one id and dropped the measurement for one of them. A distinct id per detector was enough to get separable per-model, per-detector rows without touching the type or the sink.

Reading the rate back

scripts/intervention-forensics.ts already aggregates by class/id and breaks each down byFamily; this PR adds:

  • byModel on top of byFamily (family groups every grok variant together; model doesn't).
  • A "repetition aborts by model" section that sums all three repetition-* ids per model — reads directly as "which model loops most".
  • A "repetition aborts by model, per detector" section for splitting that further.

This surfaces counts, not a dispatch-normalized rate: the log's outcome records (total completed dispatches, CL-6938) are written from the parent side without a model tag, so a per-model denominator isn't tracked yet. Counts by model already answer the issue's stated question ("which model loops most this week"); wiring a true per-model rate would mean tagging outcome records with model, which is a separate, larger change to the parent-side dispatch path and is left as a follow-up if the raw counts turn out to be insufficient.

Thresholds

No threshold value changed. DEFAULT_REPETITION_CONFIG, DEFAULT_TEXT_FOLDED_REPETITION_CONFIG, DEFAULT_THINKING_REPETITION_CONFIG, and DEFAULT_CONTENTLESS_GROWTH_CONFIG are read to report the threshold that was crossed, never written.

Gate

bun run check (lint, typecheck, build, full test suite) is green: 5345 tests pass, 0 lint errors (pre-existing warnings only, unrelated to this change).

Repetition aborts in the intervention log (CL-6938) were all filed under
one generic "repetition" id with no way to tell which of the three
detectors fired or see the measured value against its threshold. Fold
the detector name into the intervention id (repetition-raw-text-periodicity,
repetition-digit-folded-thinking, repetition-contentless-growth) and
record the measured value with its threshold for each. The contentless
growth guard previously logged no measurement at all.

scripts/intervention-forensics.ts already buckets by class/id and splits
by family; add a per-model breakdown (family groups multiple models
together) and a dedicated repetition-aborts-by-model summary so "which
model loops most" reads directly off the report.

No stream content is logged: repetitionStopDetail now reports period
length and repeat count instead of the looped window text. No threshold
values changed.
@linear-code

linear-code Bot commented Aug 23, 2026

Copy link
Copy Markdown

CL-6775

@TheGreatAxios
TheGreatAxios merged commit ed18557 into main Aug 23, 2026
5 checks passed
TheGreatAxios added a commit that referenced this pull request Aug 27, 2026
…nerate-repetition-aborts-per-model-and

Attribute mid-stream repetition aborts to model and detector (CL-6775)
TheGreatAxios added a commit that referenced this pull request Aug 27, 2026
…nerate-repetition-aborts-per-model-and

Attribute mid-stream repetition aborts to model and detector (CL-6775)
@TheGreatAxios
TheGreatAxios deleted the cl-6775-track-mid-stream-degenerate-repetition-aborts-per-model-and branch August 27, 2026 23:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant