Skip to content

Deterministic self-healing drift: remove the LLM from remediation#335

Merged
jpr5 merged 7 commits into
mainfrom
drift-rearch-clean
Jul 23, 2026
Merged

Deterministic self-healing drift: remove the LLM from remediation#335
jpr5 merged 7 commits into
mainfrom
drift-rearch-clean

Conversation

@jpr5

@jpr5 jpr5 commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Deterministic self-healing drift — remove the LLM from remediation

The drift auto-remediation subsystem broke ~8 times because it let an LLM freewrite edits to the detector's own fixtures and then tried to police that with a 916-line anti-cheat predicate — an unwinnable loop. This replaces that whole loop with robustness-by-construction: most drift now self-heals with no fix at all, mechanical model-family churn is synced deterministically, and the human surface shrinks to exactly two real decisions (mock a brand-new family or not; follow a genuine protocol redesign or not).

What changed

  • The LLM is gone. scripts/fix-drift.ts (the freewriter) and scripts/drift-success-predicate.ts (the 916-line predicate) are deleted, along with their now-orphaned tests.
  • Deterministic remediation. A daily cron fetches live /models and either:
    • ok-applied — mechanically edits model-registry.ts (via the TypeScript compiler API, not text munging) to drop a deprecated family → opens a PR.
    • needs-human — a brand-new/unclassified family, a still-referenced deprecation, or a registry structural mismatch → writes a drift-proposals/ note and opens a PR where a human sets Decision: include; the next run applies it.
    • Both PR paths are gated by scripts/drift-sync-check.ts (changed-file allowlist + classification checksum-pin re-assert + clean re-collect, all fail-closed) and are idempotent across daily re-fires (deduped on a stable content-hash changeset key). No auto-merge — humans merge.
  • Fixes the recurring failure at the root. The collector now isolates per-leg failures, so one bad live leg can no longer quarantine the batch and poison every PR's base drift report.
  • Self-healing live legs. 6 legs (anthropic, openai-chat, openai-responses, bedrock, ws-responses, ws-gemini-live) discover a live model and honest-skip on infra/deprecation instead of hard-failing, via shared resolveLiveModel/isInfraSkip helpers.
  • Frozen classification rules are checksum-pinned so a silencing edit trips a loud test failure.

Review

Built as 14 parallel slots, then a Tier-3 review that found and fixed 8 mandatory defects — each with a local red-green proof, each re-reviewed to zero on the fixed state. Notably: the sync core's recollect gate was silently breaking the new-family human-routing path (and a fake test was hiding it), and the workflow didn't persist the needs-human note (so the human-decision path was unreachable). Both would have shipped green otherwise.

Test evidence

tsc --noEmit 0 errors · full suite 4766 passed / 0 failed · build ok · classification pin 14/14 · workflow tests 37/37.

Fast-follow (non-blocking, not in this PR)

3 now-inert helper functions to delete, a couple of dead workflow permissions, excludeFamilies data not yet pinned, the byte-mirror not equivalence-tested, claude-fable-5 re-proposed each run, and a pre-existing Bedrock $metadata shape gap (only surfaces under real AWS creds).

🤖 Generated with Claude Code

https://claude.ai/code/session_01KamK73Wu5heLxJEogM6hHC

jpr5 added 6 commits July 22, 2026 23:34
…tion to deterministic sync

The fix-drift LLM-in-the-loop remediation path (scripts/fix-drift.ts) and its
anti-cheat success predicate are removed. Remediation for drift now runs
through the deterministic model-family sync (drift-sync.ts /
drift-sync-check.ts introduced in the prior commit): known model-family
changes are applied programmatically, anything outside that scope is flagged
with a needs-human note, and a human still reviews and merges. The
fix-drift workflow, Slack summary, and shared drift-types are updated to
call the new sync path instead of invoking an LLM to freewrite a fix.
@pkg-pr-new

pkg-pr-new Bot commented Jul 23, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@copilotkit/aimock@335

commit: 07b1035

…re cases

The `drift-live-pr` CI check quarantined the whole batch as an unparseable
exit-5 failure:

    expected 'claude-haiku-4-5-20251001' to be 'claude-haiku-5-1-20260201'

Root cause is cross-block pollution of `resolveLiveModel`'s per-key memo, not
a model-pin mismatch. Both sides of the live-leg 3-way comparison already use
the same dynamically-resolved id. But when ANTHROPIC_API_KEY is armed (CI),
the live `describe.skipIf` block runs FIRST, resolves the real still-live id,
and memoizes it under the shared "anthropic" key — with no afterEach reset,
exactly like the real live block. The fixture self-healing block reset the
memo only in afterEach, so its FIRST case inherited the leaked live id instead
of resolving against its own stub, then asserted a raw `.toBe()` on model ids.
That AssertionError is not a structured drift report, so the collector could
not parse it (exit 5, fatal quarantine) rather than a non-fatal exit-2 report.

Fix: reset the memo in `beforeEach` of the fixture block so each case resolves
against its own stub regardless of what the live block left cached. Add a
seeding regression guard that simulates the armed-key live block populating the
memo first (no credentials needed), reproducing the CI ordering deterministically.

Siblings audited: ws-gemini-live isolates via a distinct cache key
(gemini-live-text-unittest); openai-responses/ws-responses have no fixture
block reading the memo after their live block; openai-chat has no such
assertion. anthropic was the only leg sharing one memo key across both blocks.

Local red-green (fixture-driven; live keys unavailable locally, so the true
confirmation is the re-run drift-live-pr CI):
  RED  (before fix): REGRESSION case fails with the verbatim CI assertion.
  GREEN (after fix): all 11 runnable anthropic cases pass (6 live-key skipped).
Full gate: tsc 0, eslint/prettier clean, unit 4722 passed (logic-pin 14,
fix-drift-workflow 37), drift 118 passed, tsdown build OK.
@jpr5
jpr5 merged commit 2203982 into main Jul 23, 2026
29 checks passed
@jpr5
jpr5 deleted the drift-rearch-clean branch July 23, 2026 06:55
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