@boxxy/model 0.1.8 → 0.2.0
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.
- package/dist/facts/types.d.ts +3 -1
- package/dist/facts/work-fact-schemas.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/ports/types.d.ts +25 -2
- package/dist/test-utils/create-fake-notifier.d.ts +8 -3
- package/dist/types.d.ts +3 -0
- package/package.json +2 -2
- package/src/facts/types.ts +5 -1
- package/src/facts/work-fact-schemas.ts +3 -1
- package/src/index.ts +3 -0
- package/src/ports/types.ts +41 -5
- package/src/rows/decision-row-schema.ts +1 -1
- package/src/rows/notice-row-schema.ts +3 -0
- package/src/rows/spawn-request-schema.ts +10 -0
- package/src/test-utils/create-fake-notifier.ts +21 -19
- package/src/types.ts +10 -1
package/dist/facts/types.d.ts
CHANGED
|
@@ -87,7 +87,9 @@ export interface WorkFacts {
|
|
|
87
87
|
readonly skillsRef: CommitSha | null;
|
|
88
88
|
readonly rulesVersion: RulesVersion;
|
|
89
89
|
};
|
|
90
|
-
'boxxy.decision.recorded': DecisionRow
|
|
90
|
+
'boxxy.decision.recorded': Omit<DecisionRow, 'storeVersion'> & {
|
|
91
|
+
readonly snapshotStoreVersion: number;
|
|
92
|
+
};
|
|
91
93
|
'boxxy.attempt.started': OfAttempt & {
|
|
92
94
|
readonly atcSession: AtcSessionId;
|
|
93
95
|
readonly resumeFallback: boolean;
|
|
@@ -99,7 +99,6 @@ export declare const workFactSchemas: {
|
|
|
99
99
|
pool: z.core.$ZodBranded<z.ZodString, "PoolName", "out">;
|
|
100
100
|
rulesVersion: z.core.$ZodBranded<z.core.$ZodBranded<z.ZodString, "ContentHash", "out">, "RulesVersion", "out">;
|
|
101
101
|
snapshotHash: z.core.$ZodBranded<z.core.$ZodBranded<z.ZodString, "ContentHash", "out">, "SnapshotHash", "out">;
|
|
102
|
-
storeVersion: z.ZodNumber;
|
|
103
102
|
pepysOffsets: z.ZodRecord<z.core.$ZodBranded<z.ZodString, "StreamName", "out">, z.ZodNumber>;
|
|
104
103
|
faults: z.ZodArray<z.ZodObject<{
|
|
105
104
|
plugin: z.ZodString;
|
|
@@ -120,6 +119,7 @@ export declare const workFactSchemas: {
|
|
|
120
119
|
max: z.ZodNumber;
|
|
121
120
|
}, z.core.$strip>>;
|
|
122
121
|
at: z.core.$ZodBranded<z.ZodNumber, "Instant", "out">;
|
|
122
|
+
snapshotStoreVersion: z.ZodNumber;
|
|
123
123
|
}, z.core.$strip>;
|
|
124
124
|
'boxxy.attempt.started': z.ZodObject<{
|
|
125
125
|
attempt: z.core.$ZodBranded<z.ZodString, "AttemptId", "out">;
|
package/dist/index.d.ts
CHANGED
|
@@ -58,7 +58,7 @@ export type { AcceptanceInput, BuildCloseOut, BuildInput, CloseOut, CloseOutAnsw
|
|
|
58
58
|
export type { Claim } from './dispatch/types.ts';
|
|
59
59
|
export type { AnyNewFact, EntityRef, FactEnvelope, FactType, NewFact, OutboxFact, RelationPayload, WorkFacts, } from './facts/types.ts';
|
|
60
60
|
export type { Admission, AdmissionGrant, AdmissionName, Decision, Fault, Filter, Frame, FrameItem, FrameValues, Gate, GateName, Hold, Lift, Limit, LimitFill, Pick, PlanContext, Pool, PropagationLine, SeatRef, SeatRelease, SeatTake, Signal, SignalKey, SignalName, Snapshot, StartPick, View, ViewName, Wait, WaitReason, Waiver, WaiverName, Wake, WakePick, } from './planning/types.ts';
|
|
61
|
-
export type { ApplyResult, Attention, CallerProof, CapacityBackoff, ClaimStore, Clock, FactSink, ForgetOutcome, Forge, GitSource, HoldNotice, ItemDetailRows, ItemFilter, NewId, NoticeOutcome, Notifier, OutboxReader, PepysAnswer, PepysReader, SinkAnswer, PullRequestReading, RowWrite, SessionFault, SessionReading, SpawnRequest, StartOutcome, StopOutcome, StoreChange, StoreReader, StoreTx, SuspendOutcome, TableName, Tables, WakeSource, WorkerKind, } from './ports/types.ts';
|
|
61
|
+
export type { ApplyResult, Attention, CallerProof, CapacityBackoff, ClaimStore, Clock, FactSink, ForgetOutcome, Forge, GitSource, HoldNotice, ItemDetailRows, ItemFilter, NewId, NoticeOutcome, NoticeTryUpdate, Notifier, OutboxReader, PepysAnswer, PepysReader, SinkAnswer, PullRequestReading, RowWrite, RunnerFault, SessionFault, SessionReading, SpawnRequest, StartOutcome, StopOutcome, StoreChange, StoreReader, StoreTx, SuspendOutcome, TableName, Tables, WakeSource, WorkerKind, WorkerRefusal, } from './ports/types.ts';
|
|
62
62
|
export type { CostToLand, StageTime } from './reports/types.ts';
|
|
63
63
|
export type { OutboxStatus } from './reports/outbox-status.ts';
|
|
64
64
|
export type { ItemSetRows, ItemWithLevers } from './items/types.ts';
|
package/dist/ports/types.d.ts
CHANGED
|
@@ -32,6 +32,7 @@ export interface StoreReader extends OutboxReader {
|
|
|
32
32
|
listLimitSeats: () => Promise<LimitSeatRow[]>;
|
|
33
33
|
listItemNotes: (item: ItemId) => Promise<NoteRow[]>;
|
|
34
34
|
listUnsentNotices: (limit: number) => Promise<NoticeRow[]>;
|
|
35
|
+
listNoticesDue: (now: Instant, limit: number) => Promise<NoticeRow[]>;
|
|
35
36
|
listKeptSessions: () => Promise<{
|
|
36
37
|
readonly item: ItemId;
|
|
37
38
|
readonly kept: KeptSession;
|
|
@@ -67,7 +68,7 @@ export interface StoreTx extends StoreReader {
|
|
|
67
68
|
writeHeartbeat: (runner: RunnerId, at: Instant) => Promise<void>;
|
|
68
69
|
syncLimits: (limits: readonly Limit[], at: Instant) => Promise<void>;
|
|
69
70
|
markPullRequestChecked: (ref: PullRequestRef, at: Instant) => Promise<void>;
|
|
70
|
-
markNoticeTried: (id: number,
|
|
71
|
+
markNoticeTried: (id: number, update: NoticeTryUpdate) => Promise<void>;
|
|
71
72
|
}
|
|
72
73
|
export interface StoreChange {
|
|
73
74
|
readonly at: Instant;
|
|
@@ -204,6 +205,9 @@ export type Attention = 'working' | 'needs-input' | 'turn-ended';
|
|
|
204
205
|
export interface GitSource {
|
|
205
206
|
readonly url: string;
|
|
206
207
|
readonly ref: string;
|
|
208
|
+
readonly credentialRef?: {
|
|
209
|
+
readonly name: string;
|
|
210
|
+
};
|
|
207
211
|
}
|
|
208
212
|
export type SpawnRequest = SpawnRequestFields & ({
|
|
209
213
|
readonly cwd: string;
|
|
@@ -227,13 +231,23 @@ export interface HoldNotice {
|
|
|
227
231
|
readonly item: ItemId;
|
|
228
232
|
readonly reason: HoldReason;
|
|
229
233
|
readonly at: Instant;
|
|
234
|
+
readonly key: string;
|
|
230
235
|
}
|
|
231
236
|
export type NoticeOutcome = {
|
|
232
237
|
readonly kind: 'sent';
|
|
233
238
|
} | {
|
|
234
|
-
readonly kind: '
|
|
239
|
+
readonly kind: 'refused';
|
|
240
|
+
readonly reason: string;
|
|
241
|
+
} | {
|
|
242
|
+
readonly kind: 'uncertain';
|
|
235
243
|
readonly reason: string;
|
|
236
244
|
};
|
|
245
|
+
export interface NoticeTryUpdate {
|
|
246
|
+
readonly sentAt: Instant | null;
|
|
247
|
+
readonly keySeq: number;
|
|
248
|
+
readonly keyTries: number;
|
|
249
|
+
readonly nextTryAt: Instant;
|
|
250
|
+
}
|
|
237
251
|
export interface CallerProof {
|
|
238
252
|
prove: (request: Request) => Promise<CallerIdentity | null>;
|
|
239
253
|
}
|
|
@@ -248,6 +262,15 @@ export interface SessionFault {
|
|
|
248
262
|
readonly attempt: AttemptId;
|
|
249
263
|
readonly holder: AttemptId;
|
|
250
264
|
}
|
|
265
|
+
export interface WorkerRefusal {
|
|
266
|
+
readonly kind: 'fault';
|
|
267
|
+
readonly fault: 'spawn-refused' | 'wake-refused';
|
|
268
|
+
readonly attempt: AttemptId;
|
|
269
|
+
readonly item: ItemId;
|
|
270
|
+
readonly cause: 'capacity' | 'other';
|
|
271
|
+
readonly reason: string;
|
|
272
|
+
}
|
|
273
|
+
export type RunnerFault = SessionFault | WorkerRefusal;
|
|
251
274
|
export type SinkAnswer = {
|
|
252
275
|
readonly kind: 'stored';
|
|
253
276
|
} | {
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
import type { HoldNotice, Notifier } from '../ports/types.ts';
|
|
1
|
+
import type { HoldNotice, NoticeOutcome, Notifier } from '../ports/types.ts';
|
|
2
2
|
export interface FakeNotifier extends Notifier {
|
|
3
3
|
readonly told: readonly HoldNotice[];
|
|
4
|
+
readonly attempts: readonly HoldNotice[];
|
|
4
5
|
readonly calls: () => number;
|
|
5
|
-
failNext: (
|
|
6
|
-
|
|
6
|
+
failNext: (outcome: Exclude<NoticeOutcome, {
|
|
7
|
+
kind: 'sent';
|
|
8
|
+
}>) => void;
|
|
9
|
+
failAlways: (outcome: Exclude<NoticeOutcome, {
|
|
10
|
+
kind: 'sent';
|
|
11
|
+
}>) => void;
|
|
7
12
|
recover: () => void;
|
|
8
13
|
}
|
|
9
14
|
export declare function createFakeNotifier(): FakeNotifier;
|
package/dist/types.d.ts
CHANGED
|
@@ -261,6 +261,9 @@ export interface NoticeRow {
|
|
|
261
261
|
readonly at: Instant;
|
|
262
262
|
readonly tries: number;
|
|
263
263
|
readonly sentAt: Instant | null;
|
|
264
|
+
readonly keySeq: number;
|
|
265
|
+
readonly keyTries: number;
|
|
266
|
+
readonly nextTryAt: Instant;
|
|
264
267
|
}
|
|
265
268
|
export type Effort = 'low' | 'medium' | 'high' | 'xhigh' | 'max';
|
|
266
269
|
export interface Recipe {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@boxxy/model",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "The types that boxxy's packages share",
|
|
5
5
|
"homepage": "https://github.com/zgeoff/boxxy/tree/main/libs/model#readme",
|
|
6
6
|
"bugs": "https://github.com/zgeoff/boxxy/issues",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"typecheck": "tsrs --noEmit"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@boxxy/content-hash": "0.
|
|
34
|
+
"@boxxy/content-hash": "0.2.0",
|
|
35
35
|
"tiny-invariant": "1.3.3",
|
|
36
36
|
"zod": "4.6.7"
|
|
37
37
|
},
|
package/src/facts/types.ts
CHANGED
|
@@ -133,7 +133,11 @@ export interface WorkFacts {
|
|
|
133
133
|
readonly skillsRef: CommitSha | null;
|
|
134
134
|
readonly rulesVersion: RulesVersion;
|
|
135
135
|
};
|
|
136
|
-
|
|
136
|
+
|
|
137
|
+
// The sink adds `storeVersion` to every payload, so the decision's own field takes another name.
|
|
138
|
+
'boxxy.decision.recorded': Omit<DecisionRow, 'storeVersion'> & {
|
|
139
|
+
readonly snapshotStoreVersion: number;
|
|
140
|
+
};
|
|
137
141
|
'boxxy.attempt.started': OfAttempt & {
|
|
138
142
|
readonly atcSession: AtcSessionId;
|
|
139
143
|
readonly resumeFallback: boolean;
|
|
@@ -93,7 +93,9 @@ export const workFactSchemas = {
|
|
|
93
93
|
skillsRef: brandSchemas.commitSha.nullable(),
|
|
94
94
|
rulesVersion: brandSchemas.rulesVersion,
|
|
95
95
|
}),
|
|
96
|
-
'boxxy.decision.recorded': decisionRowSchema
|
|
96
|
+
'boxxy.decision.recorded': decisionRowSchema
|
|
97
|
+
.omit({ storeVersion: true })
|
|
98
|
+
.extend({ snapshotStoreVersion: countSchema }),
|
|
97
99
|
'boxxy.attempt.started': z.object({
|
|
98
100
|
...ofAttempt,
|
|
99
101
|
atcSession: brandSchemas.atcSessionId,
|
package/src/index.ts
CHANGED
|
@@ -229,6 +229,7 @@ export type {
|
|
|
229
229
|
ItemFilter,
|
|
230
230
|
NewId,
|
|
231
231
|
NoticeOutcome,
|
|
232
|
+
NoticeTryUpdate,
|
|
232
233
|
Notifier,
|
|
233
234
|
OutboxReader,
|
|
234
235
|
PepysAnswer,
|
|
@@ -236,6 +237,7 @@ export type {
|
|
|
236
237
|
SinkAnswer,
|
|
237
238
|
PullRequestReading,
|
|
238
239
|
RowWrite,
|
|
240
|
+
RunnerFault,
|
|
239
241
|
SessionFault,
|
|
240
242
|
SessionReading,
|
|
241
243
|
SpawnRequest,
|
|
@@ -249,6 +251,7 @@ export type {
|
|
|
249
251
|
Tables,
|
|
250
252
|
WakeSource,
|
|
251
253
|
WorkerKind,
|
|
254
|
+
WorkerRefusal,
|
|
252
255
|
} from './ports/types.ts';
|
|
253
256
|
|
|
254
257
|
export type { CostToLand, StageTime } from './reports/types.ts';
|
package/src/ports/types.ts
CHANGED
|
@@ -95,6 +95,9 @@ export interface StoreReader extends OutboxReader {
|
|
|
95
95
|
// the rows not yet sent, whatever their tries, oldest first
|
|
96
96
|
listUnsentNotices: (limit: number) => Promise<NoticeRow[]>;
|
|
97
97
|
|
|
98
|
+
// the rows not yet sent whose `nextTryAt` has passed, oldest `nextTryAt` first
|
|
99
|
+
listNoticesDue: (now: Instant, limit: number) => Promise<NoticeRow[]>;
|
|
100
|
+
|
|
98
101
|
// oldest kept first
|
|
99
102
|
listKeptSessions: () => Promise<{ readonly item: ItemId; readonly kept: KeptSession }[]>;
|
|
100
103
|
|
|
@@ -152,8 +155,8 @@ export interface StoreTx extends StoreReader {
|
|
|
152
155
|
syncLimits: (limits: readonly Limit[], at: Instant) => Promise<void>;
|
|
153
156
|
markPullRequestChecked: (ref: PullRequestRef, at: Instant) => Promise<void>;
|
|
154
157
|
|
|
155
|
-
// one more try of the notice; `
|
|
156
|
-
markNoticeTried: (id: number,
|
|
158
|
+
// one more try of the notice, with the new key state and next try time; a `sentAt` also marks it sent
|
|
159
|
+
markNoticeTried: (id: number, update: NoticeTryUpdate) => Promise<void>;
|
|
157
160
|
}
|
|
158
161
|
|
|
159
162
|
// A change may write no fact, such as the suspend mark; such a change moves no store version. The
|
|
@@ -305,11 +308,13 @@ export type SessionReading =
|
|
|
305
308
|
|
|
306
309
|
export type Attention = 'working' | 'needs-input' | 'turn-ended';
|
|
307
310
|
|
|
308
|
-
// A git repository that atc clones
|
|
309
|
-
//
|
|
311
|
+
// A git repository that atc clones for the session. The atc daemon clones it before the session
|
|
312
|
+
// exists, so a private repository needs `credentialRef`: the name of the daemon's environment
|
|
313
|
+
// variable that holds a clone token. The name is no secret; boxxy never reads the token.
|
|
310
314
|
export interface GitSource {
|
|
311
315
|
readonly url: string;
|
|
312
316
|
readonly ref: string;
|
|
317
|
+
readonly credentialRef?: { readonly name: string };
|
|
313
318
|
}
|
|
314
319
|
|
|
315
320
|
// Exactly one of the two: `cwd`, the repo's folder on a target on the atc daemon's own host, or
|
|
@@ -341,11 +346,27 @@ export interface HoldNotice {
|
|
|
341
346
|
readonly item: ItemId;
|
|
342
347
|
readonly reason: HoldReason;
|
|
343
348
|
readonly at: Instant;
|
|
349
|
+
|
|
350
|
+
// the row's current key; the adapter sends it unchanged
|
|
351
|
+
readonly key: string;
|
|
344
352
|
}
|
|
345
353
|
|
|
346
354
|
export type NoticeOutcome =
|
|
347
355
|
| { readonly kind: 'sent' }
|
|
348
|
-
|
|
356
|
+
|
|
357
|
+
// atc ran nothing
|
|
358
|
+
| { readonly kind: 'refused'; readonly reason: string }
|
|
359
|
+
|
|
360
|
+
// atc may have sent the message
|
|
361
|
+
| { readonly kind: 'uncertain'; readonly reason: string };
|
|
362
|
+
|
|
363
|
+
// What one try writes to its row, besides one more `tries`.
|
|
364
|
+
export interface NoticeTryUpdate {
|
|
365
|
+
readonly sentAt: Instant | null;
|
|
366
|
+
readonly keySeq: number;
|
|
367
|
+
readonly keyTries: number;
|
|
368
|
+
readonly nextTryAt: Instant;
|
|
369
|
+
}
|
|
349
370
|
|
|
350
371
|
// Proves who sent a request to the server. The server's root middleware calls it for every
|
|
351
372
|
// session and hook procedure, and knows no header and no token itself. null: no proof, so the
|
|
@@ -370,6 +391,21 @@ export interface SessionFault {
|
|
|
370
391
|
readonly holder: AttemptId;
|
|
371
392
|
}
|
|
372
393
|
|
|
394
|
+
// A spawn or a wake that the worker refused. A refused spawn settles the attempt as `no-capacity`
|
|
395
|
+
// or `spawn-refused`; a refused wake sleeps the attempt again for capacity, and otherwise leaves it
|
|
396
|
+
// `waking` for the next reading. The runner logs the worker's reason, which no fact carries.
|
|
397
|
+
export interface WorkerRefusal {
|
|
398
|
+
readonly kind: 'fault';
|
|
399
|
+
readonly fault: 'spawn-refused' | 'wake-refused';
|
|
400
|
+
readonly attempt: AttemptId;
|
|
401
|
+
readonly item: ItemId;
|
|
402
|
+
readonly cause: 'capacity' | 'other';
|
|
403
|
+
readonly reason: string;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// What a claim or a reading returns for the runner to log.
|
|
407
|
+
export type RunnerFault = SessionFault | WorkerRefusal;
|
|
408
|
+
|
|
373
409
|
// What one batch sent to the sink got back. `retry` may or may not have stored the batch.
|
|
374
410
|
export type SinkAnswer =
|
|
375
411
|
| { readonly kind: 'stored' }
|
|
@@ -17,7 +17,7 @@ const limitCountSchema = z.object({
|
|
|
17
17
|
max: countSchema,
|
|
18
18
|
});
|
|
19
19
|
|
|
20
|
-
// A plain object, so that the
|
|
20
|
+
// A plain object, so that the schema of `boxxy.decision.recorded` can rename one field of it.
|
|
21
21
|
export const decisionRowSchema = z.object({
|
|
22
22
|
id: brandSchemas.decisionId,
|
|
23
23
|
attempt: brandSchemas.attemptId,
|
|
@@ -14,6 +14,16 @@ export const gitSourceSchema: z.ZodType<GitSource> = z.strictObject({
|
|
|
14
14
|
.min(1)
|
|
15
15
|
.max(255)
|
|
16
16
|
.refine((ref) => !ref.startsWith('-'), 'a git source ref must not start with -'),
|
|
17
|
+
|
|
18
|
+
// atc's own rule for the name of an environment variable
|
|
19
|
+
credentialRef: z
|
|
20
|
+
.strictObject({
|
|
21
|
+
name: z
|
|
22
|
+
.string()
|
|
23
|
+
.max(255)
|
|
24
|
+
.regex(/^[A-Za-z_]\w*$/u, 'a credentialRef names an environment variable'),
|
|
25
|
+
})
|
|
26
|
+
.exactOptional(),
|
|
17
27
|
});
|
|
18
28
|
|
|
19
29
|
const spawnRequestFields = z.strictObject({
|
|
@@ -4,46 +4,48 @@ export interface FakeNotifier extends Notifier {
|
|
|
4
4
|
// each notice that was sent, in order
|
|
5
5
|
readonly told: readonly HoldNotice[];
|
|
6
6
|
|
|
7
|
-
//
|
|
7
|
+
// every call, sent or not, in order
|
|
8
|
+
readonly attempts: readonly HoldNotice[];
|
|
9
|
+
|
|
10
|
+
// the number of calls, sent or not
|
|
8
11
|
readonly calls: () => number;
|
|
9
12
|
|
|
10
|
-
// the next call
|
|
11
|
-
failNext: (
|
|
13
|
+
// the next call ends with the outcome
|
|
14
|
+
failNext: (outcome: Exclude<NoticeOutcome, { kind: 'sent' }>) => void;
|
|
12
15
|
|
|
13
|
-
// every call
|
|
14
|
-
failAlways: (
|
|
16
|
+
// every call ends with the outcome until `recover`
|
|
17
|
+
failAlways: (outcome: Exclude<NoticeOutcome, { kind: 'sent' }>) => void;
|
|
15
18
|
recover: () => void;
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
export function createFakeNotifier(): FakeNotifier {
|
|
19
22
|
const told: HoldNotice[] = [];
|
|
20
|
-
|
|
21
|
-
let next:
|
|
22
|
-
let always:
|
|
23
|
+
const attempts: HoldNotice[] = [];
|
|
24
|
+
let next: NoticeOutcome | null = null;
|
|
25
|
+
let always: NoticeOutcome | null = null;
|
|
23
26
|
|
|
24
27
|
return {
|
|
25
28
|
told,
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
attempts,
|
|
30
|
+
calls: () => attempts.length,
|
|
31
|
+
failNext: (outcome) => {
|
|
32
|
+
next = outcome;
|
|
29
33
|
},
|
|
30
|
-
failAlways: (
|
|
31
|
-
always =
|
|
34
|
+
failAlways: (outcome) => {
|
|
35
|
+
always = outcome;
|
|
32
36
|
},
|
|
33
37
|
recover: () => {
|
|
34
38
|
always = null;
|
|
35
39
|
},
|
|
36
40
|
tellHold: (notice) => {
|
|
37
|
-
|
|
41
|
+
attempts.push(notice);
|
|
38
42
|
|
|
39
|
-
const
|
|
43
|
+
const outcome = next ?? always;
|
|
40
44
|
|
|
41
45
|
next = null;
|
|
42
46
|
|
|
43
|
-
if (
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
return Promise.resolve(failed);
|
|
47
|
+
if (outcome !== null) {
|
|
48
|
+
return Promise.resolve(outcome);
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
told.push(notice);
|
package/src/types.ts
CHANGED
|
@@ -386,7 +386,7 @@ export interface RunnerRow {
|
|
|
386
386
|
readonly paused: boolean;
|
|
387
387
|
}
|
|
388
388
|
|
|
389
|
-
// A hold notice for the `Notifier` port. The tick tries it again until
|
|
389
|
+
// A hold notice for the `Notifier` port. The tick tries it again, with no cap, until atc takes it.
|
|
390
390
|
export interface NoticeRow {
|
|
391
391
|
readonly id: number;
|
|
392
392
|
readonly item: ItemId;
|
|
@@ -394,6 +394,15 @@ export interface NoticeRow {
|
|
|
394
394
|
readonly at: Instant;
|
|
395
395
|
readonly tries: number;
|
|
396
396
|
readonly sentAt: Instant | null;
|
|
397
|
+
|
|
398
|
+
// the row's current key is `boxxy-notice:<id>:<keySeq>`
|
|
399
|
+
readonly keySeq: number;
|
|
400
|
+
|
|
401
|
+
// uncertain tries under the current key; 0 after each change of key
|
|
402
|
+
readonly keyTries: number;
|
|
403
|
+
|
|
404
|
+
// a tick sends the row once now >= nextTryAt; a new row holds its `at`
|
|
405
|
+
readonly nextTryAt: Instant;
|
|
397
406
|
}
|
|
398
407
|
|
|
399
408
|
export type Effort = 'low' | 'medium' | 'high' | 'xhigh' | 'max';
|