mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-13 23:25:18 +00:00
133 lines
6.6 KiB
TypeScript
133 lines
6.6 KiB
TypeScript
import { existsSync, readFileSync } from 'node:fs'
|
||
import { resolve } from 'node:path'
|
||
import { describe, expect, it } from 'vitest'
|
||
|
||
// C218 — pins the incremental catalog skill contract: the single new state
|
||
// file (watermark + pending + review), the dated discovery artifact written by
|
||
// the subagent, the batch handoff to the C215 ingestion CLI, the curation
|
||
// modes and the receipt. The whole flow is prompt text (SKILL.md + agent), so
|
||
// this guard fails the build if a contract literal is dropped or if the
|
||
// subagent regains the ingestion/download role it must not have.
|
||
|
||
const repoRoot = process.cwd()
|
||
|
||
const read = (path: string): string => readFileSync(resolve(repoRoot, path), 'utf8')
|
||
|
||
const skill = read('.agents/skills/catalogo-falas-web/SKILL.md')
|
||
const agent = read('.opencode/agent/catalogo-falas-web.md')
|
||
|
||
describe('command /catalogo-falas-web couples to the canonical skill', () => {
|
||
it('ships the thin wrapper pointing at the SKILL.md', () => {
|
||
const command = read('.opencode/commands/catalogo-falas-web.md')
|
||
expect(existsSync(resolve(repoRoot, '.agents/skills/catalogo-falas-web/SKILL.md'))).toBe(true)
|
||
expect(command).toContain('`catalogo-falas-web`')
|
||
expect(command).toContain('$ARGUMENTS')
|
||
expect(command).toContain('.agents/skills/catalogo-falas-web/SKILL.md')
|
||
expect(command).toMatch(/^description: .+$/m)
|
||
expect(command).not.toMatch(/^\s*["']?model["']?\s*:/m)
|
||
})
|
||
})
|
||
|
||
describe('skill /catalogo-falas-web documents the incremental pipeline', () => {
|
||
it('pins the single new state file and its fail-closed read', () => {
|
||
expect(skill).toContain('## Contrato do estado')
|
||
expect(skill).toContain('data/falas-web/last-run.json')
|
||
for (const field of ['lastRunAt', 'lastStateAt', 'pending', 'review']) {
|
||
expect(skill, `state contract must carry ${field}`).toContain(field)
|
||
}
|
||
expect(skill, 'the watermark is the discovery window end').toMatch(
|
||
/`lastRunAt` é o `window\.to` da descoberta/,
|
||
)
|
||
expect(skill, 'state lives in a gitignored path').toContain('gitignored')
|
||
expect(skill, 'state write must be atomic').toMatch(/escrita atômica/i)
|
||
expect(skill, 'corrupt state stops the run').toMatch(/fail-closed/)
|
||
})
|
||
|
||
it('pins the dated discovery artifact written by the one writer', () => {
|
||
expect(skill).toContain('## Contrato do artefato de descoberta')
|
||
expect(skill).toContain('data/falas-web/discovery-<stamp>.json')
|
||
for (const field of ['generatedAt', 'window', 'queries', 'findings', 'review', 'notes']) {
|
||
expect(skill, `artifact contract must carry ${field}`).toContain(field)
|
||
}
|
||
expect(skill, 'initial scan runs without a watermark').toContain('varredura inicial')
|
||
expect(skill, 'failed discovery writes no partial artifact').toMatch(
|
||
/não escreve artefato parcial/,
|
||
)
|
||
})
|
||
|
||
it('hands the batch to the C215 ingestion CLI and reads its report', () => {
|
||
expect(skill).toContain('pnpm falas-web:import --findings')
|
||
expect(skill, 'the batch carries the exact C215 envelope').toContain(
|
||
'{ generatedAt, findings }',
|
||
)
|
||
expect(skill, 'the batch is the handoff artifact').toContain('batch-<stamp>.json')
|
||
expect(skill, 'planning runs read-only first').toContain('Planejar (obrigatório)')
|
||
expect(skill, 'planning runs read-only first').toContain('--dry-run')
|
||
expect(skill, 'the report is the source of the receipt').toContain('data/falas-web/reports/')
|
||
expect(skill, 'invalid/duplicates stop the ingestion').toMatch(/invalid > 0/)
|
||
expect(skill, 'invalid/duplicates stop the ingestion').toMatch(/duplicates > 0/)
|
||
expect(skill, 'invalid/duplicates keep the watermark').toMatch(/não avance o watermark/)
|
||
expect(skill, 'empty batch skips the CLI').toMatch(/pule o CLI/)
|
||
})
|
||
})
|
||
|
||
describe('curation, watermark and retry', () => {
|
||
it('documents the review modes without discovery or ingestion side effects', () => {
|
||
for (const mode of ['revisar', 'aprovar', 'descartar']) {
|
||
expect(skill, `mode ${mode} must be documented`).toContain(mode)
|
||
}
|
||
expect(skill, 'doubtful findings are not ingested before confirmation').toMatch(
|
||
/não é ingerido até confirmação/,
|
||
)
|
||
expect(skill, 'curation demotes to the state review list').toMatch(/não inclua\s+no lote/)
|
||
expect(skill, 'approval does not move the watermark').toMatch(/`lastRunAt` \*\*não\*\* muda/)
|
||
})
|
||
|
||
it('pins the watermark semantics and the pending retry', () => {
|
||
expect(skill).toContain('Exit 0')
|
||
expect(skill).toContain('Exit 1')
|
||
expect(skill, 'exit 1 must not advance the window').toMatch(/`lastRunAt` \*\*não\*\* avança/)
|
||
expect(skill, 'retries carry the attempt count').toContain('attempts')
|
||
expect(skill, 'pending is retried first').toMatch(/vão primeiro no próximo lote/)
|
||
expect(skill, 'the --limit tail stays in the batch').toMatch(/restam M−N achados no lote/)
|
||
})
|
||
|
||
it('pins the literal receipt', () => {
|
||
expect(skill).toContain('## Recibo (literal)')
|
||
expect(skill).toContain('[catalogo-falas-web] período:')
|
||
for (const field of ['achados:', 'novos:', 'ignorados:', 'falhas:', 'custo/tempo:']) {
|
||
expect(skill, `receipt must declare ${field}`).toContain(field)
|
||
}
|
||
})
|
||
})
|
||
|
||
describe('skill frontier and subagent role', () => {
|
||
it('forbids a second ingestion pipeline inside the skill', () => {
|
||
expect(skill, 'no media download').toMatch(/Não baixa mídia/)
|
||
expect(skill, 'no transcription').toContain('não transcreve')
|
||
expect(skill, 'no facet classification').toContain('não classifica facetas')
|
||
expect(skill, 'no own dedupe').toMatch(/não faz\s+dedupe própria/)
|
||
expect(skill, 'never exports the C215 write confirm flag').toMatch(
|
||
/Nunca exporta `FALAS_WEB_IMPORT_CONFIRM`/,
|
||
)
|
||
expect(skill, 'never exports the C215 write confirm flag').not.toMatch(
|
||
/export\s+FALAS_WEB_IMPORT_CONFIRM/,
|
||
)
|
||
})
|
||
|
||
it('keeps the subagent discovery-only', () => {
|
||
expect(agent).toMatch(/^---\n[\s\S]*mode: subagent[\s\S]*\n---/)
|
||
expect(agent).not.toMatch(/^\s*["']?model["']?\s*:/m)
|
||
expect(agent).toContain('discovery-<stamp>.json')
|
||
expect(agent).toContain('Recibo da descoberta')
|
||
expect(agent, 'subagent must not run the ingestion CLI').not.toContain('--findings')
|
||
expect(agent, 'subagent must not write the lote/state').toContain(
|
||
'nem o estado (`last-run.json`)',
|
||
)
|
||
expect(agent, 'radio/audio requires the direct media URL').toContain('mediaUrl')
|
||
for (const field of ['artifactPath', 'findingsCount', 'reviewCount', 'byPlatform']) {
|
||
expect(agent, `receipt must carry ${field}`).toContain(field)
|
||
}
|
||
expect(agent, 'subagent never reads the catalog DB').toMatch(/Não\*\* leia o banco/)
|
||
})
|
||
})
|