@boxxy/model 0.1.2 → 0.1.4
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/README.md +8 -6
- package/dist/closeouts/build-close-out-schema.d.ts +31 -0
- package/dist/closeouts/close-out-answer-schema.d.ts +3 -0
- package/dist/closeouts/close-out-schema.d.ts +3 -0
- package/dist/closeouts/design-close-out-schema.d.ts +30 -0
- package/dist/closeouts/friction-schema.d.ts +14 -0
- package/dist/closeouts/open-item-schema.d.ts +3 -0
- package/dist/closeouts/review-close-out-schema.d.ts +40 -0
- package/dist/closeouts/triage-close-out-schema.d.ts +40 -0
- package/dist/closeouts/types.d.ts +221 -0
- package/dist/dispatch/build-applied-change.d.ts +6 -0
- package/dist/dispatch/collect-seat-sync.d.ts +14 -0
- package/dist/dispatch/pick-seat-take.d.ts +10 -0
- package/dist/dispatch/types.d.ts +11 -0
- package/dist/{outbox-fact-schema.d.ts → facts/outbox-fact-schema.d.ts} +1 -1
- package/dist/facts/parse-new-fact.d.ts +2 -0
- package/dist/facts/types.d.ts +191 -0
- package/dist/facts/work-fact-schemas.d.ts +293 -0
- package/dist/index.d.ts +64 -23
- package/dist/items/build-item-views.d.ts +4 -0
- package/dist/items/collect-retries.d.ts +3 -0
- package/dist/items/collect-settled.d.ts +3 -0
- package/dist/items/derive-item-state.d.ts +17 -0
- package/dist/{live-levers.d.ts → items/live-levers.d.ts} +1 -1
- package/dist/items/types.d.ts +12 -0
- package/dist/pipeline/advance.d.ts +10 -0
- package/dist/pipeline/constants.d.ts +2 -0
- package/dist/pipeline/count-trailing.d.ts +1 -0
- package/dist/pipeline/find-position.d.ts +9 -0
- package/dist/pipeline/find-step.d.ts +3 -0
- package/dist/pipeline/merge-by-time.d.ts +9 -0
- package/dist/pipeline/position-schema.d.ts +3 -0
- package/dist/pipeline/types.d.ts +28 -0
- package/dist/planning/define-admission.d.ts +3 -0
- package/dist/planning/define-gate.d.ts +3 -0
- package/dist/planning/define-signal.d.ts +3 -0
- package/dist/planning/is-filter-match.d.ts +3 -0
- package/dist/planning/limit-fill-schema.d.ts +3 -0
- package/dist/{signal-key.d.ts → planning/signal-key.d.ts} +1 -1
- package/dist/planning/types.d.ts +155 -0
- package/dist/ports/types.d.ts +289 -0
- package/dist/reports/constants.d.ts +3 -0
- package/dist/reports/cost-to-land-schema.d.ts +29 -0
- package/dist/reports/outbox-status.d.ts +16 -0
- package/dist/reports/stage-time-schema.d.ts +25 -0
- package/dist/reports/types.d.ts +5 -0
- package/dist/rows/actor-ref-schema.d.ts +2 -0
- package/dist/rows/attempt-row-schema.d.ts +3 -0
- package/dist/rows/attempt-session-row-schema.d.ts +3 -0
- package/dist/{brand-schemas.d.ts → rows/brand-schemas.d.ts} +5 -2
- package/dist/rows/caller-identity-schema.d.ts +3 -0
- package/dist/rows/criterion-schema.d.ts +3 -0
- package/dist/rows/decision-row-schema.d.ts +34 -0
- package/dist/rows/evidence-row-schema.d.ts +3 -0
- package/dist/rows/item-row-schema.d.ts +28 -0
- package/dist/rows/item-view-schema.d.ts +3 -0
- package/dist/rows/lease-row-schema.d.ts +3 -0
- package/dist/rows/lever-row-schema.d.ts +12 -0
- package/dist/rows/limit-schema.d.ts +3 -0
- package/dist/rows/limit-seat-row-schema.d.ts +3 -0
- package/dist/rows/note-row-schema.d.ts +3 -0
- package/dist/rows/notice-row-schema.d.ts +3 -0
- package/dist/rows/pull-request-row-schema.d.ts +3 -0
- package/dist/rows/relation-row-schema.d.ts +3 -0
- package/dist/{row-schemas.d.ts → rows/row-schemas.d.ts} +2 -2
- package/dist/rows/runner-row-schema.d.ts +3 -0
- package/dist/rows/spawn-request-schema.d.ts +3 -0
- package/dist/rules/define-phase.d.ts +3 -0
- package/dist/rules/load-rejection-schema.d.ts +3 -0
- package/dist/rules/types.d.ts +244 -0
- package/dist/test-utils/build-mock-cost-to-land.d.ts +2 -0
- package/dist/test-utils/build-mock-evidence-row.d.ts +1 -1
- package/dist/test-utils/build-mock-fact-id.d.ts +1 -1
- package/dist/test-utils/build-mock-frame-item.d.ts +1 -1
- package/dist/test-utils/build-mock-frame.d.ts +2 -0
- package/dist/test-utils/build-mock-item-rules.d.ts +2 -0
- package/dist/test-utils/build-mock-lease-row.d.ts +1 -1
- package/dist/test-utils/build-mock-outbox-fact.d.ts +2 -0
- package/dist/test-utils/build-mock-phase-kind.d.ts +7 -0
- package/dist/test-utils/build-mock-pipeline.d.ts +7 -0
- package/dist/test-utils/build-mock-relation-row.d.ts +2 -0
- package/dist/test-utils/build-mock-settled.d.ts +9 -0
- package/dist/test-utils/build-mock-snapshot.d.ts +1 -1
- package/dist/test-utils/build-mock-v1-attempt-row.d.ts +2 -0
- package/dist/test-utils/build-mock-v1-item-row.d.ts +2 -0
- package/dist/test-utils/build-mock-v1-item-view.d.ts +2 -0
- package/dist/test-utils/build-mock-v1-lever-row.d.ts +2 -0
- package/dist/test-utils/build-mock-v1-pull-request-row.d.ts +2 -0
- package/dist/test-utils/build-mock-work-fact.d.ts +12 -0
- package/dist/test-utils/create-fake-notifier.d.ts +9 -0
- package/dist/test-utils/create-fake-pepys-reader.d.ts +13 -0
- package/dist/test-utils/fact-sink-contract.d.ts +14 -0
- package/dist/test-utils/pepys-reader-contract.d.ts +17 -0
- package/dist/{types/core.d.ts → types.d.ts} +93 -43
- package/package.json +13 -3
- package/src/{build-close-out-schema.ts → closeouts/build-close-out-schema.ts} +5 -10
- package/src/closeouts/close-out-answer-schema.ts +42 -0
- package/src/closeouts/close-out-schema.ts +13 -0
- package/src/closeouts/design-close-out-schema.ts +20 -0
- package/src/closeouts/friction-schema.ts +11 -0
- package/src/closeouts/open-item-schema.ts +8 -0
- package/src/closeouts/review-close-out-schema.ts +38 -0
- package/src/closeouts/triage-close-out-schema.ts +29 -0
- package/src/closeouts/types.ts +230 -0
- package/src/dispatch/build-applied-change.ts +57 -0
- package/src/dispatch/collect-seat-sync.ts +86 -0
- package/src/dispatch/pick-seat-take.ts +39 -0
- package/src/dispatch/types.ts +14 -0
- package/src/facts/outbox-fact-schema.ts +22 -0
- package/src/facts/parse-new-fact.ts +16 -0
- package/src/facts/types.ts +235 -0
- package/src/facts/work-fact-schemas.ts +201 -0
- package/src/index.ts +147 -55
- package/src/items/build-item-views.ts +146 -0
- package/src/items/collect-retries.ts +12 -0
- package/src/items/collect-settled.ts +20 -0
- package/src/items/derive-item-state.ts +95 -0
- package/src/{live-levers.ts → items/live-levers.ts} +1 -1
- package/src/items/types.ts +26 -0
- package/src/pipeline/advance.ts +78 -0
- package/src/pipeline/constants.ts +12 -0
- package/src/pipeline/count-trailing.ts +16 -0
- package/src/pipeline/find-position.ts +74 -0
- package/src/pipeline/find-step.ts +6 -0
- package/src/pipeline/merge-by-time.ts +33 -0
- package/src/pipeline/position-schema.ts +27 -0
- package/src/pipeline/types.ts +47 -0
- package/src/{define-admission.ts → planning/define-admission.ts} +2 -2
- package/src/{define-gate.ts → planning/define-gate.ts} +2 -2
- package/src/{define-signal.ts → planning/define-signal.ts} +2 -2
- package/src/planning/is-filter-match.ts +10 -0
- package/src/planning/limit-fill-schema.ts +12 -0
- package/src/{signal-key.ts → planning/signal-key.ts} +1 -1
- package/src/planning/types.ts +216 -0
- package/src/ports/types.ts +412 -0
- package/src/reports/constants.ts +6 -0
- package/src/reports/cost-to-land-schema.ts +47 -0
- package/src/reports/outbox-status.ts +22 -0
- package/src/reports/stage-time-schema.ts +21 -0
- package/src/reports/types.ts +7 -0
- package/src/rows/actor-ref-schema.ts +17 -0
- package/src/rows/attempt-row-schema.ts +69 -0
- package/src/rows/attempt-session-row-schema.ts +12 -0
- package/src/{brand-schemas.ts → rows/brand-schemas.ts} +5 -2
- package/src/rows/caller-identity-schema.ts +7 -0
- package/src/rows/criterion-schema.ts +9 -0
- package/src/rows/decision-row-schema.ts +34 -0
- package/src/rows/evidence-row-schema.ts +13 -0
- package/src/rows/item-row-schema.ts +32 -0
- package/src/rows/item-view-schema.ts +31 -0
- package/src/rows/lease-row-schema.ts +12 -0
- package/src/rows/lever-row-schema.ts +17 -0
- package/src/rows/limit-schema.ts +12 -0
- package/src/rows/limit-seat-row-schema.ts +12 -0
- package/src/rows/note-row-schema.ts +12 -0
- package/src/rows/notice-row-schema.ts +17 -0
- package/src/rows/pull-request-row-schema.ts +15 -0
- package/src/rows/relation-row-schema.ts +13 -0
- package/src/rows/row-schemas.ts +30 -0
- package/src/rows/runner-row-schema.ts +9 -0
- package/src/rows/spawn-request-schema.ts +15 -0
- package/src/rules/define-phase.ts +12 -0
- package/src/rules/load-rejection-schema.ts +51 -0
- package/src/rules/types.ts +291 -0
- package/src/test-utils/build-mock-cost-to-land.ts +31 -0
- package/src/test-utils/build-mock-evidence-row.ts +2 -2
- package/src/test-utils/build-mock-fact-id.ts +3 -3
- package/src/test-utils/build-mock-frame-item.ts +10 -5
- package/src/test-utils/build-mock-frame.ts +13 -0
- package/src/test-utils/build-mock-item-rules.ts +17 -0
- package/src/test-utils/build-mock-lease-row.ts +2 -2
- package/src/test-utils/build-mock-outbox-fact.ts +22 -0
- package/src/test-utils/build-mock-phase-kind.ts +29 -0
- package/src/test-utils/build-mock-pipeline.ts +52 -0
- package/src/test-utils/{build-mock-link-row.ts → build-mock-relation-row.ts} +4 -4
- package/src/test-utils/build-mock-settled.ts +18 -0
- package/src/test-utils/build-mock-snapshot.ts +10 -2
- package/src/test-utils/{build-mock-attempt-row.ts → build-mock-v1-attempt-row.ts} +28 -9
- package/src/test-utils/{build-mock-item-row.ts → build-mock-v1-item-row.ts} +7 -3
- package/src/test-utils/build-mock-v1-item-view.ts +29 -0
- package/src/test-utils/{build-mock-lever-row.ts → build-mock-v1-lever-row.ts} +5 -3
- package/src/test-utils/build-mock-v1-pull-request-row.ts +26 -0
- package/src/test-utils/build-mock-work-fact.ts +179 -0
- package/src/test-utils/create-fake-notifier.ts +54 -0
- package/src/test-utils/create-fake-pepys-reader.ts +73 -0
- package/src/test-utils/fact-sink-contract.ts +103 -0
- package/src/test-utils/pepys-reader-contract.ts +117 -0
- package/src/{types/core.ts → types.ts} +183 -59
- package/dist/actor-ref-schema.d.ts +0 -2
- package/dist/build-applied-change.d.ts +0 -13
- package/dist/build-close-out-schema.d.ts +0 -3
- package/dist/build-item-views.d.ts +0 -2
- package/dist/define-admission.d.ts +0 -3
- package/dist/define-gate.d.ts +0 -3
- package/dist/define-signal.d.ts +0 -3
- package/dist/derive-item-state.d.ts +0 -2
- package/dist/fact-schemas.d.ts +0 -5
- package/dist/find-slot-take.d.ts +0 -5
- package/dist/friction-schema.d.ts +0 -3
- package/dist/test-utils/build-mock-attempt-row.d.ts +0 -2
- package/dist/test-utils/build-mock-item-row.d.ts +0 -2
- package/dist/test-utils/build-mock-item-rows.d.ts +0 -2
- package/dist/test-utils/build-mock-item-view.d.ts +0 -2
- package/dist/test-utils/build-mock-lever-row.d.ts +0 -2
- package/dist/test-utils/build-mock-link-row.d.ts +0 -2
- package/dist/test-utils/build-mock-pull-request-row.d.ts +0 -2
- package/dist/types/dispatch.d.ts +0 -82
- package/dist/types/facts.d.ts +0 -154
- package/dist/types/planning.d.ts +0 -94
- package/dist/types/ports.d.ts +0 -218
- package/dist/types/registries.d.ts +0 -150
- package/src/actor-ref-schema.ts +0 -9
- package/src/build-applied-change.ts +0 -71
- package/src/build-item-views.ts +0 -128
- package/src/derive-item-state.ts +0 -76
- package/src/fact-schemas.ts +0 -132
- package/src/find-slot-take.ts +0 -12
- package/src/friction-schema.ts +0 -10
- package/src/outbox-fact-schema.ts +0 -25
- package/src/row-schemas.ts +0 -89
- package/src/test-utils/build-mock-item-rows.ts +0 -14
- package/src/test-utils/build-mock-item-view.ts +0 -8
- package/src/test-utils/build-mock-pull-request-row.ts +0 -16
- package/src/types/dispatch.ts +0 -95
- package/src/types/facts.ts +0 -166
- package/src/types/planning.ts +0 -136
- package/src/types/ports.ts +0 -262
- package/src/types/registries.ts +0 -185
- /package/dist/test-utils/{seed-faker.d.ts → pin-faker-seed.d.ts} +0 -0
- /package/dist/{format-key-path.d.ts → utils/format-key-path.d.ts} +0 -0
- /package/dist/{to-json-value.d.ts → utils/to-json-value.d.ts} +0 -0
- /package/src/test-utils/{seed-faker.ts → pin-faker-seed.ts} +0 -0
- /package/src/{format-key-path.ts → utils/format-key-path.ts} +0 -0
- /package/src/{to-json-value.ts → utils/to-json-value.ts} +0 -0
package/src/build-item-views.ts
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import { deriveItemState } from './derive-item-state.ts';
|
|
2
|
-
import { liveLevers } from './live-levers.ts';
|
|
3
|
-
import type {
|
|
4
|
-
AttemptId,
|
|
5
|
-
AttemptRow,
|
|
6
|
-
Instant,
|
|
7
|
-
ItemId,
|
|
8
|
-
ItemKindName,
|
|
9
|
-
ItemRow,
|
|
10
|
-
ItemRows,
|
|
11
|
-
ItemSetRows,
|
|
12
|
-
ItemState,
|
|
13
|
-
ItemWithLevers,
|
|
14
|
-
LeaseRow,
|
|
15
|
-
LeverRow,
|
|
16
|
-
LinkRow,
|
|
17
|
-
MaxAttemptsByKind,
|
|
18
|
-
PullRequestRow,
|
|
19
|
-
} from './types/core.ts';
|
|
20
|
-
|
|
21
|
-
export function buildItemViews(
|
|
22
|
-
rows: ItemSetRows,
|
|
23
|
-
now: Instant,
|
|
24
|
-
maxAttemptsByKind: MaxAttemptsByKind,
|
|
25
|
-
): ItemWithLevers[] {
|
|
26
|
-
const groups = collectItemGroups(rows, now);
|
|
27
|
-
|
|
28
|
-
// A blocking source counts only when it is done or archived, and no link makes an item either,
|
|
29
|
-
// so each source's state derived without its links settles its targets.
|
|
30
|
-
const ownStates = new Map<ItemId, ItemState>(
|
|
31
|
-
rows.items.map((item) => [
|
|
32
|
-
item.id,
|
|
33
|
-
deriveItemState(
|
|
34
|
-
item,
|
|
35
|
-
buildItemRows(item, groups.get(item.id), maxAttemptsByKind, {
|
|
36
|
-
links: [],
|
|
37
|
-
blockerStates: new Map(),
|
|
38
|
-
}),
|
|
39
|
-
).state,
|
|
40
|
-
]),
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
return rows.items.map((item) => {
|
|
44
|
-
const group = groups.get(item.id);
|
|
45
|
-
|
|
46
|
-
const itemRows = buildItemRows(item, group, maxAttemptsByKind, {
|
|
47
|
-
links: group?.links ?? [],
|
|
48
|
-
blockerStates: ownStates,
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
return { ...item, derived: deriveItemState(item, itemRows), levers: group?.levers ?? [] };
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
interface ItemGroup {
|
|
56
|
-
readonly links: LinkRow[];
|
|
57
|
-
readonly attempts: AttemptRow[];
|
|
58
|
-
readonly pullRequests: PullRequestRow[];
|
|
59
|
-
levers: LeverRow[];
|
|
60
|
-
liveLease: LeaseRow | null;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function collectItemGroups(rows: ItemSetRows, now: Instant): Map<ItemId, ItemGroup> {
|
|
64
|
-
const groups = new Map<ItemId, ItemGroup>(
|
|
65
|
-
rows.items.map((item) => [
|
|
66
|
-
item.id,
|
|
67
|
-
{ links: [], attempts: [], pullRequests: [], levers: [], liveLease: null },
|
|
68
|
-
]),
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
const attemptItems = new Map<AttemptId, ItemId>();
|
|
72
|
-
|
|
73
|
-
for (const link of rows.links) {
|
|
74
|
-
groups.get(link.target)?.links.push(link);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
for (const attempt of rows.attempts) {
|
|
78
|
-
attemptItems.set(attempt.id, attempt.item);
|
|
79
|
-
groups.get(attempt.item)?.attempts.push(attempt);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
for (const pullRequest of rows.pullRequests) {
|
|
83
|
-
const item = attemptItems.get(pullRequest.attempt);
|
|
84
|
-
|
|
85
|
-
if (item !== undefined) {
|
|
86
|
-
groups.get(item)?.pullRequests.push(pullRequest);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
for (const lease of rows.liveLeases) {
|
|
91
|
-
const group = groups.get(lease.item);
|
|
92
|
-
|
|
93
|
-
if (group !== undefined) {
|
|
94
|
-
group.liveLease = lease;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
for (const [item, group] of groups) {
|
|
99
|
-
group.levers = liveLevers(
|
|
100
|
-
rows.levers.filter((lever) => lever.item === item),
|
|
101
|
-
now,
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return groups;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function buildItemRows(
|
|
109
|
-
item: ItemRow,
|
|
110
|
-
group: ItemGroup | undefined,
|
|
111
|
-
maxAttemptsByKind: MaxAttemptsByKind,
|
|
112
|
-
blocking: Pick<ItemRows, 'links' | 'blockerStates'>,
|
|
113
|
-
): ItemRows {
|
|
114
|
-
return {
|
|
115
|
-
...blocking,
|
|
116
|
-
levers: group?.levers ?? [],
|
|
117
|
-
attempts: group?.attempts ?? [],
|
|
118
|
-
liveLease: group?.liveLease ?? null,
|
|
119
|
-
pullRequests: group?.pullRequests ?? [],
|
|
120
|
-
maxAttempts: pickMaxAttempts(item.kind, maxAttemptsByKind),
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function pickMaxAttempts(kind: ItemKindName, maxAttemptsByKind: MaxAttemptsByKind): number {
|
|
125
|
-
const [first] = maxAttemptsByKind.get(kind)?.values() ?? [];
|
|
126
|
-
|
|
127
|
-
return first ?? Number.POSITIVE_INFINITY;
|
|
128
|
-
}
|
package/src/derive-item-state.ts
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import type { AttemptRow, DerivedState, ItemRow, ItemRows } from './types/core.ts';
|
|
2
|
-
|
|
3
|
-
interface StateInput {
|
|
4
|
-
readonly item: ItemRow;
|
|
5
|
-
readonly rows: ItemRows;
|
|
6
|
-
|
|
7
|
-
// the succeeded and failed attempts that ended after the item's latest `item.retry` lever
|
|
8
|
-
readonly counted: readonly AttemptRow[];
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
interface StateRule {
|
|
12
|
-
readonly derived: DerivedState;
|
|
13
|
-
readonly holds: (input: StateInput) => boolean;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const stateRules: readonly StateRule[] = [
|
|
17
|
-
{ derived: { state: 'archived' }, holds: (input) => input.item.closedAt !== null },
|
|
18
|
-
{ derived: { state: 'done' }, holds: (input) => hasMergedPullRequest(input.rows) },
|
|
19
|
-
{ derived: { state: 'running' }, holds: (input) => input.rows.liveLease !== null },
|
|
20
|
-
{ derived: { state: 'waiting', reason: 'PR open' }, holds: hasOpenPullRequest },
|
|
21
|
-
{ derived: { state: 'waiting', reason: 'no PR linked' }, holds: hasSucceededWithoutPullRequest },
|
|
22
|
-
{ derived: { state: 'waiting', reason: 'attempts used up' }, holds: hasUsedUpAttempts },
|
|
23
|
-
{ derived: { state: 'idea' }, holds: (input) => input.item.acceptance.length === 0 },
|
|
24
|
-
{ derived: { state: 'blocked' }, holds: (input) => hasOpenBlocker(input.rows) },
|
|
25
|
-
];
|
|
26
|
-
|
|
27
|
-
export function deriveItemState(item: ItemRow, rows: ItemRows): DerivedState {
|
|
28
|
-
const input = { item, rows, counted: collectCountedAttempts(rows) };
|
|
29
|
-
|
|
30
|
-
return stateRules.find((rule) => rule.holds(input))?.derived ?? { state: 'ready' };
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function collectCountedAttempts(rows: ItemRows): AttemptRow[] {
|
|
34
|
-
const retryAt = Math.max(
|
|
35
|
-
Number.NEGATIVE_INFINITY,
|
|
36
|
-
...rows.levers.filter((lever) => lever.kind === 'item.retry').map((lever) => lever.at),
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
return rows.attempts.filter((attempt) => attempt.endedAt !== null && attempt.endedAt > retryAt);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function hasMergedPullRequest(rows: ItemRows): boolean {
|
|
43
|
-
const succeeded = new Set(collectSucceeded(rows.attempts).map((attempt) => attempt.id));
|
|
44
|
-
|
|
45
|
-
return rows.pullRequests.some((pr) => pr.state === 'merged' && succeeded.has(pr.attempt));
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function collectSucceeded(attempts: readonly AttemptRow[]): AttemptRow[] {
|
|
49
|
-
return attempts.filter((attempt) => attempt.state === 'succeeded');
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function hasOpenPullRequest(input: StateInput): boolean {
|
|
53
|
-
const succeeded = new Set(collectSucceeded(input.counted).map((attempt) => attempt.id));
|
|
54
|
-
|
|
55
|
-
return input.rows.pullRequests.some((pr) => pr.state === 'open' && succeeded.has(pr.attempt));
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function hasSucceededWithoutPullRequest(input: StateInput): boolean {
|
|
59
|
-
const linked = new Set(input.rows.pullRequests.map((pr) => pr.attempt));
|
|
60
|
-
|
|
61
|
-
return collectSucceeded(input.counted).some((attempt) => !linked.has(attempt.id));
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function hasUsedUpAttempts(input: StateInput): boolean {
|
|
65
|
-
const failed = input.counted.filter((attempt) => attempt.state === 'failed');
|
|
66
|
-
|
|
67
|
-
return failed.length >= input.rows.maxAttempts;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function hasOpenBlocker(rows: ItemRows): boolean {
|
|
71
|
-
return rows.links.some((link) => {
|
|
72
|
-
const blockerState = rows.blockerStates.get(link.source);
|
|
73
|
-
|
|
74
|
-
return link.type === 'blocks' && blockerState !== 'done' && blockerState !== 'archived';
|
|
75
|
-
});
|
|
76
|
-
}
|
package/src/fact-schemas.ts
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { actorRefSchema } from './actor-ref-schema.ts';
|
|
3
|
-
import { brandSchemas } from './brand-schemas.ts';
|
|
4
|
-
import { buildCloseOutSchema } from './build-close-out-schema.ts';
|
|
5
|
-
import { frictionSchema } from './friction-schema.ts';
|
|
6
|
-
import type { FactType, SliceOneFacts } from './types/facts.ts';
|
|
7
|
-
|
|
8
|
-
const criterionSchema = z.object({
|
|
9
|
-
id: brandSchemas.criterionId,
|
|
10
|
-
text: z.string().min(1),
|
|
11
|
-
evidence: z.array(brandSchemas.factId),
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
const linkPayloadSchema = z.object({
|
|
15
|
-
source: brandSchemas.itemId,
|
|
16
|
-
target: brandSchemas.itemId,
|
|
17
|
-
type: brandSchemas.linkTypeName,
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
const faultSchema = z.object({
|
|
21
|
-
plugin: z.string().min(1),
|
|
22
|
-
kind: z.enum(['signal', 'gate', 'waiver', 'admission', 'propagation', 'filter-field']),
|
|
23
|
-
item: brandSchemas.itemId.nullable(),
|
|
24
|
-
error: z.string(),
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
const copiedEvidenceSchema = z.object({
|
|
28
|
-
criterion: brandSchemas.criterionId,
|
|
29
|
-
evidence: z.array(brandSchemas.factId),
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
const pullRequestNumberSchema = z.number().int().positive();
|
|
33
|
-
|
|
34
|
-
export const factSchemas: { readonly [T in FactType]: z.ZodType<SliceOneFacts[T]> } = {
|
|
35
|
-
'boxxy.item.filed': z.object({
|
|
36
|
-
id: brandSchemas.itemId,
|
|
37
|
-
kind: brandSchemas.itemKindName,
|
|
38
|
-
repo: brandSchemas.repoName,
|
|
39
|
-
title: z.string().min(1),
|
|
40
|
-
outcome: z.string().min(1),
|
|
41
|
-
acceptance: z.array(criterionSchema),
|
|
42
|
-
foundInAttempt: brandSchemas.attemptId.nullable(),
|
|
43
|
-
filedBy: actorRefSchema,
|
|
44
|
-
filedAt: brandSchemas.instant,
|
|
45
|
-
closedAt: brandSchemas.instant.nullable(),
|
|
46
|
-
closeReason: z.string().nullable(),
|
|
47
|
-
}),
|
|
48
|
-
'boxxy.item.edited': z
|
|
49
|
-
.object({
|
|
50
|
-
title: z.string().min(1).exactOptional(),
|
|
51
|
-
outcome: z.string().min(1).exactOptional(),
|
|
52
|
-
acceptance: z.array(criterionSchema).exactOptional(),
|
|
53
|
-
})
|
|
54
|
-
.refine((fields) => Object.keys(fields).length > 0, 'an edit changes at least one field'),
|
|
55
|
-
'boxxy.item.closed': z.object({ reason: z.string().min(1) }),
|
|
56
|
-
'boxxy.link.added': linkPayloadSchema,
|
|
57
|
-
'boxxy.link.removed': linkPayloadSchema,
|
|
58
|
-
'boxxy.lever.recorded': z.object({
|
|
59
|
-
seq: z.number().int().nonnegative(),
|
|
60
|
-
kind: z.templateLiteral([z.string().min(1), '.', z.string().min(1)]),
|
|
61
|
-
item: brandSchemas.itemId,
|
|
62
|
-
until: brandSchemas.instant.nullable(),
|
|
63
|
-
expiresAt: brandSchemas.instant.nullable(),
|
|
64
|
-
reason: z.string().nullable(),
|
|
65
|
-
actor: actorRefSchema,
|
|
66
|
-
at: brandSchemas.instant,
|
|
67
|
-
}),
|
|
68
|
-
'boxxy.attempt.claimed': z.object({
|
|
69
|
-
item: brandSchemas.itemId,
|
|
70
|
-
phase: brandSchemas.phaseName,
|
|
71
|
-
number: z.number().int().positive(),
|
|
72
|
-
pool: brandSchemas.poolName,
|
|
73
|
-
slot: z.number().int().nonnegative(),
|
|
74
|
-
gen: z.number().int().nonnegative(),
|
|
75
|
-
recipeHash: brandSchemas.recipeHash,
|
|
76
|
-
rulesVersion: brandSchemas.rulesVersion,
|
|
77
|
-
}),
|
|
78
|
-
'boxxy.decision.recorded': z.object({
|
|
79
|
-
id: brandSchemas.decisionId,
|
|
80
|
-
attempt: brandSchemas.attemptId,
|
|
81
|
-
item: brandSchemas.itemId,
|
|
82
|
-
pool: brandSchemas.poolName,
|
|
83
|
-
rulesVersion: brandSchemas.rulesVersion,
|
|
84
|
-
snapshotHash: brandSchemas.snapshotHash,
|
|
85
|
-
storeVersion: z.number().int().nonnegative(),
|
|
86
|
-
pepysOffsets: z.record(brandSchemas.streamName, z.number().int().nonnegative()),
|
|
87
|
-
faults: z.array(faultSchema),
|
|
88
|
-
at: brandSchemas.instant,
|
|
89
|
-
}),
|
|
90
|
-
'boxxy.attempt.started': z.object({ atcSession: brandSchemas.atcSessionId }),
|
|
91
|
-
'boxxy.attempt.reconciling': z.object({ reason: z.string().min(1) }),
|
|
92
|
-
'boxxy.attempt.reconciled': z.object({ atcSession: brandSchemas.atcSessionId }),
|
|
93
|
-
'boxxy.attempt.session_bound': z.object({
|
|
94
|
-
atcSession: brandSchemas.atcSessionId,
|
|
95
|
-
agentSession: brandSchemas.agentSessionId,
|
|
96
|
-
seenAt: brandSchemas.instant,
|
|
97
|
-
}),
|
|
98
|
-
'boxxy.attempt.closed_out': z.object({ closeOut: buildCloseOutSchema }),
|
|
99
|
-
'boxxy.attempt.settled': z.object({
|
|
100
|
-
state: z.enum(['succeeded', 'failed']),
|
|
101
|
-
failure: z.string().min(1).nullable(),
|
|
102
|
-
endedAt: brandSchemas.instant,
|
|
103
|
-
criteria: z.array(copiedEvidenceSchema),
|
|
104
|
-
matched: z.array(brandSchemas.itemId),
|
|
105
|
-
frictionDropped: z.number().int().nonnegative(),
|
|
106
|
-
}),
|
|
107
|
-
'boxxy.evidence.recorded': z.object({
|
|
108
|
-
kind: z.enum(['pr', 'commit', 'test', 'ci-run', 'live-check']),
|
|
109
|
-
ref: z.string().min(1),
|
|
110
|
-
observed: z.string().nullable(),
|
|
111
|
-
}),
|
|
112
|
-
'boxxy.evidence.pr_linked': z.object({
|
|
113
|
-
repo: brandSchemas.repoName,
|
|
114
|
-
number: pullRequestNumberSchema,
|
|
115
|
-
url: z.url(),
|
|
116
|
-
}),
|
|
117
|
-
'boxxy.evidence.commit_linked': z.object({
|
|
118
|
-
repo: brandSchemas.repoName,
|
|
119
|
-
sha: brandSchemas.commitSha,
|
|
120
|
-
pr: pullRequestNumberSchema,
|
|
121
|
-
}),
|
|
122
|
-
'boxxy.pr.merged': z.object({
|
|
123
|
-
repo: brandSchemas.repoName,
|
|
124
|
-
number: pullRequestNumberSchema,
|
|
125
|
-
mergedAt: brandSchemas.instant,
|
|
126
|
-
mergeCommit: brandSchemas.commitSha,
|
|
127
|
-
}),
|
|
128
|
-
'boxxy.pr.closed': z.object({ repo: brandSchemas.repoName, number: pullRequestNumberSchema }),
|
|
129
|
-
'boxxy.proposal.recorded': frictionSchema,
|
|
130
|
-
'boxxy.runner.paused': z.object({ runner: brandSchemas.runnerId }),
|
|
131
|
-
'boxxy.runner.resumed': z.object({ runner: brandSchemas.runnerId }),
|
|
132
|
-
};
|
package/src/find-slot-take.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import invariant from 'tiny-invariant';
|
|
2
|
-
import type { RowWrite } from './types/ports.ts';
|
|
3
|
-
|
|
4
|
-
export type SlotTake = Extract<RowWrite, { op: 'take-slot' }>;
|
|
5
|
-
|
|
6
|
-
export function findSlotTake(writes: readonly RowWrite[]): SlotTake | null {
|
|
7
|
-
const takes = writes.filter((write): write is SlotTake => write.op === 'take-slot');
|
|
8
|
-
|
|
9
|
-
invariant(takes.length <= 1, 'a change takes one slot at most');
|
|
10
|
-
|
|
11
|
-
return takes.at(0) ?? null;
|
|
12
|
-
}
|
package/src/friction-schema.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import type { Friction } from './types/facts.ts';
|
|
3
|
-
|
|
4
|
-
export const frictionSchema: z.ZodType<Friction> = z.object({
|
|
5
|
-
target: z.object({
|
|
6
|
-
kind: z.enum(['skill', 'rule', 'lint', 'agents-md', 'tool']),
|
|
7
|
-
name: z.string().min(1),
|
|
8
|
-
}),
|
|
9
|
-
change: z.string().min(1),
|
|
10
|
-
});
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { actorRefSchema } from './actor-ref-schema.ts';
|
|
3
|
-
import { brandSchemas } from './brand-schemas.ts';
|
|
4
|
-
import type { OutboxFact } from './types/facts.ts';
|
|
5
|
-
|
|
6
|
-
const idSchema = z.string();
|
|
7
|
-
|
|
8
|
-
const entityRefSchema = z.union([
|
|
9
|
-
z.templateLiteral(['boxxy:item:', idSchema]),
|
|
10
|
-
z.templateLiteral(['boxxy:link:', idSchema, ':', idSchema, ':', idSchema]),
|
|
11
|
-
z.templateLiteral(['boxxy:attempt:', idSchema]),
|
|
12
|
-
z.templateLiteral(['boxxy:decision:', idSchema]),
|
|
13
|
-
z.templateLiteral(['boxxy:runner:', idSchema]),
|
|
14
|
-
]);
|
|
15
|
-
|
|
16
|
-
export const outboxFactSchema: z.ZodType<OutboxFact> = z.object({
|
|
17
|
-
seq: z.number().int().positive(),
|
|
18
|
-
factId: brandSchemas.factId,
|
|
19
|
-
type: z.string().min(1),
|
|
20
|
-
entity: entityRefSchema,
|
|
21
|
-
actor: actorRefSchema,
|
|
22
|
-
at: brandSchemas.instant,
|
|
23
|
-
payload: z.json(),
|
|
24
|
-
sentAt: brandSchemas.instant.nullable(),
|
|
25
|
-
});
|
package/src/row-schemas.ts
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { contentHashSchema } from '@boxxy/content-hash';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
import { actorRefSchema } from './actor-ref-schema.ts';
|
|
4
|
-
import { brandSchemas } from './brand-schemas.ts';
|
|
5
|
-
import { buildCloseOutSchema } from './build-close-out-schema.ts';
|
|
6
|
-
import { factSchemas } from './fact-schemas.ts';
|
|
7
|
-
import type { TableName, Tables } from './types/ports.ts';
|
|
8
|
-
|
|
9
|
-
const countSchema = z.number().int().nonnegative();
|
|
10
|
-
|
|
11
|
-
export const rowSchemas: { readonly [T in TableName]: z.ZodType<Tables[T]> } = {
|
|
12
|
-
items: factSchemas['boxxy.item.filed'],
|
|
13
|
-
links: z.object({
|
|
14
|
-
source: brandSchemas.itemId,
|
|
15
|
-
target: brandSchemas.itemId,
|
|
16
|
-
type: brandSchemas.linkTypeName,
|
|
17
|
-
addedBy: actorRefSchema,
|
|
18
|
-
addedAt: brandSchemas.instant,
|
|
19
|
-
removedAt: brandSchemas.instant.nullable(),
|
|
20
|
-
}),
|
|
21
|
-
levers: factSchemas['boxxy.lever.recorded'],
|
|
22
|
-
attempts: z.object({
|
|
23
|
-
id: brandSchemas.attemptId,
|
|
24
|
-
item: brandSchemas.itemId,
|
|
25
|
-
phase: brandSchemas.phaseName,
|
|
26
|
-
number: z.number().int().positive(),
|
|
27
|
-
runner: brandSchemas.runnerId,
|
|
28
|
-
recipeHash: brandSchemas.recipeHash,
|
|
29
|
-
rulesVersion: brandSchemas.rulesVersion,
|
|
30
|
-
pool: brandSchemas.poolName,
|
|
31
|
-
slot: countSchema,
|
|
32
|
-
slotGen: countSchema,
|
|
33
|
-
leaseGen: countSchema,
|
|
34
|
-
spawnRequest: z.json(),
|
|
35
|
-
spawnRequestHash: contentHashSchema,
|
|
36
|
-
state: z.enum(['starting', 'running', 'reconciling', 'succeeded', 'failed']),
|
|
37
|
-
failure: z.string().nullable(),
|
|
38
|
-
atcSession: brandSchemas.atcSessionId.nullable(),
|
|
39
|
-
closeOut: buildCloseOutSchema.nullable(),
|
|
40
|
-
claimedAt: brandSchemas.instant,
|
|
41
|
-
startedAt: brandSchemas.instant.nullable(),
|
|
42
|
-
endedAt: brandSchemas.instant.nullable(),
|
|
43
|
-
}),
|
|
44
|
-
attempt_sessions: z.object({
|
|
45
|
-
attempt: brandSchemas.attemptId,
|
|
46
|
-
agentSession: brandSchemas.agentSessionId,
|
|
47
|
-
atcSession: brandSchemas.atcSessionId,
|
|
48
|
-
seenAt: brandSchemas.instant,
|
|
49
|
-
}),
|
|
50
|
-
leases: z.object({
|
|
51
|
-
item: brandSchemas.itemId,
|
|
52
|
-
phase: brandSchemas.phaseName,
|
|
53
|
-
attempt: brandSchemas.attemptId,
|
|
54
|
-
gen: countSchema,
|
|
55
|
-
takenAt: brandSchemas.instant,
|
|
56
|
-
releasedAt: brandSchemas.instant.nullable(),
|
|
57
|
-
}),
|
|
58
|
-
pool_slots: z.object({
|
|
59
|
-
pool: brandSchemas.poolName,
|
|
60
|
-
slot: countSchema,
|
|
61
|
-
holder: brandSchemas.attemptId.nullable(),
|
|
62
|
-
gen: countSchema,
|
|
63
|
-
retired: z.boolean(),
|
|
64
|
-
}),
|
|
65
|
-
decisions: factSchemas['boxxy.decision.recorded'],
|
|
66
|
-
evidence: z.object({
|
|
67
|
-
factId: brandSchemas.factId,
|
|
68
|
-
attempt: brandSchemas.attemptId,
|
|
69
|
-
kind: z.enum(['pr', 'commit', 'test', 'ci-run', 'live-check']),
|
|
70
|
-
ref: z.string().min(1),
|
|
71
|
-
observed: z.string().nullable(),
|
|
72
|
-
source: z.enum(['hook', 'trailer', 'agent', 'watch']),
|
|
73
|
-
at: brandSchemas.instant,
|
|
74
|
-
}),
|
|
75
|
-
pull_requests: z.object({
|
|
76
|
-
repo: brandSchemas.repoName,
|
|
77
|
-
number: z.number().int().positive(),
|
|
78
|
-
attempt: brandSchemas.attemptId,
|
|
79
|
-
state: z.enum(['open', 'closed', 'merged']),
|
|
80
|
-
mergedAt: brandSchemas.instant.nullable(),
|
|
81
|
-
mergeCommit: brandSchemas.commitSha.nullable(),
|
|
82
|
-
checkedAt: brandSchemas.instant,
|
|
83
|
-
}),
|
|
84
|
-
runners: z.object({
|
|
85
|
-
id: brandSchemas.runnerId,
|
|
86
|
-
heartbeatAt: brandSchemas.instant,
|
|
87
|
-
paused: z.boolean(),
|
|
88
|
-
}),
|
|
89
|
-
};
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { ItemRows } from '../types/core.ts';
|
|
2
|
-
|
|
3
|
-
export function buildMockItemRows(overrides: Partial<ItemRows> = {}): ItemRows {
|
|
4
|
-
return {
|
|
5
|
-
links: [],
|
|
6
|
-
blockerStates: new Map(),
|
|
7
|
-
levers: [],
|
|
8
|
-
attempts: [],
|
|
9
|
-
liveLease: null,
|
|
10
|
-
pullRequests: [],
|
|
11
|
-
maxAttempts: 2,
|
|
12
|
-
...overrides,
|
|
13
|
-
};
|
|
14
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { ItemView } from '../types/core.ts';
|
|
2
|
-
import { buildMockItemRow } from './build-mock-item-row.ts';
|
|
3
|
-
|
|
4
|
-
export function buildMockItemView(overrides: Partial<ItemView> = {}): ItemView {
|
|
5
|
-
const { derived, ...row } = overrides;
|
|
6
|
-
|
|
7
|
-
return { ...buildMockItemRow(row), derived: derived ?? { state: 'ready' } };
|
|
8
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { faker } from '@faker-js/faker';
|
|
2
|
-
import { brandSchemas } from '../brand-schemas.ts';
|
|
3
|
-
import type { PullRequestRow } from '../types/core.ts';
|
|
4
|
-
|
|
5
|
-
export function buildMockPullRequestRow(overrides: Partial<PullRequestRow> = {}): PullRequestRow {
|
|
6
|
-
return {
|
|
7
|
-
repo: brandSchemas.repoName.parse(`${faker.string.alpha(8)}/${faker.string.alpha(8)}`),
|
|
8
|
-
number: faker.number.int({ min: 1, max: 10_000 }),
|
|
9
|
-
attempt: brandSchemas.attemptId.parse(faker.string.uuid({ version: 7 })),
|
|
10
|
-
state: 'open',
|
|
11
|
-
mergedAt: null,
|
|
12
|
-
mergeCommit: null,
|
|
13
|
-
checkedAt: brandSchemas.instant.parse(faker.number.int({ max: 1_800_000_000_000 })),
|
|
14
|
-
...overrides,
|
|
15
|
-
};
|
|
16
|
-
}
|
package/src/types/dispatch.ts
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import type { ContentHash } from '@boxxy/content-hash';
|
|
2
|
-
import type {
|
|
3
|
-
AttemptId,
|
|
4
|
-
AttemptRow,
|
|
5
|
-
CriterionId,
|
|
6
|
-
EvidenceRow,
|
|
7
|
-
FactId,
|
|
8
|
-
ForcedFailure,
|
|
9
|
-
Instant,
|
|
10
|
-
ItemView,
|
|
11
|
-
KnownFailure,
|
|
12
|
-
LiveAttemptState,
|
|
13
|
-
Minutes,
|
|
14
|
-
RecipeName,
|
|
15
|
-
RepoName,
|
|
16
|
-
} from './core.ts';
|
|
17
|
-
import type { Friction, OpenItem } from './facts.ts';
|
|
18
|
-
import type { SessionReading, SpawnRequest } from './ports.ts';
|
|
19
|
-
|
|
20
|
-
export interface SpawnContext {
|
|
21
|
-
readonly repoPaths: ReadonlyMap<RepoName, string>;
|
|
22
|
-
readonly pluginFolder: { readonly path: string; readonly hash: ContentHash };
|
|
23
|
-
readonly promptTemplates: ReadonlyMap<RecipeName, string>;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface Claim {
|
|
27
|
-
readonly attempt: AttemptRow;
|
|
28
|
-
readonly spawn: SpawnRequest;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export type ReconcileAction =
|
|
32
|
-
| {
|
|
33
|
-
readonly kind: 'move-to-running';
|
|
34
|
-
readonly fact: 'boxxy.attempt.started' | 'boxxy.attempt.reconciled';
|
|
35
|
-
}
|
|
36
|
-
| { readonly kind: 'bind-session' }
|
|
37
|
-
| { readonly kind: 'settle' }
|
|
38
|
-
| { readonly kind: 'fail'; readonly failure: Extract<KnownFailure, 'session-lost'> }
|
|
39
|
-
| {
|
|
40
|
-
readonly kind: 'respawn';
|
|
41
|
-
readonly giveUpAfter: Minutes;
|
|
42
|
-
readonly then: Extract<KnownFailure, 'spawn-lost'>;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
export type ReconcileTable = Readonly<
|
|
46
|
-
Record<SessionReading['kind'], Readonly<Record<LiveAttemptState, ReconcileAction>>>
|
|
47
|
-
>;
|
|
48
|
-
|
|
49
|
-
export interface Settlement {
|
|
50
|
-
readonly state: 'succeeded' | 'failed';
|
|
51
|
-
readonly failure: string | null;
|
|
52
|
-
readonly openItems: readonly OpenItem[];
|
|
53
|
-
readonly criteria: readonly {
|
|
54
|
-
readonly criterion: CriterionId;
|
|
55
|
-
readonly evidence: readonly FactId[];
|
|
56
|
-
}[];
|
|
57
|
-
readonly friction: readonly Friction[];
|
|
58
|
-
readonly frictionDropped: number;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export interface SettleRule<Out = unknown> {
|
|
62
|
-
settle: (input: SettleInput<Out>) => Settlement;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export interface SettleInput<Out> {
|
|
66
|
-
readonly attempt: AttemptRow;
|
|
67
|
-
readonly item: ItemView;
|
|
68
|
-
readonly closeOut: CloseOutParse<Out> | null;
|
|
69
|
-
|
|
70
|
-
// a `forced` reason wins over the close-out's state
|
|
71
|
-
readonly forced: ForcedFailure | null;
|
|
72
|
-
readonly now: Instant;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export interface CloseOutContext {
|
|
76
|
-
readonly item: ItemView;
|
|
77
|
-
readonly attempt: AttemptId;
|
|
78
|
-
|
|
79
|
-
// the attempt's own evidence rows
|
|
80
|
-
readonly evidence: readonly EvidenceRow[];
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export type CloseOutProblem =
|
|
84
|
-
| { readonly kind: 'schema'; readonly path: string; readonly message: string }
|
|
85
|
-
| { readonly kind: 'unknown-criterion'; readonly criterion: CriterionId }
|
|
86
|
-
| { readonly kind: 'foreign-evidence'; readonly evidence: FactId }
|
|
87
|
-
| { readonly kind: 'built-without-evidence'; readonly criteria: readonly CriterionId[] };
|
|
88
|
-
|
|
89
|
-
export type CloseOutParse<Out> =
|
|
90
|
-
| { readonly kind: 'valid'; readonly closeOut: Out }
|
|
91
|
-
| { readonly kind: 'invalid'; readonly problems: readonly CloseOutProblem[] };
|
|
92
|
-
|
|
93
|
-
export interface CloseOutParser<Out> {
|
|
94
|
-
parse: (raw: unknown, ctx: CloseOutContext) => CloseOutParse<Out>;
|
|
95
|
-
}
|