mirror of https://github.com/garrytan/gstack.git
fix(learnings): accept type:"investigation" in gstack-learnings-log
The /investigate skill instructed agents to log learnings with type:"investigation", but bin/gstack-learnings-log:22 rejected anything not in [pattern, pitfall, preference, architecture, tool, operational]. Every investigation run exited 1 to stderr and the learning was dropped, silently to the user. Fix: add 'investigation' to ALLOWED_TYPES. Regression test: round-trips a learning with type:"investigation" and asserts exit 0 + file write; second test reads investigate/SKILL.md.tmpl and asserts it emits the literal type:"investigation" string, guarding the template/validator contract at both ends. Fixes #1423. Reported by diogolealassis.
This commit is contained in:
parent
386fe518f9
commit
f94aef7303
|
|
@ -1,6 +1,7 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# gstack-learnings-log — append a learning to the project learnings file
|
# gstack-learnings-log — append a learning to the project learnings file
|
||||||
# Usage: gstack-learnings-log '{"skill":"review","type":"pitfall","key":"n-plus-one","insight":"...","confidence":8,"source":"observed"}'
|
# Usage: gstack-learnings-log '{"skill":"review","type":"pitfall","key":"n-plus-one","insight":"...","confidence":8,"source":"observed"}'
|
||||||
|
# Valid types: pattern, pitfall, preference, architecture, tool, operational, investigation
|
||||||
#
|
#
|
||||||
# Append-only storage. Duplicates (same key+type) are resolved at read time
|
# Append-only storage. Duplicates (same key+type) are resolved at read time
|
||||||
# by gstack-learnings-search ("latest winner" per key+type).
|
# by gstack-learnings-search ("latest winner" per key+type).
|
||||||
|
|
@ -19,7 +20,7 @@ let j;
|
||||||
try { j = JSON.parse(raw); } catch { process.stderr.write('gstack-learnings-log: invalid JSON, skipping\n'); process.exit(1); }
|
try { j = JSON.parse(raw); } catch { process.stderr.write('gstack-learnings-log: invalid JSON, skipping\n'); process.exit(1); }
|
||||||
|
|
||||||
// Field validation: type must be from allowed list
|
// Field validation: type must be from allowed list
|
||||||
const ALLOWED_TYPES = ['pattern', 'pitfall', 'preference', 'architecture', 'tool', 'operational'];
|
const ALLOWED_TYPES = ['pattern', 'pitfall', 'preference', 'architecture', 'tool', 'operational', 'investigation'];
|
||||||
if (!j.type || !ALLOWED_TYPES.includes(j.type)) {
|
if (!j.type || !ALLOWED_TYPES.includes(j.type)) {
|
||||||
process.stderr.write('gstack-learnings-log: invalid type \"' + (j.type || '') + '\", must be one of: ' + ALLOWED_TYPES.join(', ') + '\n');
|
process.stderr.write('gstack-learnings-log: invalid type \"' + (j.type || '') + '\", must be one of: ' + ALLOWED_TYPES.join(', ') + '\n');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,27 @@ describe('gstack-learnings-log', () => {
|
||||||
const lines = fs.readFileSync(f!, 'utf-8').trim().split('\n');
|
const lines = fs.readFileSync(f!, 'utf-8').trim().split('\n');
|
||||||
expect(lines.length).toBe(2);
|
expect(lines.length).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Regression test for #1423: investigate skill emits type:"investigation"
|
||||||
|
// but ALLOWED_TYPES previously rejected it. Now accepted.
|
||||||
|
test('accepts type:"investigation" (regression: #1423)', () => {
|
||||||
|
const input = '{"skill":"investigate","type":"investigation","key":"root-cause","insight":"verified","confidence":9,"source":"observed"}';
|
||||||
|
const result = runLog(input);
|
||||||
|
expect(result.exitCode).toBe(0);
|
||||||
|
const f = findLearningsFile();
|
||||||
|
expect(f).not.toBeNull();
|
||||||
|
const parsed = JSON.parse(fs.readFileSync(f!, 'utf-8').trim());
|
||||||
|
expect(parsed.type).toBe('investigation');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Caller contract: investigate/SKILL.md.tmpl must emit type:"investigation"
|
||||||
|
// verbatim. Guards against the template drifting to an invalid type and
|
||||||
|
// silently breaking the log path. See codex review finding for #1423.
|
||||||
|
test('investigate template emits type:"investigation" verbatim (caller contract)', () => {
|
||||||
|
const tmpl = fs.readFileSync(path.join(ROOT, 'investigate/SKILL.md.tmpl'), 'utf-8');
|
||||||
|
// The invocation line must include "type":"investigation" exactly.
|
||||||
|
expect(tmpl).toContain('"type":"investigation"');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('gstack-learnings-search', () => {
|
describe('gstack-learnings-search', () => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue