Merge reviewed observer status counting repair and retain combined registry binding

This commit is contained in:
affaan-m
2026-09-28 02:17:53 -04:00
3 changed files with 281 additions and 3 deletions
File diff suppressed because one or more lines are too long
@@ -156,8 +156,14 @@ case "$ACTION" in
echo "Observer is running (PID: $pid)"
echo "Log: $LOG_FILE"
echo "Observations: $(wc -l < "$OBSERVATIONS_FILE" 2>/dev/null || echo 0) lines"
# Also show instinct count
instinct_count=$(find "$INSTINCTS_DIR" -name "*.yaml" 2>/dev/null | wc -l)
# Count eligible files, not parsed records: the loader accepts these
# suffixes case-insensitively and follows links to regular files.
# Stay at the top level, excluding dot-only names with no Path.suffix.
# Count NUL records so newlines in filenames cannot inflate the result.
instinct_find_expr=( \( -iname "*.yaml" -o -iname "*.yml" -o -iname "*.md" \) )
instinct_count=$(find -L "$INSTINCTS_DIR" -mindepth 1 -maxdepth 1 -type f \
"${instinct_find_expr[@]}" ! -iname ".yaml" ! -iname ".yml" ! -iname ".md" \
-print0 2>/dev/null | tr -cd '\000' | wc -c | tr -d '[:space:]')
echo "Instincts: $instinct_count"
exit 0
else
@@ -0,0 +1,272 @@
/**
* Regression tests for #2859: status counts eligible top-level instinct files.
* The loader accepts .yaml/.yml/.md; files can contain zero or many instincts,
* so this count does not establish parsed-record counts or observer health.
*/
'use strict';
const assert = require('assert');
const { spawnSync } = require('child_process');
const fs = require('fs');
const os = require('os');
const path = require('path');
const repoRoot = path.resolve(__dirname, '..', '..');
const skillRoot = path.join(repoRoot, 'skills', 'continuous-learning-v2');
const observerScript = path.join(skillRoot, 'agents', 'start-observer.sh');
const instinctCli = path.join(skillRoot, 'scripts', 'instinct-cli.py');
const bashBinary = process.env.ECC_TEST_BASH || (process.platform === 'win32' ? null : '/bin/bash');
const childTimeoutMs = 3000;
const childMaxBuffer = 64 * 1024;
class SkipTest extends Error {}
function toShellPath(filePath) {
const normalized = filePath.split(path.sep).join('/');
return normalized.replace(/^([A-Za-z]):\//, (_, drive) => `/${drive.toLowerCase()}/`);
}
function readAllowedExtensions() {
const cliSource = fs.readFileSync(instinctCli, 'utf8');
const match = cliSource.match(/ALLOWED_INSTINCT_EXTENSIONS\s*=\s*\(([^)]*)\)/);
assert.ok(match, 'ALLOWED_INSTINCT_EXTENSIONS not found in instinct-cli.py');
return match[1].split(',')
.map(part => part.trim().replace(/^["']|["']$/g, ''))
.filter(Boolean);
}
function fixtureAt(root) {
const home = path.join(root, 'home');
const temp = path.join(root, 'tmp');
const bin = path.join(root, 'bin');
const homunculus = path.join(root, 'homunculus');
const instincts = path.join(homunculus, 'instincts', 'personal');
const unexpected = path.join(root, 'unexpected-command');
for (const directory of [home, temp, bin, instincts]) fs.mkdirSync(directory, { recursive: true });
for (const command of ['python', 'python3', 'git', 'claude']) {
fs.writeFileSync(path.join(bin, command),
'#!/bin/sh\nprintf unexpected > "$FIXTURE_UNEXPECTED_COMMAND"\nexit 97\n', { mode: 0o700 });
}
fs.writeFileSync(path.join(homunculus, 'observations.jsonl'), '');
return {
root, instincts, unexpected,
env: {
PATH: [toShellPath(bin), '/usr/bin', '/bin'].join(':'),
HOME: toShellPath(home), USERPROFILE: home, TMPDIR: toShellPath(temp),
TMP: temp, TEMP: temp, LC_ALL: 'C',
...(process.platform === 'win32' ? { SystemRoot: process.env.SystemRoot } : {}),
CLV2_NO_PROJECT: '1', CLV2_HOMUNCULUS_DIR: toShellPath(homunculus),
CLV2_CONFIG: toShellPath(path.join(root, 'absent-config.json')),
CLV2_PYTHON_CMD: toShellPath(path.join(bin, 'python3')),
FIXTURE_UNEXPECTED_COMMAND: toShellPath(unexpected),
},
};
}
function withFixture(callback, remove = fs.rmSync) {
const root = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), 'ecc-observer-')));
let failed = false; let primary; let result;
try {
result = callback(fixtureAt(root));
} catch (error) {
failed = true;
primary = error;
}
try { remove(root, { recursive: true, force: true }); }
catch (error) { if (!failed) throw error; }
if (failed) throw primary;
return result;
}
function checkChild(result) {
if (result.error) throw result.error;
assert.strictEqual(result.status, 0, result.stderr || result.stdout || `child signal: ${result.signal}`);
}
function runStatus(files, { run = spawnSync, setup = () => {}, remove = fs.rmSync } = {}) {
return withFixture(fixture => {
for (const name of files) {
const target = path.join(fixture.instincts, name);
fs.mkdirSync(path.dirname(target), { recursive: true });
fs.writeFileSync(target, 'id: fixture\n');
}
setup(fixture);
// Only this foreground shell's own PID is advertised. No observer, sleep,
// provider or other background child is started or signalled.
const program = 'printf "%s\\n" "$$" > "$CLV2_HOMUNCULUS_DIR/.observer.pid"\nexec "$BASH" "$1" status';
const result = run(bashBinary, ['--noprofile', '--norc', '-c', program,
'observer-status-test', toShellPath(observerScript)], {
cwd: fixture.root, encoding: 'utf8', env: fixture.env,
timeout: childTimeoutMs, maxBuffer: childMaxBuffer, killSignal: 'SIGKILL',
});
checkChild(result);
assert.ok(!fs.existsSync(fixture.unexpected), 'status must not invoke Git, Python or a provider');
const lines = (result.stdout || '').split('\n').filter(line => line.startsWith('Instincts:'));
assert.strictEqual(lines.length, 1, `expected one count in status output:\n${result.stdout}`);
assert.match(lines[0], /^Instincts:\s+\d+\s*$/);
return Number(lines[0].split(':')[1].trim());
}, remove);
}
function fileLink(target, link, type = 'file') {
try { fs.symlinkSync(target, link, type); }
catch (error) {
const unsupported = ['ENOSYS', 'ENOTSUP'].includes(error.code)
|| (process.platform === 'win32' && ['EPERM', 'EACCES'].includes(error.code));
if (unsupported) throw new SkipTest(`symlink capability unavailable: ${error.code}`);
throw error;
}
}
function shellTest(fn) {
return () => {
if (!bashBinary) throw new SkipTest('requires bash; set ECC_TEST_BASH on Windows');
return fn();
};
}
function cleanupTests() {
return [
['status child has a private environment and bounded execution', () => {
let root;
assert.strictEqual(runStatus([], { run: (_command, args, options) => {
root = options.cwd;
assert.strictEqual(options.timeout, childTimeoutMs);
assert.strictEqual(options.maxBuffer, childMaxBuffer);
assert.strictEqual(options.killSignal, 'SIGKILL');
assert.strictEqual(options.env.CLV2_NO_PROJECT, '1');
for (const key of ['BASH_ENV', 'ENV', 'NODE_OPTIONS', 'ANTHROPIC_API_KEY', 'CLAUDE_PROJECT_DIR']) {
assert.ok(!Object.hasOwn(options.env, key), `unexpected inherited ${key}`);
}
assert.ok(options.env.CLV2_CONFIG.endsWith('/absent-config.json'));
assert.ok(!fs.existsSync(options.env.CLV2_CONFIG));
assert.strictEqual(args.at(-1), toShellPath(observerScript));
assert.match(args[3], /\nexec "\$BASH" "\$1" status$/);
assert.doesNotMatch(args[3], /sleep|kill|&/);
return { status: 0, stdout: 'Instincts: 0\n', stderr: '' };
} }), 0);
assert.ok(!fs.existsSync(root));
}],
...['timeout', 'nonzero', 'spawn error'].map(kind => [`${kind} cleans its private fixture`, () => {
let root;
const failure = Object.assign(new Error(kind), { code: kind === 'timeout' ? 'ETIMEDOUT' : 'EIO' });
assert.throws(() => runStatus([], { run: (_command, _args, options) => {
root = options.cwd;
return kind === 'nonzero' ? { status: 7, stdout: '', stderr: 'fixture rejected' } : { error: failure };
} }), error => kind === 'nonzero' ? /fixture rejected/.test(error.message) : error === failure);
assert.ok(!fs.existsSync(root));
}]),
['cleanup preserves frozen and falsy primary failures', () => {
for (const primary of [Object.freeze(new Error('primary')), null, false, 0, undefined]) {
let root; let caught = false;
try {
withFixture(value => { root = value.root; throw primary; }, (value, options) => {
fs.rmSync(value, options); throw new Error('cleanup');
});
} catch (error) { caught = true; assert.strictEqual(error, primary); }
assert.ok(caught);
assert.ok(!fs.existsSync(root));
}
}],
['cleanup failure is reported when the fixture otherwise succeeds', () => {
let root;
const failure = new Error('cleanup');
assert.throws(() => withFixture(value => { root = value.root; }, (value, options) => {
fs.rmSync(value, options); throw failure;
}), error => error === failure);
assert.ok(!fs.existsSync(root));
}],
];
}
function buildTests() {
const allowed = readAllowedExtensions();
return [
['the loader still declares several instinct extensions', () => {
assert.ok(allowed.length >= 3, `expected several extensions, got ${allowed}`);
}],
...allowed.map(ext => [`status counts ${ext} - the loader accepts it`, shellTest(() => {
assert.strictEqual(runStatus([`one${ext}`]), 1);
})]),
['status does not recurse - the loader does not', shellTest(() => {
assert.strictEqual(runStatus(['a.md', 'nested/deep.yaml']), 1);
})],
['status skips directories', shellTest(() => {
assert.strictEqual(runStatus([], { setup: value => fs.mkdirSync(path.join(value.instincts, 'directory.md')) }), 0);
})],
['status matches case-insensitively', shellTest(() => {
assert.strictEqual(runStatus(['a.YAML', 'b.YmL', 'c.MD']), 3);
})],
['start-observer.sh parses', shellTest(() => withFixture(fixture => {
checkChild(spawnSync(bashBinary, ['--noprofile', '--norc', '-n', toShellPath(observerScript)], {
cwd: fixture.root, env: fixture.env, encoding: 'utf8',
timeout: childTimeoutMs, maxBuffer: childMaxBuffer, killSignal: 'SIGKILL',
}));
}))],
['markdown instincts are counted', shellTest(() => {
assert.strictEqual(runStatus(['a.md', 'b.md', 'c.md']), 3);
})],
['the count matches the loader eligible-file rules', shellTest(() => {
assert.strictEqual(runStatus(['a.md', 'b.yaml', 'c.yml', 'd.YAML', 'notes.txt', 'nested/deep.md']), 4);
})],
['an empty instincts directory reports 0', shellTest(() => {
assert.strictEqual(runStatus([]), 0);
})],
['hidden stems count but dot-only extension names have no suffix', shellTest(() => {
assert.strictEqual(runStatus(['.note.MD', '.yaml', '.YML', '.md']), 1);
})],
['newlines and spaces in one eligible filename count once', shellTest(() => {
assert.strictEqual(runStatus(['two\nlines with spaces.MD']), 1);
})],
['shell metacharacters in a filename remain inert data', shellTest(() => {
assert.strictEqual(runStatus(['$(touch unwanted).md'], { setup: value => {
assert.ok(!fs.existsSync(path.join(value.root, 'unwanted')));
}, run: (command, args, options) => {
const result = spawnSync(command, args, options);
assert.ok(!fs.existsSync(path.join(options.cwd, 'unwanted')));
return result;
} }), 1);
})],
['linked regular files count without traversing directory links', shellTest(() => {
assert.strictEqual(runStatus(['a.md', 'b.yaml', 'c.yml', 'd.YAML', '.note.MD',
'.md', '.yaml', '.YML', 'notes.txt', 'nested/deep.md'], { setup: value => {
const outside = path.join(value.root, 'outside');
fs.mkdirSync(outside);
const target = path.join(outside, 'regular.txt');
fs.writeFileSync(target, 'private fixture\n');
fs.writeFileSync(path.join(outside, 'deep.md'), 'not top-level\n');
fs.mkdirSync(path.join(value.instincts, 'directory.md'));
fileLink(target, path.join(value.instincts, 'linked.MD'));
fileLink(outside, path.join(value.instincts, 'directory-link.yaml'), 'dir');
fileLink(path.join(outside, 'missing'), path.join(value.instincts, 'dangling.yml'));
} }), 6);
})],
...cleanupTests(),
];
}
function main() {
console.log('\n=== Testing observer status instinct count (#2859) ===\n');
let passed = 0; let failed = 0; let skipped = 0; let tests;
try { tests = buildTests(); }
catch (error) {
console.error(` FAIL could not build the test list: ${error.message}`);
tests = []; failed += 1;
}
for (const [name, fn] of tests) {
try { fn(); console.log(` PASS ${name}`); passed += 1; }
catch (error) {
if (error instanceof SkipTest) {
console.log(` SKIP ${name}: ${error.message}`); skipped += 1;
} else {
console.error(` FAIL ${name}: ${error.message}`); failed += 1;
}
}
}
console.log(`\n Passed: ${passed}\n Failed: ${failed}\n Skipped: ${skipped}`);
// Let piped summary output drain before the aggregate runner reads it.
if (failed > 0) process.exitCode = 1;
}
main();