@paigy/mcp 0.40.27 → 0.40.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  // ../../packages/schema/dist/index.js
2
- import { z as z7 } from "zod";
2
+ import { z as z9 } from "zod";
3
3
  import { z } from "zod";
4
4
  import { z as z3 } from "zod";
5
5
  import { zodToJsonSchema } from "zod-to-json-schema";
@@ -10,12 +10,18 @@ import { z as z5 } from "zod";
10
10
  import { zodToJsonSchema as zodToJsonSchema3 } from "zod-to-json-schema";
11
11
  import { z as z6 } from "zod";
12
12
  import { zodToJsonSchema as zodToJsonSchema4 } from "zod-to-json-schema";
13
+ import { z as z7 } from "zod";
14
+ import { zodToJsonSchema as zodToJsonSchema5 } from "zod-to-json-schema";
15
+ import { z as z8 } from "zod";
16
+ import { zodToJsonSchema as zodToJsonSchema6 } from "zod-to-json-schema";
13
17
  var OPTIONS_MIN = 2;
14
18
  var OPTIONS_MAX = 6;
19
+ var OPTION_LABEL_MAX = 50;
20
+ var OPTION_HINT_MAX = 200;
15
21
  var OptionSchema = z.object({
16
22
  id: z.string(),
17
23
  label: z.string(),
18
- hint: z.string().max(500).describe("Optional short projection of consequence or action if this option is chosen (e.g. 'Reruns test suite', 'Merges to main').").optional(),
24
+ hint: z.string().max(500).describe(`Optional: what choosing it does, at most ${OPTION_HINT_MAX} characters (e.g. 'Reruns test suite', 'Merges to main').`).optional(),
19
25
  // .describe() flows into the MCP contact JSON schema (zodToJsonSchema), so
20
26
  // the constraints below are what an agent reads when deciding to use these.
21
27
  html: z.string().max(16384).describe(
@@ -29,8 +35,10 @@ var OptionInputSchema = z.object({
29
35
  id: z.string().trim().min(1).max(64).regex(/^[A-Za-z0-9_.:-]+$/).optional().describe(
30
36
  `Optional: this option's own id, which answers name it by (selectedOptionIds). Give every option one, or none: without them the options are numbered "1", "2", \u2026 in order.`
31
37
  ),
32
- label: z.string().trim().min(1).max(1e3),
33
- hint: OptionSchema.shape.hint,
38
+ // SHORT CHOICES (owner, 2026-10-07: "options label should be maybe max 50 characters and the hint 200"):
39
+ // a label is one choice the person reads, or hears on a call; a hint says its consequence in a line.
40
+ label: z.string().trim().min(1).max(OPTION_LABEL_MAX, `option_label_too_long: an option's label is at most ${OPTION_LABEL_MAX} characters; say the choice, and put its consequence in the hint.`).describe(`The choice, at most ${OPTION_LABEL_MAX} characters, standing on its own.`),
41
+ hint: z.string().max(OPTION_HINT_MAX, `option_hint_too_long: an option's hint is at most ${OPTION_HINT_MAX} characters.`).describe(`Optional: what choosing it does, at most ${OPTION_HINT_MAX} characters (e.g. 'Reruns test suite', 'Merges to main').`).optional(),
34
42
  htmlPreview: OptionSchema.shape.html,
35
43
  imgUrl: OptionSchema.shape.image
36
44
  }).strict();
@@ -132,15 +140,48 @@ var UpdateInputSchema = z2.object({
132
140
  message: z2.string().trim().min(1).describe(`The one point, at most ${ASK_MAX} characters; the context goes in units.`),
133
141
  goalIds: z2.array(z2.string().uuid()).min(1).max(10).describe("The Goals it is about, each one that exists: the one it is mainly about first."),
134
142
  units,
143
+ // A REPORT KEEPS ITS TAP (#2799, #3260; owner, 2026-10-08, settling #2776: "keep the reports open
144
+ // until the user acknowledges them"). A report asks nothing, so it opens no Question -- but it
145
+ // still waits to be acknowledged, and it carries the ONE tap that closes it. Never a decision: the
146
+ // tap lands as a contribution, the person's own words on the Goal, because there is no Question
147
+ // for it to answer.
148
+ //
149
+ // AND ITS WORDS ARE WRITTEN FOR THIS REPORT (owner, 2026-10-08, Goal 3c12d3c6: "Agent
150
+ // acknowledgments vary (e.g. 'sounds good, I will test later') instead of always 'got it'"). `Got
151
+ // it` and `Noted` say only that a card was cleared, where "Sounds good, I'll test later" says the
152
+ // work was RECEIVED and not verified -- the distinction a session spent an hour recovering from a
153
+ // call transcript on 2026-10-07, having read "not quite" as a defect report when it meant *not
154
+ // tested yet*. The words are worth writing because the agent reads them back.
155
+ //
156
+ // ONE STRING, NOT A LIST (owner, 2026-10-08 15:47, Goal 31a1e2ac, asked whether an agent should
157
+ // write up to four of them: "just on the cards, but it should be more like just they should only
158
+ // get one basically string value that they can enter that replaces got it"). A report has exactly
159
+ // one way to close, so the only thing an agent writes is what that button SAYS. #3260's 1..6
160
+ // `options` and this field are one job: the list is deleted, not deprecated (ONE JOB, ONE
161
+ // MECHANISM). It rides the door as the report's single stored option (`storedOption`,
162
+ // `apps/api/src/goal/router.ts`), so no reader below the door learns a second shape.
163
+ reply: z2.string().trim().min(1).describe(
164
+ `What this report's button says instead of "Got it", at most ${OPTION_LABEL_MAX} characters, written in THEIR voice for THIS report ("Sounds good, I'll test later") -- the care you give a question's options, so what they tap tells you whether they verified your work or only received it. One tap sends exactly these words back to you. Words that would CHANGE what happens next are a question, not a reply to a report: it still asks nothing and still owes you no answer. Left out, the button says "Got it", as every card did.`
165
+ ).optional(),
135
166
  userExplicitlyRequested
136
- }).strict().superRefine((u, ctx) => refuseOverCaps(u.message, u.units, "message", ctx));
167
+ }).strict().superRefine((u, ctx) => {
168
+ refuseOverCaps(u.message, u.units, "message", ctx);
169
+ if (u.reply && u.reply.length > OPTION_LABEL_MAX) {
170
+ ctx.addIssue({
171
+ code: z2.ZodIssueCode.custom,
172
+ path: ["reply"],
173
+ params: { refusal: "reply_too_long", length: u.reply.length, cap: OPTION_LABEL_MAX },
174
+ message: `reply_too_long: the reply is ${u.reply.length} characters; the cap is ${OPTION_LABEL_MAX}. It is a button's words, so say it in a breath.`
175
+ });
176
+ }
177
+ });
137
178
  var questionFields = {
138
179
  question: z2.string().trim().min(1).describe(
139
180
  `ONE question, in at most ${ASK_MAX} characters, and only what is needed to answer it; the context goes in units. Several questions are several objects, one each: an answer settles the one question it was given, so a person who answers the part of a bundled question that interested them settles nothing and is asked again. Separate questions cost nothing: ANY contact for a person already on a call JOINS that call, so several arrive as one call.`
140
181
  ),
141
182
  goalId: z2.string().uuid().describe("The Goal the question is about, which must exist (create it with manage_goals first). Its answer comes back there."),
142
183
  units,
143
- options: z2.array(OptionInputSchema).min(1).max(6).optional().describe("The choices, when you have them. Each label stands on its own."),
184
+ options: z2.array(OptionInputSchema).min(1).max(6).optional().describe("The choices, when you have them. Each label stands on its own, at most 50 characters; a hint, at most 200."),
144
185
  // HOW THE OPTIONS ARE ANSWERED, SAID BY THE AGENT (owner, 2026-10-02: "one and many makes sense";
145
186
  // brain_prompts.md §1: structured agent questions need no model). The app draws all three.
146
187
  pickMode: z2.enum(["one", "many", "rank"]).optional().describe(
@@ -217,6 +258,8 @@ QUESTIONS: one question per object; several questions are several objects in one
217
258
 
218
259
  CUT A LONG MESSAGE BEFORE YOU SEND IT: a question, an update's message or an answer is the one point, in at most ${ASK_MAX} characters; everything else it needs goes in 'units', up to ${UNITS_MAX} {title, body} in reading order, one idea each, every title at most ${UNIT_TITLE_MAX} characters and every body at most ${UNIT_BODY_MAX}. The person sees the main text and the titles, and opens a unit to read its body. Over a cap is refused by name (ask_too_long, too_many_units, unit_title_too_long, unit_body_too_long) and nothing is sent.
219
260
 
261
+ GIVE A REPORT ITS REPLY: an update takes \`reply\` too, one line the person can tap instead of typing, written in THEIR voice for THAT report ("Sounds good, I'll test later") \u2014 the same care you give a question's options. It is what their button says instead of "Got it", and what they tap is what you read back, which tells you whether they verified your work or only received it. One line, because a report has one way to close, and it may not change what happens next: a reply that would is a question. Nothing is owed on it either way, and a report that writes none offers "Got it".
262
+
220
263
  UPDATES ask nothing, so no answer is owed and none should be awaited. An update reaches the person only when they asked you for it (userExplicitlyRequested), when it answers something they said, or once its Goal is done; any other is recorded as the Goal's progress and nobody is notified. So when the work is finished, mark the Goal done first (manage_goals), then send one update saying what is done and anything they need to do or check. On a Goal whose report card is still open, an update that reaches them is added to that card, with no new push. If the person is already on a call, anything that reaches them joins that call, with no ring.
221
264
 
222
265
  RECEIVING: a contact that sends nothing returns \`events\`, a limited batch of what is addressed to you (not a history page): \`question\`, a Question you owe (answer it in answers, with its questionId); \`update\`, something new on one of your Goals (a reply, an answer: read it with get_goal); \`instruction\`, a request or note sent to you. \`hasMore\` says more are waiting. Reading acknowledges nothing: once you have handled events, confirm their eventIds with contact({ackEventIds}), and the next batch can come. contact({}) waits up to about 45 seconds for something to arrive; contact({wait:false}) returns at once. It also lists work given to you that nobody has started (\`assigned\`; your first write to it starts it) and your work gone quiet (\`stalled\`).`;
@@ -260,7 +303,8 @@ var UpdateGoalSchema = z3.object({
260
303
  }).strict();
261
304
  var changedGoal = z3.string().uuid().describe("The Goal to change, as a read shows it.");
262
305
  var goalTitle = z3.string().trim().min(1).max(80).describe("The Goal's short display name: one to five words, how a person refers to it out loud.");
263
- var goalOutcome = z3.string().trim().min(1).max(1e4).describe("The full desired result. There is no third description field.");
306
+ var GOAL_OUTCOME_MAX = 500;
307
+ var goalOutcome = z3.string().trim().min(1).max(GOAL_OUTCOME_MAX, `outcome_too_long: a Goal's outcome is one paragraph, at most ${GOAL_OUTCOME_MAX} characters; split the rest into child Goals (create with parentGoalId).`).describe(`The desired result, one paragraph of at most ${GOAL_OUTCOME_MAX} characters. More than that is more work: create child Goals under it (parentGoalId). There is no third description field.`);
264
308
  var CreateChange = z3.object({
265
309
  kind: z3.literal("create"),
266
310
  title: goalTitle,
@@ -286,7 +330,7 @@ var DependencyChange = z3.object({
286
330
  goalId: changedGoal,
287
331
  dependsOnGoalId: z3.string().uuid().describe("The Goal it waits on."),
288
332
  action: z3.enum(["start", "complete"]).describe("What waits: starting goalId, or completing it."),
289
- reason: z3.string().trim().min(1).max(2e3).optional().describe("Why, as an explanation, never as policy.")
333
+ reason: z3.string().trim().min(1).max(250).optional().describe("Why, at most 250 characters, as an explanation, never as policy.")
290
334
  }).strict();
291
335
  var read = { revision: z3.number().int().positive().optional() };
292
336
  var GoalChangeSchema = z3.discriminatedUnion("kind", [
@@ -310,7 +354,7 @@ var ManageGoalsSchema = z3.object({
310
354
  var ManageGoalsToolSchema = z3.object({
311
355
  changes: z3.array(z3.discriminatedUnion("kind", [CreateChange, EditChange, StateChange, AssignChange, DeferChange, MoveChange, DependencyChange])).min(1).max(50).describe("The changes, applied in order, each on its own.")
312
356
  }).strict().superRefine((v, ctx) => editNames(v.changes, ctx));
313
- var MANAGE_GOALS_DESCRIPTION = "Create, edit, assign, organize or close work. Every change here changes Goals; answering, withdrawing or asking Questions stays in contact. Each change applies independently: a refused one names why (`results[i].error`, e.g. goal_revision_conflict, goal_children_open, goal_not_found) and the rest still apply, so read every result: a partial result is never a complete success. Kinds: create (title, outcome, ownerId, parentGoalId, sourceEntryIds) returns the new Goal's id in `results[i].goalId`, in the order requested, to use in later calls; edit (title and/or outcome); state (open, completed, canceled); assign (ownerId); defer (until: the Goal waits until then and its owner is woken when it passes; null takes it back); move (parentGoalId, or null for a root: only this Goal moves); dependency (add or remove: goalId waits on dependsOnGoalId to start or to complete). A Goal cannot be completed while its required children or dependencies remain open: finish or move them first. Finishing the children does not prove the parent's own work is done. An edit applies at the version you last read: if someone changed the Goal since, it is refused as goal_revision_conflict, so read it again (get_goal) and reconsider. You may change any Goal of your person; a change puts you on it. Returns `ok` (every change applied), `results` per change (applied or failed), and `goals`, each changed Goal's id, state, title, outcome and revision.";
357
+ var MANAGE_GOALS_DESCRIPTION = "Create, edit, assign, organize or close work. Every change here changes Goals; answering, withdrawing or asking Questions stays in contact. Each change applies independently: a refused one names why (`results[i].error`, e.g. goal_revision_conflict, goal_children_open, goal_not_found) and the rest still apply, so read every result: a partial result is never a complete success. Kinds: create (title, outcome, ownerId, parentGoalId, sourceEntryIds) returns the new Goal's id in `results[i].goalId`, in the order requested, to use in later calls (an outcome is one paragraph, at most 500 characters: split more into child Goals with parentGoalId); edit (title and/or outcome); state (open, completed, canceled); assign (ownerId); defer (until: the Goal waits until then and its owner is woken when it passes; null takes it back); move (parentGoalId, or null for a root: only this Goal moves); dependency (add or remove: goalId waits on dependsOnGoalId to start or to complete). A Goal cannot be completed while its required children or dependencies remain open: finish or move them first. Finishing the children does not prove the parent's own work is done. An edit applies at the version you last read: if someone changed the Goal since, it is refused as goal_revision_conflict, so read it again (get_goal) and reconsider. You may change any Goal of your person; a change puts you on it. Returns `ok` (every change applied), `results` per change (applied or failed), and `goals`, each changed Goal's id, state, title, outcome and revision.";
314
358
  var GetGoalSchema = z3.object({
315
359
  goalId: z3.string().uuid(),
316
360
  /** Every entry in full. Without it the read carries the person's words, open questions and your
@@ -328,7 +372,7 @@ var SearchToolSchema = z3.object({
328
372
  goalId: z3.string().uuid().optional(),
329
373
  limit: z3.number().int().min(1).max(20).optional()
330
374
  }).strict();
331
- var SEARCH_DESCRIPTION = "Search your person's history across all of their agents: Entries (what anyone said or wrote, typed or spoken on a call), Goals (by title and outcome) and Answers (found by their Question or by the words that gave them). query is words to look for; records sharing more of its words rank first, and exact names work. types narrows it to entry, goal and/or answer (default: all three). goalId searches under one Goal: its Entries, its Questions' Answers, and it and its immediate children. limit is matches per type, 1 to 20 (default 8). Read-only. Each match carries its whole saved words, its ID and its links (an Answer carries its Question, the choice made and the Entries that support it); `omitted` counts what matched but was left out, so narrow the words or add a goalId to see it. Nothing found is not proof that nothing exists; a refused search says why. Sealed (encrypted) content is never searched or returned.";
375
+ var SEARCH_DESCRIPTION = "Search your person's history across all of their agents: Entries (what anyone said or wrote, typed or spoken on a call), Goals (by title and outcome) and replies -- the person's answers, acknowledgements and deferrals (type answer; found by their summary, by the question or report they reply to, or by the words that gave them). query is words to look for; records sharing more of its words rank first, and exact names work. types narrows it to entry, goal and/or answer (default: all three). goalId searches under one Goal: its Entries, the replies to its items, and it and its immediate children. limit is matches per type, 1 to 20 (default 8). Read-only. Each match carries its whole saved words, its ID and its links (a reply carries its kind -- answered, acknowledged or deferred -- whether it is closed (a deferral is not), its summary in under ten words, its question or report, the choice made and the Entries that support it); `omitted` counts what matched but was left out, so narrow the words or add a goalId to see it. Nothing found is not proof that nothing exists; a refused search says why. Sealed (encrypted) content is never searched or returned.";
332
376
  var CheckActivitySchema = z3.object({}).strict();
333
377
  var FEEDBACK_TEXT_MAX = 5e4;
334
378
  var SendFeedbackSchema = z3.object({
@@ -348,7 +392,7 @@ var AGENT_TOOLS = [
348
392
  var AGENT_TOOL_NAMES = AGENT_TOOLS.map((t) => t.name);
349
393
  function serverInstructions(opts) {
350
394
  const waits = opts.waits ? "contact({..., wait:true}) holds one bounded ~45 s window for a response to what you sent; contact({}) holds one for anything addressed to you." : "A contact here returns after one read (`waitOutcome: not_waited`); answers wake you, and contact({wait:false}) collects them.";
351
- return `On startup and after a wake, call contact({wait:false}) for the events addressed to you (acknowledge the ones you handled with contact({ackEventIds})), which hand you your work: answers, assignments, reviews and due Goals. get_goal reads a Goal and the conversation on it; a read never puts you on it. You are on a Goal from your first write to it (a contact update, question or answer naming it, or a manage_goals change); there is nothing to claim or join. Every Goal of your person is open to you, whichever of their agents owns it: read it with get_goal, write on it (a contact naming its id) and change it (manage_goals). Create, edit, assign, organize or close work with manage_goals, never as a contact; a contact only names Goals that already exist. Every read ends in \`next\`, the one step to take. Sending returns immediately unless you ask it to wait: keep working and collect answers by receiving or through get_goal. ${waits} Events repeat until you acknowledge them: reading alone acknowledges nothing; an \`update\` event acknowledged is a review cleared. Report progress as a contact update: one the person does not need yet is kept as the Goal's progress and reaches no one. To follow up later, defer the Goal with manage_goals: you are woken when its time comes. Never infer ringing from an open Call Delivery. Soft waiting and re-presentation are unsupported. Your user is remote. Always interact with the user through Paigy. For decisions, approvals, or questions, contact them with structured options. Never assume anyone is reading the terminal stdout.
395
+ return `On startup and after a wake, call contact({wait:false}) for the events addressed to you (acknowledge the ones you handled with contact({ackEventIds})), which hand you your work: answers, assignments, reviews and due Goals. get_goal reads a Goal and the conversation on it; a read never puts you on it. You are on a Goal from your first write to it (a contact update, question or answer naming it, or a manage_goals change); there is nothing to claim or join. Every Goal of your person is open to you, whichever of their agents owns it: read it with get_goal, write on it (a contact naming its id) and change it (manage_goals). Create, edit, assign, organize or close work with manage_goals, never as a contact; a contact only names Goals that already exist. Every read ends in \`next\`, the one step to take. Sending returns immediately unless you ask it to wait: keep working and collect answers by receiving or through get_goal. ${waits} Events repeat until you acknowledge them: reading alone acknowledges nothing; an \`update\` event acknowledged is a review cleared. Report progress as a contact update: one the person does not need yet is kept as the Goal's progress and reaches no one. To follow up later, defer the Goal with manage_goals: you are woken when its time comes. Never infer ringing from an open Call Delivery. While a Call you placed is open, stay with it until it ends: keep receiving window after window, because the person may give you follow-ups or instructions on the call. Soft waiting and re-presentation are unsupported. Your user is remote. Always interact with the user through Paigy. For decisions, approvals, or questions, contact them with structured options. Give a report its reply too (an update's \`reply\`): one line the person can tap instead of "Got it", written in their voice for that report, so what they tap tells you whether they verified your work or only received it. Never assume anyone is reading the terminal stdout.
352
396
 
353
397
  HOW TO ASK:
354
398
  1. One question per question object. Five questions are five objects in \`questions\`, in one contact, so each can be answered on its own; one question with five parts settles nothing until all five are answered.
@@ -405,6 +449,7 @@ var QuestionChangeSchema = z4.union([
405
449
  z4.object({
406
450
  kind: z4.literal("create"),
407
451
  text: z4.string().min(1),
452
+ summary: z4.string().optional(),
408
453
  answererId: participant,
409
454
  goal: ResultRefSchema.optional(),
410
455
  blocks: z4.array(z4.object({ question: ResultRefSchema }).strict()),
@@ -455,12 +500,12 @@ var BrainSearchSchema = z4.object({
455
500
  }).strict();
456
501
  var BrainResultSchema = z4.object({
457
502
  messages: z4.array(BrainMessageSchema),
458
- entries: z4.array(z4.object({ key, sources: z4.array(SourceSchema).min(1), goals: z4.array(ResultRefSchema) }).strict()),
503
+ entries: z4.array(z4.object({ key, sources: z4.array(SourceSchema).min(1), goals: z4.array(ResultRefSchema), summary: z4.string().optional() }).strict()),
459
504
  questions: z4.array(z4.object({ key, entryKeys: z4.array(key), change: QuestionChangeSchema }).strict()),
460
505
  answers: z4.array(z4.object({
461
506
  question: ResultRefSchema,
462
507
  entryKeys: z4.array(key).min(1),
463
- summary: z4.string().min(1),
508
+ summary: z4.string(),
464
509
  selectedOptionIds: z4.array(z4.string().min(1)).optional()
465
510
  }).strict()),
466
511
  goals: z4.array(z4.object({ key, entryKeys: z4.array(key), change: BrainGoalChangeSchema }).strict()),
@@ -505,12 +550,15 @@ var TalkerReplySchema = z5.object({
505
550
  messages: z5.array(z5.object({ key: str2, to: str2, text: str2, about: strs2, blocks: str2 }).strict()),
506
551
  /** What the call does next: listen, hold (the person asked for a moment) or end (they asked to). */
507
552
  then: z5.enum(["listen", "hold", "end"]),
508
- /** Items the person's words settle: the item's handle, the chosen option IDs, the line handles. */
509
- answers: z5.array(z5.object({ item: str2, options: strs2, lines: strs2 }).strict()),
510
- /** The line handles that hold a new instruction from the person. */
553
+ /** The person's replies to items (replies, owner 2026-10-07): the item's handle, the chosen option
554
+ * IDs, the line handles, how they replied in under ten words (keeping any condition), and `defer`:
555
+ * "" when their words settle the item, else what a reply that puts it off waits for -- "call" (the
556
+ * end of this call), a question's handle (that question's answer) or an ISO time. */
557
+ replies: z5.array(z5.object({ item: str2, options: strs2, lines: strs2, summary: str2, defer: str2 }).strict()),
558
+ /** The line handles that tell the talker how to run this call; they last until it ends and reach no agent. */
511
559
  instruction: strs2,
512
- /** The line handles that ask for new work, a change to existing work, or a standing rule: the filer
513
- * reads only these (3e). */
560
+ /** The line handles the filer acts on, and the only ones it reads (3e): new work, a change to existing
561
+ * work, feedback on Paigy, anything said to an agent, and any rule meant to outlast the call. */
514
562
  file: strs2,
515
563
  /** Evidence to fetch for a second round: a search, an item's full text, or an agent by name. */
516
564
  need: z5.object({ kind: z5.enum(["search", "item", "agent", ""]), text: str2 }).strict(),
@@ -523,8 +571,9 @@ var TALKER_REPLY_JSON_SCHEMA = (({ $schema: _, ...rest }) => rest)(
523
571
  var str3 = z6.string();
524
572
  var strs3 = z6.array(z6.string());
525
573
  var FilerReplySchema = z6.object({
526
- /** Which Goals each new line goes on: a line's handle and Goal handles (or keys of new Goals). */
527
- filed: z6.array(z6.object({ line: str3, goals: strs3 }).strict()),
574
+ /** Which Goals each new line goes on: a line's handle, Goal handles (or keys of new Goals), and what
575
+ * the line says in at most ten words. */
576
+ filed: z6.array(z6.object({ line: str3, goals: strs3, summary: str3 }).strict()),
528
577
  goals: z6.array(z6.object({
529
578
  op: z6.enum(["create", "edit", "complete", "cancel", "reopen", "assign", "defer", "move", "block", "unblock"]),
530
579
  key: str3,
@@ -543,6 +592,7 @@ var FilerReplySchema = z6.object({
543
592
  key: str3,
544
593
  question: str3,
545
594
  text: str3,
595
+ summary: str3,
546
596
  to: str3,
547
597
  goal: str3,
548
598
  options: z6.array(z6.object({ id: str3, label: str3 }).strict()),
@@ -556,6 +606,60 @@ var FilerReplySchema = z6.object({
556
606
  var FILER_REPLY_JSON_SCHEMA = (({ $schema: _, ...rest }) => rest)(
557
607
  zodToJsonSchema4(FilerReplySchema, { $refStrategy: "none" })
558
608
  );
609
+ var ExplainerReplySchema = z7.object({
610
+ /** The explanation, as sentences, spoken in order. */
611
+ say: z7.array(z7.string()),
612
+ /** Questions to an agent about gaps in what it read: the agent's handle and the question. */
613
+ followUps: z7.array(z7.object({ to: z7.string(), text: z7.string() }).strict())
614
+ }).strict();
615
+ var EXPLAINER_REPLY_JSON_SCHEMA = (({ $schema: _, ...rest }) => rest)(
616
+ zodToJsonSchema5(ExplainerReplySchema, { $refStrategy: "none" })
617
+ );
618
+ var DISTILLER_DEFECTS = [
619
+ "reasked",
620
+ // a question put to the person again after they answered it
621
+ "unsupported",
622
+ // a fact stated that nothing in the input supports
623
+ "unsaid",
624
+ // an agent's answer arrived during the call and was never said
625
+ "skipped",
626
+ // an agenda item never put to the person
627
+ "unsaved",
628
+ // something the person answered or asked for did not save, was refused or dropped
629
+ "ignored",
630
+ // the person asked or said something and was never answered (the critic's ignored_a_question)
631
+ "promised",
632
+ // said it did or would do something, and nothing shows it done (the critic's broken_promise)
633
+ "dropped"
634
+ // something it had to say never played and was never said later (owner, 2026-10-08, call 65433a9d)
635
+ ];
636
+ var DistillerReplySchema = z8.object({
637
+ defects: z8.array(z8.object({
638
+ kind: z8.enum(DISTILLER_DEFECTS),
639
+ /** The handles of the lines it shows in. */
640
+ lines: z8.array(z8.string()),
641
+ /** The handle of the record it concerns, or "". */
642
+ about: z8.string(),
643
+ /** One plain sentence, in words, never handles: it is what the feedback row keeps. */
644
+ why: z8.string()
645
+ }).strict())
646
+ }).strict();
647
+ var DISTILLER_REPLY_JSON_SCHEMA = (({ $schema: _, ...rest }) => rest)(
648
+ zodToJsonSchema6(DistillerReplySchema, { $refStrategy: "none" })
649
+ );
650
+ var TIDY_AUDIENCES = ["talker", "filer", "agents"];
651
+ var TidyReplySchema = z8.object({
652
+ lessons: z8.array(z8.object({
653
+ lesson: z8.string(),
654
+ op: z8.enum(["keep", "revise", "withdraw"]),
655
+ text: z8.string(),
656
+ for: z8.enum([...TIDY_AUDIENCES, ""]),
657
+ into: z8.string()
658
+ }).strict())
659
+ }).strict();
660
+ var TIDY_REPLY_JSON_SCHEMA = (({ $schema: _, ...rest }) => rest)(
661
+ zodToJsonSchema6(TidyReplySchema, { $refStrategy: "none" })
662
+ );
559
663
  function entryWords(entry) {
560
664
  const content = entry.content;
561
665
  if (content && "sealed" in content) return "";
@@ -582,20 +686,20 @@ function entryUnit(entry) {
582
686
  }
583
687
  var LIVE_MS = 3 * 6e4;
584
688
  var WORKING_MS = 60 * 6e4;
585
- var ContextSchema = z7.object({
586
- title: z7.string().min(1).describe("One-line headline of what you need (required, non-empty)."),
587
- description: z7.array(z7.string().min(1)).describe(
689
+ var ContextSchema = z9.object({
690
+ title: z9.string().min(1).describe("One-line headline of what you need (required, non-empty)."),
691
+ description: z9.array(z9.string().min(1)).describe(
588
692
  "Semantic chunks of detail (each a standalone, non-empty piece). The user can select chunks to ask you to expand. MAY BE EMPTY: a claim whose whole content is its heading \u2014 a single sentence \u2014 has no body, and saying so beats repeating the heading underneath itself. That repeat is what `min(1)` used to force, at 2x the storage, with every reader subtracting it back out at render time."
589
693
  ),
590
694
  /** THE ASK'S UNITS (3c): its context as titled units, in order. The app lists the titles and opens
591
695
  * a body on a tap. Absent on an ask sent without units, which renders as before. */
592
- units: z7.array(z7.object({ title: z7.string(), body: z7.string() })).optional()
696
+ units: z9.array(z9.object({ title: z9.string(), body: z9.string() })).optional()
593
697
  });
594
- var ParticipantSchema = z7.object({
595
- kind: z7.enum(["human", "agent"]),
596
- id: z7.string()
698
+ var ParticipantSchema = z9.object({
699
+ kind: z9.enum(["human", "agent"]),
700
+ id: z9.string()
597
701
  });
598
- var TransformSchema = z7.enum([
702
+ var TransformSchema = z9.enum([
599
703
  "structure",
600
704
  // shape intent into an answer contract; pick channel/urgency — broker `ask`, `select` shapes, `points`
601
705
  "request_more",
@@ -611,13 +715,13 @@ var TransformSchema = z7.enum([
611
715
  "summarize"
612
716
  // reduce volume, keep decision value — 30-turn cap, spoken briefing
613
717
  ]);
614
- var VisualSchema = z7.object({
615
- url: z7.string().url(),
616
- label: z7.string().optional()
718
+ var VisualSchema = z9.object({
719
+ url: z9.string().url(),
720
+ label: z9.string().optional()
617
721
  });
618
- var NotifyLevelSchema = z7.enum(["inbox", "push", "banner", "call"]);
619
- var SelectShapeSchema = z7.enum(["one", "many", "rank", "confirm", "text"]);
620
- var ReceiptEventSchema = z7.enum([
722
+ var NotifyLevelSchema = z9.enum(["inbox", "push", "banner", "call"]);
723
+ var SelectShapeSchema = z9.enum(["one", "many", "rank", "confirm", "text"]);
724
+ var ReceiptEventSchema = z9.enum([
621
725
  "delivered",
622
726
  // the bundle reached the recipient at some level
623
727
  "seen",
@@ -647,47 +751,47 @@ var ReceiptEventSchema = z7.enum([
647
751
  // be rewound by a writer that forgot to advance it.
648
752
  "restarted"
649
753
  ]);
650
- var AttentionSchema = z7.object({
754
+ var AttentionSchema = z9.object({
651
755
  urgency: NotifyLevelSchema,
652
756
  /** The required answer shape, or null for a plain notify that asks nothing back. */
653
757
  select: SelectShapeSchema.nullable(),
654
758
  /** Coverage contract (#396) — points the answer must address; null = none declared. */
655
- points: z7.array(z7.string()).nullable(),
759
+ points: z9.array(z9.string()).nullable(),
656
760
  /** Whether the ask blocks the sender — what lets arbitration escalate it on silence. */
657
- blocking: z7.boolean(),
761
+ blocking: z9.boolean(),
658
762
  /** Reserved (docs/model/model.md lists it): a response deadline. No row column yet — a later Phase 2
659
763
  * slice wires it; optional so today's rows/callers project cleanly. */
660
- deadline: z7.string().datetime().nullable().optional()
764
+ deadline: z9.string().datetime().nullable().optional()
661
765
  });
662
- var NotifyRequestFields = z7.object({
766
+ var NotifyRequestFields = z9.object({
663
767
  /** Plaintext message content. Present on the plaintext path (today's shape);
664
768
  * ABSENT on the E2EE path, where the sealed `envelope` below carries it. The
665
769
  * superRefine at the bottom enforces exactly one of the two. */
666
770
  context: ContextSchema.optional(),
667
- options: z7.array(OptionSchema.omit({ id: true }).extend({ label: z7.string().trim().min(1).max(1e3) }).strict()).min(OPTIONS_MIN).max(OPTIONS_MAX).optional().describe(
771
+ options: z9.array(OptionSchema.omit({ id: true }).extend({ label: z9.string().trim().min(1).max(1e3) }).strict()).min(OPTIONS_MIN).max(OPTIONS_MAX).optional().describe(
668
772
  "The choices, in order \u2014 required when select is 'one'/'many'/'rank', omitted otherwise. Ids are assigned automatically by position ('1', '2', \u2026); the user's answer references them as optionId(s)."
669
773
  ),
670
- points: z7.array(z7.string().min(1)).optional().describe(
774
+ points: z9.array(z9.string().min(1)).optional().describe(
671
775
  "The distinct things you need answered, each a short phrase \u2014 on a call the broker keeps the conversation going until each is addressed, and the reply reports which were covered, so a half-answer is never silently returned as final. Omit for single-part asks."
672
776
  ),
673
- visuals: z7.array(VisualSchema).optional().describe(
777
+ visuals: z9.array(VisualSchema).optional().describe(
674
778
  "Images attached to the message itself \u2014 context for the whole question (a screenshot, a chart). For a preview on one selectable choice, use that option's `html`/`image` instead."
675
779
  ),
676
780
  /** Git repo the agent is working in ("owner/name"). Local MCP fills this from the checkout — omit unless overriding. */
677
- repo: z7.string().optional(),
781
+ repo: z9.string().optional(),
678
782
  /** Git branch the agent is on. Local MCP fills this from the checkout — omit unless overriding. */
679
- branch: z7.string().optional(),
783
+ branch: z9.string().optional(),
680
784
  /** Continue an existing conversation — the id of any notification in it (its root
681
785
  * is the conversation's identity). Omitted = start a new conversation. Renamed
682
786
  * from `parentId` (2026-08-03): one linkage system, the parent; the API edge
683
787
  * still accepts the old name from older clients. */
684
- parentId: z7.string().uuid().optional(),
788
+ parentId: z9.string().uuid().optional(),
685
789
  /** The durable outcome this contact advances. Optional during the notification-to-Work
686
790
  * migration; when present, a blocking ask creates a DecisionNeed for this Work. */
687
- workId: z7.string().uuid().optional(),
791
+ workId: z9.string().uuid().optional(),
688
792
  /** Target Goal scope. During staged migration this is accepted by the shared contract but
689
793
  * target delivery activation remains model-gated; workId and goalId are mutually exclusive. */
690
- goalId: z7.string().uuid().optional(),
794
+ goalId: z9.string().uuid().optional(),
691
795
  urgency: NotifyLevelSchema.default("inbox").describe(
692
796
  "The level you're requesting \u2014 the user's account permissions + session mode can lower it. 'inbox' (default) = sits silently in the inbox for the user to get to. 'push' = a quiet passive push (lands in Notification Center, no sound) \u2014 a gentle heads-up. 'banner' = a time-sensitive banner/lock-screen push with sound (a 'paige') they tap to open \u2014 use when you need them soon-ish but it's not worth ringing them. 'call' = rings the user's phone now (a CallKit voice call) \u2014 use only when you genuinely need them in the moment (blocked and waiting, time-sensitive). context.title is what they see on the banner/ring, so make it specific."
693
797
  ),
@@ -695,7 +799,7 @@ var NotifyRequestFields = z7.object({
695
799
  * visible and marks it needs_input. Renamed from the old `parentId` (2026-08-03)
696
800
  * when `parentId` became the conversation handle: `parentId` says WHERE, this
697
801
  * says HOW. */
698
- clarifies: z7.string().optional(),
802
+ clarifies: z9.string().optional(),
699
803
  select: SelectShapeSchema.optional().describe(
700
804
  "How the user answers \u2014 required on the fully-shaped form, pick the shape that fits the question: 'one' = pick one option, 'many' = pick several, 'rank' = pick & order (each needs `options`); 'confirm' = yes/no or approve/deny; 'text' = free-form reply only (status updates, open questions). 'confirm' and 'text' take no options. Omit only when sending the simplified `ask` form \u2014 the broker picks the shape."
701
805
  ),
@@ -709,20 +813,20 @@ var NotifyRequestFields = z7.object({
709
813
  // (docs/brain/broker/agenda-design.md) — not by a wire cap the agent has to pre-summarize under.
710
814
  // Owner, 2026-07-28: "our actual limitation on how long something is to the user should
711
815
  // come from the broker splitting and summarizing." The cap that remains is a size guard.
712
- ask: z7.string().min(1).max(1e4).optional().describe(
816
+ ask: z9.string().min(1).max(1e4).optional().describe(
713
817
  'SIMPLIFIED FORM \u2014 state in plain prose what you need to learn from the user and why it matters now (e.g. "I need to know whether to deploy the auth fix \u2014 tests are green, staging verified"). Write as much as the situation needs (up to 10k characters) \u2014 Paigy breaks it into topics and reads it back a few sentences at a time; do NOT pre-summarize it into one line. Paigy derives the title, answer shape, options, and delivery channel for you. Mutually exclusive with context/select/options \u2014 send one form or the other.'
714
818
  ),
715
- needs: z7.array(z7.string().min(1)).optional().describe(
819
+ needs: z9.array(z9.string().min(1)).optional().describe(
716
820
  "With `ask` only: the distinct things you need answered when the ask is multi-part \u2014 becomes the coverage contract (`points`), so a half-answer is never silently final."
717
821
  ),
718
- urgencyHint: z7.enum(["whenever", "soon", "now"]).optional().describe(
822
+ urgencyHint: z9.enum(["whenever", "soon", "now"]).optional().describe(
719
823
  "With `ask` only: how urgently you need the answer \u2014 'whenever' (inbox), 'soon' (worth a heads-up), 'now' (you're blocked this minute). A hint, not a command: the user's settings still have the final word."
720
824
  ),
721
825
  /** #575: the ONE self-report that replaces urgencyHint + blocking — what happens
722
826
  * to the agent's work while it waits. Normalized server-side into those two
723
827
  * fields (normalizeWaiting) so everything downstream is untouched; explicit
724
828
  * urgencyHint/blocking win when both are sent. */
725
- waiting: z7.enum(["none", "soft", "hard"]).optional().describe(
829
+ waiting: z9.enum(["none", "soft", "hard"]).optional().describe(
726
830
  "With `ask`: what happens to your work while you wait. 'none' = you're just informing the user. 'soft' = you'd like an answer but can keep working. 'hard' = you are stopped until they answer (reaches them urgently and escalates to a real phone call if unanswered). Replaces urgencyHint + blocking \u2014 send this one field."
727
831
  ),
728
832
  /** Δ9b (#895): HOLD this claim so the sender can correct the plan before anyone is
@@ -730,98 +834,98 @@ var NotifyRequestFields = z7.object({
730
834
  * holding by default would charge every quiet claim that minute before any agent could
731
835
  * correct anything. Ignored for `waiting: 'hard'`: a blocking ask rings on what we have,
732
836
  * and the enrichment can still land mid-call (#781 re-plans the unspoken tail). */
733
- confirm: z7.boolean().optional().describe(
837
+ confirm: z9.boolean().optional().describe(
734
838
  "Hold this one so you can correct the plan before the user is interrupted. The response comes back with `held: true` and the plan; POST the confirm route to release it (with options/visuals/urgency corrections, or nothing at all). If you never do, it is announced anyway a couple of minutes later. Ignored when waiting is 'hard'."
735
839
  ),
736
840
  /** #575: a RELAY of the user's explicitly stated preference, never the agent's
737
841
  * choice. Outranks waiting in both directions: 'call' rings even for a
738
842
  * waiting:'none' "call me when it's done"; 'message' never rings even for
739
843
  * waiting:'hard'. */
740
- channel: z7.enum(["call", "message"]).optional().describe(
844
+ channel: z9.enum(["call", "message"]).optional().describe(
741
845
  "Only if the user explicitly said how to reach them \u2014 'call me' \u2192 'call', 'just message/text me' \u2192 'message'. Omit otherwise; Paigy picks."
742
846
  ),
743
- confirmStyle: z7.enum(["yesno", "approve"]).default("yesno").describe(
847
+ confirmStyle: z9.enum(["yesno", "approve"]).default("yesno").describe(
744
848
  "Labels for a select:'confirm' paige \u2014 'yesno' (Yes/No) or 'approve' (Approve/Deny). Ignored unless select is 'confirm'."
745
849
  ),
746
- blocking: z7.boolean().default(false).describe(
850
+ blocking: z9.boolean().default(false).describe(
747
851
  "Set true when real downstream work is stuck behind this specific decision \u2014 you can't make meaningful progress until it's answered. This is the real signal for how urgently the user should be reached; it's what the premier use case (an agent that stays unblocked instead of going idle) depends on. Independent of `urgency`: a `banner`-level question can still be `blocking` (something IS stuck, just not time-critical enough to ring for immediately) \u2014 if it goes unanswered a while, Paigy escalates it to a real call using this flag rather than guessing from how many other things happen to be pending. Leave false for anything you could work around, defer, or where other useful work exists meanwhile."
748
852
  )
749
853
  });
750
854
  var NotifyRequestSchema = NotifyRequestFields.superRefine((r, ctx) => {
751
- if (r.workId && r.goalId) ctx.addIssue({ code: z7.ZodIssueCode.custom, path: ["goalId"], message: "pass goalId or workId, not both" });
855
+ if (r.workId && r.goalId) ctx.addIssue({ code: z9.ZodIssueCode.custom, path: ["goalId"], message: "pass goalId or workId, not both" });
752
856
  if (r.ask !== void 0) {
753
857
  for (const f of ["context", "select", "points"]) {
754
858
  if (r[f] !== void 0)
755
- ctx.addIssue({ code: z7.ZodIssueCode.custom, path: [f], message: `the simplified \`ask\` form takes no ${f} \u2014 the broker derives the answer shape from your prose. Drop ${f} and say it in \`ask\` instead ("should I\u2026" for approve/deny, "which of these\u2026" for a pick), passing \`options\` when you're offering concrete alternatives.` });
859
+ ctx.addIssue({ code: z9.ZodIssueCode.custom, path: [f], message: `the simplified \`ask\` form takes no ${f} \u2014 the broker derives the answer shape from your prose. Drop ${f} and say it in \`ask\` instead ("should I\u2026" for approve/deny, "which of these\u2026" for a pick), passing \`options\` when you're offering concrete alternatives.` });
756
860
  }
757
861
  return;
758
862
  }
759
863
  if (r.needs !== void 0 || r.urgencyHint !== void 0)
760
- ctx.addIssue({ code: z7.ZodIssueCode.custom, path: ["needs"], message: "needs/urgencyHint belong to the simplified `ask` form \u2014 with a shaped request use points/urgency" });
864
+ ctx.addIssue({ code: z9.ZodIssueCode.custom, path: ["needs"], message: "needs/urgencyHint belong to the simplified `ask` form \u2014 with a shaped request use points/urgency" });
761
865
  if (!r.context)
762
- ctx.addIssue({ code: z7.ZodIssueCode.custom, path: ["context"], message: "context is required (plaintext path)" });
866
+ ctx.addIssue({ code: z9.ZodIssueCode.custom, path: ["context"], message: "context is required (plaintext path)" });
763
867
  if (!r.select)
764
- ctx.addIssue({ code: z7.ZodIssueCode.custom, path: ["select"], message: "select is required on the shaped form" });
868
+ ctx.addIssue({ code: z9.ZodIssueCode.custom, path: ["select"], message: "select is required on the shaped form" });
765
869
  const needsOptions = r.select === "one" || r.select === "many" || r.select === "rank";
766
870
  if (needsOptions && !r.options?.length)
767
- ctx.addIssue({ code: z7.ZodIssueCode.custom, path: ["options"], message: `select:'${r.select}' requires options` });
871
+ ctx.addIssue({ code: z9.ZodIssueCode.custom, path: ["options"], message: `select:'${r.select}' requires options` });
768
872
  if (!needsOptions && r.options?.length)
769
- ctx.addIssue({ code: z7.ZodIssueCode.custom, path: ["options"], message: `select:'${r.select}' takes no options` });
873
+ ctx.addIssue({ code: z9.ZodIssueCode.custom, path: ["options"], message: `select:'${r.select}' takes no options` });
770
874
  });
771
- var NotifyStatusSchema = z7.enum(["pending", "answered", "ignored"]);
772
- var AgentStateSchema = z7.enum(["idle", "in_progress", "completed", "needs_input"]);
773
- var TurnSchema = z7.object({
774
- prompt: z7.string(),
775
- reply: z7.string()
875
+ var NotifyStatusSchema = z9.enum(["pending", "answered", "ignored"]);
876
+ var AgentStateSchema = z9.enum(["idle", "in_progress", "completed", "needs_input"]);
877
+ var TurnSchema = z9.object({
878
+ prompt: z9.string(),
879
+ reply: z9.string()
776
880
  });
777
- var UserAnswerSchema = z7.discriminatedUnion("kind", [
778
- z7.object({ kind: z7.literal("option"), optionId: z7.string(), label: z7.string().optional() }),
779
- z7.object({ kind: z7.literal("text"), text: z7.string() }),
780
- z7.object({ kind: z7.literal("ignored") }),
781
- z7.object({ kind: z7.literal("multi"), optionIds: z7.array(z7.string()), labels: z7.array(z7.string()).optional() }),
782
- z7.object({ kind: z7.literal("ranked"), optionIds: z7.array(z7.string()), labels: z7.array(z7.string()).optional() }),
783
- z7.object({ kind: z7.literal("clarify"), chunks: z7.array(z7.string()).min(1) }),
784
- z7.object({ kind: z7.literal("confirm"), approved: z7.boolean() }),
785
- z7.object({ kind: z7.literal("turns"), turns: z7.array(TurnSchema).min(1) }),
881
+ var UserAnswerSchema = z9.discriminatedUnion("kind", [
882
+ z9.object({ kind: z9.literal("option"), optionId: z9.string(), label: z9.string().optional() }),
883
+ z9.object({ kind: z9.literal("text"), text: z9.string() }),
884
+ z9.object({ kind: z9.literal("ignored") }),
885
+ z9.object({ kind: z9.literal("multi"), optionIds: z9.array(z9.string()), labels: z9.array(z9.string()).optional() }),
886
+ z9.object({ kind: z9.literal("ranked"), optionIds: z9.array(z9.string()), labels: z9.array(z9.string()).optional() }),
887
+ z9.object({ kind: z9.literal("clarify"), chunks: z9.array(z9.string()).min(1) }),
888
+ z9.object({ kind: z9.literal("confirm"), approved: z9.boolean() }),
889
+ z9.object({ kind: z9.literal("turns"), turns: z9.array(TurnSchema).min(1) }),
786
890
  /** An auto-answer derived from the user's PAST decisions (docs/brain/broker/precedent-design.md §2):
787
891
  * delivered through the same settle/await path as a human answer, carrying the judge's
788
892
  * derivation and the precedent ids it grew from. Always paired with a visible trail
789
893
  * card the user can reply to — the broker never overrides the user. */
790
- z7.object({ kind: z7.literal("precedent"), answer: z7.string(), derivation: z7.string(), sources: z7.array(z7.string()).min(1) })
894
+ z9.object({ kind: z9.literal("precedent"), answer: z9.string(), derivation: z9.string(), sources: z9.array(z9.string()).min(1) })
791
895
  ]);
792
- var IntentSchema = z7.object({
896
+ var IntentSchema = z9.object({
793
897
  // The full vocabulary the bot's mapper emits (mapper.INTENT_KINDS) — the schema lagged
794
898
  // it by two ("detail", "feedback"), and because the settle handler parsed the array
795
899
  // all-or-nothing, ONE feedback act silently dropped EVERY intent on the call,
796
900
  // questions included. Found auditing five calls' stored feedback, 2026-08-01.
797
- kind: z7.enum(["defer", "delegate", "channel", "question", "detail", "feedback", "command", "control"]),
798
- detail: z7.string(),
901
+ kind: z9.enum(["defer", "delegate", "channel", "question", "detail", "feedback", "command", "control"]),
902
+ detail: z9.string(),
799
903
  /** Defer only: seconds until the callback the caller asked for, when something upstream
800
904
  * already read the time. Nothing sets it today (#397 documented an MCP parser that was
801
905
  * never written) — the API reads the defer's `detail` itself with `notes/when.ts`
802
906
  * (`parseDelay`, #1292), and a value here simply wins over that reading. */
803
- dueInSeconds: z7.number().int().positive().optional(),
907
+ dueInSeconds: z9.number().int().positive().optional(),
804
908
  /** Feedback only (#812): WHICH failure the complaint names — typed by the mapper that
805
909
  * already read the utterance, so `signals.kind` stops defaulting to
806
910
  * 'other' on every row. A table that records that something was wrong and nothing
807
911
  * about what cannot answer "is the bot looping less this week?". */
808
- fault: z7.enum(["loop", "unanswered", "overridden", "misheard", "slow", "other"]).optional()
912
+ fault: z9.enum(["loop", "unanswered", "overridden", "misheard", "slow", "other"]).optional()
809
913
  });
810
- var RideAlongSchema = z7.object({
914
+ var RideAlongSchema = z9.object({
811
915
  /** The note this came from — assign/clarify/close it through /api/notes/:id. */
812
- noteId: z7.string(),
916
+ noteId: z9.string(),
813
917
  /** What to do, in the owner's own words (the note's headline). Never model-rewritten. */
814
- text: z7.string(),
918
+ text: z9.string(),
815
919
  /** The thread to report back on, when the note was dispatched over the request rail. */
816
- parentId: z7.string().nullable()
920
+ parentId: z9.string().nullable()
817
921
  });
818
- var AwaitItemSchema = z7.discriminatedUnion("type", [
819
- z7.object({
820
- type: z7.literal("reply"),
821
- parentId: z7.string(),
822
- notificationId: z7.string(),
823
- workId: z7.string().uuid().optional(),
824
- decisionId: z7.string().uuid().optional(),
922
+ var AwaitItemSchema = z9.discriminatedUnion("type", [
923
+ z9.object({
924
+ type: z9.literal("reply"),
925
+ parentId: z9.string(),
926
+ notificationId: z9.string(),
927
+ workId: z9.string().uuid().optional(),
928
+ decisionId: z9.string().uuid().optional(),
825
929
  answer: UserAnswerSchema,
826
930
  /** WHAT THE AGENT CANNOT KNOW FROM THE FIELDS BESIDE IT (owner, 2026-09-04, issue
827
931
  * #1537). One line, built from the record: the ask and the caller's reply VERBATIM,
@@ -831,103 +935,103 @@ var AwaitItemSchema = z7.discriminatedUnion("type", [
831
935
  * "call me back after you merge" in their own words decides for itself what to do,
832
936
  * and now knows exactly which call to make. Absent when either half is missing —
833
937
  * a sentence with a hole in it is worse than no sentence. */
834
- note: z7.string().optional(),
938
+ note: z9.string().optional(),
835
939
  /** The call record rendered for THIS agent (`docs/brain/voice/record-design.md`): the words the
836
940
  * shaped answer was mapped from, filtered to its own claims. There is no second list
837
941
  * of labels beside it — the acts went 2026-09-04 and `intents` went with them (owner,
838
942
  * 2026-09-04): the agent reads the sentence and decides. */
839
- transcript: z7.string().optional(),
943
+ transcript: z9.string().optional(),
840
944
  /** Coverage report (#396), when the ask declared `points`: which of them this
841
945
  * answer addressed. Missing points = re-ask or proceed knowingly partial. */
842
- covered: z7.array(z7.string()).optional(),
946
+ covered: z9.array(z9.string()).optional(),
843
947
  /** Ride-alongs (RideAlongSchema) — pending work for you, attached to the moment you
844
948
  * became free. Only `reply` and `idle` carry it: those are the two outcomes that
845
949
  * END a wait. `remind`, `superseded` and `turn` are mid-flight, and handing an
846
950
  * agent a side-quest while it is still holding the line is how the main thing gets
847
951
  * dropped. Absent/empty = nothing owed. */
848
- also: z7.array(RideAlongSchema).optional()
952
+ also: z9.array(RideAlongSchema).optional()
849
953
  }),
850
- z7.object({
851
- type: z7.literal("remind"),
852
- parentId: z7.string(),
853
- notificationId: z7.string(),
854
- remindAt: z7.string().datetime({ offset: true }),
954
+ z9.object({
955
+ type: z9.literal("remind"),
956
+ parentId: z9.string(),
957
+ notificationId: z9.string(),
958
+ remindAt: z9.string().datetime({ offset: true }),
855
959
  /** Seconds until remindAt, server-computed — pass straight to ScheduleWakeup. */
856
- remindInSeconds: z7.number()
960
+ remindInSeconds: z9.number()
857
961
  }),
858
962
  /** The awaited ask was REPLACED by a newer notification on its thread (e.g. a
859
963
  * post-feedback revision, #633) — the user will never answer this id. Stop
860
964
  * awaiting it; the live ask is the thread's newest turn (await that one, or
861
965
  * re-orient via contact({})). */
862
- z7.object({
863
- type: z7.literal("superseded"),
864
- parentId: z7.string(),
865
- notificationId: z7.string()
966
+ z9.object({
967
+ type: z9.literal("superseded"),
968
+ parentId: z9.string(),
969
+ notificationId: z9.string()
866
970
  }),
867
971
  /** A LIVE call's turn, streamed as it lands (#783). PROVISIONAL: the user can still
868
972
  * revise any of these until the final reply arrives — partial = intelligence,
869
973
  * settled = authorization. Use it to PREPARE (fetch, draft, warm), never to act
870
974
  * irreversibly. If `acts` carries a question aimed at you and you know the answer,
871
975
  * contact on the same thread right away — the caller hears it on the same call. */
872
- z7.object({
873
- type: z7.literal("partial"),
874
- notificationId: z7.string(),
875
- inFlight: z7.literal(true),
876
- turn: z7.object({
877
- idx: z7.number(),
878
- prompt: z7.string(),
879
- reply: z7.string(),
880
- acts: z7.array(IntentSchema).nullable().optional()
976
+ z9.object({
977
+ type: z9.literal("partial"),
978
+ notificationId: z9.string(),
979
+ inFlight: z9.literal(true),
980
+ turn: z9.object({
981
+ idx: z9.number(),
982
+ prompt: z9.string(),
983
+ reply: z9.string(),
984
+ acts: z9.array(IntentSchema).nullable().optional()
881
985
  })
882
986
  }),
883
- z7.object({
884
- type: z7.literal("idle"),
885
- also: z7.array(RideAlongSchema).optional(),
987
+ z9.object({
988
+ type: z9.literal("idle"),
989
+ also: z9.array(RideAlongSchema).optional(),
886
990
  /** Is a call live for this agent's user right now? The SDK polls the partial stream
887
991
  * (#783) between idle ticks ONLY while this is not `false` — a partial can only exist
888
992
  * during a live call, and polling for one on a banner/message was a wasted HTTP call +
889
993
  * 3 queries on every idle tick of every waiting agent (~80% of all traffic at scale).
890
994
  * Absent = an older API → the SDK keeps polling, exactly as before. */
891
- inFlight: z7.boolean().optional()
995
+ inFlight: z9.boolean().optional()
892
996
  })
893
997
  ]);
894
- var VoiceKeySchema = z7.enum(["rachel", "george", "jessica", "brian", "lily"]);
895
- var AgendaTurnSchema = z7.object({
998
+ var VoiceKeySchema = z9.enum(["rachel", "george", "jessica", "brian", "lily"]);
999
+ var AgendaTurnSchema = z9.object({
896
1000
  /** THE TURN'S IDENTITY (the first-sentence stream, 2026-09-09): the brain call that wrote
897
1001
  * it and its place in that reply — `<brainCallId>:<index>`, with `:p` on the first
898
1002
  * sentence a re-plan publishes ahead of the rest. A turn is spoken once, by this id: the
899
1003
  * completion of a streamed re-plan carries the published sentence again, and the walk
900
1004
  * drops what it already said by identity, never by the API's guess of what was polled.
901
1005
  * Absent on plans nothing streams (a ring plan, a floor). */
902
- id: z7.string().optional(),
1006
+ id: z9.string().optional(),
903
1007
  /** Twin coverage (#1089): sibling claim ids this asking turn's answer ALSO settles —
904
1008
  * the planner declares duplicates instead of asking them twice. */
905
- coveredIds: z7.array(z7.string()).optional(),
1009
+ coveredIds: z9.array(z9.string()).optional(),
906
1010
  /** The spoken sentences of the turn, in order. No count: how long a turn is is the brain's call
907
1011
  * (owner, 2026-09-25), and a count here refused whole plans. */
908
- info: z7.array(z7.string().min(1)).default([]),
909
- question: z7.string().min(1).nullable(),
1012
+ info: z9.array(z9.string().min(1)).default([]),
1013
+ question: z9.string().min(1).nullable(),
910
1014
  /** True on the one turn carrying the agent's own declared question. */
911
- asks: z7.boolean().optional(),
1015
+ asks: z9.boolean().optional(),
912
1016
  /** The claim this turn belongs to (#781) — the RETURN identity: answers route by it.
913
1017
  * Absent on a single-claim plan (the session's own claim) and on shared context turns,
914
1018
  * which route nothing. */
915
- claimId: z7.string().optional(),
1019
+ claimId: z9.string().optional(),
916
1020
  /** The claim's voice key (#462) — the OUTBOUND identity, audible who-is-asking. */
917
- voice: z7.string().optional(),
1021
+ voice: z9.string().optional(),
918
1022
  /** The claim's AGENT NAME (#838) — the spoken identity. A voice alone doesn't say
919
1023
  * whose request this is: an item that folded in from another agent arrived as a bare
920
1024
  * non-sequitur ("First real production sign-in is yours to make whenever you want.")
921
1025
  * and the owner answered "What?". The bot names the agent before its first turn. */
922
- agent: z7.string().optional(),
1026
+ agent: z9.string().optional(),
923
1027
  /** The claim's agent by ID — the pairing's connection id (`notifications.token_id`), the
924
1028
  * same id a face is minted from. A name is not an identity: two pairings may be called
925
1029
  * "Claude", and a name cannot be joined on. The record's entries carry it (`agent_id`)
926
1030
  * so "who said that" survives the call, and it rides PER TURN because a coalesced call
927
1031
  * speaks for several agents — the turn is the only place that knows which. */
928
- agentId: z7.string().optional(),
1032
+ agentId: z9.string().optional(),
929
1033
  select: SelectShapeSchema.optional(),
930
- options: z7.array(OptionSchema.omit({ id: true })).optional(),
1034
+ options: z9.array(OptionSchema.omit({ id: true })).optional(),
931
1035
  /* `pace` STOOD HERE (#826). A turn could carry seconds and the model chose them. The walk
932
1036
  paces itself now — a short beat between the sentences of a turn, the longer one at its end
933
1037
  (owner, 2026-09-30: "remove the bot deciding pace") — and it does that where the words are
@@ -936,33 +1040,33 @@ var AgendaTurnSchema = z7.object({
936
1040
  /** Whether the walk WAITS for an answer before moving on. Absent = derived as today
937
1041
  * (a question blocks, context flows). blocking:false on a question = ask and move
938
1042
  * on, the claim stays pending; blocking:true on context = hold for a reply. */
939
- blocking: z7.boolean().optional(),
1043
+ blocking: z9.boolean().optional(),
940
1044
  /** SPOKEN ONLY IF THEY SAY NOTHING (owner, 2026-10-01, call 812de935: "you're gonna re-ask, but it
941
1045
  * shouldn't be the same words … more like, hey, are you still there, or are you able to answer, or
942
1046
  * would you need more information"). The walk holds this turn out of its queue; at the queue's end it
943
1047
  * listens for the last word, and only if that listen is silent is this turn said and asked. If they
944
1048
  * speak, it is dropped and their words are taken like any reply. */
945
- ifSilent: z7.boolean().optional()
1049
+ ifSilent: z9.boolean().optional()
946
1050
  });
947
1051
  var CLAIM_STALE_MS = 30 * 6e4;
948
- var InboxItemSchema = z7.object({
949
- id: z7.string(),
950
- tokenId: z7.string().optional(),
1052
+ var InboxItemSchema = z9.object({
1053
+ id: z9.string(),
1054
+ tokenId: z9.string().optional(),
951
1055
  status: NotifyStatusSchema,
952
1056
  context: ContextSchema,
953
- options: z7.array(OptionSchema).optional(),
1057
+ options: z9.array(OptionSchema).optional(),
954
1058
  /** The ask's declared coverage points (#396), when the agent sent them. */
955
- points: z7.array(z7.string()).optional(),
1059
+ points: z9.array(z9.string()).optional(),
956
1060
  /** Does this claim want an ANSWER, or is it telling you something? Written per row from
957
1061
  * `requestAsks` — the agent's own declaration, not a guess. `false` is what earns a card
958
1062
  * its acknowledge affordance: without it a status update offers a text box and a dismiss,
959
1063
  * and neither of those is "got it" (owner, 2026-08-10). */
960
- asks: z7.boolean().optional(),
1064
+ asks: z9.boolean().optional(),
961
1065
  /** When a live process last pulsed for this row's agent — the liveness input for
962
1066
  * "working requires a pulse" (#928): the list said "Working…" from agent_state alone
963
1067
  * while the party called the same dead claim stalled. Absent = no token/no data,
964
1068
  * which must never CLAIM stalled. */
965
- lastSeenAt: z7.string().optional(),
1069
+ lastSeenAt: z9.string().optional(),
966
1070
  /** WHEN THE AGENT LAST SAID ANYTHING ABOUT THIS CLAIM — the newest `agent_state` row in
967
1071
  * the `notification_events` ledger (trigger-written since 20260621010000, so every row a
968
1072
  * user can see has one). The age input for `CLAIM_STALE_MS`, and it has to be this rather
@@ -972,7 +1076,7 @@ var InboxItemSchema = z7.object({
972
1076
  * work. Reading the row's birth as the claim's age brands that "No update in 8h" the
973
1077
  * instant the agent picks it up (#997). Absent = pre-trigger row; fall back to
974
1078
  * `createdAt`. */
975
- agentStateAt: z7.string().datetime().optional(),
1079
+ agentStateAt: z9.string().datetime().optional(),
976
1080
  /** THE QUESTIONS A CALL CARRIES — the call screen's agenda spine (docs/clients/app/walk/design.md §11, owner
977
1081
  * 2026-09-22). One per DecisionNeed on the Call, in the Call's order, answered or open (a
978
1082
  * superseded or cancelled need is no longer a question anyone is asked). Present only on a
@@ -986,54 +1090,61 @@ var InboxItemSchema = z7.object({
986
1090
  * `turn` topic (`asking`, `settled`), because the bot never sees a DecisionNeed id. `title` is
987
1091
  * the card's own concise heading; `answer` the accepted answer in words, null while open. It
988
1092
  * REPLACED `agenda` (turns), which nothing ever filled. */
989
- questions: z7.array(z7.object({
990
- id: z7.string(),
991
- entryId: z7.string(),
992
- title: z7.string(),
993
- state: z7.enum(["open", "answered"]),
994
- answer: z7.string().nullable(),
1093
+ questions: z9.array(z9.object({
1094
+ id: z9.string(),
1095
+ entryId: z9.string(),
1096
+ title: z9.string(),
1097
+ state: z9.enum(["open", "answered"]),
1098
+ answer: z9.string().nullable(),
995
1099
  /** WHO ASKED IT (owner, 2026-09-23, Goal a345e906: each agenda row wears its agent's face) — the
996
1100
  * request Entry's author, as the same three facts the item's own `tokenId`/`name`/`voice`
997
1101
  * carry for the call's one agent, so the phone draws it with the same seed. Absent when the
998
1102
  * author is not an agent this account holds (unpaired since, or a person). */
999
- agent: z7.object({ tokenId: z7.string(), name: z7.string(), voice: VoiceKeySchema.optional() }).optional(),
1103
+ agent: z9.object({ tokenId: z9.string(), name: z9.string(), voice: VoiceKeySchema.optional() }).optional(),
1000
1104
  /** ITS OPTIONS, WHEN THERE IS SOMETHING TO SEE (owner, 2026-09-25: "Yes, add it"): the options
1001
1105
  * its need offers, exactly as its own card carries them, present only when one of them has a
1002
1106
  * preview (`html` or `image`). The call screen opens them from the agenda row, so a preview is
1003
- * never re-sent as a second card to be seen mid-call. Words-only options are absent — the bot
1004
- * says those, and the list stays small (an `html` is up to 16 KB). */
1005
- options: z7.array(OptionSchema).optional()
1107
+ * never re-sent as a second card to be seen mid-call. Words-only options are `choices`. */
1108
+ options: z9.array(OptionSchema).optional(),
1109
+ /** ITS OPTIONS WHEN THEY ARE WORDS (owner, 2026-10-02, on a call: "whenever there are pre-made
1110
+ * options … now for a checklist, we should also show them on the screen"; design C, 2026-10-08):
1111
+ * numbered chips above the call's controls, so a checklist is never only something read aloud. A
1112
+ * field of its own so `options` keeps meaning "previews": a phone on an older bundle opens the
1113
+ * preview layout for any `options`, and must see exactly what it did. */
1114
+ choices: z9.array(OptionSchema).optional(),
1115
+ /** HOW MANY MAY BE PICKED, beside its `choices`: one, any (`many`) or an order (`rank`). */
1116
+ select: z9.enum(["one", "many", "rank"]).optional()
1006
1117
  })).optional(),
1007
- visuals: z7.array(VisualSchema).optional(),
1118
+ visuals: z9.array(VisualSchema).optional(),
1008
1119
  /** The connected agent's name (the single pairing name — user-typed, or the
1009
1120
  * agent's suggestion, or a default silly name). */
1010
- name: z7.string(),
1121
+ name: z9.string(),
1011
1122
  /** The pairing's assigned voice (#462); absent = the default voice. */
1012
1123
  voice: VoiceKeySchema.optional(),
1013
- repo: z7.string().optional(),
1014
- branch: z7.string().optional(),
1015
- createdAt: z7.string().datetime(),
1016
- snoozedUntil: z7.string().datetime().optional(),
1124
+ repo: z9.string().optional(),
1125
+ branch: z9.string().optional(),
1126
+ createdAt: z9.string().datetime(),
1127
+ snoozedUntil: z9.string().datetime().optional(),
1017
1128
  agentState: AgentStateSchema.default("idle"),
1018
1129
  /** Whose action the item is waiting on: "you" = an agent asked you (the default,
1019
1130
  * every agent→user notification); "agent" = you sent a request and it's awaiting the
1020
1131
  * agent (held in the inbox until the agent replies on the thread). */
1021
- turn: z7.enum(["you", "agent"]).default("you"),
1132
+ turn: z9.enum(["you", "agent"]).default("you"),
1022
1133
  /** Hard error reason on an awaiting request (turn="agent") — the wake failed to reach
1023
1134
  * the agent (provider-agnostic; set server-side). Absent = no hard error. Drives the inbox
1024
1135
  * error badge + Retry. */
1025
- error: z7.string().optional(),
1136
+ error: z9.string().optional(),
1026
1137
  /** WHEN THIS AGENT WORK WENT QUIET (turn="agent"), by the one rule (`coldSince`: three days
1027
1138
  * with nothing said), or absent while it is not stalled. The inbox's stalled badge reads
1028
1139
  * this and nothing else (2026-09-23: a 3-minute age rule badged every live Goal stalled,
1029
1140
  * and "dismiss the stalled ones" cancelled 37 pieces of live work). */
1030
- cold: z7.string().datetime().optional(),
1031
- clarifies: z7.string().optional(),
1141
+ cold: z9.string().datetime().optional(),
1142
+ clarifies: z9.string().optional(),
1032
1143
  /** THIS CARD'S QUESTION IS ON A LIVE CALL (owner, 2026-09-24: "Mark it while the call is
1033
1144
  * live"). Present only while an open Call Delivery carries the card's request Entry — read
1034
1145
  * off the same open list the card came from, so it clears when the Call does. A card is the
1035
1146
  * backup for a call not taken; while the call has it, the call is where it is answered. */
1036
- onCall: z7.literal(true).optional(),
1147
+ onCall: z9.literal(true).optional(),
1037
1148
  /** THE RING, ON THE ITEM (docs/clients/app/walk/design.md §12 §17, #2251): the last ring on this card was
1038
1149
  * declined, and what the ladder will do next — read off the cron's own row, never computed
1039
1150
  * on the phone. Present only while a `declined` receipt stands on the card's last Call.
@@ -1043,31 +1154,31 @@ var InboxItemSchema = z7.object({
1043
1154
  * It replaced `gaveUp` (deleted 2026-09-22): "the ladder spent" was a boolean the projection
1044
1155
  * never set, and it is `nextRingAt === null` here — the party's *Missed you* (`party/dress.ts`)
1045
1156
  * and the roster's `unreached` read `declinedAt`, and stand while it does. */
1046
- ring: z7.object({
1047
- declinedAt: z7.string().datetime(),
1048
- anchorAt: z7.string().datetime(),
1049
- nextRingAt: z7.string().datetime().nullable(),
1050
- step: z7.number().int()
1157
+ ring: z9.object({
1158
+ declinedAt: z9.string().datetime(),
1159
+ anchorAt: z9.string().datetime(),
1160
+ nextRingAt: z9.string().datetime().nullable(),
1161
+ step: z9.number().int()
1051
1162
  }).optional(),
1052
1163
  /** Why this arrived the way it did, read back off the delivery receipt (`notify/why.ts`).
1053
1164
  * Absent for anything never delivered through a push, and for older rows written before
1054
1165
  * the reason was recorded. Deliberately a debug affordance, shown small (owner,
1055
1166
  * 2026-08-07) — its real job is to give "this didn't need a call" something to be
1056
1167
  * feedback ABOUT. */
1057
- why: z7.object({
1168
+ why: z9.object({
1058
1169
  asked: NotifyLevelSchema,
1059
1170
  got: NotifyLevelSchema,
1060
- because: z7.enum(["unresponsive", "dismissed", "not_permitted", "silent", "coalesced", "agent_capped", "unplanned", "learned_raise"]).optional(),
1061
- line: z7.string()
1171
+ because: z9.enum(["unresponsive", "dismissed", "not_permitted", "silent", "coalesced", "agent_capped", "unplanned", "learned_raise"]).optional(),
1172
+ line: z9.string()
1062
1173
  }).optional(),
1063
- select: z7.enum(["one", "many", "rank", "confirm", "text"]).default("one"),
1064
- confirmStyle: z7.enum(["yesno", "approve"]).default("yesno").describe(
1174
+ select: z9.enum(["one", "many", "rank", "confirm", "text"]).default("one"),
1175
+ confirmStyle: z9.enum(["yesno", "approve"]).default("yesno").describe(
1065
1176
  "Labels for a select:'confirm' paige \u2014 'yesno' (Yes/No) or 'approve' (Approve/Deny). Ignored unless select is 'confirm'."
1066
1177
  ),
1067
1178
  /** Real downstream work is stuck behind this one — set by the agent, independent of
1068
1179
  * urgency (see the main README's "premier use case" + docs/delivery/notify/states.md). Drives the
1069
1180
  * inbox's blocking badge and the extra confirm step before dismissing it. */
1070
- blocking: z7.boolean().default(false),
1181
+ blocking: z9.boolean().default(false),
1071
1182
  /** The user's locked-in answer; present only for replied items (GET /api/replied/:id). */
1072
1183
  answer: UserAnswerSchema.optional(),
1073
1184
  /** THE TARGET FACTS A CARD RENDERS (#1796 point 5, 2026-09-11): the Delivery it is a view of,
@@ -1075,17 +1186,17 @@ var InboxItemSchema = z7.object({
1075
1186
  * for a request that asks nothing), whether its content is sealed, and that Goal's state. The
1076
1187
  * answer writer (`POST /api/entries`) and the disposition (`close_delivery`) take their ids from
1077
1188
  * here. The server projects it (`apps/api/src/inbox/project.ts`); a client never builds it. */
1078
- communication: z7.object({
1079
- deliveryId: z7.string(),
1080
- kind: z7.enum(["notification", "call"]),
1081
- entryId: z7.string(),
1082
- goalIds: z7.array(z7.string()),
1083
- decisionNeedId: z7.string().optional(),
1084
- sealed: z7.boolean(),
1085
- goalState: z7.string().optional(),
1189
+ communication: z9.object({
1190
+ deliveryId: z9.string(),
1191
+ kind: z9.enum(["notification", "call"]),
1192
+ entryId: z9.string(),
1193
+ goalIds: z9.array(z9.string()),
1194
+ decisionNeedId: z9.string().optional(),
1195
+ sealed: z9.boolean(),
1196
+ goalState: z9.string().optional(),
1086
1197
  /** THAT GOAL'S NAME (#2416) — what Activity's row is headed by, since a row there is one Goal
1087
1198
  * and the cards it holds sit behind it. Stamped by the same read as `goalState`. */
1088
- goalTitle: z7.string().optional()
1199
+ goalTitle: z9.string().optional()
1089
1200
  }).optional(),
1090
1201
  /** WHAT THIS CARD IS, IN TWELVE CHARACTERS (#3019) — the hash of every other field on it, stamped
1091
1202
  * by the one read that serves the open list (`apps/api/src/inbox/project.ts` `inboxFor`). It is
@@ -1097,27 +1208,27 @@ var InboxItemSchema = z7.object({
1097
1208
  * own moves (its Goal's state and name, how cold the work behind it has gone, whether a ring is
1098
1209
  * live). Optional, so a fixture, the demo and the archive lens need not spell one, and a card
1099
1210
  * with no rev is simply always re-sent. */
1100
- rev: z7.string().optional()
1211
+ rev: z9.string().optional()
1101
1212
  });
1102
1213
  var APNS_TOKEN_RE = /^[0-9a-fA-F]{64}$/;
1103
- var PushTokenSchema = z7.object({
1104
- voipToken: z7.string().min(1).optional(),
1105
- alertToken: z7.string().min(1).optional(),
1106
- fcmToken: z7.string().min(1).optional(),
1107
- platform: z7.enum(["ios", "android"])
1214
+ var PushTokenSchema = z9.object({
1215
+ voipToken: z9.string().min(1).optional(),
1216
+ alertToken: z9.string().min(1).optional(),
1217
+ fcmToken: z9.string().min(1).optional(),
1218
+ platform: z9.enum(["ios", "android"])
1108
1219
  }).superRefine((v, ctx) => {
1109
1220
  if (v.platform !== "ios") return;
1110
1221
  for (const field of ["voipToken", "alertToken"]) {
1111
1222
  const token = v[field];
1112
1223
  if (token === void 0 || APNS_TOKEN_RE.test(token)) continue;
1113
1224
  ctx.addIssue({
1114
- code: z7.ZodIssueCode.custom,
1225
+ code: z9.ZodIssueCode.custom,
1115
1226
  path: [field],
1116
1227
  message: `not an APNs device token (want 64 hex chars, got ${token.length})`
1117
1228
  });
1118
1229
  }
1119
1230
  });
1120
- var MissedCallSchema = z7.enum([
1231
+ var MissedCallSchema = z9.enum([
1121
1232
  "retry_10m",
1122
1233
  "retry_30m",
1123
1234
  "retry_60m",
@@ -1129,31 +1240,31 @@ var MissedCallSchema = z7.enum([
1129
1240
  ]);
1130
1241
  var clock = (h) => h === 0 ? "midnight" : h === 12 ? "noon" : h < 12 ? `${h} am` : `${h - 12} pm`;
1131
1242
  var QUIET = ` Nothing rings from ${clock(NIGHT.from)} to ${clock(NIGHT.to)} your time; the count waits for morning.`;
1132
- var BrokerTuningSchema = z7.object({
1243
+ var BrokerTuningSchema = z9.object({
1133
1244
  /** 'none' = skip the spoken ack after a mapped answer (power users find it slow). */
1134
- ackVerbosity: z7.enum(["normal", "none"]).optional(),
1245
+ ackVerbosity: z9.enum(["normal", "none"]).optional(),
1135
1246
  /** How readily the mapper asks its one clarification: 'low' = only when truly
1136
1247
  * uninterpretable, 'high' = whenever not fully certain. */
1137
- clarifyEagerness: z7.enum(["low", "normal", "high"]).optional(),
1248
+ clarifyEagerness: z9.enum(["low", "normal", "high"]).optional(),
1138
1249
  /** The user's own shorthand: when they say `say`, they mean `mean`. */
1139
- phrasebook: z7.array(z7.object({ say: z7.string().min(1).max(60), mean: z7.string().min(1).max(120) })).max(24).optional(),
1250
+ phrasebook: z9.array(z9.object({ say: z9.string().min(1).max(60), mean: z9.string().min(1).max(120) })).max(24).optional(),
1140
1251
  /** The language calls are PLANNED in, when the account has chosen one (#1272). Absent —
1141
1252
  * which is every account today — means the agent's own words decide, per ask: a call
1142
1253
  * about an English ask opens in English. This is the only thing that overrides that,
1143
1254
  * and a live caller who switches language mid-call still outranks it (broker/lang.ts).
1144
1255
  * Set per user (no UI yet), like `voiceTuning`. */
1145
- language: z7.enum(["en", "es"]).optional()
1256
+ language: z9.enum(["en", "es"]).optional()
1146
1257
  });
1147
- var UserSettingsSchema = z7.object({
1148
- permissions: z7.object({
1149
- call: z7.boolean(),
1150
- banner: z7.boolean(),
1151
- push: z7.boolean()
1258
+ var UserSettingsSchema = z9.object({
1259
+ permissions: z9.object({
1260
+ call: z9.boolean(),
1261
+ banner: z9.boolean(),
1262
+ push: z9.boolean()
1152
1263
  }),
1153
1264
  /** LockedIn / Default / DateNight on screen; the stored words are unchanged on purpose —
1154
1265
  * they are an enum on a live column across every account, and the rename is a rename of
1155
1266
  * what people read (owner, 2026-09-30). */
1156
- sessionMode: z7.enum(["default", "all_calls", "silent"]),
1267
+ sessionMode: z9.enum(["default", "all_calls", "silent"]),
1157
1268
  /** `silentPush` lived here until #2813 and is now GONE, field and column both. It was kept as an
1158
1269
  * optional long after DateNight stopped reading it, on the theory that a phone on an older
1159
1270
  * bundle PATCHing the whole settings object would be REFUSED for sending a key we had stopped
@@ -1162,7 +1273,7 @@ var UserSettingsSchema = z7.object({
1162
1273
  * an old bundle's `silentPush` is accepted and ignored. Worth remembering before keeping the
1163
1274
  * next dead field for the same reason. */
1164
1275
  /** Opt-in (default false) to using your content to improve Paigy and train models. */
1165
- improveConsent: z7.boolean(),
1276
+ improveConsent: z9.boolean(),
1166
1277
  missedCall: MissedCallSchema.default("backoff_standard"),
1167
1278
  /** Where voice audio is processed. 'hosted' (default) = Paigy's voice services
1168
1279
  * (ElevenLabs TTS, faster-whisper STT, the call bot); 'on_device' = the phone
@@ -1170,17 +1281,17 @@ var UserSettingsSchema = z7.object({
1170
1281
  * Optional, NOT defaulted: a stale client PATCHing the full settings object
1171
1282
  * must not silently reset this privacy choice. Absent = leave unchanged on
1172
1283
  * write, 'hosted' on read (see store.ts). */
1173
- voiceMode: z7.enum(["hosted", "on_device"]).optional(),
1284
+ voiceMode: z9.enum(["hosted", "on_device"]).optional(),
1174
1285
  /** Talk — after you answer, the next step is read aloud (docs/clients/app/walk/design.md §6). ALWAYS ON until
1175
1286
  * turned off (owner, 2026-09-18, #2249): a setting, not a per-walk toggle. Optional, NOT
1176
1287
  * defaulted, for the same reason `voiceMode` is: a stale client PATCHing the full settings
1177
1288
  * object must not silently turn it back on. Absent = leave unchanged on write, true on
1178
1289
  * read (see store.ts). */
1179
- talk: z7.boolean().optional(),
1290
+ talk: z9.boolean().optional(),
1180
1291
  /** CALL DIAGNOSTICS (owner, 2026-10-01): the call report carries each listen and the bot's own
1181
1292
  * load timings. SERVER-SET, no UI — on for every account that existed on 2026-10-01, off for
1182
1293
  * newer ones (migration 20261001132859). Read-only here: the settings PATCH never writes it. */
1183
- callDiagnostics: z7.boolean().optional(),
1294
+ callDiagnostics: z9.boolean().optional(),
1184
1295
  /** Per-user ring budget (#603): calls per rolling day before further calls
1185
1296
  * degrade to banner. Absent = the global default (25). A number, never a
1186
1297
  * bypass — every account keeps a ceiling. No UI; set per user for testing. */
@@ -1188,7 +1299,7 @@ var UserSettingsSchema = z7.object({
1188
1299
  * payload['tuning'] (e.g. { silence_s: 3.5 } — a longer pause window for a
1189
1300
  * slower speaker). No API-side semantics; the bot resolves each key with its
1190
1301
  * own defaults. Set per user (no UI yet); absent = bot defaults. */
1191
- voiceTuning: z7.record(z7.string(), z7.union([z7.number(), z7.string()])).optional(),
1302
+ voiceTuning: z9.record(z9.string(), z9.union([z9.number(), z9.string()])).optional(),
1192
1303
  /** The user's IANA timezone (e.g. "America/Bogota"), recorded by the app — it is the
1193
1304
  * only party that knows it. REMINDERS are why it exists: "remind me at ten" becomes
1194
1305
  * an absolute `due_at` only if we know whose ten. Optional and never defaulted, for
@@ -1197,53 +1308,53 @@ var UserSettingsSchema = z7.object({
1197
1308
  * that failure reads as the reminder rail being unreliable rather than as a missing
1198
1309
  * setting. Absent = a spoken time can't be landed, so the reminder rides the next
1199
1310
  * call — honest about what we know. */
1200
- timezone: z7.string().min(1).max(64).optional(),
1311
+ timezone: z9.string().min(1).max(64).optional(),
1201
1312
  /** Rung-2 broker tuning (#381). Optional and NOT defaulted, same stale-client
1202
1313
  * clobber guard as voiceMode: absent = leave unchanged on write. */
1203
1314
  broker: BrokerTuningSchema.optional()
1204
1315
  });
1205
- var HistoryWorkSchema = z7.object({
1206
- id: z7.string(),
1207
- title: z7.string(),
1208
- state: z7.enum(["done", "cancelled"]),
1316
+ var HistoryWorkSchema = z9.object({
1317
+ id: z9.string(),
1318
+ title: z9.string(),
1319
+ state: z9.enum(["done", "cancelled"]),
1209
1320
  /** Who held it (`agent:<tokenId>` or `human:<userId>`). */
1210
- assignee: z7.string()
1321
+ assignee: z9.string()
1211
1322
  });
1212
- var HistoryEntrySchema = z7.union([
1213
- z7.object({ at: z7.string(), card: InboxItemSchema }),
1214
- z7.object({ at: z7.string(), work: HistoryWorkSchema })
1323
+ var HistoryEntrySchema = z9.union([
1324
+ z9.object({ at: z9.string(), card: InboxItemSchema }),
1325
+ z9.object({ at: z9.string(), work: HistoryWorkSchema })
1215
1326
  ]);
1216
- var HistoryPageSchema = z7.object({
1217
- entries: z7.array(HistoryEntrySchema),
1218
- next: z7.string().nullable()
1327
+ var HistoryPageSchema = z9.object({
1328
+ entries: z9.array(HistoryEntrySchema),
1329
+ next: z9.string().nullable()
1219
1330
  });
1220
1331
  var ACTIVITY_LINES = 2;
1221
1332
  var ACTIVITY_LINE_MAX = 80;
1222
- var AgentActivitySchema = z7.object({
1333
+ var AgentActivitySchema = z9.object({
1223
1334
  /** Oldest first, so the newest line is last — the one that replaces in place. */
1224
- lines: z7.array(z7.string().max(ACTIVITY_LINE_MAX)).max(ACTIVITY_LINES),
1335
+ lines: z9.array(z9.string().max(ACTIVITY_LINE_MAX)).max(ACTIVITY_LINES),
1225
1336
  /** When the harness observed this tail. Its own timestamp, not the heartbeat's: a beat
1226
1337
  * that carries an UNCHANGED tail must not make a stalled agent look like it just moved. */
1227
- at: z7.string().datetime()
1338
+ at: z9.string().datetime()
1228
1339
  });
1229
- var ConnectionSummarySchema = z7.object({
1340
+ var ConnectionSummarySchema = z9.object({
1230
1341
  /** The connection = the agent's token id (used to address a request). */
1231
- id: z7.string(),
1342
+ id: z9.string(),
1232
1343
  /** The credential kind: "device" = a paired machine (mint-only — it hosts and mints, it
1233
1344
  * never talks); "agent" = an identity that sends. The roster and devices surfaces split
1234
1345
  * on this. Optional/absent reads as "agent" (a row predating the kind column). See
1235
1346
  * docs/server/tokens/devices-vs-agents-design.md. */
1236
- kind: z7.enum(["device", "agent"]).optional(),
1347
+ kind: z9.enum(["device", "agent"]).optional(),
1237
1348
  /** For an agent, the token id of the DEVICE that minted it — so agents group under their
1238
1349
  * machine, and revoking a device cascades to them. Null on devices, and on unlinked
1239
1350
  * agents (phone-launched, provider-managed, or minted before the link existed). */
1240
- mintedByDevice: z7.string().nullable().optional(),
1241
- device: z7.string().nullable(),
1351
+ mintedByDevice: z9.string().nullable().optional(),
1352
+ device: z9.string().nullable(),
1242
1353
  /** The agent's display name (the single pairing name). */
1243
- name: z7.string(),
1354
+ name: z9.string(),
1244
1355
  /** For a managed connection, the provider key (e.g. "cma") that agentOrigin maps to a
1245
1356
  * label; null for a local connection. Sourced from the token's provider, not the name. */
1246
- provider: z7.string().nullable(),
1357
+ provider: z9.string().nullable(),
1247
1358
  /** The pairing's assigned voice (#462); null = the default voice. */
1248
1359
  voice: VoiceKeySchema.nullable(),
1249
1360
  /** The LOUDEST this agent may ever reach you — a ceiling on `NOTIFY_LADDER`, set by the
@@ -1254,34 +1365,34 @@ var ConnectionSummarySchema = z7.object({
1254
1365
  * every surface at once and outranks even `sessionMode: all_calls` — a mode the user
1255
1366
  * set once must not overrule a rule they set about one agent. */
1256
1367
  reach: NotifyLevelSchema.nullable().optional(),
1257
- createdAt: z7.string().datetime(),
1368
+ createdAt: z9.string().datetime(),
1258
1369
  /** Most recent notification on this connection, either direction. Null = no contact yet.
1259
1370
  * Drives the agents-page recency grouping (Today / This week / …). */
1260
- lastContactAt: z7.string().datetime().nullable(),
1371
+ lastContactAt: z9.string().datetime().nullable(),
1261
1372
  /** Last presence heartbeat from a running agent process (POST /api/presence) — the
1262
1373
  * desktop app while open. Null = never seen; stale = offline. */
1263
- lastSeenAt: z7.string().datetime().nullable().optional(),
1374
+ lastSeenAt: z9.string().datetime().nullable().optional(),
1264
1375
  /** WORKING, NOT JUST CONNECTED (owner, 2026-09-30): the last time the agent itself acted on one of
1265
- * its Goals — took its lease or recorded an operation (`tokens.last_worked_at`). Within
1376
+ * its Goals — wrote on one or recorded an operation (`tokens.last_worked_at`). Within
1266
1377
  * `WORKING_MS` it is working; otherwise it is connected but idle. Null = not seen working yet. */
1267
- lastWorkedAt: z7.string().datetime().nullable().optional(),
1378
+ lastWorkedAt: z9.string().datetime().nullable().optional(),
1268
1379
  /** The oldest of its Goals that is `ready` for it — work handed to it that nobody has started.
1269
1380
  * With no work of its own for `WORKING_MS`, an agent sitting on this is not taking its work. */
1270
- oldestReadyAt: z7.string().datetime().nullable().optional(),
1381
+ oldestReadyAt: z9.string().datetime().nullable().optional(),
1271
1382
  /** What a live desktop can run (docs/clients/desktop/companion.md §2.2), advertised on its heartbeat:
1272
1383
  * harness availabilities + granted workspaces — the option set the phone's
1273
1384
  * "new session" sheet offers. Absent for ordinary MCP agents. */
1274
- runtime: z7.object({
1385
+ runtime: z9.object({
1275
1386
  /** The @paigy/harness this host is running — a machine the self-update has not reached
1276
1387
  * shows its age here (`apps/desktop/src/update.ts`). */
1277
- version: z7.string().optional(),
1278
- harnesses: z7.array(z7.object({ name: z7.string(), label: z7.string(), status: z7.string() })).optional(),
1279
- workspaces: z7.array(z7.string()).optional(),
1388
+ version: z9.string().optional(),
1389
+ harnesses: z9.array(z9.object({ name: z9.string(), label: z9.string(), status: z9.string() })).optional(),
1390
+ workspaces: z9.array(z9.string()).optional(),
1280
1391
  /** THE GIT REPOS IN THOSE FOLDERS (2026-10-01, Goal 26982211): each granted folder that is a
1281
1392
  * repo, and each repo directly inside one, with its `origin` remote. A session started for
1282
1393
  * work on `mauurda/paigy` opens in that repo rather than the folder above it, where the repo's
1283
1394
  * own AGENTS.md is never read (`workspaceForRepo`). Absent on hosts that predate it. */
1284
- repos: z7.array(z7.object({ path: z7.string(), remote: z7.string() })).optional()
1395
+ repos: z9.array(z9.object({ path: z9.string(), remote: z9.string() })).optional()
1285
1396
  }).optional(),
1286
1397
  /** The tail of this agent's working log, when a harness is driving it — the agent page's
1287
1398
  * live strip. Absent for anything the desktop harness isn't running (a hatched identity
@@ -1290,156 +1401,156 @@ var ConnectionSummarySchema = z7.object({
1290
1401
  activity: AgentActivitySchema.optional(),
1291
1402
  /** True = a provider-managed agent running in the provider's cloud (e.g. Anthropic CMA);
1292
1403
  * false = a local MCP connection running on the user's computer (Claude Code/Codex/…). */
1293
- managed: z7.boolean()
1404
+ managed: z9.boolean()
1294
1405
  });
1295
- var LedgerItemSchema = z7.object({ id: z7.string(), parentId: z7.string(), title: z7.string(), createdAt: z7.string() });
1296
- var AgentLedgerSchema = z7.object({
1406
+ var LedgerItemSchema = z9.object({ id: z9.string(), parentId: z9.string(), title: z9.string(), createdAt: z9.string() });
1407
+ var AgentLedgerSchema = z9.object({
1297
1408
  /** Null when the agent has not named itself yet — never a placeholder (owner, 2026-10-01). */
1298
- agent: z7.object({ id: z7.string(), name: z7.string().nullable(), revokedAt: z7.string().nullable() }),
1409
+ agent: z9.object({ id: z9.string(), name: z9.string().nullable(), revokedAt: z9.string().nullable() }),
1299
1410
  /** Its own questions you have not answered. */
1300
- asks: z7.array(LedgerItemSchema),
1411
+ asks: z9.array(LedgerItemSchema),
1301
1412
  /** Its questions you answered that nobody acted on — still owed to somebody. */
1302
- answered: z7.array(LedgerItemSchema),
1413
+ answered: z9.array(LedgerItemSchema),
1303
1414
  /** Requests you sent it that it never took. */
1304
- requests: z7.array(LedgerItemSchema),
1305
- goals: z7.array(z7.object({ id: z7.string(), outcome: z7.string(), state: z7.string() })),
1306
- callbacks: z7.array(z7.object({ id: z7.string(), parentId: z7.string(), trigger: z7.string(), note: z7.string(), dueAt: z7.string().nullable() }))
1415
+ requests: z9.array(LedgerItemSchema),
1416
+ goals: z9.array(z9.object({ id: z9.string(), outcome: z9.string(), state: z9.string() })),
1417
+ callbacks: z9.array(z9.object({ id: z9.string(), parentId: z9.string(), trigger: z9.string(), note: z9.string(), dueAt: z9.string().nullable() }))
1307
1418
  });
1308
- var ReassignResultSchema = z7.object({
1309
- moved: z7.object({ asks: z7.number(), answered: z7.number(), requests: z7.number(), goals: z7.number(), callbacks: z7.number() }),
1310
- parentId: z7.string().nullable()
1419
+ var ReassignResultSchema = z9.object({
1420
+ moved: z9.object({ asks: z9.number(), answered: z9.number(), requests: z9.number(), goals: z9.number(), callbacks: z9.number() }),
1421
+ parentId: z9.string().nullable()
1311
1422
  });
1312
- var LessonStateSchema = z7.enum(["active", "proposed", "retired"]);
1313
- var LessonViewSchema = z7.object({
1314
- id: z7.string(),
1315
- text: z7.string(),
1423
+ var LessonStateSchema = z9.enum(["active", "proposed", "retired"]);
1424
+ var LessonViewSchema = z9.object({
1425
+ id: z9.string(),
1426
+ text: z9.string(),
1316
1427
  state: LessonStateSchema,
1317
1428
  /** The Goal it is scoped to; null = the whole account. */
1318
- scopeGoalId: z7.string().nullable(),
1319
- goalTitle: z7.string().nullable(),
1320
- version: z7.number(),
1321
- pinned: z7.boolean(),
1429
+ scopeGoalId: z9.string().nullable(),
1430
+ goalTitle: z9.string().nullable(),
1431
+ version: z9.number(),
1432
+ pinned: z9.boolean(),
1322
1433
  /** When the person last wrote its text themselves. */
1323
- editedAt: z7.string().nullable(),
1324
- createdAt: z7.string(),
1325
- updatedAt: z7.string(),
1434
+ editedAt: z9.string().nullable(),
1435
+ createdAt: z9.string(),
1436
+ updatedAt: z9.string(),
1326
1437
  /** The Entries it came from, oldest first; `words` is null when an Entry has none to show (sealed). */
1327
- sources: z7.array(z7.object({ entryId: z7.string(), words: z7.string().nullable(), at: z7.string() }))
1438
+ sources: z9.array(z9.object({ entryId: z9.string(), words: z9.string().nullable(), at: z9.string() }))
1328
1439
  });
1329
- var QueueQuestionSchema = z7.object({
1440
+ var QueueQuestionSchema = z9.object({
1330
1441
  /** The decision need's id — what an answer is accepted against. */
1331
- id: z7.string(),
1442
+ id: z9.string(),
1332
1443
  /** The words that were asked, from the request Entry that asked them. */
1333
- question: z7.string(),
1444
+ question: z9.string(),
1334
1445
  /** Where it was asked — which is where the ruling goes (`POST /api/entries`). Null only
1335
1446
  * for a need whose request Entry is carried by no interactive Delivery, which nothing
1336
1447
  * can answer. */
1337
- deliveryId: z7.string().nullable().default(null),
1448
+ deliveryId: z9.string().nullable().default(null),
1338
1449
  /** The Entry the ruling is about. */
1339
- aboutId: z7.string().nullable().default(null),
1450
+ aboutId: z9.string().nullable().default(null),
1340
1451
  /** Empty for a free-text question. */
1341
- options: z7.array(OptionSchema).default([]),
1342
- select: z7.enum(["one", "many", "rank", "confirm", "text"]).default("text"),
1343
- askedAt: z7.string(),
1452
+ options: z9.array(OptionSchema).default([]),
1453
+ select: z9.enum(["one", "many", "rank", "confirm", "text"]).default("text"),
1454
+ askedAt: z9.string(),
1344
1455
  /** Null while the question is open — which is how the page tells the two apart. */
1345
- answeredAt: z7.string().nullable().default(null),
1456
+ answeredAt: z9.string().nullable().default(null),
1346
1457
  /** The ruling in the person's own words, from the contribution that replied — not the
1347
1458
  * option id, which is not something anyone reads back. Null while it is open, and null
1348
1459
  * for a settled question whose reply carried nothing readable. */
1349
- answer: z7.string().nullable().default(null),
1460
+ answer: z9.string().nullable().default(null),
1350
1461
  /** The Goal this question belongs to — a step knows its Goal on its own, not only through
1351
1462
  * an `InboxItem`'s `communication.goalIds[0]` (docs/clients/app/walk/design.md §12 item 3).
1352
1463
  * READ BY `apps/client/src/walk/order.ts`, which stamps it onto every `WalkStep`: the walk's
1353
1464
  * order, its route, home's trees and the list of steps all take a step's Goal from here, so
1354
1465
  * this is the field they agree through rather than each re-deriving it from the row it
1355
1466
  * arrived under. Required because the API projects it on every need it sends. */
1356
- goalId: z7.string(),
1467
+ goalId: z9.string(),
1357
1468
  /** True only while an unmet START gate holds the Goal — a Goal that merely waits to
1358
1469
  * *finish* does not stop a person from answering (owner, 2026-09-16: "per need gate from
1359
1470
  * the API"; §4's dashed node). Not the same fact as `QueueItem.blocked`, which counts any
1360
1471
  * gate at all. */
1361
- blocked: z7.boolean().default(false)
1472
+ blocked: z9.boolean().default(false)
1362
1473
  });
1363
- var QueueReplySchema = z7.object({
1474
+ var QueueReplySchema = z9.object({
1364
1475
  /** The card this note was (`deliveryId:requestEntryId`, minted by the server like every card
1365
1476
  * id) — so the phone can tell a reply it just sent from one the queue already carries, and the
1366
1477
  * walk can name it in its zoom. */
1367
- id: z7.string(),
1478
+ id: z9.string(),
1368
1479
  /** The Goal the note is on. */
1369
- goalId: z7.string(),
1480
+ goalId: z9.string(),
1370
1481
  /** What the note said. */
1371
- note: z7.string(),
1482
+ note: z9.string(),
1372
1483
  /** Where it was carried — where a second reply goes (`POST /api/entries`, #2252). */
1373
- deliveryId: z7.string(),
1374
- requestEntryId: z7.string(),
1375
- askedAt: z7.string(),
1484
+ deliveryId: z9.string(),
1485
+ requestEntryId: z9.string(),
1486
+ askedAt: z9.string(),
1376
1487
  /** When the person last replied — the window's start. */
1377
- repliedAt: z7.string(),
1488
+ repliedAt: z9.string(),
1378
1489
  /** The person's latest words about it; null when there is nothing readable in them. */
1379
- reply: z7.string().nullable()
1490
+ reply: z9.string().nullable()
1380
1491
  });
1381
- var QueueItemSchema = z7.object({
1382
- id: z7.string(),
1492
+ var QueueItemSchema = z9.object({
1493
+ id: z9.string(),
1383
1494
  /** One-line headline — the first sentence of the outcome. */
1384
- title: z7.string(),
1495
+ title: z9.string(),
1385
1496
  /** The outcome in full, verbatim: the person's own words are what an assignee sees. */
1386
- intent: z7.string(),
1497
+ intent: z9.string(),
1387
1498
  /** `ready` | `active` | `waiting` | `done` | `cancelled`, straight off the Goal. */
1388
- state: z7.string(),
1499
+ state: z9.string(),
1389
1500
  /** Who holds it (a participant ref); null when nobody does yet. */
1390
- assignee: z7.string().nullable().default(null),
1501
+ assignee: z9.string().nullable().default(null),
1391
1502
  /** What the agent last said it was doing; null if it has said nothing. */
1392
- progress: z7.string().nullable().default(null),
1503
+ progress: z9.string().nullable().default(null),
1393
1504
  /** HOME'S LINE FOR THAT NOTE (owner, 2026-09-23): a few plain words one read wrote from `progress`,
1394
1505
  * served only while it was written for the current note. Null means show the Goal's name. */
1395
- progressLine: z7.string().nullable().optional(),
1396
- reviewPending: z7.boolean().default(false),
1397
- dueAt: z7.string().nullable().default(null),
1506
+ progressLine: z9.string().nullable().optional(),
1507
+ reviewPending: z9.boolean().default(false),
1508
+ dueAt: z9.string().nullable().default(null),
1398
1509
  /** WHEN ITS OWNER SAID DONE WHILE CHILDREN WERE OPEN (#2704): its own work is finished and it closes
1399
1510
  * with its last open child. Null otherwise; optional, so hand-built queues need not spell it. */
1400
- finishedAt: z7.string().nullable().optional(),
1511
+ finishedAt: z9.string().nullable().optional(),
1401
1512
  /** The Goal this one was opened under; null at the root. */
1402
- parentGoalId: z7.string().nullable().default(null),
1513
+ parentGoalId: z9.string().nullable().default(null),
1403
1514
  /** Goals opened under this one — only those the same list holds. */
1404
- childGoalIds: z7.array(z7.string()).default([]),
1515
+ childGoalIds: z9.array(z9.string()).default([]),
1405
1516
  /** Goals this one waits on (start or finish gates). */
1406
- dependencyGoalIds: z7.array(z7.string()).default([]),
1517
+ dependencyGoalIds: z9.array(z9.string()).default([]),
1407
1518
  /** True while any gate is on a Goal that is not done — the walk draws it dashed. */
1408
- blocked: z7.boolean().default(false),
1519
+ blocked: z9.boolean().default(false),
1409
1520
  /** Its questions: every OPEN one, and at most ten settled, newest settled first
1410
1521
  * (20260929133308) — the page decides which of them to show. NOT the whole set: `asked` and
1411
1522
  * `answered` are, and a settled one's words are a line (280 characters), its body read when the
1412
1523
  * question is opened. */
1413
- questions: z7.array(QueueQuestionSchema).default([]),
1524
+ questions: z9.array(QueueQuestionSchema).default([]),
1414
1525
  /** HOW MANY QUESTIONS THIS WORK HAS ASKED, and how many are answered — the Goal's own totals,
1415
1526
  * bounded at 100 server-side. A tally counted off `questions` is a wrong number that looks
1416
1527
  * right once the cap bites (`walk/trees.ts` `tallyOf`). Optional, and defaulted from the array
1417
1528
  * by the projection, so hand-built queues (fixtures, the demo) need not spell them. */
1418
- asked: z7.number().optional(),
1419
- answered: z7.number().optional(),
1529
+ asked: z9.number().optional(),
1530
+ answered: z9.number().optional(),
1420
1531
  /** Every note on it the person replied to (`QueueReplySchema`) — the page decides which to show.
1421
1532
  * Optional, not defaulted: absent is none, and every hand-built queue (fixtures, the demo) need
1422
1533
  * not spell an empty list. */
1423
- replies: z7.array(QueueReplySchema).optional(),
1534
+ replies: z9.array(QueueReplySchema).optional(),
1424
1535
  /** The repository or project identifier this Goal belongs to (#2280), null if untracked. */
1425
- repo: z7.string().nullable().optional(),
1426
- createdAt: z7.string(),
1427
- updatedAt: z7.string().nullable().default(null),
1536
+ repo: z9.string().nullable().optional(),
1537
+ createdAt: z9.string(),
1538
+ updatedAt: z9.string().nullable().default(null),
1428
1539
  /** When its owner last SAID something about it (the newest `progress` Entry: a contact update kept
1429
1540
  * as progress). `updatedAt` moves for reasons nobody chose — a
1430
1541
  * state recomputed, a review flag — so it cannot tell work in hand from work gone quiet. */
1431
- lastProgressAt: z7.string().nullable().optional(),
1542
+ lastProgressAt: z9.string().nullable().optional(),
1432
1543
  /** THE GOAL'S NEWEST WORD, FROM EITHER SIDE (owner, 2026-09-27): the newest Entry on it, of any
1433
1544
  * kind — what the person added ("Add to this"), their reply, the agent's ask or its progress
1434
1545
  * note. A progress note is an Entry, so this is already the newer of the two: the person's note
1435
1546
  * shows the moment it is written, and the agent's reply or next note replaces it by being newer.
1436
1547
  * `said` is bounded to 280 characters server-side (a line, not the conversation). Null when the
1437
1548
  * Goal carries no readable Entry; optional, so hand-built queues need not spell it. */
1438
- latest: z7.object({
1439
- from: z7.enum(["person", "agent"]),
1440
- said: z7.string(),
1441
- at: z7.string(),
1442
- entryId: z7.string()
1549
+ latest: z9.object({
1550
+ from: z9.enum(["person", "agent"]),
1551
+ said: z9.string(),
1552
+ at: z9.string(),
1553
+ entryId: z9.string()
1443
1554
  }).nullable().optional(),
1444
1555
  /** WHEN THIS PERSON LAST PUT A HAND ON IT THEMSELVES (owner, Paigy Goal 16d18f51, 2026-09-30):
1445
1556
  * the newest Entry on the Goal they wrote, of any kind — a line they added, a reply to a note, an
@@ -1452,7 +1563,7 @@ var QueueItemSchema = z7.object({
1452
1563
  * minute after the person speaks erases their instant from it, and the durable traces the client
1453
1564
  * can see (`replies`, `questions[].answeredAt`) miss a spontaneous note entirely — a `request`
1454
1565
  * Entry with no `about_id` is in neither. */
1455
- lastPersonAt: z7.string().nullable().optional(),
1566
+ lastPersonAt: z9.string().nullable().optional(),
1456
1567
  /** WHAT THIS ROW IS, IN TWELVE CHARACTERS (#2928) — the hash of every other field on it, stamped
1457
1568
  * by the one projection that builds the row (`apps/api/src/goal/queue.ts`). It is how the
1458
1569
  * incremental read knows a row has not moved: the phone echoes back the revs it holds
@@ -1460,43 +1571,43 @@ var QueueItemSchema = z7.object({
1460
1571
  *
1461
1572
  * IT IS THE PAYLOAD'S OWN HASH, NEVER A STAMP ON THE WORK. Nothing here reasons about which
1462
1573
  * writes change which field — the comparison is over the bytes the phone is holding, so a fact
1463
- * the row shows that no `updated_at` moves for (a lease lapsing, a dependency's state, a
1574
+ * the row shows that no `updated_at` moves for (`active` lapsing, a dependency's state, a
1464
1575
  * sibling appearing in `childGoalIds`) cannot go unnoticed. Optional because a hand-built
1465
1576
  * queue (a fixture, the demo) spells none, and a row with no rev is simply always re-sent. */
1466
- rev: z7.string().optional()
1577
+ rev: z9.string().optional()
1467
1578
  });
1468
- var QueueDeltaSchema = z7.object({
1469
- ids: z7.array(z7.string()),
1470
- items: z7.array(QueueItemSchema)
1579
+ var QueueDeltaSchema = z9.object({
1580
+ ids: z9.array(z9.string()),
1581
+ items: z9.array(QueueItemSchema)
1471
1582
  });
1472
1583
  var COLD_AFTER_MS = 3 * 24 * 60 * 60 * 1e3;
1473
- var NoteSourceSchema = z7.enum(["app", "call"]);
1474
- var NoteStatusSchema = z7.enum(["open", "assigned", "in_progress", "done"]);
1475
- var NoteRepeatSchema = z7.enum(["once", "until_done"]);
1476
- var DecisionSchema = z7.object({
1477
- id: z7.string(),
1584
+ var NoteSourceSchema = z9.enum(["app", "call"]);
1585
+ var NoteStatusSchema = z9.enum(["open", "assigned", "in_progress", "done"]);
1586
+ var NoteRepeatSchema = z9.enum(["once", "until_done"]);
1587
+ var DecisionSchema = z9.object({
1588
+ id: z9.string(),
1478
1589
  /** The note this decision refines; null = recorded on a bare thread (the
1479
1590
  * extensibility seam — any conversation can accrue decisions). */
1480
- noteId: z7.string().nullable(),
1591
+ noteId: z9.string().nullable(),
1481
1592
  /** What was ambiguous — the broker's (or the user's own) question. */
1482
- question: z7.string(),
1593
+ question: z9.string(),
1483
1594
  /** The user's ruling; null while the question is open. */
1484
- answer: z7.string().nullable(),
1485
- decidedAt: z7.string().nullable(),
1486
- createdAt: z7.string()
1595
+ answer: z9.string().nullable(),
1596
+ decidedAt: z9.string().nullable(),
1597
+ createdAt: z9.string()
1487
1598
  });
1488
- var NoteSchema = z7.object({
1489
- id: z7.string(),
1599
+ var NoteSchema = z9.object({
1600
+ id: z9.string(),
1490
1601
  /** One-line headline (broker-titled; deterministic floor). */
1491
- title: z7.string(),
1602
+ title: z9.string(),
1492
1603
  /** The original intent, verbatim — assignees always see the user's own words. */
1493
- intent: z7.string(),
1604
+ intent: z9.string(),
1494
1605
  source: NoteSourceSchema,
1495
1606
  status: NoteStatusSchema,
1496
1607
  /** Who it was assigned to (a participant ref, 'agent:<tokenId>'); null = unassigned. */
1497
- assignee: z7.string().nullable(),
1608
+ assignee: z9.string().nullable(),
1498
1609
  /** The request thread minted at assignment; null until assigned. */
1499
- parentId: z7.string().nullable(),
1610
+ parentId: z9.string().nullable(),
1500
1611
  /** REMINDERS (docs/model/notes/reminders-design.md): the NOT-BEFORE this becomes eligible to ride a
1501
1612
  * call — never a deadline. It only ever comes from the user's own words, so when it
1502
1613
  * passes Paigy rings ONCE (#1293, owner 2026-08-26: a time said out loud is consent to
@@ -1505,152 +1616,152 @@ var NoteSchema = z7.object({
1505
1616
  // Defaulted, not required: a Note from an API deploy older than the reminders
1506
1617
  // migration has none of these, and the defaults ARE what it means — no not-before,
1507
1618
  // one ride, never ridden. Parsing must not fail across a rolling deploy.
1508
- dueAt: z7.string().nullable().default(null),
1619
+ dueAt: z9.string().nullable().default(null),
1509
1620
  repeat: NoteRepeatSchema.default("once"),
1510
1621
  /** How many calls have already carried it — the fatigue cap counts rides, not days. */
1511
- rides: z7.number().int().default(0),
1512
- lastRideAt: z7.string().nullable().default(null),
1513
- createdAt: z7.string()
1622
+ rides: z9.number().int().default(0),
1623
+ lastRideAt: z9.string().nullable().default(null),
1624
+ createdAt: z9.string()
1514
1625
  });
1515
- var TriageItemSchema = z7.object({
1516
- noteId: z7.string(),
1626
+ var TriageItemSchema = z9.object({
1627
+ noteId: z9.string(),
1517
1628
  /** The note's headline at run time. */
1518
- title: z7.string(),
1629
+ title: z9.string(),
1519
1630
  /** WHY, in one short human line, evidence first — this is read on a phone underneath
1520
1631
  * the note's title: "no movement in 34 days", "worked 3 notes in this repo this week".
1521
1632
  * Never a model's reasoning transcript, never an id. */
1522
- why: z7.string()
1633
+ why: z9.string()
1523
1634
  });
1524
- var TriageAssignmentSchema = z7.object({
1635
+ var TriageAssignmentSchema = z9.object({
1525
1636
  /** The agent's token id — what `dispatchNote` resolves and what a request is addressed to. */
1526
- agent: z7.string(),
1637
+ agent: z9.string(),
1527
1638
  /** Its display name at run time (the name on the hatchling's card). Denormalized for the
1528
1639
  * same reason as `title`: the card must render from the proposal alone. */
1529
- agentName: z7.string(),
1530
- notes: z7.array(TriageItemSchema)
1640
+ agentName: z9.string(),
1641
+ notes: z9.array(TriageItemSchema)
1531
1642
  });
1532
- var TriageStatusSchema = z7.enum(["open", "superseded", "dismissed"]);
1533
- var SubmitTriageSchema = z7.object({
1643
+ var TriageStatusSchema = z9.enum(["open", "superseded", "dismissed"]);
1644
+ var SubmitTriageSchema = z9.object({
1534
1645
  /** Which runtime judged: "ollama" (inference never left the machine) or a harness the
1535
1646
  * user already runs under their own credentials ("claude" / "codex" / "agy"). Recorded
1536
1647
  * so the phone can say where the content went — an unattributed privacy claim is worth
1537
1648
  * nothing, and #1106's promise is precisely "Paigy's servers never see this". */
1538
- provider: z7.string().min(1).max(60),
1649
+ provider: z9.string().min(1).max(60),
1539
1650
  /** The concrete model when the provider names one (an ollama tag); null otherwise. */
1540
- model: z7.string().max(200).nullable().optional(),
1651
+ model: z9.string().max(200).nullable().optional(),
1541
1652
  /** How many open notes the run actually looked at — the denominator on the phone
1542
1653
  * ("6 of 50"), and the honest answer to "did it read the whole queue?". */
1543
- reviewed: z7.number().int().min(0).max(1e4).default(0),
1544
- close: z7.array(TriageItemSchema).max(200).default([]),
1545
- stale: z7.array(TriageItemSchema).max(200).default([]),
1546
- assign: z7.array(TriageAssignmentSchema).max(50).default([])
1654
+ reviewed: z9.number().int().min(0).max(1e4).default(0),
1655
+ close: z9.array(TriageItemSchema).max(200).default([]),
1656
+ stale: z9.array(TriageItemSchema).max(200).default([]),
1657
+ assign: z9.array(TriageAssignmentSchema).max(50).default([])
1547
1658
  });
1548
1659
  var TriageProposalSchema = SubmitTriageSchema.extend({
1549
- id: z7.string(),
1550
- runAt: z7.string(),
1660
+ id: z9.string(),
1661
+ runAt: z9.string(),
1551
1662
  status: TriageStatusSchema,
1552
- model: z7.string().nullable().default(null)
1663
+ model: z9.string().nullable().default(null)
1553
1664
  });
1554
- var AcceptTriageSchema = z7.discriminatedUnion("group", [
1555
- z7.object({ group: z7.literal("close"), noteIds: z7.array(z7.string()).max(200).optional() }),
1556
- z7.object({ group: z7.literal("stale"), noteIds: z7.array(z7.string()).max(200).optional() }),
1557
- z7.object({
1558
- group: z7.literal("assign"),
1559
- agent: z7.string().min(1),
1560
- noteIds: z7.array(z7.string()).max(200).optional()
1665
+ var AcceptTriageSchema = z9.discriminatedUnion("group", [
1666
+ z9.object({ group: z9.literal("close"), noteIds: z9.array(z9.string()).max(200).optional() }),
1667
+ z9.object({ group: z9.literal("stale"), noteIds: z9.array(z9.string()).max(200).optional() }),
1668
+ z9.object({
1669
+ group: z9.literal("assign"),
1670
+ agent: z9.string().min(1),
1671
+ noteIds: z9.array(z9.string()).max(200).optional()
1561
1672
  })
1562
1673
  ]);
1563
- var AcceptTriageResultSchema = z7.object({
1564
- accepted: z7.array(z7.string()),
1565
- failed: z7.array(z7.object({ noteId: z7.string(), reason: z7.string() }))
1674
+ var AcceptTriageResultSchema = z9.object({
1675
+ accepted: z9.array(z9.string()),
1676
+ failed: z9.array(z9.object({ noteId: z9.string(), reason: z9.string() }))
1566
1677
  });
1567
- var DeliveryModeSchema = z7.enum(["poll", "self_hosted"]);
1568
- var RegisterDeliverySchema = z7.object({ mode: DeliveryModeSchema });
1569
- var OAuthStartSchema = z7.object({
1570
- provider: z7.enum(["cma"]),
1571
- returnTo: z7.string().min(1)
1678
+ var DeliveryModeSchema = z9.enum(["poll", "self_hosted"]);
1679
+ var RegisterDeliverySchema = z9.object({ mode: DeliveryModeSchema });
1680
+ var OAuthStartSchema = z9.object({
1681
+ provider: z9.enum(["cma"]),
1682
+ returnTo: z9.string().min(1)
1572
1683
  });
1573
- var DeliveryConfigSchema = z7.object({
1574
- tokenId: z7.string(),
1684
+ var DeliveryConfigSchema = z9.object({
1685
+ tokenId: z9.string(),
1575
1686
  mode: DeliveryModeSchema,
1576
1687
  /** null when the deployment has no anon key configured. `self_hosted` is then REFUSED
1577
1688
  * (503 `self_hosted_unavailable`) rather than registered, so a self_hosted config always
1578
1689
  * carries credentials; only a `poll` registration can come back with null here. */
1579
- realtime: z7.object({ url: z7.string(), anonKey: z7.string() }).nullable()
1690
+ realtime: z9.object({ url: z9.string(), anonKey: z9.string() }).nullable()
1580
1691
  });
1581
- var HostDecisionSchema = z7.object({
1692
+ var HostDecisionSchema = z9.object({
1582
1693
  /** The agent's token id: the row's `recipient`. */
1583
- agent: z7.string().uuid(),
1584
- decision: z7.enum(["stood_back", "took_over"]),
1694
+ agent: z9.string().uuid(),
1695
+ decision: z9.enum(["stood_back", "took_over"]),
1585
1696
  /** The work it was about: the Goal waiting on that agent next (`claimable` on its `contact({})` read). */
1586
- goalId: z7.string().uuid().nullable().optional(),
1697
+ goalId: z9.string().uuid().nullable().optional(),
1587
1698
  /** When the server last heard from the agent, as the host read it: the presence it stood back for. */
1588
- seenAt: z7.string().datetime().nullable().optional(),
1699
+ seenAt: z9.string().datetime().nullable().optional(),
1589
1700
  /** When that work last moved (`claimable.since` on an agent's `contact({})` read), the fact the bound is judged on. */
1590
- since: z7.string().datetime().nullable().optional(),
1701
+ since: z9.string().datetime().nullable().optional(),
1591
1702
  /** What the host said, in its log's own words: why it stood back, or what the take-over did. */
1592
- said: z7.string().max(300).optional()
1703
+ said: z9.string().max(300).optional()
1593
1704
  });
1594
- var WakeNudgeSchema = z7.object({
1595
- kind: z7.enum(["reply", "request", "callback"]),
1596
- notificationId: z7.string().optional(),
1597
- parentId: z7.string()
1705
+ var WakeNudgeSchema = z9.object({
1706
+ kind: z9.enum(["reply", "request", "callback"]),
1707
+ notificationId: z9.string().optional(),
1708
+ parentId: z9.string()
1598
1709
  });
1599
- var PairingStatusSchema = z7.enum(["pending", "approved", "denied", "expired"]);
1600
- var DeviceCodeSchema = z7.object({
1601
- device_code: z7.string(),
1602
- user_code: z7.string(),
1603
- verification_uri: z7.string().url(),
1604
- verification_uri_complete: z7.string().url(),
1605
- interval: z7.number(),
1606
- expires_in: z7.number()
1710
+ var PairingStatusSchema = z9.enum(["pending", "approved", "denied", "expired"]);
1711
+ var DeviceCodeSchema = z9.object({
1712
+ device_code: z9.string(),
1713
+ user_code: z9.string(),
1714
+ verification_uri: z9.string().url(),
1715
+ verification_uri_complete: z9.string().url(),
1716
+ interval: z9.number(),
1717
+ expires_in: z9.number()
1607
1718
  });
1608
- var DeviceInfoSchema = z7.object({
1609
- code: z7.string(),
1719
+ var DeviceInfoSchema = z9.object({
1720
+ code: z9.string(),
1610
1721
  /** The agent's suggested name (from /device/code) — shown on the approval screen,
1611
1722
  * pre-filling the name field the human can edit. */
1612
- name: z7.string(),
1723
+ name: z9.string(),
1613
1724
  /** @deprecated Legacy alias of `name` for the pre-#531 embedded bundle in App Store
1614
1725
  * build 35, whose DeviceFlow renders `info.agent.slice(0, 2)` — without this a FRESH
1615
1726
  * install crashes on the pairing screen on first launch, before the OTA lands
1616
1727
  * (seen live: PAIGY-5T, 2026-07-21). Remove once a newer binary is the floor. */
1617
- agent: z7.string().optional(),
1618
- device: z7.string().nullable(),
1728
+ agent: z9.string().optional(),
1729
+ device: z9.string().nullable(),
1619
1730
  status: PairingStatusSchema
1620
1731
  });
1621
- var DeviceTokenSchema = z7.object({
1622
- access_token: z7.string(),
1732
+ var DeviceTokenSchema = z9.object({
1733
+ access_token: z9.string(),
1623
1734
  /** The pairing's single name (user-typed at approval, the agent's suggestion, or
1624
1735
  * a default silly name). */
1625
- name: z7.string(),
1626
- device: z7.string().nullable(),
1736
+ name: z9.string(),
1737
+ device: z9.string().nullable(),
1627
1738
  /** The pairing's assigned voice, cached so the desktop can seed the SAME face the phone
1628
1739
  * draws — voice is the third ingredient of a hatchling's build (party/traits.ts). */
1629
- voice: z7.string().nullable().optional(),
1740
+ voice: z9.string().nullable().optional(),
1630
1741
  /** The token's server-side id — the face's COLOUR anchor, and the only seed ingredient
1631
1742
  * that survives a rename. Cached by the host's identity beat. */
1632
- token_id: z7.string().nullable().optional(),
1743
+ token_id: z9.string().nullable().optional(),
1633
1744
  /** WHERE this identity works — the folder a wake should land it in. Written by the host
1634
1745
  * at spawn and by `paigy-harness handoff` from a live terminal. Without it every wake
1635
1746
  * landed in the FIRST granted workspace and the agent rediscovered its own repo from
1636
1747
  * the thread each time (host.ts, live catch 2026-08-06 — prompt-papered until now). */
1637
- workspace: z7.string().nullable().optional(),
1748
+ workspace: z9.string().nullable().optional(),
1638
1749
  /** Local host recovery must preserve the launch's runtime and Paigy identity. */
1639
- harness: z7.enum(["claude", "codex", "agy"]).optional(),
1640
- session_id: z7.string().uuid().optional(),
1750
+ harness: z9.enum(["claude", "codex", "agy"]).optional(),
1751
+ session_id: z9.string().uuid().optional(),
1641
1752
  /** A conversation the host must not resume: its context is full, so every turn fails
1642
1753
  * ("Prompt is too long"). Written when a run hits it (`run.ts` `onFull`); the host skips a slot
1643
1754
  * whose resumable session is this one, so its Goals reach the dead-agent handoff instead of a
1644
1755
  * copy that types the person's words into a turn that cannot run (Calls, 2026-10-06). */
1645
- full_session: z7.string().optional(),
1646
- uik_pub: z7.string().nullable().optional()
1756
+ full_session: z9.string().optional(),
1757
+ uik_pub: z9.string().nullable().optional()
1647
1758
  });
1648
- var SupportRequestSchema = z7.object({
1649
- email: z7.string().email().max(320),
1650
- message: z7.string().trim().min(1).max(5e3),
1651
- name: z7.string().trim().max(120).optional()
1759
+ var SupportRequestSchema = z9.object({
1760
+ email: z9.string().email().max(320),
1761
+ message: z9.string().trim().min(1).max(5e3),
1762
+ name: z9.string().trim().max(120).optional()
1652
1763
  });
1653
- var NotificationFeedbackKindSchema = z7.enum([
1764
+ var NotificationFeedbackKindSchema = z9.enum([
1654
1765
  "break_down",
1655
1766
  // "This should be more than one ask — break it down."
1656
1767
  "regenerate_options",
@@ -1665,127 +1776,137 @@ var NotificationFeedbackKindSchema = z7.enum([
1665
1776
  // anything else — the note carries it.
1666
1777
  ]);
1667
1778
  var SlimOptionSchema = OptionSchema.omit({ html: true });
1668
- var QuestionRowSchema = z7.object({
1779
+ var QuestionRowSchema = z9.object({
1669
1780
  /** The card's id (`deliveryId:needId`, or `deliveryId:entryId` for an update), as the inbox mints it. */
1670
- id: z7.string(),
1671
- deliveryId: z7.string(),
1672
- entryId: z7.string(),
1781
+ id: z9.string(),
1782
+ deliveryId: z9.string(),
1783
+ entryId: z9.string(),
1673
1784
  /** The decision it waits on; null for an update, which asks nothing. */
1674
- needId: z7.string().nullable(),
1675
- goalIds: z7.array(z7.string()),
1785
+ needId: z9.string().nullable(),
1786
+ goalIds: z9.array(z9.string()),
1676
1787
  /** The name of the work it is about, when the read could word it. */
1677
- goalTitle: z7.string().optional(),
1678
- tokenId: z7.string().optional(),
1679
- name: z7.string(),
1680
- title: z7.string(),
1681
- body: z7.string(),
1682
- select: z7.enum(["one", "many", "rank", "confirm", "text"]),
1683
- options: z7.array(SlimOptionSchema),
1684
- hasPreview: z7.boolean(),
1685
- blocking: z7.boolean(),
1686
- askedAt: z7.string().datetime(),
1788
+ goalTitle: z9.string().optional(),
1789
+ tokenId: z9.string().optional(),
1790
+ name: z9.string(),
1791
+ title: z9.string(),
1792
+ body: z9.string(),
1793
+ select: z9.enum(["one", "many", "rank", "confirm", "text"]),
1794
+ options: z9.array(SlimOptionSchema),
1795
+ hasPreview: z9.boolean(),
1796
+ blocking: z9.boolean(),
1797
+ askedAt: z9.string().datetime(),
1687
1798
  ring: InboxItemSchema.shape.ring,
1688
- onCall: z7.literal(true).optional(),
1689
- sealed: z7.boolean()
1799
+ onCall: z9.literal(true).optional(),
1800
+ sealed: z9.boolean()
1690
1801
  });
1691
- var WorkStateSchema = z7.enum(["ready", "active", "waiting", "done", "cancelled"]);
1692
- var WorkRowSchema = z7.object({
1693
- id: z7.string(),
1694
- parentId: z7.string().nullable(),
1695
- title: z7.string(),
1802
+ var WorkStateSchema = z9.enum(["ready", "active", "waiting", "done", "cancelled"]);
1803
+ var WorkRowSchema = z9.object({
1804
+ id: z9.string(),
1805
+ parentId: z9.string().nullable(),
1806
+ title: z9.string(),
1696
1807
  /** Straight off the Goal. */
1697
1808
  state: WorkStateSchema,
1698
- owner: z7.string().nullable(),
1699
- revision: z7.number().int(),
1809
+ owner: z9.string().nullable(),
1810
+ revision: z9.number().int(),
1700
1811
  /** Open questions on it, counted to 100. */
1701
- waiting: z7.number().int(),
1812
+ waiting: z9.number().int(),
1702
1813
  /** Held by a gate on work that is not done. */
1703
- blocked: z7.boolean(),
1704
- lastProgressAt: z7.string().datetime().nullable(),
1814
+ blocked: z9.boolean(),
1815
+ lastProgressAt: z9.string().datetime().nullable(),
1705
1816
  /** The line written for its newest progress note, else that note's first words. */
1706
- line: z7.string().nullable(),
1817
+ line: z9.string().nullable(),
1707
1818
  /** Work directly under it, counted to 100; the list carries up to 12 of them. */
1708
- children: z7.number().int(),
1709
- createdAt: z7.string().datetime(),
1710
- updatedAt: z7.string().datetime(),
1819
+ children: z9.number().int(),
1820
+ createdAt: z9.string().datetime(),
1821
+ updatedAt: z9.string().datetime(),
1711
1822
  /** When anything at or under it last moved — the order the list is in. */
1712
- activeAt: z7.string().datetime(),
1823
+ activeAt: z9.string().datetime(),
1713
1824
  /** A sealed outcome has no title here; the work's page opens it. */
1714
- sealed: z7.boolean()
1825
+ sealed: z9.boolean()
1715
1826
  });
1716
1827
  var ComputerRowSchema = ConnectionSummarySchema.omit({ activity: true });
1717
1828
  var AgentRowSchema = ComputerRowSchema.extend({
1718
1829
  /** Open questions it is asking the person, over every open card; null when that read failed. */
1719
- asking: z7.number().int().nullable(),
1720
- oldestAskAt: z7.string().datetime().nullable(),
1830
+ asking: z9.number().int().nullable(),
1831
+ oldestAskAt: z9.string().datetime().nullable(),
1721
1832
  /** Up to three of the live Goals it holds, oldest first (the order it picks them up), and how
1722
1833
  * many in all among the account's 200 most recently active agent-held live Goals
1723
1834
  * (`agent_holds`); null when that read failed. */
1724
- holds: z7.array(z7.object({ id: z7.string(), title: z7.string() })).nullable(),
1725
- held: z7.number().int().nullable(),
1835
+ holds: z9.array(z9.object({ id: z9.string(), title: z9.string() })).nullable(),
1836
+ held: z9.number().int().nullable(),
1726
1837
  /** The earliest instant any Goal it holds went quiet, by the one rule (`coldSince`); null
1727
1838
  * while none has, or when that read failed. */
1728
- cold: z7.string().datetime().nullable(),
1839
+ cold: z9.string().datetime().nullable(),
1729
1840
  /** The newest line of its working log, and when the harness saw it. */
1730
- line: z7.string().nullable(),
1731
- lineAt: z7.string().datetime().nullable()
1841
+ line: z9.string().nullable(),
1842
+ lineAt: z9.string().datetime().nullable()
1732
1843
  });
1733
- var SnapshotSchema = z7.object({
1844
+ var SnapshotSchema = z9.object({
1734
1845
  /** The API's clock, taken before the first read: what a later delta will start from. */
1735
- at: z7.string().datetime(),
1736
- questions: z7.object({
1846
+ at: z9.string().datetime(),
1847
+ questions: z9.object({
1737
1848
  /** The newest 30 open cards, questions before updates. */
1738
- items: z7.array(QuestionRowSchema),
1849
+ items: z9.array(QuestionRowSchema),
1739
1850
  /** Every open question, and apart from them every update, and what was put off. */
1740
- total: z7.number().int(),
1741
- updates: z7.number().int(),
1742
- putOff: z7.number().int()
1851
+ total: z9.number().int(),
1852
+ updates: z9.number().int(),
1853
+ putOff: z9.number().int()
1743
1854
  }).nullable(),
1744
- agents: z7.object({
1855
+ agents: z9.object({
1745
1856
  /** Up to 60, most recently seen first. */
1746
- items: z7.array(AgentRowSchema),
1747
- more: z7.boolean()
1857
+ items: z9.array(AgentRowSchema),
1858
+ more: z9.boolean()
1748
1859
  }).nullable(),
1749
- work: z7.object({
1860
+ work: z9.object({
1750
1861
  /** The 60 most recently active roots, each followed by up to 12 children; 240 rows at most. */
1751
- items: z7.array(WorkRowSchema),
1862
+ items: z9.array(WorkRowSchema),
1752
1863
  /** How much work is behind each of the Work tab's four filters, each counted to 100, read with
1753
1864
  * the rows. `work_list` (20260928023533) owns the predicates: Live is `ready`, `active` or
1754
1865
  * `waiting`; Waiting on you is live work with an open question or an unmet gate; Not started
1755
1866
  * is `ready`; Done is `done` or `cancelled`. */
1756
- counts: z7.object({ live: z7.number().int(), waiting: z7.number().int(), notStarted: z7.number().int(), done: z7.number().int() })
1867
+ counts: z9.object({ live: z9.number().int(), waiting: z9.number().int(), notStarted: z9.number().int(), done: z9.number().int() })
1757
1868
  }).nullable(),
1758
- you: z7.object({
1869
+ you: z9.object({
1759
1870
  settings: UserSettingsSchema,
1760
- callable: z7.boolean(),
1871
+ callable: z9.boolean(),
1761
1872
  /** Up to 20 paired computers; null when the roster read failed. */
1762
- computers: z7.array(ComputerRowSchema).nullable()
1873
+ computers: z9.array(ComputerRowSchema).nullable()
1763
1874
  }).nullable()
1764
1875
  });
1765
- var CallRecapSchema = z7.object({
1766
- call: z7.object({
1767
- status: z7.string(),
1768
- startedAt: z7.string(),
1769
- durationMs: z7.number().nullable(),
1770
- agents: z7.array(z7.object({ id: z7.string(), name: z7.string().nullable() }))
1876
+ var CallRecapSchema = z9.object({
1877
+ call: z9.object({
1878
+ status: z9.string(),
1879
+ startedAt: z9.string(),
1880
+ durationMs: z9.number().nullable(),
1881
+ agents: z9.array(z9.object({ id: z9.string(), name: z9.string().nullable() }))
1771
1882
  }),
1772
- topics: z7.array(z7.object({
1773
- goalId: z7.string().uuid(),
1774
- title: z7.string(),
1775
- owner: z7.string(),
1776
- state: z7.string(),
1777
- questions: z7.array(z7.object({ id: z7.string().uuid(), state: z7.string(), title: z7.string() })),
1778
- /** `words` is always what they SAID, verbatim — the record, never replaced. `headline` is
1779
- * their answer on one line when the call's read wrote one (owner, 2026-10-01: "render them
1780
- * summarized like a pre-made option is"), so the row scans like a chosen option and their
1781
- * own words stay under it. Absent on every line stored before the read wrote them, and on
1782
- * anything that is not an answer. */
1883
+ topics: z9.array(z9.object({
1884
+ goalId: z9.string().uuid(),
1885
+ title: z9.string(),
1886
+ owner: z9.string(),
1887
+ state: z9.string(),
1888
+ questions: z9.array(z9.object({ id: z9.string().uuid(), state: z9.string(), title: z9.string() })),
1889
+ /** `words` is always what they SAID, verbatim — the record, never replaced. `summary` is what
1890
+ * the line says in ten words (owner, 2026-10-07): the filer's, or the talker's for the answer it
1891
+ * gave, so the row scans like a chosen option and their own words stay under it. Absent when
1892
+ * neither wrote one. */
1783
1893
  /** `about` is the request the line answered (its question), null for words that answered none —
1784
1894
  * the key the screen groups on, so one question is one row however many times it was answered. */
1785
- lines: z7.array(z7.object({ entryId: z7.string().uuid(), words: z7.string(), headline: z7.string().optional(), about: z7.string().nullable().optional() }))
1895
+ /** `reply` is the reply the line makes up (an answer, an ok, a deferral), so one reply is one row
1896
+ * however many lines it cites; `at` is the call lines it came from, so a filed line an answer already
1897
+ * said is not drawn again (owner, 2026-10-07: "fix them all"); `replyKind` says which replies are answers. */
1898
+ lines: z9.array(z9.object({
1899
+ entryId: z9.string().uuid(),
1900
+ words: z9.string(),
1901
+ summary: z9.string().optional(),
1902
+ about: z9.string().nullable().optional(),
1903
+ reply: z9.string().nullable().optional(),
1904
+ replyKind: z9.string().nullable().optional(),
1905
+ at: z9.array(z9.number()).optional()
1906
+ }))
1786
1907
  })),
1787
- unfiled: z7.array(z7.object({ lineId: z7.string().uuid(), words: z7.string(), atMs: z7.number() })),
1788
- more: z7.object({ lines: z7.number(), entries: z7.number(), topics: z7.number() })
1908
+ unfiled: z9.array(z9.object({ lineId: z9.string().uuid(), words: z9.string(), atMs: z9.number() })),
1909
+ more: z9.object({ lines: z9.number(), entries: z9.number(), topics: z9.number() })
1789
1910
  });
1790
1911
 
1791
1912
  // src/listening.ts