Require two materials for content schedules and scope readiness copy
The engine plans each production piece from a pair of documents, so a summary, quiz or similar schedule with one material can never plan. Approving such a plan is now blocked with a note to choose or upload another material, and the engine's refusal on an existing schedule is explained in plain language. Video and research schedules still work with one material. The engine now checks only a schedule's own material before a run, so the run error and Upload texts no longer say the whole Library or Brain is checked. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import type { ContentRule, ResearchRule } from './parse'
|
||||
import { budgetFor, canSchedule, configFor, ruleOf, VIDEO, type ExpressAgent } from './schedules'
|
||||
import { budgetFor, canSchedule, configFor, needsTwoSources, productionError, ruleOf, VIDEO, type ExpressAgent } from './schedules'
|
||||
|
||||
const rule = (kind: ContentRule['kind'], count = 2, per: ContentRule['per'] = 'week', topic = 'onboarding', language: ContentRule['language'] = 'English'): ContentRule =>
|
||||
({ type: 'content', kind, count, per, topic, language })
|
||||
@@ -108,3 +108,17 @@ describe('canSchedule', () => {
|
||||
expect(canSchedule(rule('summary', 0))).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('production sources', () => {
|
||||
it('needs two sources for planned content, not for video or research', () => {
|
||||
expect(needsTwoSources(rule('quiz'))).toBe(true)
|
||||
expect(needsTwoSources(rule('video', 1))).toBe(false)
|
||||
expect(needsTwoSources({ type: 'research', cadence: 'weekly', weekday: 2, topic: 'sales', autoApprove: false })).toBe(false)
|
||||
})
|
||||
|
||||
it("explains the engine's refusal for too few sources and passes others through", () => {
|
||||
expect(productionError('At least two ready sources with complementary evidence are required')).toMatch(/2/)
|
||||
expect(productionError('At least two ready sources with complementary evidence are required')).not.toMatch(/complementary/)
|
||||
expect(productionError('Something else')).toBe('Something else')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// use run_schedule (one run per day or week; a video run renders one video).
|
||||
import { opKey, request } from '../api/client'
|
||||
import { listDocuments, type Agent, type RunSchedule } from '../api/engine'
|
||||
import { getLang } from '../i18n'
|
||||
import { getLang, t } from '../i18n'
|
||||
import {
|
||||
KINDS, LANGUAGES, SCHEDULABLE, videoCadence, weeklyTarget,
|
||||
type ContentKind, type ContentRule, type OutputLanguage, type Per, type ResearchRule, type Rule,
|
||||
@@ -110,6 +110,15 @@ export const listSchedules = () => expressAgents()
|
||||
/** Schedules made of one engine run per slot (research, video), rather than weekly production plans. */
|
||||
export const isRunSchedule = (rule: Rule) => rule.type === 'research' || rule.kind === 'video'
|
||||
|
||||
// The engine plans each production piece from a pair of documents, so a content schedule
|
||||
// with fewer ready sources than this cannot plan anything. Video and research runs need one.
|
||||
export const MIN_PRODUCTION_SOURCES = 2
|
||||
export const needsTwoSources = (rule: Rule) => !isRunSchedule(rule)
|
||||
const TOO_FEW_SOURCES = 'At least two ready sources with complementary evidence are required'
|
||||
/** The engine's planner refusal, said in the UI language; any other message as it came. */
|
||||
export const productionError = (message: string) =>
|
||||
(message.includes(TOO_FEW_SOURCES) ? t('sch.tooFewSources', { n: MIN_PRODUCTION_SOURCES }) : message)
|
||||
|
||||
// Video length is fixed per schedule: 4 scenes, 40 seconds in all (the engine allows 4–15 s per scene).
|
||||
export const VIDEO = { scenes: 4, seconds: 40 }
|
||||
|
||||
@@ -362,8 +371,8 @@ export interface RunSummary {
|
||||
|
||||
export const listRuns = (id: number) => request<RunSummary[]>(`${AGENTS}/${id}/runs`)
|
||||
|
||||
// What stops a run with knowledge_not_ready. The engine checks the whole Library, so a blocking
|
||||
// document need not be part of the schedule's chosen material. This is the current state, not the run's.
|
||||
// What stops a run with knowledge_not_ready: the schedule's own material that is not ready (the whole
|
||||
// Library only for an agent with no material). This is the current state, not the run's.
|
||||
export interface ReadinessIssue {
|
||||
kind: 'document' | 'compose_set'
|
||||
resource_id: number
|
||||
|
||||
Reference in New Issue
Block a user