#493 was not the last instance of the kv-Date hazard — it was the most
reachable. Audit of the rest of the learning pipeline found 11 more
unprotected kv-read sites where TypeScript declares `Date` but JSON
round-trip through `memory.get` yields an ISO string at runtime.
Two failure modes, both already documented at
learning-coordinator.ts:898-904 (#491 Bug 3):
1. THROW — `record.someDate.getTime()` raises TypeError. Surfaces
immediately on the first invocation once any record exists.
2. SILENT — `timeRange.contains(record.someDate)` or
`new Date() > record.expiresAt` coerces string vs Date to NaN; all
comparisons return false; records are silently filtered out or
expiry is never recognised. No error, just empty/stale analytics.
The silent variant is the worse one — #491 Bug 3 was the same class
and shipped for a release cycle undetected.
Strategic fix: a single `rehydrateDates<T>(record, dateFields[])` helper
at `src/shared/utils/kv-date-rehydrate.ts` applied at every kv-read seam
that touches Date-bearing types. Shallow-copies the record and coerces
named string fields back to Date; pass-through for already-Date, null,
undefined.
Sites patched (11 total):
src/domains/learning-optimization/services/
production-intel.ts — 4 sites (HIGH #2-#5 throw, MEDIUM #8 silent)
getMetricsHistory, getRecentIncidents (×2),
resolveIncident, getRecentMilestones
metrics-optimizer.ts — 1 site (HIGH #1 throw)
getMetricsHistory.sort
learning-coordinator.ts — 1 site (HIGH #6 throw)
getReplayBuffer.sort
transfer-specialist.ts — 4 sites (HIGH #7 throw, MEDIUM #9 silent)
queryKnowledge (×2), getKnowledgeById,
bulkTransfer
src/domains/learning-optimization/
coordinator-helpers.ts — 1 site (SILENT)
getExperiencesForDomain
coordinator.ts — 1 site (SILENT, duplicate of above)
getExperiencesForDomain (private)
Sites verified SAFE (kv-read but only access non-Date fields):
- coordinator.ts:1045/1134/1175 — uses .domain/.confidence/.version
- metrics-optimizer.ts:676 — uses .metrics map
- learning-coordinator.ts:379/438/483/547/830/842 — uses
.confidence/.successRate/.domain/.usageCount
- learning-coordinator.ts:901 — already has #491 Bug 3 inline
rehydration with instanceof guard
- experience-capture.ts:520/563 — TaskExperience uses number
timestamps, not Date
Sites NOT patched (deferred per scope):
- coordination/protocols/learning-consolidation.ts — defined but
never imported anywhere. Dead code; would resurrect the bug if
reactivated. Documented in the audit but not fixed.
Regression tests (29 new, 6 files):
tests/unit/shared/utils/kv-date-rehydrate.test.ts (10)
tests/unit/domains/learning-optimization/
production-intel-date-coercion.test.ts (5)
metrics-optimizer-date-coercion.test.ts (2)
learning-coordinator-date-coercion.test.ts (2)
transfer-specialist-date-coercion.test.ts (5)
coordinator-helpers-date-coercion.test.ts (2)
Each service test seeds its mock memory backend with kv-shape records
(ISO strings instead of Date instances — matching the post-JSON.parse
shape that better-sqlite3-backed memory yields in production) and
exercises the kv-read → consumer path that would fail pre-fix. Both
throw and silent failure modes are pinned: throws are asserted not to
fire, silent failures are caught by behavioural assertions (e.g. the
expired-knowledge test asserts `expired.score < live.score * 0.5 ±`,
which would fail pre-fix because the 0.5 penalty never triggered).
Verification:
- 29/29 new regression tests green
- 135/135 existing tests for patched services green (production-intel,
metrics-optimizer, transfer-specialist, learning-coordinator,
learning-consolidation, learning-consolidation-mining,
learning-consolidation-liveness)
- `tsc --noEmit` clean
- `npm run build` produces dist with rehydrateDates at all 17
expected call sites across the 6 patched files
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Commit 3 of 6 for ADR-093 Opus 4.7 migration. Adds effort-level plumbing
with xhigh as the fleet-wide default and max override on security agents.
* src/shared/llm/effort-resolver.ts (new): resolveEffortLevel() implements
the ADR-093 priority chain:
runtime override > per-agent frontmatter > QE_EFFORT_LEVEL env
> config/fleet-defaults.yaml > DEFAULT_EFFORT_LEVEL (xhigh)
Plus downgradeEffort() for models that don't support xhigh.
Minimal regex-based YAML parse avoids a new dependency.
* config/fleet-defaults.yaml (new): effort_level: xhigh.
* src/shared/llm/interfaces.ts: GenerateOptions gains optional
`effort?: 'low' | 'medium' | 'high' | 'xhigh' | 'max'`.
* src/shared/llm/providers/claude.ts: resolve effort per request and
include in /v1/messages body; silently downgrade to 'high' when the
target model lacks supportsEffortXHigh capability.
* .claude/agents/v3/qe-security-auditor.md,
qe-pentest-validator.md,
qe-security-scanner.md: add `effort: max` frontmatter per user
direction. Also corrects stale `advisor.model: claude-opus-4-6`
(non-existent ID) to `claude-opus-4-7` on the two agents that had it.
Note: fleet has 3 security/pentest qe-* agents (qe-security-auditor,
qe-security-scanner, qe-pentest-validator). The Cyber Verification
application lists 4 (including qe-security-reviewer which does not
exist in .claude/agents/v3/). If the submitted application needs an
amendment, re-file with the correct 3-agent list.
* tests/unit/shared/llm/effort-resolver.test.ts (new): 13 tests
covering the priority chain, invalid-input fallback, YAML read,
and downgrade helper.
Verification:
* 0 tsc errors (npx tsc --noEmit)
* 677/677 LLM unit tests pass (+13 new)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
125 test files had beforeEach/beforeAll but no afterEach/afterAll,
leaking state between tests and causing order-dependent failures.
Added cleanup to 104 files (skipped 4 archived, 16 import-only):
- 2 critical DB handle leaks (witness-chain): added db.close()
- 7 high-risk service files: added vi.restoreAllMocks()
- 7 beforeAll files: added matching afterAll
- 88 medium/low risk: added afterEach with appropriate cleanup
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Update default embed model from nomic-embed-text to all-MiniLM-L6-v2
in Ollama LLM provider
- Fix 15 test files with hardcoded 768-dim references
- Update mock model names in Ollama health checks
- Update comments referencing old model name
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>