mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-08 17:58:13 +01:00
feat(hooks): an early exit (STATUS: BLOCKED, Nothing to review) meets the contract (GST-1088 lane A)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
c19a685950
commit
e49c9bee65
4 files changed
+33
-7
No files matched your search
@@ -96,6 +96,12 @@ describe('block once, with the pinned text', () => {
|
||||
expect((Object.values(record().runs)[0] as any).outcome).toBe('met');
|
||||
});
|
||||
|
||||
test('an /investigate run that ends with Status: BLOCKED in its DEBUG REPORT is met, not blocked', () => {
|
||||
const file = transcript([...J1_TRANSCRIPT.slice(0, -1), say(DEBUG_REPORT.replace('Status: DONE', 'Status: BLOCKED'))]);
|
||||
expect(stop(file)).toEqual({ code: 0, stdout: '', stderr: '' });
|
||||
expect((Object.values(record().runs)[0] as any).outcome).toBe('met');
|
||||
});
|
||||
|
||||
test('a met run stays met: a later unrelated edit turn in the same session is not blocked', () => {
|
||||
const file = transcript([...J1_TRANSCRIPT.slice(0, -1), tool('b9', 'Bash', { command: 'bun test' }), result('b9', 'pass'), say(DEBUG_REPORT)]);
|
||||
expect(stop(file).stdout).toBe('');
|
||||
|
||||
@@ -114,7 +114,7 @@ describe('checkContract is a pure function of the transcript', () => {
|
||||
expect(check([slash('review'), sm, ...red, report], 'review').items[0].detail).toBe('selected State Machines; no Agent dispatch for State Machines');
|
||||
expect(check([slash('review'), sm, ...agent('s', 'State Machines specialist'), ...red, report], 'review').met).toBe(true);
|
||||
expect(check([slash('review'), say('Dispatching 2\nspecialists: Testing, Security'), ...red, report], 'review').items[0].detail).toBe('selected Testing, Security; no Agent dispatch for Testing, Security');
|
||||
expect(DEFAULT_MATCHERS).toEqual({ specialistSelection: 'Dispatching N specialists:', specialistsSkipped: 'specialists skipped' });
|
||||
expect(DEFAULT_MATCHERS).toEqual({ specialistSelection: 'Dispatching N specialists:', specialistsSkipped: 'specialists skipped', earlyExit: 'Nothing to review' });
|
||||
expect(check([slash('review'), ...red, report], 'review').items[0].detail).toBe('no specialist selection line found');
|
||||
const fixedLine = say('Dispatching adversarial pass: native');
|
||||
expect(check([slash('review'), fixedLine, ...agent('d', 'Adversarial pass', 'Find the ways this diff fails.')], 'review').items[1]).toMatchObject({ status: 'met', detail: 'printed "Dispatching adversarial pass: native", then an Agent dispatch' });
|
||||
@@ -151,6 +151,18 @@ describe('checkContract is a pure function of the transcript', () => {
|
||||
expect(r.missing).toEqual(['debug-report', 'repro-after-fix']);
|
||||
});
|
||||
|
||||
test('an early exit counts as met: /review "Nothing to review" or STATUS: BLOCKED, /investigate Status: BLOCKED in its DEBUG REPORT', () => {
|
||||
const early = (lines: string[], skill: string) => check(lines, skill);
|
||||
const nothing = early([slash('review'), say('Nothing to review — no changes against the base branch.')], 'review');
|
||||
expect(nothing).toMatchObject({ met: true, follow: true, missing: [] });
|
||||
expect(nothing.items[0].detail).toBe('the skill ended the run early (Nothing to review)');
|
||||
expect(early([slash('review'), say('Base branch could not be found.\nSTATUS: BLOCKED')], 'review').met).toBe(true);
|
||||
const blockedReport = DEBUG_REPORT.replace('Status: DONE', 'Status: BLOCKED');
|
||||
expect(early([...J1_TRANSCRIPT.slice(0, -1), say(blockedReport)], 'investigate')).toMatchObject({ met: true, statusLine: 'BLOCKED' });
|
||||
expect(early([...J1_TRANSCRIPT.slice(0, -1), say(DEBUG_REPORT)], 'investigate').missing).toEqual(['repro-after-fix']);
|
||||
expect(early([slash('review'), say('I would print STATUS: BLOCKED if the base were missing, but it is here. Done.')], 'review').met).toBe(false);
|
||||
});
|
||||
|
||||
test('a Read of a SKILL.md counts as a load only under a skills/ directory, not in a gstack checkout', () => {
|
||||
const loads = (file_path: string) => skillLoads(parseTranscript(tool('r', 'Read', { file_path }))).map(l => l.skill);
|
||||
expect(loads('/home/u/.claude/skills/gstack/investigate/SKILL.md')).toEqual(['investigate']);
|
||||
|
||||
Reference in new issue
Block a user