fix(tool-todo): reject unknown item keys instead of silently dropping them
An item carrying keys beyond content/status (ids, children, priority) was
flattened to {content, status} on append, so the logged snapshot diverged
from what the model believed it wrote (model-visible must equal logged).
Reject loudly; the isError result lets the model self-correct.
This commit is contained in:
@@ -28,14 +28,21 @@ const DESCRIPTION =
|
||||
|
||||
/**
|
||||
* Validate the value constraints the ParameterSchemaSpec can't express and build the canonical {@link
|
||||
* TodoItem}[]: trimmed non-empty unique content and at most one in-progress item. The registry
|
||||
* has already enforced the status enum; the cast below records that guarantee.
|
||||
* TodoItem}[]: known keys only, trimmed non-empty unique content, and at most one in-progress
|
||||
* item. The registry has already enforced the status enum; the cast below records that
|
||||
* guarantee. Unknown keys are rejected rather than dropped — the logged snapshot must equal
|
||||
* what the model believes it wrote (model-visible ⟺ logged), so a nested/extended item shape
|
||||
* fails loud instead of silently flattening.
|
||||
*/
|
||||
function toTodoList(raw: { content: string; status: string }[]): TodoItem[] {
|
||||
const todos: TodoItem[] = []
|
||||
const seen = new Set<string>()
|
||||
let inProgress = 0
|
||||
for (const item of raw) {
|
||||
const unknown = Object.keys(item).filter(key => key !== 'content' && key !== 'status')
|
||||
if (unknown.length > 0) {
|
||||
throw new Error(`invalid todo: unknown key(s) ${unknown.map(k => JSON.stringify(k)).join(', ')} — each item is exactly { content, status }`)
|
||||
}
|
||||
const content = item.content.trim()
|
||||
if (content.length === 0) {
|
||||
throw new Error('invalid todo: `content` must be a non-empty string')
|
||||
|
||||
Reference in New Issue
Block a user