test: cover first-run detection + repoint browse-content assertions to /browse

- New unit tests for every detection bucket, the eval-safe enum contract, and the
  first-run gating (test/preamble-first-task-scaffold.test.ts); periodic E2E that runs
  the detector through the real harness (test/skill-e2e-first-task-scaffold.test.ts).
- Repoint browse-content assertions (gen-skill-docs, audit-compliance, skill-validation,
  LLM-judge eval) from the root skill to browse/SKILL.md following the router split;
  add a regression pinning that the router carries no browse body.
- Register first-task-scaffold touchfiles + periodic tier; bump parity/carve size caps
  ~1-2KB per skill for the shared first-run-guidance preamble section.
- Refresh ship golden fixtures for the preamble addition.
This commit is contained in:
Garry Tan
2026-06-21 07:16:24 -07:00
parent 938fa4a035
commit 866159861d
12 changed files with 438 additions and 51 deletions
+11 -8
View File
@@ -26,15 +26,18 @@ function readShipUnion(): string {
}
describe('SKILL.md command validation', () => {
test('all $B commands in SKILL.md are valid browse commands', () => {
// P2 (v1.2.0): the top-level gstack skill is a pure ROUTER, not the browse
// skill. The browse body lives only in browse/SKILL.md now. This regression
// pins the split: the router carries routing rules and zero browse commands,
// while browse/SKILL.md still advertises the full QA surface (asserted below).
test('top-level SKILL.md is a router with no browse body (P2)', () => {
const md = fs.readFileSync(path.join(ROOT, 'SKILL.md'), 'utf-8');
expect(md).not.toContain('gstack browse: QA Testing'); // browse body removed
expect(md).toContain('## Route first'); // router head present
expect(md).toContain('invoke `/investigate`'); // routing rules present
const result = validateSkill(path.join(ROOT, 'SKILL.md'));
expect(result.invalid).toHaveLength(0);
expect(result.valid.length).toBeGreaterThan(0);
});
test('all snapshot flags in SKILL.md are valid', () => {
const result = validateSkill(path.join(ROOT, 'SKILL.md'));
expect(result.snapshotFlagErrors).toHaveLength(0);
expect(result.invalid).toHaveLength(0); // no INVALID browse commands
expect(result.valid.length).toBe(0); // and no browse commands at all — it routes, not browses
});
test('all $B commands in browse/SKILL.md are valid browse commands', () => {