@boxxy/model 0.1.9 → 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 +13 -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 +1 -0
- package/src/ports/types.ts +22 -3
- package/src/rows/decision-row-schema.ts +1 -1
- package/src/rows/notice-row-schema.ts +3 -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, RunnerFault, SessionFault, SessionReading, SpawnRequest, StartOutcome, StopOutcome, StoreChange, StoreReader, StoreTx, SuspendOutcome, TableName, Tables, WakeSource, WorkerKind, WorkerRefusal, } 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;
|
|
@@ -230,13 +231,23 @@ export interface HoldNotice {
|
|
|
230
231
|
readonly item: ItemId;
|
|
231
232
|
readonly reason: HoldReason;
|
|
232
233
|
readonly at: Instant;
|
|
234
|
+
readonly key: string;
|
|
233
235
|
}
|
|
234
236
|
export type NoticeOutcome = {
|
|
235
237
|
readonly kind: 'sent';
|
|
236
238
|
} | {
|
|
237
|
-
readonly kind: '
|
|
239
|
+
readonly kind: 'refused';
|
|
240
|
+
readonly reason: string;
|
|
241
|
+
} | {
|
|
242
|
+
readonly kind: 'uncertain';
|
|
238
243
|
readonly reason: string;
|
|
239
244
|
};
|
|
245
|
+
export interface NoticeTryUpdate {
|
|
246
|
+
readonly sentAt: Instant | null;
|
|
247
|
+
readonly keySeq: number;
|
|
248
|
+
readonly keyTries: number;
|
|
249
|
+
readonly nextTryAt: Instant;
|
|
250
|
+
}
|
|
240
251
|
export interface CallerProof {
|
|
241
252
|
prove: (request: Request) => Promise<CallerIdentity | null>;
|
|
242
253
|
}
|
|
@@ -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
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
|
|
@@ -343,11 +346,27 @@ export interface HoldNotice {
|
|
|
343
346
|
readonly item: ItemId;
|
|
344
347
|
readonly reason: HoldReason;
|
|
345
348
|
readonly at: Instant;
|
|
349
|
+
|
|
350
|
+
// the row's current key; the adapter sends it unchanged
|
|
351
|
+
readonly key: string;
|
|
346
352
|
}
|
|
347
353
|
|
|
348
354
|
export type NoticeOutcome =
|
|
349
355
|
| { readonly kind: 'sent' }
|
|
350
|
-
|
|
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
|
+
}
|
|
351
370
|
|
|
352
371
|
// Proves who sent a request to the server. The server's root middleware calls it for every
|
|
353
372
|
// session and hook procedure, and knows no header and no token itself. null: no proof, so the
|
|
@@ -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,
|
|
@@ -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';
|