feat(observer): recommended-node resolver for direct episodes
Mirrors missed-activations dormancy logic (id === false strict). First live recommended node from classification-map, else null. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Brain Status (auto-generated)
|
||||
|
||||
Last updated: 2026-05-23T10:16:44.994Z
|
||||
Last updated: 2026-05-23T10:20:01.355Z
|
||||
|
||||
| Контролёр | Состояние | Детали |
|
||||
|---|---|---|
|
||||
@@ -8,12 +8,12 @@ Last updated: 2026-05-23T10:16:44.994Z
|
||||
| C2 Cross-ref consistency | ✅ | [cross-ref-checker] OK — 0 drift in 4 files |
|
||||
| C3 Observer-of-observer | ✅ | [observer-of-observer] OK — last read 0 week(s) ago |
|
||||
| C4 Сигнальный статус | ✅ | This file (self-reference) |
|
||||
| C5 Observer-coverage | ⚠️ | 143 episode(s) this month · Stop-hook + post-commit OK · 21 missed activation(s) — see /brain-retro |
|
||||
| C5 Observer-coverage | ⚠️ | 144 episode(s) this month · Stop-hook + post-commit OK · 21 missed activation(s) — see /brain-retro |
|
||||
| C6 Chain map sync | ✅ | [chain-map-checker] OK — 16 chains in sync |
|
||||
|
||||
## Метрики (информационные, не алерты)
|
||||
|
||||
- Observer evidence: 143 episodes this month, 0 observer_error markers, 64 PII matches before filter
|
||||
- Observer evidence: 144 episodes this month, 0 observer_error markers, 67 PII matches before filter
|
||||
- Legacy v1 episodes (not in factor analysis): 5
|
||||
- Last /brain-retro: 0 day(s) ago
|
||||
- Использование узлов: см. `/brain-retro` (раз в спринт). missed_activations: 21. **Неиспользованные узлы — не алерт, если профильной задачи не было** (Pravila §16.4 v1.36; capability-readiness; см. memory `feedback_brain_unused_tools_not_problem` — outside-repo memory store).
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Recommended-node resolver for direct episodes.
|
||||
* Pure — read-only, no exec, no fs (Security Guidance #40).
|
||||
*
|
||||
* For an episode classified as `taskClassification` with node_chosen='direct',
|
||||
* return the first live (non-dormant) recommended node ID from the
|
||||
* classification map. Mirrors missed-activations.mjs dormancy logic:
|
||||
* dormancy[id] === false strictly (missing/true → not live).
|
||||
*
|
||||
* Per spec: docs/superpowers/specs/2026-05-23-observer-parser-skill-hook-expand-design.md
|
||||
*/
|
||||
|
||||
export function recommendNode(taskClassification, classificationMap, dormancy) {
|
||||
if (!taskClassification || !classificationMap || !dormancy) return null;
|
||||
const recommended = classificationMap[taskClassification];
|
||||
if (!Array.isArray(recommended) || recommended.length === 0) return null;
|
||||
for (const id of recommended) {
|
||||
if (dormancy[id] === false) return id;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { recommendNode } from './observer-recommended-node.mjs';
|
||||
|
||||
const MAP = {
|
||||
feature: ['#19'],
|
||||
refactor: ['#11', '#12', '#43'],
|
||||
question: [],
|
||||
other: [],
|
||||
};
|
||||
|
||||
describe('recommendNode', () => {
|
||||
it('returns first live node ID for a known classification', () => {
|
||||
expect(recommendNode('feature', MAP, { '#19': false })).toBe('#19');
|
||||
});
|
||||
|
||||
it('skips dormant first node, returns next live', () => {
|
||||
expect(recommendNode('refactor', MAP, { '#11': true, '#12': false, '#43': false })).toBe('#12');
|
||||
});
|
||||
|
||||
it('returns null when all recommended nodes are dormant', () => {
|
||||
expect(recommendNode('refactor', MAP, { '#11': true, '#12': true, '#43': true })).toBeNull();
|
||||
});
|
||||
|
||||
it('returns null for classification absent from map', () => {
|
||||
expect(recommendNode('nonexistent', MAP, {})).toBeNull();
|
||||
});
|
||||
|
||||
it('returns null for empty-array classification (question/memory-sync)', () => {
|
||||
expect(recommendNode('question', MAP, {})).toBeNull();
|
||||
expect(recommendNode('other', MAP, {})).toBeNull();
|
||||
});
|
||||
|
||||
it('treats missing dormancy entry as live (defensive, parity with missed-activations)', () => {
|
||||
// missed-activations uses dormancy[id] === false; recommendNode mirrors:
|
||||
// unknown/missing → not live (paranoid — only positive false counts as live).
|
||||
expect(recommendNode('feature', MAP, {})).toBeNull();
|
||||
});
|
||||
|
||||
it('handles null/undefined inputs without throwing', () => {
|
||||
expect(recommendNode(null, MAP, {})).toBeNull();
|
||||
expect(recommendNode('feature', null, {})).toBeNull();
|
||||
expect(recommendNode('feature', MAP, null)).toBeNull();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user