@detergent-software/conductor 1.1.0 → 1.2.0-dev.10

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.
Files changed (60) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/README.md +36 -17
  3. package/build/brief-cli.js +2 -0
  4. package/build/brief-cli.js.map +1 -1
  5. package/build/brief.js +13 -0
  6. package/build/brief.js.map +1 -1
  7. package/build/cli.js +196 -40
  8. package/build/cli.js.map +1 -1
  9. package/build/conditions.js +20 -0
  10. package/build/conditions.js.map +1 -1
  11. package/build/daemon.js +20 -7
  12. package/build/daemon.js.map +1 -1
  13. package/build/help.js +16 -3
  14. package/build/help.js.map +1 -1
  15. package/build/history.js +96 -0
  16. package/build/history.js.map +1 -1
  17. package/build/inbox.js +87 -15
  18. package/build/inbox.js.map +1 -1
  19. package/build/manager.js +46 -6
  20. package/build/manager.js.map +1 -1
  21. package/build/note.js +14 -3
  22. package/build/note.js.map +1 -1
  23. package/build/notes.js +80 -6
  24. package/build/notes.js.map +1 -1
  25. package/build/paths.js +2 -0
  26. package/build/paths.js.map +1 -1
  27. package/build/profile.js +8 -0
  28. package/build/profile.js.map +1 -1
  29. package/build/queue.js +67 -14
  30. package/build/queue.js.map +1 -1
  31. package/build/rule-actions.js +144 -25
  32. package/build/rule-actions.js.map +1 -1
  33. package/build/rules-service.js +29 -10
  34. package/build/rules-service.js.map +1 -1
  35. package/build/rules.js +34 -6
  36. package/build/rules.js.map +1 -1
  37. package/build/scheduler.js +93 -12
  38. package/build/scheduler.js.map +1 -1
  39. package/build/server.js +6 -3
  40. package/build/server.js.map +1 -1
  41. package/build/spend.js +13 -8
  42. package/build/spend.js.map +1 -1
  43. package/build/startup.js +30 -16
  44. package/build/startup.js.map +1 -1
  45. package/build/stop-request.js +83 -0
  46. package/build/stop-request.js.map +1 -0
  47. package/build/store.js +68 -2
  48. package/build/store.js.map +1 -1
  49. package/build/supervise.js +153 -0
  50. package/build/supervise.js.map +1 -0
  51. package/build/transcript.js +179 -0
  52. package/build/transcript.js.map +1 -0
  53. package/build/upgrade.js +9 -5
  54. package/build/upgrade.js.map +1 -1
  55. package/build/watchers/linear-queue.js +66 -5
  56. package/build/watchers/linear-queue.js.map +1 -1
  57. package/mod/hooks/model.ts +6 -0
  58. package/mod/hooks/register.tsx +4 -1
  59. package/mod/types/index.d.ts +2 -0
  60. package/package.json +1 -1
package/build/queue.js CHANGED
@@ -3,13 +3,24 @@ export const pickSchema = z.object({
3
3
  area: z.string().nullable(),
4
4
  id: z.string(),
5
5
  project: z.string(),
6
+ // The released items it shares its Area with: their PRs are open.
7
+ sharing: z.array(z.string()).default([]),
6
8
  title: z.string().nullable(),
7
9
  trackerProject: z.string().nullable(),
8
10
  });
11
+ // Why an item waits, as a tally can count it (ATK-418): `held` is quiet hours or a pause,
12
+ // `release` a release wait, and `triage` a new item Jason hasn't triaged.
13
+ export const WAITING_KINDS = ['in-flight', 'human', 'triage', 'blocked', 'release', 'area', 'held', 'slot'];
9
14
  export const waitingSchema = z.object({
15
+ // For an Area wait: the item that holds the Area, and its Area (the waiting item's, or one that
16
+ // covers it or that it covers).
17
+ holder: z.object({ area: z.string(), item: z.string() }).optional(),
10
18
  id: z.string(),
19
+ // Optional, as are `holder`'s, so a newer CLI reads an older daemon's queue.
20
+ kind: z.enum(WAITING_KINDS).optional(),
11
21
  // It will start once a slot, an Area or a blocker frees up (or the hold ends); false when it
12
- // never will on its own (labelled human, blocked by an item nobody works on).
22
+ // never will on its own (labelled human or triage, blocked by an item nobody works on, a release
23
+ // wait with no blocker).
13
24
  pending: z.boolean(),
14
25
  project: z.string(),
15
26
  reason: z.string(),
@@ -52,9 +63,15 @@ export function conductedProjects(projects) {
52
63
  .filter((p) => p.priority !== null && p.priority >= 1 && p.priority <= 4)
53
64
  .sort((a, b) => (a.priority ?? 5) - (b.priority ?? 5) || (a.sortOrder ?? 0) - (b.sortOrder ?? 0));
54
65
  }
66
+ // Whether an item carries a label, ignoring case: Boards tags keep the organization's spelling.
67
+ export function hasLabel(labels, label) {
68
+ const wanted = label.toLowerCase();
69
+ return labels.some((l) => l.toLowerCase() === wanted);
70
+ }
55
71
  // The items to start now, in order, and why the others wait. An Area is held, per project, by
56
- // every item in flight and every item the tracker says is started, and by the Areas it covers or
57
- // is covered by. Slots count running workers: a parked worker keeps its Area but not its slot.
72
+ // every item in flight and every item the tracker says is started, except the project's released
73
+ // ones, and by the Areas it covers or is covered by. So an Area has at most one item before its PR.
74
+ // Slots count running workers: a parked worker keeps its Area but not its slot.
58
75
  export function planQueue({ held, inFlight, projects, slots }) {
59
76
  const states = new Map();
60
77
  const candidates = [];
@@ -71,6 +88,7 @@ export function planQueue({ held, inFlight, projects, slots }) {
71
88
  const parked = own.filter((w) => w.status === 'parked').length;
72
89
  const running = own.length - parked;
73
90
  const holders = new Map();
91
+ const prOpen = new Map();
74
92
  const state = {
75
93
  free: Math.max(0, queue.slots - running),
76
94
  holders,
@@ -78,13 +96,18 @@ export function planQueue({ held, inFlight, projects, slots }) {
78
96
  open,
79
97
  parked,
80
98
  picked: 0,
99
+ prOpen,
81
100
  queue,
82
101
  queued: new Set(),
83
102
  rank,
84
103
  running,
85
104
  };
86
105
  const hold = (area, id) => {
87
- if (area && !holders.has(area))
106
+ if (!area)
107
+ return;
108
+ if (queue.released?.has(id))
109
+ prOpen.set(id, area);
110
+ else if (!holders.has(area))
88
111
  holders.set(area, id);
89
112
  };
90
113
  for (const w of mine.values())
@@ -95,7 +118,7 @@ export function planQueue({ held, inFlight, projects, slots }) {
95
118
  for (const i of open.values()) {
96
119
  if (i.trackerProject !== null && rank.has(i.trackerProject) && READY.has(i.stateType ?? '')) {
97
120
  candidates.push({ issue: i, state });
98
- if (!i.labels.includes(queue.humanLabel))
121
+ if (!i.labels.includes(queue.humanLabel) && !untriaged(i, queue))
99
122
  state.queued.add(i.id);
100
123
  }
101
124
  }
@@ -120,6 +143,7 @@ export function planQueue({ held, inFlight, projects, slots }) {
120
143
  const { areaLabels } = state.queue.snapshot;
121
144
  const area = areaOf(issue, areaLabels);
122
145
  const blockers = issue.blockedBy.filter((b) => state.open.has(b));
146
+ const releasing = releaseWaitOf(state.queue.snapshot, issue.id);
123
147
  const heldBy = state.holders.has(area ?? '')
124
148
  ? [area, state.holders.get(area ?? '')]
125
149
  : [...state.holders].find(([h]) => areasOverlap(h, area));
@@ -127,31 +151,47 @@ export function planQueue({ held, inFlight, projects, slots }) {
127
151
  const active = (b) => state.inFlight.has(b) || state.open.get(b)?.stateType === 'started' || state.queued.has(b);
128
152
  let wait = null;
129
153
  if (state.inFlight.has(issue.id))
130
- wait = { pending: false, reason: 'in flight' };
154
+ wait = { kind: 'in-flight', pending: false, reason: 'in flight' };
131
155
  else if (issue.labels.includes(state.queue.humanLabel))
132
- wait = { pending: false, reason: `labelled ${state.queue.humanLabel}` };
156
+ wait = { kind: 'human', pending: false, reason: `labelled ${state.queue.humanLabel}` };
157
+ else if (untriaged(issue, state.queue))
158
+ wait = {
159
+ kind: 'triage',
160
+ pending: false,
161
+ reason: `labelled ${state.queue.triageLabel ?? ''}: new, waits for Jason to triage it`,
162
+ };
133
163
  else if (blockers.length > 0) {
134
164
  const stuck = blockers.filter((b) => !active(b));
135
165
  wait =
136
166
  stuck.length > 0
137
- ? { pending: false, reason: `blocked by ${blockers.join(', ')} (${stuck.join(', ')} not being worked)` }
138
- : { pending: true, reason: `blocked by ${blockers.join(', ')}` };
167
+ ? {
168
+ kind: 'blocked',
169
+ pending: false,
170
+ reason: `blocked by ${blockers.join(', ')} (${stuck.join(', ')} not being worked)`,
171
+ }
172
+ : { kind: 'blocked', pending: true, reason: `blocked by ${blockers.join(', ')}` };
139
173
  }
174
+ else if (releasing && releasing.unshipped.length > 0)
175
+ wait = { kind: 'release', pending: true, reason: `waits for ${releasing.unshipped.join(', ')} to ship` };
176
+ else if (releasing?.blockers === 0)
177
+ wait = { kind: 'release', pending: false, reason: `labelled ${releasing.label} with no blocker to wait on` };
140
178
  else if (heldBy) {
141
179
  const [heldArea, holder] = heldBy;
142
180
  wait = {
181
+ kind: 'area',
143
182
  pending: true,
144
183
  reason: `Area ${area ?? ''} held by ${holder ?? '?'}${heldArea === area ? '' : ` (${heldArea ?? ''})`}`,
184
+ ...(heldArea && holder ? { holder: { area: heldArea, item: holder } } : {}),
145
185
  };
146
186
  }
147
187
  else if (held !== null)
148
- wait = { pending: true, reason: held };
188
+ wait = { kind: 'held', pending: true, reason: held };
149
189
  else if (state.queue.paused !== null)
150
- wait = { pending: true, reason: state.queue.paused };
190
+ wait = { kind: 'held', pending: true, reason: state.queue.paused };
151
191
  else if (state.picked >= state.free)
152
- wait = { pending: true, reason: 'no free slot' };
192
+ wait = { kind: 'slot', pending: true, reason: 'no free slot' };
153
193
  else if (picks.length >= globalFree)
154
- wait = { pending: true, reason: `no free slot (all ${slots} in use across projects)` };
194
+ wait = { kind: 'slot', pending: true, reason: `no free slot (all ${slots} in use across projects)` };
155
195
  if (wait) {
156
196
  waiting.push({ id: issue.id, project: state.queue.name, trackerProject: issue.trackerProject, ...wait });
157
197
  continue;
@@ -160,6 +200,7 @@ export function planQueue({ held, inFlight, projects, slots }) {
160
200
  area,
161
201
  id: issue.id,
162
202
  project: state.queue.name,
203
+ sharing: [...state.prOpen].filter(([, a]) => areasOverlap(a, area)).map(([id]) => id),
163
204
  title: issue.title,
164
205
  trackerProject: issue.trackerProject,
165
206
  });
@@ -171,7 +212,9 @@ export function planQueue({ held, inFlight, projects, slots }) {
171
212
  drained: picks.length === 0 && !waiting.some((w) => w.pending) && inFlight.length === 0,
172
213
  picks,
173
214
  readyToRelease: [...states.values()].flatMap((s) => conductedProjects(s.queue.snapshot.projects)
174
- .filter((p) => !s.queue.snapshot.issues.some((i) => i.trackerProject === p.name))
215
+ // An item that waits only for a release can't hold back the release it waits for.
216
+ .filter((p) => !s.queue.snapshot.issues.some((i) => i.trackerProject === p.name &&
217
+ !(i.blockedBy.length === 0 && (releaseWaitOf(s.queue.snapshot, i.id)?.unshipped.length ?? 0) > 0)))
175
218
  .map((p) => ({ project: s.queue.name, trackerProject: p.name }))),
176
219
  slots: {
177
220
  free: globalFree,
@@ -195,4 +238,14 @@ function issuePriority(issue) {
195
238
  function keyNumber(key) {
196
239
  return Number(key.split('-')[1]);
197
240
  }
241
+ // The release wait of an item labelled to need its blockers released, with the label; null for any
242
+ // other item.
243
+ function releaseWaitOf(snapshot, id) {
244
+ const item = snapshot.releaseWait?.items[id];
245
+ return item && snapshot.releaseWait ? { ...item, label: snapshot.releaseWait.label } : null;
246
+ }
247
+ // A new item that waits for Jason to triage it: it carries the project's triage label.
248
+ function untriaged(issue, queue) {
249
+ return queue.triageLabel !== undefined && hasLabel(issue.labels, queue.triageLabel);
250
+ }
198
251
  //# sourceMappingURL=queue.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"queue.js","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"queue.js","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"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"}
@@ -1,15 +1,27 @@
1
1
  import { z } from 'zod';
2
+ import { parseLocalTime } from "./clock.js";
2
3
  import { ConductorError } from "./errors.js";
4
+ import { isQuiet } from "./notify.js";
3
5
  import { PAUSE } from "./overrides.js";
4
6
  import { clockFields, describeAction, resolveUntil, selectRules, } from "./rules.js";
5
7
  import { localDay } from "./spend.js";
6
8
  import { ACTIVE_STATUSES, } from "./store.js";
7
9
  const GATES = ['plan', 'merge', 'npm-otp'];
10
+ const APPROVE_NOW = { afterMinutes: 0, verb: 'auto-approve' };
11
+ const NOW_TEXT = describeAction(APPROVE_NOW);
8
12
  const TICK_SECONDS = 60;
9
13
  const MAX_LABELS = 20;
10
- const autoApprove = z.object({ kind: z.literal('auto-approve'), plan: z.number(), rule: z.string() });
14
+ // `minutes` is the rule's wait; todos set before it was recorded have none.
15
+ const autoApprove = z.object({
16
+ kind: z.literal('auto-approve'),
17
+ minutes: z.number().optional(),
18
+ plan: z.number(),
19
+ rule: z.string(),
20
+ });
11
21
  const noteData = z.looseObject({
22
+ autoApprove: z.string().optional(),
12
23
  kind: z.string().nullable().optional(),
24
+ landing: z.string().optional(),
13
25
  phase: z.string(),
14
26
  tier: z.string().optional(),
15
27
  worker: z.number().optional(),
@@ -28,6 +40,34 @@ export function ruleActions(deps) {
28
40
  void task.finally(() => tasks.delete(task)).catch(() => { });
29
41
  };
30
42
  const minutesSince = (iso) => Math.max(0, (now().getTime() - Date.parse(iso)) / 60_000);
43
+ // An auto-approve deadline `minutes` from now, or that long after quiet hours end when now or
44
+ // the deadline falls in them: quiet hours hold the push, so Jason gets his minutes to revise
45
+ // once the quiet-hours summary reaches him. (A wait as long as the hours between quiet hours
46
+ // lands in the next ones whatever it does; dueTodos keeps holding it, so it never approves.)
47
+ const autoApproveAt = (minutes) => {
48
+ const { quietHours } = notifier.status();
49
+ const at = new Date(now().getTime() + minutes * 60_000);
50
+ if (quietHours === null)
51
+ return at;
52
+ const from = isQuiet(quietHours, now()) ? now() : isQuiet(quietHours, at) ? at : null;
53
+ const end = from === null ? null : parseLocalTime(quietHours.to, from);
54
+ return end === null ? at : new Date(end.getTime() + minutes * 60_000);
55
+ };
56
+ // Approves `item`'s plan `minutes` from now (outside quiet hours) unless it is answered first,
57
+ // and says so on the plan's inbox item.
58
+ const scheduleApproval = (plan, item, rule, minutes) => {
59
+ const at = autoApproveAt(minutes);
60
+ store.addTodo({
61
+ action: JSON.stringify({ kind: 'auto-approve', minutes, plan: plan.id, rule }),
62
+ after: at.toISOString(),
63
+ item,
64
+ project: plan.project,
65
+ });
66
+ const when = clock(at);
67
+ const text = `${item} auto-approves at ${when} unless you revise it`;
68
+ store.setInboxText(plan.id, text);
69
+ return { text, when };
70
+ };
31
71
  // ---------- subjects ----------
32
72
  // Read once per event or tick, not once per subject: spend sums scan the spend table.
33
73
  const factsNow = () => ({
@@ -45,6 +85,7 @@ export function ruleActions(deps) {
45
85
  'item.id': item,
46
86
  ...(queued?.area ? { 'item.area': queued.area } : {}),
47
87
  ...(queued ? { 'item.labels': queued.labels } : {}),
88
+ 'item.phases': store.itemPhases(project, item),
48
89
  ...(queued?.priority === null || queued === undefined ? {} : { 'item.priority': queued.priority }),
49
90
  ...(tier === null ? {} : { 'item.tier': tier }),
50
91
  ...(spend === undefined ? {} : { 'spend.item': spend }),
@@ -90,6 +131,16 @@ export function ruleActions(deps) {
90
131
  wait: null,
91
132
  worker,
92
133
  });
134
+ const noteFields = (target, facts, data) => {
135
+ const plan = data.phase === 'Plan';
136
+ return {
137
+ ...base(target, facts),
138
+ 'note.phase': data.phase,
139
+ ...(data.kind ? { 'note.kind': data.kind } : {}),
140
+ ...(plan && data.landing ? { 'plan.landing': data.landing } : {}),
141
+ ...(plan && data.tier ? { 'plan.tier': data.tier } : {}),
142
+ };
143
+ };
93
144
  // The rule events a daemon event is, with what they act on; null for one no rule watches.
94
145
  const fromEvent = (event, facts) => {
95
146
  const worker = (id) => (id === undefined ? null : store.getWorker(id));
@@ -110,15 +161,9 @@ export function ruleActions(deps) {
110
161
  if (!data)
111
162
  return null;
112
163
  const target = targetOf(event, worker(data.worker));
113
- const plan = data.phase === 'Plan';
114
164
  return {
115
- events: plan ? ['note', 'plan'] : ['note'],
116
- fields: {
117
- ...base(target, facts),
118
- 'note.phase': data.phase,
119
- ...(data.kind ? { 'note.kind': data.kind } : {}),
120
- ...(plan && data.tier ? { 'plan.tier': data.tier } : {}),
121
- },
165
+ events: data.phase === 'Plan' ? ['note', 'plan'] : ['note'],
166
+ fields: noteFields(target, facts, data),
122
167
  target,
123
168
  };
124
169
  }
@@ -214,22 +259,25 @@ export function ruleActions(deps) {
214
259
  };
215
260
  switch (action.verb) {
216
261
  case 'auto-approve': {
262
+ if (action.afterMinutes === 0) {
263
+ // No inbox item and no push: the note raised none (notes.ts asked planApproval first).
264
+ if (target.item === null || target.project === null)
265
+ throw new ConductorError('auto-approve now needs an item of a project');
266
+ const { comment } = await inbox.autoApprove({
267
+ item: target.item,
268
+ project: target.project,
269
+ rule: by,
270
+ worker: target.worker?.id ?? null,
271
+ });
272
+ return `approved ${target.item}'s plan at once (comment ${comment.id})`;
273
+ }
217
274
  const plan = openPlan(target);
218
275
  if (!plan || target.item === null)
219
276
  return 'no plan waits in the inbox';
220
- const at = new Date(now().getTime() + action.afterMinutes * 60_000);
221
- store.addTodo({
222
- action: JSON.stringify({ kind: 'auto-approve', plan: plan.id, rule: by }),
223
- after: at.toISOString(),
224
- item: target.item,
225
- project: target.project,
226
- });
227
- const when = clock(at);
228
- const pushed = await notifier.announce({ kind: 'plan' }, {
229
- item: target.item,
230
- project: target.project,
231
- text: `${target.item} auto-approves at ${when} unless you revise it`,
232
- }, by);
277
+ if (target.project !== null && store.planRevised(target.project, target.item))
278
+ return 'Jason revised a plan of the item: its plans wait on him';
279
+ const { text, when } = scheduleApproval(plan, target.item, by, action.afterMinutes);
280
+ const pushed = await notifier.announce({ kind: 'plan' }, { item: target.item, project: target.project, text }, by);
233
281
  return `auto-approves ${target.item}'s plan at ${when}${pushed === null ? '' : ` (not pushed: ${pushed})`}`;
234
282
  }
235
283
  case 'escalate':
@@ -282,7 +330,11 @@ export function ruleActions(deps) {
282
330
  if (target.item === null || target.project === null)
283
331
  throw new ConductorError('a label edit needs an item');
284
332
  const profile = store.listProjects().find((p) => p.name === target.project)?.profile;
285
- const label = action.label === 'human' ? (profile?.tracker.humanLabel ?? 'human') : action.label;
333
+ const label = action.label === 'human'
334
+ ? (profile?.tracker.humanLabel ?? 'human')
335
+ : action.label === 'triage'
336
+ ? (profile?.tracker.triageLabel ?? 'triage')
337
+ : action.label;
286
338
  if (labelEdits(target.item) >= MAX_LABELS)
287
339
  throw new ConductorError(`${target.item} has had ${MAX_LABELS} label edits from rules today: no more until tomorrow`);
288
340
  const done = await deps.labels.label(target.item, label, action.op, profile);
@@ -384,12 +436,22 @@ export function ruleActions(deps) {
384
436
  project: found.target.project,
385
437
  scope: null,
386
438
  });
439
+ // A Plan a rule approves at once: that rule, as notes.ts recorded it before the inbox saw the
440
+ // note, and no other auto-approve. Its note raised no item, so it is approved even when the
441
+ // rules changed since (by its ref, as it was).
442
+ const now = event.kind === 'note.posted' ? noteData.safeParse(event.data).data?.autoApprove : undefined;
387
443
  for (const { action, rule } of fired) {
388
444
  if (['launch', 'none', 'park', 'resume', 'retire'].includes(action.verb) &&
389
445
  !(action.verb === 'launch' && found.events.includes('item.unblocked')))
390
446
  continue;
447
+ if (action.verb === 'auto-approve' && (now !== undefined || action.afterMinutes === 0))
448
+ continue;
391
449
  await run(rule, action, found.target, found.events.join(', '), event.id);
392
450
  }
451
+ if (now !== undefined) {
452
+ const rule = deps.rules().find((r) => r.ref === now) ?? standIn(now);
453
+ await run(rule, APPROVE_NOW, found.target, found.events.join(', '), event.id);
454
+ }
393
455
  };
394
456
  // ---------- state rules ----------
395
457
  const stateSubjects = (facts) => {
@@ -454,6 +516,26 @@ export function ruleActions(deps) {
454
516
  for (const held of released)
455
517
  liftPauses(held);
456
518
  await dueTodos();
519
+ await unapprovedPlans();
520
+ };
521
+ // A Plan a rule approves at once whose approval never ran (the daemon stopped between recording
522
+ // its note and acting on it): its worker's approval wait would raise nothing and never resolve,
523
+ // so it is approved now, once the note is 2 minutes old (an approval in flight has landed by then).
524
+ const unapprovedPlans = async () => {
525
+ for (const wait of store.openWaits()) {
526
+ if (!wait.condition.startsWith('approval:'))
527
+ continue;
528
+ const worker = store.getWorker(wait.worker);
529
+ const plan = worker ? store.latestPlan(worker.project, worker.item) : null;
530
+ if (!worker || !plan?.autoApprove || plan.approved || plan.failed || plan.revised)
531
+ continue;
532
+ const note = store.getEvent(plan.note);
533
+ if (!note || minutesSince(note.at) < 2)
534
+ continue;
535
+ const rule = deps.rules().find((r) => r.ref === plan.autoApprove) ?? standIn(plan.autoApprove);
536
+ const target = { inbox: null, item: worker.item, project: worker.project, wait, worker };
537
+ await run(rule, APPROVE_NOW, target, `state of wait:${wait.id}`, plan.note);
538
+ }
457
539
  };
458
540
  // Lifts the open-ended pauses a state rule set, except where it still holds: a pause of every
459
541
  // project while any subject holds, one project's while a subject of that project does.
@@ -494,13 +576,31 @@ export function ruleActions(deps) {
494
576
  }
495
577
  };
496
578
  // Auto-approvals at their deadline: the plan still waits (no revise answered it, no newer Plan).
579
+ // None while quiet hours hold (config.json can move them over a deadline): a deadline due then
580
+ // moves to their end plus its wait, as a new one would, so Jason still gets that long to revise.
497
581
  const dueTodos = async () => {
582
+ const quiet = isQuiet(notifier.status().quietHours, now());
498
583
  for (const todo of store.dueTodos(now().toISOString())) {
499
- store.finishTodo(todo.id);
500
584
  const parsed = autoApprove.safeParse(safeJson(todo.action));
585
+ const plan = parsed.success ? inbox.open().find((i) => i.id === parsed.data.plan) : undefined;
586
+ if (quiet) {
587
+ // Without its wait (an older todo), it waits for the first tick after quiet hours.
588
+ if (!parsed.success || parsed.data.minutes === undefined || !plan || todo.item === null)
589
+ continue;
590
+ store.finishTodo(todo.id);
591
+ const { when } = scheduleApproval(plan, todo.item, parsed.data.rule, parsed.data.minutes);
592
+ store.appendEvent({
593
+ data: { outcome: `held by quiet hours: auto-approves ${todo.item}'s plan at ${when}` },
594
+ kind: 'rule.done',
595
+ project: todo.project,
596
+ rule: parsed.data.rule,
597
+ subject: todo.item,
598
+ });
599
+ continue;
600
+ }
601
+ store.finishTodo(todo.id);
501
602
  if (!parsed.success)
502
603
  continue;
503
- const plan = inbox.open().find((i) => i.id === parsed.data.plan);
504
604
  const target = { inbox: plan ?? null, item: todo.item, project: todo.project, wait: null, worker: null };
505
605
  if (!plan) {
506
606
  store.appendEvent({
@@ -528,6 +628,8 @@ export function ruleActions(deps) {
528
628
  }
529
629
  catch (error) {
530
630
  const message = error instanceof Error ? error.message : String(error);
631
+ // The plan still waits, now on Jason: its item no longer says it approves itself.
632
+ store.setInboxText(plan.id, `${todo.item ?? 'the item'}'s plan waits on your approval (auto-approve failed: ${message})`);
531
633
  store.appendEvent({
532
634
  data: { error: message },
533
635
  kind: 'rule.failed',
@@ -555,6 +657,19 @@ export function ruleActions(deps) {
555
657
  return;
556
658
  track(onEvent(event).catch((error) => log.log('error', 'rule actions failed on an event', { error: String(error), event: event.id })));
557
659
  },
660
+ // The fields the plan event gives its rules (fromEvent), before the note is recorded.
661
+ // `item.tier` is this Plan's, as it is once the note is recorded.
662
+ planApproval: ({ item, landing, project, tier, worker }) => {
663
+ const target = { inbox: null, item, project, wait: null, worker };
664
+ const { 'item.tier': _previous, ...fields } = noteFields(target, factsNow(), { landing, phase: 'Plan', tier });
665
+ const { fired } = selectRules(deps.rules(), {
666
+ events: ['note', 'plan'],
667
+ fields: { ...fields, ...(tier === null ? {} : { 'item.tier': tier }) },
668
+ project,
669
+ scope: null,
670
+ });
671
+ return fired.find((f) => f.action.verb === 'auto-approve' && f.action.afterMinutes === 0)?.rule.ref ?? null;
672
+ },
558
673
  start: () => {
559
674
  timer = setInterval(() => void tick(), (deps.tickSeconds ?? TICK_SECONDS) * 1000);
560
675
  timer.unref();
@@ -578,4 +693,8 @@ function safeJson(text) {
578
693
  return null;
579
694
  }
580
695
  }
696
+ // An `auto-approve now` rule by its ref, after the rules changed since its Plan was recorded.
697
+ function standIn(ref) {
698
+ return { ref, text: { do: [NOW_TEXT], when: null } };
699
+ }
581
700
  //# sourceMappingURL=rule-actions.js.map