teqo-backup/tests/unit/briefingSkill.unit.spec.ts

94 lines
4.1 KiB
TypeScript

import { existsSync, readFileSync } from 'node:fs'
import { resolve } from 'node:path'
import { describe, expect, it } from 'vitest'
// C210: the briefing skill, the command and the author subagent are prompt
// text, so the product contract (label, 4-page cap, vote literal, anchor
// fail-closed, no second research) lives in the SKILL.md prose. This guard
// fails the build if the flow, the guardrails or the CLI contract are dropped.
const repoRoot = process.cwd()
const read = (path: string): string => readFileSync(resolve(repoRoot, path), 'utf8')
const skill = read('.agents/skills/briefing-capacitacao-solla/SKILL.md')
const agent = read('.opencode/agent/briefing-capacitacao-solla.md')
const command = read('.opencode/commands/briefing-capacitacao-solla.md')
describe('skill /briefing-capacitacao-solla documents the flow', () => {
it('declares when to use it, the batch selector and the integration', () => {
expect(skill).toContain('## Quando usar')
expect(skill).toContain('## Lote (recortes)')
expect(skill).toContain('cidade:')
expect(skill).toContain('instituicao:')
expect(skill).toContain('tema:')
expect(skill).toContain('/dossie-solla-cidade')
expect(skill).toMatch(/3º entregável/)
})
it('pins the canonical builder CLI and the gitignored artifacts', () => {
expect(skill).toContain('node scripts/build-dossie-solla-briefing.mjs')
expect(skill).toContain('--unit=')
expect(skill).toContain('data/dossie-solla-')
expect(skill).toContain('docs/research/dossie-solla-')
expect(skill).toContain('gitignored')
})
it('pins the hard product literals', () => {
expect(skill).toContain('Insumo interno de capacitação — não publicar')
expect(skill).toContain('vote 1313')
expect(skill).toMatch(/4 páginas/)
expect(skill).toContain('insumo interno')
expect(skill).toMatch(/sem CTA público/i)
})
it('pins the fail-closed content contract', () => {
expect(skill).toContain('## Contrato do')
expect(skill).toContain('factId')
expect(skill).toContain('gapReason')
expect(skill).toContain('estimatedVotes')
expect(skill).toMatch(/sem fonte, o item não entra/i)
expect(skill).toMatch(/dois lados/)
})
it('pins the hard four-page cap with declared shed and the .md superset', () => {
expect(skill).toMatch(/teto de \*\*4 páginas é rígido\*\*/)
expect(skill).toMatch(/corta por\s+prioridade/)
expect(skill).toContain('no briefing completo (.md)')
expect(skill).toMatch(/nunca\*\* são cortados/)
})
it('pins the offline guardrail: no second factual research', () => {
expect(skill).toMatch(/sem segunda pesquisa factual/i)
expect(skill).toMatch(/nunca faz segunda pesquisa factual/i)
})
})
describe('author subagent is writer-only (briefing.json)', () => {
it('stays a subagent that writes the briefing.json and returns the receipt', () => {
expect(agent).toMatch(/^---\n[\s\S]*mode: subagent[\s\S]*\n---/)
expect(agent).toContain('.briefing.json')
expect(agent).toContain('Recibo do autor')
const frontmatter = agent.match(/^---\n([\s\S]*?)\n---/)
expect(frontmatter, 'agent frontmatter must be delimited by ---').not.toBeNull()
expect(frontmatter![1]).not.toMatch(/^\s*["']?model["']?\s*:/m)
})
it('does not run the deterministic build or a new web research', () => {
expect(agent, 'author must not run the builder CLI').not.toContain('--snapshot=')
expect(agent, 'author must not do new web research').toMatch(/não\*\* faça pesquisa web/i)
expect(agent, 'author must not edit the research files').toMatch(/não\*\* edite os/)
})
})
describe('command /briefing-capacitacao-solla couples to the skill', () => {
it('references the canonical skill file and passes arguments', () => {
expect(existsSync(resolve(repoRoot, '.opencode/commands/briefing-capacitacao-solla.md'))).toBe(
true,
)
expect(command).toContain('`briefing-capacitacao-solla`')
expect(command).toContain('$ARGUMENTS')
expect(command).toContain('.agents/skills/briefing-capacitacao-solla/SKILL.md')
expect(command).toContain('insumo interno')
})
})