fix(models): make tier-change listener registration non-destructive
This commit is contained in:
@@ -14,6 +14,7 @@ Scope: Production-risk-first audit of bugs, code improvements, and feature oppor
|
|||||||
- ✅ F-012 addressed: synthetic repeated-tool nudge no longer emits invalid `tool_result.tool_use_id`; nudge is injected as plain user text guidance.
|
- ✅ F-012 addressed: synthetic repeated-tool nudge no longer emits invalid `tool_result.tool_use_id`; nudge is injected as plain user text guidance.
|
||||||
- ✅ F-009 addressed: gateway now enforces per-connection WebSocket ingress rate limits with deterministic throttle errors and close-on-repeated-violation behavior.
|
- ✅ F-009 addressed: gateway now enforces per-connection WebSocket ingress rate limits with deterministic throttle errors and close-on-repeated-violation behavior.
|
||||||
- ✅ F-008 addressed: WhatsApp Chromium launch is now sandboxed by default; no-sandbox mode is behind explicit `whatsapp.no_sandbox: true` opt-in.
|
- ✅ F-008 addressed: WhatsApp Chromium launch is now sandboxed by default; no-sandbox mode is behind explicit `whatsapp.no_sandbox: true` opt-in.
|
||||||
|
- ✅ F-014 addressed: `ModelRouter.setOnTierChange` now preserves existing listeners instead of replacing them, removing destructive listener-setter behavior.
|
||||||
|
|
||||||
## Executive Summary
|
## Executive Summary
|
||||||
|
|
||||||
|
|||||||
@@ -2512,6 +2512,18 @@
|
|||||||
"docs/plans/analysis/2026-02-16-codebase-audit-report.md"
|
"docs/plans/analysis/2026-02-16-codebase-audit-report.md"
|
||||||
],
|
],
|
||||||
"test_status": "pnpm test:run src/channels/whatsapp/adapter.test.ts src/config/schema.test.ts + pnpm typecheck passing"
|
"test_status": "pnpm test:run src/channels/whatsapp/adapter.test.ts src/config/schema.test.ts + pnpm typecheck passing"
|
||||||
|
},
|
||||||
|
"audit-followup-modelrouter-listeners": {
|
||||||
|
"status": "completed",
|
||||||
|
"date": "2026-02-16",
|
||||||
|
"updated": "2026-02-16",
|
||||||
|
"summary": "Removed ModelRouter tier-change listener setter footgun: setOnTierChange now appends instead of replacing existing listeners, with regression test coverage.",
|
||||||
|
"files_modified": [
|
||||||
|
"src/models/router.ts",
|
||||||
|
"src/models/router.test.ts",
|
||||||
|
"docs/plans/analysis/2026-02-16-codebase-audit-report.md"
|
||||||
|
],
|
||||||
|
"test_status": "pnpm test:run src/models/router.test.ts + pnpm typecheck passing"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"overall_progress": {
|
"overall_progress": {
|
||||||
|
|||||||
@@ -463,4 +463,22 @@ describe('setClient and labels', () => {
|
|||||||
expect(fallback.chat).not.toHaveBeenCalled();
|
expect(fallback.chat).not.toHaveBeenCalled();
|
||||||
expect(router.isTierStrict('default')).toBe(true);
|
expect(router.isTierStrict('default')).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('setOnTierChange does not replace existing listeners', () => {
|
||||||
|
const router = new ModelRouter({
|
||||||
|
default: { chat: vi.fn() } as unknown as ModelClient,
|
||||||
|
fast: { chat: vi.fn() } as unknown as ModelClient,
|
||||||
|
fallbackChain: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
const first = vi.fn();
|
||||||
|
const second = vi.fn();
|
||||||
|
router.addOnTierChange(first);
|
||||||
|
router.setOnTierChange(second);
|
||||||
|
|
||||||
|
router.setTier('fast');
|
||||||
|
|
||||||
|
expect(first).toHaveBeenCalledWith('fast');
|
||||||
|
expect(second).toHaveBeenCalledWith('fast');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ export class ModelRouter implements ModelClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setOnTierChange(callback: (tier: ModelTier) => void): void {
|
setOnTierChange(callback: (tier: ModelTier) => void): void {
|
||||||
this.tierChangeListeners = [callback];
|
this.addOnTierChange(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
addOnTierChange(callback: (tier: ModelTier) => void): void {
|
addOnTierChange(callback: (tier: ModelTier) => void): void {
|
||||||
|
|||||||
Reference in New Issue
Block a user