kenaz 0.3.10 → 0.3.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/.claude/skills/code_reviewer/SKILL.md +0 -1
- package/core/.claude/skills/code_reviewer/patterns.yaml +0 -8
- package/core/.claude/skills/dev_agent/SKILL.md +3 -6
- package/core/.claude/skills/heimdall/SKILL.md +5 -6
- package/core/.claude/skills/huginn/SKILL.md +11 -38
- package/core/.collaboration/core/task-2288-followups.test.js +2 -37
- package/core/.collaboration/core/task-2421-replica.test.js +229 -0
- package/core/.collaboration/core/task-api.js +223 -230
- package/core/.collaboration/core/task-api.test.js +1 -138
- package/core/.collaboration/core/task-replica.js +189 -0
- package/core/.formation/.merge-lock +1 -0
- package/core/.formation/bifrost/codex-doctor.js +12 -2
- package/core/.formation/bifrost/codex-doctor.test.js +15 -0
- package/core/.formation/bifrost/launch.js +2 -2
- package/core/.formation/bifrost/launch.test.js +2 -2
- package/core/.formation/bifrost/setup-codex.js +84 -16
- package/core/.formation/bifrost/shared/ansuz-boot-policy.js +3 -3
- package/core/.formation/bifrost/shared/codex-injection.js +3 -17
- package/core/.formation/bifrost/shared/consolidate.js +1 -51
- package/core/.formation/bifrost/sync.js +4 -5
- package/core/.formation/tools/__tests__/subagent-bifrost-guard.test.js +1 -1
- package/core/.formation/tools/dispatch.js +2 -2
- package/core/.formation/tools/kenaz-stats.js +1 -1
- package/core/.formation/tools/mcp-allowlist.test.js +5 -3
- package/core/.formation/tools/post-complete/bounded-http.js +1 -40
- package/core/.formation/tools/post-complete/bounded-http.test.js +2 -89
- package/core/.formation/tools/post-complete/cognitive.js +2 -119
- package/core/.formation/tools/post-complete/task2420.test.js +129 -0
- package/core/.formation/tools/post-complete/testing.js +3 -21
- package/core/.formation/tools/post-complete.js +131 -436
- package/core/.formation/tools/post-complete.test.js +0 -135
- package/core/.formation/tools/route-audit.test.js +8 -20
- package/core/.kenaz/specialist/memory_guard_fired.json +1 -1
- package/core/.kenaz/specialist/memory_guard_trigger_cache.json +1 -1
- package/core/.rule/INDEX.yaml +3 -3
- package/core/.rule/general/ddx-synapse-stack.yaml +11 -11
- package/core/.rule/general/specialist-identity-contract.yaml +5 -5
- package/core/.rule/general/synapse-code-intelligence.yaml +25 -111
- package/core/.rule/general/worktree-isolation.yaml +2 -2
- package/core/.rule/pipeline/task-execution.yaml +6 -9
- package/core/.specialist/Amelia/README.md +5 -5
- package/core/.specialist/Amelia/capability.yaml +10 -18
- package/core/.specialist/Amelia/knowledge.yaml +15 -66
- package/core/.specialist/Amelia/workflow.yaml +12 -21
- package/core/.specialist/Ansuz/capability.yaml +12 -87
- package/core/.specialist/Ansuz/concepts/autonomous_agenda.yaml +1 -1
- package/core/.specialist/Ansuz/concepts/autonomy_contract.yaml +2 -3
- package/core/.specialist/Ansuz/concepts/capability_pointers.yaml +1 -3
- package/core/.specialist/Ansuz/concepts/cognitive_fluency_contract.yaml +8 -21
- package/core/.specialist/Ansuz/concepts/cognitive_systems_overview.yaml +0 -4
- package/core/.specialist/Ansuz/concepts/cognitive_systems_turn_context.yaml +1 -1
- package/core/.specialist/Ansuz/concepts/completion_tracking.yaml +0 -1
- package/core/.specialist/Ansuz/concepts/deep_knowledge_pointers.yaml +0 -3
- package/core/.specialist/Ansuz/concepts/evolvable_guardrails.yaml +3 -3
- package/core/.specialist/Ansuz/concepts/fatigue_handoff.yaml +1 -7
- package/core/.specialist/Ansuz/concepts/guardrails_immutable.yaml +3 -4
- package/core/.specialist/Ansuz/concepts/identity.yaml +1 -2
- package/core/.specialist/Ansuz/concepts/phase9_verification.yaml +0 -1
- package/core/.specialist/Ansuz/concepts/phase_protocol.yaml +3 -4
- package/core/.specialist/Ansuz/core.yaml +3 -6
- package/core/.specialist/Ansuz/elixir.yaml +6 -6
- package/core/.specialist/Ansuz/exo_cortex_tools.yaml +5 -9
- package/core/.specialist/Ansuz/guards/blind_spot_guards.yaml +2 -2
- package/core/.specialist/Ansuz/guards/lesson_guards.yaml +6 -19
- package/core/.specialist/Ansuz/identity_contract.yaml +4 -4
- package/core/.specialist/Ansuz/knowledge.yaml +13 -40
- package/core/.specialist/Ansuz/modules/ddx.yaml +2 -2
- package/core/.specialist/Ansuz/modules/prophecy.yaml +19 -19
- package/core/.specialist/Ansuz/modules/pulse_empty.yaml +6 -17
- package/core/.specialist/Ansuz/tools/ansuz-handoff-snapshot.js +3 -102
- package/core/.specialist/Ansuz/tools/ansuz-sdk-runner.js +2 -44
- package/core/.specialist/Ansuz/workflow.yaml +32 -76
- package/core/.specialist/Forseti/core.yaml +2 -7
- package/core/.specialist/Forseti/rule.yaml +1 -1
- package/core/.specialist/Heimdall/SKILL.md +2 -3
- package/core/.specialist/Heimdall/capability.yaml +22 -45
- package/core/.specialist/Heimdall/core.yaml +24 -126
- package/core/.specialist/Heimdall/principles.yaml +8 -11
- package/core/.specialist/Heimdall/rule.yaml +2 -2
- package/core/.specialist/Huginn/capability.yaml +31 -52
- package/core/.specialist/Huginn/core.yaml +43 -123
- package/core/.specialist/Huginn/principles.yaml +5 -5
- package/core/.specialist/Huginn/rule.yaml +3 -9
- package/core/.specialist/REFLECTION_TO_CONTROL.md +3 -4
- package/core/.specialist/shared/guard_schema.json +1 -1
- package/core/.specialist/shared/principles.yaml +6 -6
- package/core/.specialist/tools/__tests__/rea-detect.test.js +10 -0
- package/core/.specialist/tools/phase-gate.js +10 -230
- package/core/.specialist/tools/phase-gate.test.js +2 -2
- package/core/.specialist/tools/prompt-files.test.js +1 -1
- package/core/.specialist/tools/rea-detect.js +6 -2
- package/core/.specialist/tools/session.js +2 -89
- package/core/.synapse/memory-shared.json.sync +1 -0
- package/core/.system/memory/README.md +3 -0
- package/core/CLAUDE.md +6 -7
- package/core/KENAZ_CORE_VERSION +1 -1
- package/core/dev/plans/CLI_FIRST_INSTALL_FLOW.md +75 -83
- package/core/dev/specs/peer/CODEX_MANAGED_DAEMON.md +54 -0
- package/core/dev/specs/peer/setup-codex-hooks.test.js +38 -0
- package/core/dev/spikes/task2145-evidence-20261004/backend-log-excerpt.txt +56 -0
- package/core/dev/spikes/task2145-evidence-20261004/graph.shadow +0 -0
- package/core/dev/spikes/task2145-evidence-20261004/graph.wal +0 -0
- package/core/dev/spikes/task2145-evidence-20261004/graph_corrupt_suspect.marker +1 -0
- package/core/plugins/kenaz/INVENTORY.md +1 -1
- package/core/plugins/kenaz/scripts/kenaz.test.js +70 -1
- package/core/plugins/kenaz/scripts/ygg.js +45 -4
- package/core/plugins/kenaz/skills/code_reviewer/SKILL.md +0 -1
- package/core/plugins/kenaz/skills/code_reviewer/patterns.yaml +0 -8
- package/core/plugins/kenaz/skills/dev_agent/SKILL.md +3 -6
- package/lib/cli.js +17 -9
- package/lib/cli.test.js +10 -0
- package/lib/dashboard.test.js +3 -3
- package/package.json +6 -6
- package/vendor/install-kenaz-cli.js +167 -16
- package/core/.claude/hooks/handoff-snapshot-on-decision.js +0 -188
- package/core/.claude/skills/synapse_maintain/SKILL.md +0 -84
- package/core/.collaboration/core/task-2264-single-after-capture.test.js +0 -61
- package/core/.formation/tools/alaya-gate.js +0 -198
- package/core/.formation/tools/post-complete/health.js +0 -464
- package/core/.formation/tools/post-complete/task2038.test.js +0 -246
- package/core/.formation/tools/post-complete/task2341.test.js +0 -74
- package/core/.rule/general/cortex-tools.yaml +0 -181
- package/core/.rule/general/memory-language.yaml +0 -67
- package/core/.rule/general/memory-source-priority.yaml +0 -207
- package/core/.rule/general/synapse-cognitive-fusion.yaml +0 -301
- package/core/.specialist/Ansuz/concepts/cognitive_systems_hippocampus.yaml +0 -14
- package/core/.specialist/Ansuz/concepts/write_verification.yaml +0 -26
- package/core/.specialist/Ansuz/modules/recall.yaml +0 -45
- package/core/.specialist/tools/MEMORY_RECALL_TRIGGERS.md +0 -156
- package/core/.specialist/tools/context-injection.js +0 -395
- package/core/dev/scripts/probe/hippocampus-concurrency.js +0 -247
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
# synapse_maintain
|
|
2
|
-
|
|
3
|
-
Unified Synapse maintenance checkpoint for agent-facing health reviews.
|
|
4
|
-
|
|
5
|
-
## when_to_call
|
|
6
|
-
|
|
7
|
-
- Phase 2 research: run before planning when the task depends on current codebase health, stale cognition, or cleanup priority.
|
|
8
|
-
- Cognitive checkpoint: run after a risky implementation burst to see whether new gaps, conflicts, or stale runes appeared.
|
|
9
|
-
- Session end: run before handoff so the next agent receives a single dashboard instead of seven separate tool calls.
|
|
10
|
-
|
|
11
|
-
## tool
|
|
12
|
-
|
|
13
|
-
Call `synapse_maintain` with:
|
|
14
|
-
|
|
15
|
-
```json
|
|
16
|
-
{
|
|
17
|
-
"projectPath": "<worktree-or-project-path>",
|
|
18
|
-
"top_n": 5
|
|
19
|
-
}
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
## sections
|
|
23
|
-
|
|
24
|
-
### orphans
|
|
25
|
-
|
|
26
|
-
- Meaning: code symbols that look unreachable and may be removable.
|
|
27
|
-
- Read it as: high count + high removal impact means cleanup can simplify the graph quickly.
|
|
28
|
-
- Follow-up: inspect candidates before deletion; route handlers and command entry points can still be legitimate.
|
|
29
|
-
- Rune guidance: inscribe `fix` after a confirmed deletion or `risk` when a false-positive pattern is discovered.
|
|
30
|
-
|
|
31
|
-
### stale_runes
|
|
32
|
-
|
|
33
|
-
- Meaning: runes whose attached symbols drifted heavily or disappeared from the graph.
|
|
34
|
-
- Read it as: `auto_rejected` is urgent because memory was already invalidated; `needs_review` means knowledge may be stale.
|
|
35
|
-
- Follow-up: refresh or supersede outdated runes before using them in planning.
|
|
36
|
-
- Rune guidance: inscribe `decision` when you intentionally keep a flagged rune valid, or `fix` when you replace stale guidance.
|
|
37
|
-
|
|
38
|
-
### conflicts
|
|
39
|
-
|
|
40
|
-
- Meaning: contradictory runes on the same symbol or within the same sigil.
|
|
41
|
-
- Read it as: any `high` conflict blocks blind trust in recall results.
|
|
42
|
-
- Follow-up: verify, reject, or supersede conflicting runes before further automation.
|
|
43
|
-
- Rune guidance: inscribe `decision` with the resolved interpretation after adjudicating the conflict.
|
|
44
|
-
|
|
45
|
-
### gaps
|
|
46
|
-
|
|
47
|
-
- Meaning: heavily used symbols with no cognitive memory.
|
|
48
|
-
- Read it as: these are high-leverage documentation targets, especially when danger score is high.
|
|
49
|
-
- Follow-up: inspect the top hotspots and inscribe only non-obvious behavior, risks, or design choices.
|
|
50
|
-
- Rune guidance: inscribe `insight`, `risk`, or `summary` depending on the symbol and what was learned.
|
|
51
|
-
|
|
52
|
-
### pain_paths
|
|
53
|
-
|
|
54
|
-
- Meaning: long call chains crossing too many community boundaries.
|
|
55
|
-
- Read it as: repeated community crossings usually signal architecture drag rather than a single bug.
|
|
56
|
-
- Follow-up: use the chain preview to decide where a facade, shortcut, or boundary cleanup would reduce coupling.
|
|
57
|
-
- Rune guidance: inscribe `risk` when a path is fragile, or `decision` when you adopt a refactoring boundary.
|
|
58
|
-
|
|
59
|
-
### overdue_episodes
|
|
60
|
-
|
|
61
|
-
- Meaning: closed episodes with high consolidation scores that still need memory compression or review.
|
|
62
|
-
- Read it as: these sessions contain learnings that are likely to be lost unless consolidated.
|
|
63
|
-
- Follow-up: consolidate, summarize key facts, or extract repeatable lessons.
|
|
64
|
-
- Rune guidance: inscribe `ash` only after a stable cross-session lesson is clear.
|
|
65
|
-
|
|
66
|
-
### audit_summary
|
|
67
|
-
|
|
68
|
-
- Meaning: anomaly rule findings from the structural audit engine.
|
|
69
|
-
- Read it as: `high` findings are active breakage or architectural risk; `medium` usually deserves planned follow-up.
|
|
70
|
-
- Follow-up: treat the file paths as the first investigation slice, not as automatic proof.
|
|
71
|
-
- Rune guidance: inscribe `fix` after resolving a confirmed audit issue, or `risk` if a known anomaly must remain temporarily.
|
|
72
|
-
|
|
73
|
-
## interpretation
|
|
74
|
-
|
|
75
|
-
- `severity=high` means act before more feature work if the section affects active scope.
|
|
76
|
-
- `severity=medium` means plan remediation or inscribe context before handing off.
|
|
77
|
-
- `severity=low` means no urgent action, but keep the diagnosis in the task summary if it influenced decisions.
|
|
78
|
-
- If a section is `degraded`, treat the diagnosis as tool coverage failure, not proof that the codebase is healthy.
|
|
79
|
-
|
|
80
|
-
## output_discipline
|
|
81
|
-
|
|
82
|
-
- Do not summarize the dashboard as "all green" unless every section is both `status=ok` and `severity=low`.
|
|
83
|
-
- If `items` is empty but `status=degraded`, report the error explicitly; degraded sections are not passes.
|
|
84
|
-
- Prefer one follow-up rune with high confidence over bulk inscription from raw dashboard findings.
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
// TASK_2264 — completeTask must schedule exactly ONE 'after' health capture.
|
|
2
|
-
// moveTask used to schedule a detached 'after' capture on every ->done move even when
|
|
3
|
-
// completeTask's own postComplete was about to measure the same snapshot.
|
|
4
|
-
// Counting seam: child_process.spawn is patched (task-api requires it at call time) and
|
|
5
|
-
// calls whose inline script carries phase "after" are counted. Isolated temp project.
|
|
6
|
-
// Usage: node .collaboration/core/task-2264-single-after-capture.test.js
|
|
7
|
-
const fs = require('fs');
|
|
8
|
-
const path = require('path');
|
|
9
|
-
const os = require('os');
|
|
10
|
-
const cp = require('child_process');
|
|
11
|
-
const { TaskAPI, toYAML } = require('./task-api.js');
|
|
12
|
-
|
|
13
|
-
const SB = fs.mkdtempSync(path.join(os.tmpdir(), 't2264_'));
|
|
14
|
-
const tasksDir = path.join(SB, '.kenaz', 'tasks');
|
|
15
|
-
for (const d of ['backlog', 'active', 'done', 'blocked', 'cancel', 'archived']) fs.mkdirSync(path.join(tasksDir, d), { recursive: true });
|
|
16
|
-
delete process.env.FORMATION_SCHEDULER; delete process.env.FORMATION_HEADLESS;
|
|
17
|
-
|
|
18
|
-
let pass = 0, fail = 0;
|
|
19
|
-
const check = (n, c, d) => { console.log((c ? 'PASS' : 'FAIL') + ' | ' + n + (c ? '' : ' | ' + d)); c ? pass++ : fail++; };
|
|
20
|
-
|
|
21
|
-
let phases = [];
|
|
22
|
-
const realSpawn = cp.spawn;
|
|
23
|
-
cp.spawn = function (cmd, argv, opts) {
|
|
24
|
-
const script = Array.isArray(argv) ? argv.find(a => typeof a === 'string' && a.includes('const CFG')) : null;
|
|
25
|
-
if (script) {
|
|
26
|
-
const m = script.match(/"phase":"(before|after)"/);
|
|
27
|
-
phases.push(m ? m[1] : '?');
|
|
28
|
-
return { unref() {}, on() {} };
|
|
29
|
-
}
|
|
30
|
-
return realSpawn.apply(this, arguments);
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
const mkActive = (id) => fs.writeFileSync(path.join(tasksDir, 'active', id + '_t.yaml'),
|
|
34
|
-
toYAML({ id, title: 't2264 ' + id, priority: 'P2', status: 'in_progress' }));
|
|
35
|
-
|
|
36
|
-
(async () => {
|
|
37
|
-
const api = new TaskAPI({ tasksDir, projectPath: SB });
|
|
38
|
-
try {
|
|
39
|
-
// A: complete with post-complete running in-process (dry run, no git/archive) -> post-complete owns 'after'
|
|
40
|
-
mkActive('TASK_9001'); phases = [];
|
|
41
|
-
await api.completeTask('TASK_9001', { dryRun: true, skipGit: true, skipArchive: true });
|
|
42
|
-
check('A complete w/ post-complete: moveTask schedules NO after capture', phases.filter(p => p === 'after').length === 0, JSON.stringify(phases));
|
|
43
|
-
|
|
44
|
-
// B control: post-complete skipped -> nobody else measures, moveTask must still capture exactly once
|
|
45
|
-
mkActive('TASK_9002'); phases = [];
|
|
46
|
-
await api.completeTask('TASK_9002', { skipPostComplete: true });
|
|
47
|
-
check('B control: complete w/ skipPostComplete schedules exactly 1 after capture', phases.filter(p => p === 'after').length === 1, JSON.stringify(phases));
|
|
48
|
-
|
|
49
|
-
// C control: bare move done (no post-complete) keeps its single capture
|
|
50
|
-
mkActive('TASK_9003'); phases = [];
|
|
51
|
-
await api.moveTask('TASK_9003', 'done');
|
|
52
|
-
check('C control: bare move done schedules exactly 1 after capture', phases.filter(p => p === 'after').length === 1, JSON.stringify(phases));
|
|
53
|
-
} catch (e) {
|
|
54
|
-
check('no exception', false, e && e.stack);
|
|
55
|
-
} finally {
|
|
56
|
-
cp.spawn = realSpawn;
|
|
57
|
-
try { fs.rmSync(SB, { recursive: true, force: true }); } catch { /* best effort */ }
|
|
58
|
-
}
|
|
59
|
-
console.log(`\n${pass} passed, ${fail} failed`);
|
|
60
|
-
process.exit(fail ? 1 : 0);
|
|
61
|
-
})();
|
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
// TASK_2104: shared, dependency-free Alaya relevance gate — extracted out
|
|
2
|
-
// of prompt.js so task-api.js's echoAlayaLessons (TASK_1992) applies the
|
|
3
|
-
// same TASK_2101 cosine-floor + stack-match gate instead of a hand-copied
|
|
4
|
-
// near-duplicate that had neither. Zero deps (no memory-loader/core-resolve)
|
|
5
|
-
// so it still require()s from a sub-project with no .formation/ checkout —
|
|
6
|
-
// callers must treat a require() failure as "gate unavailable" and degrade
|
|
7
|
-
// gracefully (see task-api.js echoAlayaLessons).
|
|
8
|
-
// Shared by: prompt.js appendAlayaLessons(), task-api.js echoAlayaLessons().
|
|
9
|
-
|
|
10
|
-
'use strict';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Build the cross-project context query shared by Cortex and Alaya lookups:
|
|
14
|
-
* scope_paths basenames (extension stripped) + up to 4 non-stop-word
|
|
15
|
-
* keywords from the task title.
|
|
16
|
-
*
|
|
17
|
-
* @param {string|object} taskData - task JSON string or parsed object
|
|
18
|
-
* @returns {string|null} the query string, or null when nothing to query
|
|
19
|
-
*/
|
|
20
|
-
function buildTaskContextQuery(taskData) {
|
|
21
|
-
let scopePaths = [];
|
|
22
|
-
let taskTitle = '';
|
|
23
|
-
try {
|
|
24
|
-
const parsed = typeof taskData === 'string' ? JSON.parse(taskData) : taskData;
|
|
25
|
-
if (parsed) {
|
|
26
|
-
scopePaths = parsed.scope_paths || [];
|
|
27
|
-
taskTitle = parsed.title || '';
|
|
28
|
-
}
|
|
29
|
-
} catch { /* taskData not JSON, skip */ }
|
|
30
|
-
|
|
31
|
-
if (scopePaths.length === 0 && !taskTitle) return null;
|
|
32
|
-
|
|
33
|
-
// Build query from scope_paths file names + task title keywords
|
|
34
|
-
const queryParts = [];
|
|
35
|
-
for (const sp of scopePaths) {
|
|
36
|
-
const parts = String(sp).replace(/\\/g, '/').split('/');
|
|
37
|
-
const last = parts[parts.length - 1].replace(/\.[^.]+$/, '');
|
|
38
|
-
if (last && last.length > 2) queryParts.push(last);
|
|
39
|
-
}
|
|
40
|
-
if (taskTitle) {
|
|
41
|
-
const stopWords = new Set(['the','a','an','is','are','to','of','and','in','for','on','at','by','with','fix','task','add','update']);
|
|
42
|
-
const words = taskTitle.replace(/[^a-zA-Z0-9_\s]/g, ' ').split(/\s+/).filter(w => w.length > 2 && !stopWords.has(w.toLowerCase()));
|
|
43
|
-
queryParts.push(...words.slice(0, 4));
|
|
44
|
-
}
|
|
45
|
-
if (queryParts.length === 0) return null;
|
|
46
|
-
|
|
47
|
-
return [...new Set(queryParts)].join(' ');
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// TASK_2101: absolute relevance gate for Alaya lesson injection.
|
|
51
|
-
//
|
|
52
|
-
// Why: alaya_recall's only pre-2101 score is RRF rank fusion (~0.016-0.032),
|
|
53
|
-
// which carries no absolute relevance — lexical overlap on a single common
|
|
54
|
-
// word ("checkpoint", "gate") was enough to rank a bija first regardless of
|
|
55
|
-
// domain. Every bija also had source_count=1 (hub distiller not implemented),
|
|
56
|
-
// so nothing self-corrects via aggregation either. The fix is two gates that
|
|
57
|
-
// must BOTH pass before a bija is even a candidate for injection:
|
|
58
|
-
// 1. cosine floor — the RAW semantic cosine (never the RRF score) must
|
|
59
|
-
// clear ALAYA_MIN_COSINE_DEFAULT. A bija the semantic arm never scored
|
|
60
|
-
// (cosine=null: fts-only hit, or bija has no embedding yet) fails the
|
|
61
|
-
// floor by construction — an unverifiable relevance is not a floor pass.
|
|
62
|
-
// 2. stack match — the bija's coarse tech stack (source_symbol's file
|
|
63
|
-
// extension/dir, plus tags) must overlap the task's (scope_paths'
|
|
64
|
-
// extensions/dirs), UNLESS the cosine is very high
|
|
65
|
-
// (>= ALAYA_STACK_OVERRIDE_COSINE) — a strong enough semantic match can
|
|
66
|
-
// override a stack that a coarse heuristic failed to resolve.
|
|
67
|
-
//
|
|
68
|
-
// Calibration (R4, measured 2026-09-28 against the live backend, 5 real
|
|
69
|
-
// dispatch queries x top-10 semantic hits = 50 bijas, hand-labelled):
|
|
70
|
-
// - ArcticEmbedXs cosines are compressed high: clearly irrelevant noise
|
|
71
|
-
// (payment/CRM/UI-colour/backtest seeds on Rust and JS infra cards)
|
|
72
|
-
// scored 0.656-0.697; on-topic bijas scored 0.709-0.810. 0.45 (the
|
|
73
|
-
// earlier placeholder) passed all 50, i.e. it was not a filter at all.
|
|
74
|
-
// - Confusion at 0.45: 20 on-topic kept, 30 noise kept. At 0.70: 20 kept,
|
|
75
|
-
// 0 noise. The margin is only ~0.012, so treat 0.70 as fitted to a small
|
|
76
|
-
// sample and re-measure when the bija population changes.
|
|
77
|
-
// - The stack half of the gate currently has no real signal: every live
|
|
78
|
-
// bija has source_symbol='' (hub predates the pass-through) and `tags`
|
|
79
|
-
// are content word-bags, not stack labels. In practice a bija on a task
|
|
80
|
-
// with scope_paths passes only at >= ALAYA_STACK_OVERRIDE_COSINE (0.8),
|
|
81
|
-
// so today's effective floor for scoped tasks is 0.8 and 0.70 applies to
|
|
82
|
-
// unscoped tasks. A3 check (dispatch --dry-run on TASK_2096/2097/2100):
|
|
83
|
-
// 10/10 candidates dropped on each; no noise injected.
|
|
84
|
-
// - Also seen: the on-topic hits were near-duplicates (8-9 copies of one
|
|
85
|
-
// "community detection void" / "KuzuDB graph broken" observation) and
|
|
86
|
-
// months stale (the conditions they describe are fixed). Relevance is
|
|
87
|
-
// not the only gap: dedup (distiller) and retraction are next.
|
|
88
|
-
const ALAYA_MIN_COSINE_DEFAULT = 0.70;
|
|
89
|
-
const ALAYA_STACK_OVERRIDE_COSINE = 0.8;
|
|
90
|
-
// Candidate pool requested from alaya_recall — wider than the render cap (3)
|
|
91
|
-
// so post-filtering by the two gates still has real candidates to keep.
|
|
92
|
-
const ALAYA_CANDIDATE_POOL = 10;
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Coarse stack tokens (lowercase file extensions + 1-2 top path segments)
|
|
96
|
-
* from a list of paths. Shared by the task side (scope_paths) and the bija
|
|
97
|
-
* side (source_symbol's `{file_path}:{symbol}:{kind}` shape, split on ':').
|
|
98
|
-
*
|
|
99
|
-
* @param {string} normPath - a single '/'-normalised path
|
|
100
|
-
* @param {Set<string>} tokens - mutated in place
|
|
101
|
-
*/
|
|
102
|
-
function addStackTokens(normPath, tokens) {
|
|
103
|
-
if (!normPath) return;
|
|
104
|
-
const extMatch = normPath.match(/\.([a-zA-Z0-9]+)$/);
|
|
105
|
-
if (extMatch) tokens.add(extMatch[1].toLowerCase());
|
|
106
|
-
const parts = normPath.split('/').filter(Boolean);
|
|
107
|
-
if (parts.length > 0) tokens.add(parts[0].toLowerCase());
|
|
108
|
-
if (parts.length > 1) tokens.add(`${parts[0]}/${parts[1]}`.toLowerCase());
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Derive the task's coarse stack from its scope_paths (file extensions +
|
|
113
|
-
* top-level dirs, e.g. {'rs', 'js', 'dashboard', '.formation/tools'}).
|
|
114
|
-
* @param {string[]} scopePaths
|
|
115
|
-
* @returns {Set<string>}
|
|
116
|
-
*/
|
|
117
|
-
function deriveTaskStack(scopePaths) {
|
|
118
|
-
const tokens = new Set();
|
|
119
|
-
for (const sp of scopePaths || []) {
|
|
120
|
-
addStackTokens(String(sp).replace(/\\/g, '/'), tokens);
|
|
121
|
-
}
|
|
122
|
-
return tokens;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Derive a bija's coarse stack from its tags (comma-separated string, as
|
|
127
|
-
* returned by alaya_recall) and its source_symbol (TASK_2101 — hub
|
|
128
|
-
* pass-through of the originating rune's symbol_stable_id; empty for hubs
|
|
129
|
-
* that predate the field, or project-level seeds with no single symbol).
|
|
130
|
-
* @param {object} bija
|
|
131
|
-
* @returns {Set<string>}
|
|
132
|
-
*/
|
|
133
|
-
function deriveBijaStack(bija) {
|
|
134
|
-
const tokens = new Set();
|
|
135
|
-
for (const t of String(bija.tags || '').split(',')) {
|
|
136
|
-
const tag = t.trim().toLowerCase();
|
|
137
|
-
if (tag) tokens.add(tag);
|
|
138
|
-
}
|
|
139
|
-
const sourceSymbol = String(bija.source_symbol || '');
|
|
140
|
-
if (sourceSymbol) {
|
|
141
|
-
const filePath = sourceSymbol.split(':')[0].replace(/\\/g, '/');
|
|
142
|
-
addStackTokens(filePath, tokens);
|
|
143
|
-
}
|
|
144
|
-
return tokens;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Whether a bija passes the TASK_2101 relevance gate: cosine floor AND
|
|
149
|
-
* (stack overlap OR a cosine high enough to override a stack miss).
|
|
150
|
-
* A task with no derivable stack (empty scope_paths) cannot be judged on
|
|
151
|
-
* stack at all, so the stack half of the gate is skipped — the floor alone
|
|
152
|
-
* still applies.
|
|
153
|
-
*
|
|
154
|
-
* @param {object} bija - one alaya_recall result (cosine, tags, source_symbol, ...)
|
|
155
|
-
* @param {Set<string>} taskStack - from deriveTaskStack
|
|
156
|
-
* @param {number} floor - ALAYA_MIN_COSINE_DEFAULT (or an override)
|
|
157
|
-
* @returns {boolean}
|
|
158
|
-
*/
|
|
159
|
-
function passesAlayaRelevanceGate(bija, taskStack, floor) {
|
|
160
|
-
const cosine = typeof bija.cosine === 'number' ? bija.cosine : null;
|
|
161
|
-
if (cosine === null || cosine < floor) return false;
|
|
162
|
-
if (taskStack.size === 0) return true; // no task-side stack signal to judge against
|
|
163
|
-
if (cosine >= ALAYA_STACK_OVERRIDE_COSINE) return true;
|
|
164
|
-
const bijaStack = deriveBijaStack(bija);
|
|
165
|
-
for (const tok of bijaStack) {
|
|
166
|
-
if (taskStack.has(tok)) return true;
|
|
167
|
-
}
|
|
168
|
-
return false;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Dedup a list of alaya_recall bijas: key = id, else first 100 chars of
|
|
173
|
-
* content. Shared by prompt.js's appendAlayaLessons and task-api.js's
|
|
174
|
-
* echoAlayaLessons — both queried the same hub, so the same duplicate hubs
|
|
175
|
-
* (near-identical seeds re-inscribed by different sources) can show up.
|
|
176
|
-
*
|
|
177
|
-
* @param {object[]} bijas
|
|
178
|
-
* @returns {object[]}
|
|
179
|
-
*/
|
|
180
|
-
function dedupBijas(bijas) {
|
|
181
|
-
const seen = new Set();
|
|
182
|
-
return (bijas || []).filter(b => {
|
|
183
|
-
const key = b.id || (b.content || '').slice(0, 100);
|
|
184
|
-
if (!key || seen.has(key)) return false;
|
|
185
|
-
seen.add(key); return true;
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
module.exports = {
|
|
190
|
-
buildTaskContextQuery,
|
|
191
|
-
deriveTaskStack,
|
|
192
|
-
deriveBijaStack,
|
|
193
|
-
passesAlayaRelevanceGate,
|
|
194
|
-
dedupBijas,
|
|
195
|
-
ALAYA_MIN_COSINE_DEFAULT,
|
|
196
|
-
ALAYA_STACK_OVERRIDE_COSINE,
|
|
197
|
-
ALAYA_CANDIDATE_POOL,
|
|
198
|
-
};
|