import type { GoalTodoRandomBytes } from "./ids.js"; import type { GoalTodoNode, GoalTodoOwner, GoalTodoPriority, GoalTodoStatus, Result } from "./types.js"; import type { GoalTodoRejectionCode, GoalTodoRetryPolicy } from "./transition.js"; /** Statuses that keep a required TODO from counting as closed (zob mirror). */ export declare const OPEN_REQUIRED_STATUSES: ReadonlySet; /** Statuses counted as active work (zob mirror). */ export declare const ACTIVE_STATUSES: ReadonlySet; /** Statuses a user/agent can still act on (zob mirror). */ export declare const ACTIONABLE_STATUSES: ReadonlySet; /** Bounds for tree shape; mirrors zob maxTodoDepth/maxChildrenPerTodo/maxOpenTodos. */ export interface TreePolicy { /** Maximum root-to-leaf chain length (root nodes are depth 1). */ maxDepth: number; /** Maximum children per parent — applied uniformly, root level included (D-T2). */ maxFanout: number; /** Maximum items accepted by one batch add. */ maxBatch: number; } /** zob defaultGoalTodoPolicy caps: 6 / 8 / 80. */ export declare const DEFAULT_TREE_POLICY: Readonly; /** Fill a partial policy with safe zob-derived defaults; invalid values fall back. */ export declare function normalizeTreePolicy(policy?: Partial): TreePolicy; export type TreeOpErrorCode = "invalid_title" | "empty_batch" | "batch_too_large" | "parent_not_found" | "todo_not_found" | "depth_exceeded" | "fanout_exceeded" | "split_titles_required" | "status_change_forbidden" | "field_not_patchable" | "id_collision" | "transition_rejected"; export interface TreeOpError { readonly code: TreeOpErrorCode; readonly message: string; /** Phase 2b rejection detail when code is transition_rejected. */ readonly transition?: { readonly code: GoalTodoRejectionCode; readonly retryPolicy: GoalTodoRetryPolicy; }; } export interface TreeOpSuccess { /** The full NEW node array; unchanged no-ops return the input reference. */ readonly nodes: readonly GoalTodoNode[]; /** False only for verified no-op metadata patches. */ readonly changed: boolean; /** Nodes created by add/split ops, in creation order. */ readonly created?: readonly GoalTodoNode[]; /** The single node updated by update/reopen ops. */ readonly updated?: GoalTodoNode; } export type TreeOpResult = Result; export interface AddGoalTodoNodeInput { title: string; status?: GoalTodoStatus; owner?: GoalTodoOwner; /** zob semantics: required !== false → true. */ required?: boolean; priority?: GoalTodoPriority; acceptanceCriteria?: string[]; evidenceRefs?: string[]; validationCommands?: string[]; } export interface AddGoalTodoNodeOptions { parentId?: string; input: AddGoalTodoNodeInput; policy?: TreePolicy; randomBytes: GoalTodoRandomBytes; now: number; } /** * Add one TODO node. Enforces depth <= policy.maxDepth and sibling count * <= policy.maxFanout (root level included, D-T2); ids come from the * injected random source, timestamps from the injected clock. */ export declare function addGoalTodoNode(nodes: readonly GoalTodoNode[], options: AddGoalTodoNodeOptions): TreeOpResult; export interface AddGoalTodoNodeItem { parentId?: string; input: AddGoalTodoNodeInput; } export interface AddGoalTodoNodesOptions { items: readonly AddGoalTodoNodeItem[]; policy?: TreePolicy; randomBytes: GoalTodoRandomBytes; now: number; } /** * Add multiple TODO nodes in one atomic operation: items apply sequentially * (so paths continue each parent's numbering in input order) and ANY failure * fails the whole batch, leaving the caller's nodes untouched (D-T1). */ export declare function addGoalTodoNodes(nodes: readonly GoalTodoNode[], options: AddGoalTodoNodesOptions): TreeOpResult; export interface GoalTodoNodeMetadataPatch { title?: string; priority?: GoalTodoPriority; owner?: GoalTodoOwner; required?: boolean; acceptanceCriteria?: string[]; evidenceRefs?: string[]; validationCommands?: string[]; } /** * Patch title/priority/owner/required/acceptanceCriteria/evidenceRefs/ * validationCommands. NEVER status — that belongs to the Phase 2b transition * engine (reopenGoalTodoNode is this module's only status-changing op). * Verified no-op patches return changed=false with the input array reference. */ export declare function updateGoalTodoNodeMetadata(nodes: readonly GoalTodoNode[], id: string, patch: GoalTodoNodeMetadataPatch, options: { now: number; }): TreeOpResult; export interface SplitGoalTodoNodeOptions { policy?: TreePolicy; randomBytes: GoalTodoRandomBytes; now: number; } /** * Split one TODO into subtodos: titles are trimmed, blanks dropped, and the * children are APPENDED after any existing siblings (paths continue the * parent's numbering). Children inherit zob split defaults: required=true, * priority from the parent, owner=agent, status=planned. Bounded by * maxFanout (existing + new) and maxDepth (parent depth + 1). D-T4: the * parent's status is not re-authorized here. */ export declare function splitGoalTodoNode(nodes: readonly GoalTodoNode[], id: string, titles: readonly string[], options: SplitGoalTodoNodeOptions): TreeOpResult; export interface ReopenGoalTodoNodeOptions { reason: string; now: number; } /** * Integration hook: authorize+apply the reopen through the Phase 2b * transition engine, then swap only status/updatedAt. Paths and every other * field stay stable. Rejections surface as transition_rejected with the * engine's code and retry policy. */ export declare function reopenGoalTodoNode(nodes: readonly GoalTodoNode[], id: string, options: ReopenGoalTodoNodeOptions): TreeOpResult; export interface GoalTodoSummaryNodeRef { readonly id: string; readonly path: string; readonly title: string; readonly status: GoalTodoStatus; readonly owner: GoalTodoOwner; readonly priority: GoalTodoPriority; readonly required: boolean; } export interface GoalTodoSummary { readonly total: number; readonly required: number; readonly done: number; readonly skipped: number; /** Open = status in OPEN_REQUIRED_STATUSES (zob counts by status, not required flag). */ readonly open: number; readonly perStatus: Readonly>; readonly active: number; readonly inProgress: number; readonly delegated: number; readonly claimReturned: number; readonly blocked: readonly GoalTodoSummaryNodeRef[]; readonly nextActionableTodo?: GoalTodoSummaryNodeRef; readonly maxDepth: number; /** Closed fraction: (done + skipped) / total; 0 for an empty tree. */ readonly progress: number; } /** * zob-compatible progress summary: total/required/done/skipped/open counts, * per-status counts, active/in_progress/delegated/claim counters, the blocked * list, the next actionable TODO (zob nextAgent rule with nextUser fallback), * max depth, and the closed fraction. */ export declare function summarizeGoalTodos(nodes: readonly GoalTodoNode[]): GoalTodoSummary; export type GoalTodoGraphIssueCode = "duplicate_id" | "missing_parent" | "parent_cycle" | "depth_exceeded" | "fanout_exceeded"; export interface GoalTodoGraphIssue { readonly todoId: string; readonly path: string; readonly code: GoalTodoGraphIssueCode; readonly message: string; } /** * Pure structural validation over the node array (zob validateGoalTodoGraph, // adapted to the depth-free node shape): duplicate ids, missing parents, * parent-chain cycles, path depth beyond maxDepth, and per-todo fanout * beyond maxFanout (root-level breadth is not a per-todo issue, mirroring * zob; mutation-time guards still cap it via D-T2). */ export declare function validateGoalTodoGraph(nodes: readonly GoalTodoNode[], policy?: TreePolicy): readonly GoalTodoGraphIssue[];