mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-14 08:53:11 +00:00
Register com --plan nasce blocked (não claimável); pnpm agent:ready promove após o plano em main. Gate da skill plan-issue endurecido. Co-authored-by: Francisco Solla <fsolla@users.noreply.github.com>
89 lines
2.5 KiB
TypeScript
89 lines
2.5 KiB
TypeScript
// @vitest-environment node
|
|
|
|
import { describe, expect, it } from 'vitest'
|
|
|
|
import {
|
|
canPromotePlanIssue,
|
|
resolveRegisterStateLabel,
|
|
} from '../../scripts/lib/agent-plan-lifecycle.mjs'
|
|
|
|
type TestIssue = {
|
|
number: number
|
|
title: string
|
|
body: string
|
|
state: string
|
|
labels: Array<{ name: string }>
|
|
}
|
|
|
|
const issue = (over: Partial<TestIssue> = {}): TestIssue => ({
|
|
number: 1,
|
|
title: 'Issue de teste',
|
|
body: 'Plano: [`docs/plans/x.md`](docs/plans/x.md)',
|
|
state: 'OPEN',
|
|
labels: [{ name: 'blocked' }, { name: 'prio:P2' }],
|
|
...over,
|
|
})
|
|
|
|
describe('resolveRegisterStateLabel', () => {
|
|
it('keeps chores without a plan as ready', () => {
|
|
expect(resolveRegisterStateLabel({ hasPlan: false })).toBe('ready')
|
|
})
|
|
|
|
it('starts plan-linked issues as blocked (OPS17)', () => {
|
|
expect(resolveRegisterStateLabel({ hasPlan: true })).toBe('blocked')
|
|
})
|
|
|
|
it('honors explicit --blocked even without a plan', () => {
|
|
expect(resolveRegisterStateLabel({ hasPlan: false, explicitBlocked: true })).toBe('blocked')
|
|
})
|
|
|
|
it('stays blocked when both --plan and --blocked are set', () => {
|
|
expect(resolveRegisterStateLabel({ hasPlan: true, explicitBlocked: true })).toBe('blocked')
|
|
})
|
|
})
|
|
|
|
describe('canPromotePlanIssue', () => {
|
|
it('accepts an open blocked issue with a docs/plans/ link', () => {
|
|
expect(canPromotePlanIssue(issue())).toEqual({ ok: true })
|
|
})
|
|
|
|
it('rejects closed issues', () => {
|
|
expect(canPromotePlanIssue(issue({ state: 'CLOSED' }))).toEqual({
|
|
ok: false,
|
|
reason: 'not-open',
|
|
})
|
|
})
|
|
|
|
it('rejects issues that are not blocked', () => {
|
|
expect(canPromotePlanIssue(issue({ labels: [{ name: 'ready' }] }))).toEqual({
|
|
ok: false,
|
|
reason: 'not-blocked',
|
|
})
|
|
})
|
|
|
|
it.each(['in-progress', 'done', 'in-prod'])(
|
|
'rejects when %s coexists with blocked',
|
|
(stateLabel) => {
|
|
expect(
|
|
canPromotePlanIssue(issue({ labels: [{ name: 'blocked' }, { name: stateLabel }] })),
|
|
).toEqual({ ok: false, reason: 'state-label' })
|
|
},
|
|
)
|
|
|
|
it('rejects human-gated blocked issues even when they link a plan', () => {
|
|
expect(
|
|
canPromotePlanIssue(
|
|
issue({
|
|
labels: [{ name: 'blocked' }, { name: 'needs:consent' }],
|
|
}),
|
|
),
|
|
).toEqual({ ok: false, reason: 'needs-human' })
|
|
})
|
|
|
|
it('rejects blocked issues without a plan link (product block, not awaiting plan)', () => {
|
|
expect(canPromotePlanIssue(issue({ body: 'bloqueio jurídico' }))).toEqual({
|
|
ok: false,
|
|
reason: 'no-plan-link',
|
|
})
|
|
})
|
|
})
|