v3/@claude-flow/guidance/docs/adrs/ADR-G026-review-remediation.md
Accepted
2026-02-02
A comprehensive code review of the @claude-flow/guidance package identified several critical, high, and medium severity issues that required remediation before the package could be considered production-ready.
createProofChain() called without signing key (ruvbot-integration.ts:858). The RuvBotBridge.handleSessionCreate() method called createProofChain() without providing an HMAC signing key. The ProofChain constructor throws if no key is supplied, meaning any session with enableProofChain: true would crash at runtime.
createProofChain factory type mismatch (proof.ts). The factory accepted config?: { signingKey?: string }, allowing callers to omit the key entirely. The inner ProofChain constructor then throws, making the optional typing misleading and unsafe.
Hardcoded fallback signing key (conformance-kit.ts:700). The ConformanceRunner constructor fell back to 'default-signing-key' when no key was provided, silently using a well-known value in what could be a production path.
Duplicated timingSafeEqual. Two independent implementations of constant-time string comparison existed in proof.ts and authority.ts. Both used manual byte-level XOR rather than Node.js's native crypto.timingSafeEqual, and neither was a faithful constant-time implementation (early return on length mismatch leaked length information).
Unbounded event growth in RunLedger. The ledger's in-memory events array had no upper bound, leading to unbounded memory growth in long-running sessions.
O(n) shift() eviction in ThreatDetector.addSignal() and CollusionDetector.recordInteraction(). Both used Array.shift() for single-element eviction on every insertion once at capacity. In V8, shift() is O(n) because it reindexes all remaining elements.
HashEmbeddingProvider undocumented as test-only. The hash-based embedding provider has no semantic meaning but lacked a clear warning against production use.
simulateChangeEffect in optimizer presented as A/B testing. The method applies fixed multipliers, not real traffic measurement, but the surrounding code and ADR language implied real experimentation.
Uncached regex compilation in matchGlob. ShardRetriever.matchGlob() compiled a new RegExp on every call for the same glob pattern.
signingKey in createProofChain factoryChanged the factory signature from optional to required:
export function createProofChain(config: { signingKey: string }): ProofChain {
return new ProofChain(config.signingKey);
}
This makes the type system enforce what the runtime already enforced, catching missing keys at compile time.
proofSigningKey to RuvBotBridgeConfigAdded a proofSigningKey?: string field to the bridge configuration. When enableProofChain is true, the bridge now validates that the key is present before calling createProofChain(), throwing a clear error message instead of an opaque constructor crash.
ConformanceRunnerThe constructor now throws if no signingKey is provided. The createConformanceRunner() factory function provides a default test key ('conformance-test-key') for convenience in test code, making it explicit that the default is for testing only.
timingSafeEqual to crypto-utils.tsCreated src/crypto-utils.ts with a single implementation that delegates to Node.js native crypto.timingSafeEqual via Buffer. Both proof.ts and authority.ts now import from this shared module. The native implementation is truly constant-time at the CPU level.
RunLedgerAdded a maxEvents constructor parameter (default 0 = unlimited). When the limit is exceeded, the oldest 10% of events are removed in a single splice() call. This amortizes the O(n) cost across multiple insertions instead of paying it on every insert.
Both logEvent() and finalizeEvent() call the private evictIfNeeded() method. The createLedger() factory now accepts the maxEvents parameter.
ThreatDetector and CollusionDetectorReplaced single-element shift() calls with batch splice():
ThreatDetector.addSignal(): trims 10% of maxSignals when over capacityCollusionDetector.recordInteraction(): trims 1,000 interactions (10% of the 10,000 limit) when over capacityHashEmbeddingProvider as test-onlyAdded a JSDoc block explicitly stating the provider has no semantic meaning and must not be used in production.
simulateChangeEffect as heuristicReplaced the JSDoc with a clear statement that the method applies conservative fixed multipliers, not real A/B test measurements.
matchGlobAdded a Map<string, RegExp> cache to ShardRetriever so that each glob pattern is compiled once and reused on subsequent calls.
timingSafeEqual. One implementation using the native Node.js API, no manual byte comparison.createProofChain. Callers that relied on the optional signature must now pass { signingKey }. Existing tests were updated.ConformanceRunner constructor. Direct callers must now provide a signing key. The factory function mitigates this for test code.src/crypto-utils.ts -- Shared timing-safe comparisonsrc/proof.ts -- ProofChain, createProofChain factorysrc/authority.ts -- MemoryAuthority (imports crypto-utils)src/ruvbot-integration.ts -- RuvBotBridge, RuvBotBridgeConfigsrc/conformance-kit.ts -- ConformanceRunner, createConformanceRunnersrc/ledger.ts -- RunLedger, evictIfNeeded, createLedgersrc/adversarial.ts -- ThreatDetector.addSignal, CollusionDetector.recordInteractionsrc/optimizer.ts -- simulateChangeEffect documentationsrc/retriever.ts -- HashEmbeddingProvider documentation, matchGlob cache