@boxxy/model 0.1.2 → 0.1.3
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
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import type { ContentHash, JsonValue } from '@boxxy/content-hash';
|
|
2
|
+
import type { CloseOut, Effect, Friction } from '../closeouts/types.ts';
|
|
3
|
+
import type { SeatRef } from '../planning/types.ts';
|
|
4
|
+
import type { WakeSource } from '../ports/types.ts';
|
|
5
|
+
import type {
|
|
6
|
+
ActorRef,
|
|
7
|
+
AgentSessionId,
|
|
8
|
+
AtcSessionId,
|
|
9
|
+
AttemptId,
|
|
10
|
+
CallerIdentity,
|
|
11
|
+
ClosingCause,
|
|
12
|
+
CommitSha,
|
|
13
|
+
Criterion,
|
|
14
|
+
CriterionId,
|
|
15
|
+
DecisionRow,
|
|
16
|
+
DesignMode,
|
|
17
|
+
EvidenceKind,
|
|
18
|
+
FactId,
|
|
19
|
+
FieldValues,
|
|
20
|
+
Instant,
|
|
21
|
+
ItemId,
|
|
22
|
+
ItemKindName,
|
|
23
|
+
ItemRow,
|
|
24
|
+
LeverRow,
|
|
25
|
+
Minutes,
|
|
26
|
+
PhaseName,
|
|
27
|
+
PoolName,
|
|
28
|
+
Product,
|
|
29
|
+
RecipeHash,
|
|
30
|
+
RelationTypeName,
|
|
31
|
+
RepoName,
|
|
32
|
+
RulesVersion,
|
|
33
|
+
SessionMode,
|
|
34
|
+
} from '../types.ts';
|
|
35
|
+
|
|
36
|
+
// Every fact on the stream names an item; a fact about an attempt names the attempt in its
|
|
37
|
+
// payload. The consumer rebuilds an item from the one scope of the item.
|
|
38
|
+
export type EntityRef = `boxxy:item:${string}`;
|
|
39
|
+
|
|
40
|
+
export interface FactEnvelope<M extends object, T extends keyof M & string = keyof M & string> {
|
|
41
|
+
readonly id: FactId;
|
|
42
|
+
readonly type: T;
|
|
43
|
+
|
|
44
|
+
// oxlint-disable-next-line id-length -- pepys's fact envelope names this field
|
|
45
|
+
readonly v: 1;
|
|
46
|
+
readonly api: 'boxxy/1';
|
|
47
|
+
readonly entity: EntityRef;
|
|
48
|
+
readonly actor: ActorRef;
|
|
49
|
+
readonly at: Instant;
|
|
50
|
+
readonly payload: M[T] & { readonly storeVersion: number };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface NewFact<T extends FactType> {
|
|
54
|
+
readonly id: FactId;
|
|
55
|
+
readonly type: T;
|
|
56
|
+
readonly entity: EntityRef;
|
|
57
|
+
readonly actor: ActorRef;
|
|
58
|
+
readonly payload: WorkFacts[T];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export type AnyNewFact = { [T in FactType]: NewFact<T> }[FactType];
|
|
62
|
+
|
|
63
|
+
export interface OutboxFact {
|
|
64
|
+
readonly seq: number;
|
|
65
|
+
readonly factId: FactId;
|
|
66
|
+
readonly type: FactType;
|
|
67
|
+
readonly entity: EntityRef;
|
|
68
|
+
readonly actor: ActorRef;
|
|
69
|
+
readonly at: Instant;
|
|
70
|
+
readonly payload: JsonValue;
|
|
71
|
+
readonly sentAt: Instant | null;
|
|
72
|
+
|
|
73
|
+
// when the sender gave the row up, and why: `too-large`, `unknown-type` or the sink's refusal
|
|
74
|
+
readonly parkedAt: Instant | null;
|
|
75
|
+
readonly parkedReason: string | null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export type FactType = keyof WorkFacts;
|
|
79
|
+
|
|
80
|
+
export interface RelationPayload {
|
|
81
|
+
readonly source: ItemId;
|
|
82
|
+
readonly target: ItemId;
|
|
83
|
+
readonly type: RelationTypeName;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
interface OfAttempt {
|
|
87
|
+
readonly attempt: AttemptId;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// The fact catalog of the stream `facts.boxxy.work`. A payload holds no `storeVersion`: the sink
|
|
91
|
+
// adds it to the wire form. Instants in a payload are epoch milliseconds.
|
|
92
|
+
export interface WorkFacts {
|
|
93
|
+
// the kept session is state between two attempts, and no fact carries it
|
|
94
|
+
'boxxy.item.filed': Omit<ItemRow, 'keptSession'>;
|
|
95
|
+
'boxxy.item.noted': { readonly seq: number; readonly text: string };
|
|
96
|
+
'boxxy.item.edited': {
|
|
97
|
+
readonly title?: string;
|
|
98
|
+
readonly outcome?: string;
|
|
99
|
+
readonly acceptance?: readonly Criterion[];
|
|
100
|
+
readonly kind?: ItemKindName;
|
|
101
|
+
readonly fields?: { readonly designMode?: DesignMode };
|
|
102
|
+
|
|
103
|
+
// the whole new list
|
|
104
|
+
readonly labels?: readonly string[];
|
|
105
|
+
|
|
106
|
+
// the attempt whose settle made the edit
|
|
107
|
+
readonly byAttempt: AttemptId | null;
|
|
108
|
+
};
|
|
109
|
+
'boxxy.item.closed': {
|
|
110
|
+
readonly reason: string;
|
|
111
|
+
readonly byAttempt: AttemptId | null;
|
|
112
|
+
readonly ended: readonly {
|
|
113
|
+
readonly attempt: AttemptId;
|
|
114
|
+
readonly how: 'settled' | 'closing';
|
|
115
|
+
}[];
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// the entity is the source item
|
|
119
|
+
'boxxy.relation.added': RelationPayload;
|
|
120
|
+
'boxxy.relation.removed': RelationPayload;
|
|
121
|
+
'boxxy.lever.recorded': LeverRow;
|
|
122
|
+
'boxxy.attempt.claimed': OfAttempt & {
|
|
123
|
+
readonly phase: PhaseName;
|
|
124
|
+
readonly number: number;
|
|
125
|
+
readonly round: number;
|
|
126
|
+
readonly mode: SessionMode;
|
|
127
|
+
readonly pool: PoolName;
|
|
128
|
+
readonly fields: FieldValues;
|
|
129
|
+
readonly seats: readonly SeatRef[];
|
|
130
|
+
readonly recipeHash: RecipeHash;
|
|
131
|
+
|
|
132
|
+
// the skills pin of the rules at the claim
|
|
133
|
+
readonly skillsRef: CommitSha | null;
|
|
134
|
+
readonly rulesVersion: RulesVersion;
|
|
135
|
+
};
|
|
136
|
+
'boxxy.decision.recorded': DecisionRow;
|
|
137
|
+
'boxxy.attempt.started': OfAttempt & {
|
|
138
|
+
readonly atcSession: AtcSessionId;
|
|
139
|
+
readonly resumeFallback: boolean;
|
|
140
|
+
readonly caller: CallerIdentity | null;
|
|
141
|
+
};
|
|
142
|
+
'boxxy.attempt.spawn_unanswered': OfAttempt & { readonly reason: string };
|
|
143
|
+
'boxxy.attempt.reconciled': OfAttempt & {
|
|
144
|
+
readonly atcSession: AtcSessionId;
|
|
145
|
+
readonly caller: CallerIdentity | null;
|
|
146
|
+
};
|
|
147
|
+
'boxxy.attempt.session_bound': OfAttempt & {
|
|
148
|
+
readonly atcSession: AtcSessionId;
|
|
149
|
+
readonly agentSession: AgentSessionId;
|
|
150
|
+
readonly product: Product;
|
|
151
|
+
readonly source: 'worker' | 'hook';
|
|
152
|
+
readonly seenAt: Instant;
|
|
153
|
+
};
|
|
154
|
+
'boxxy.attempt.slept': OfAttempt & { readonly idleSince: Instant; readonly asked: boolean };
|
|
155
|
+
'boxxy.attempt.wake_requested': OfAttempt & { readonly by: WakeSource };
|
|
156
|
+
'boxxy.attempt.woken': OfAttempt & {
|
|
157
|
+
readonly holdGen: number;
|
|
158
|
+
readonly seats: readonly SeatRef[];
|
|
159
|
+
readonly overCap: boolean;
|
|
160
|
+
};
|
|
161
|
+
'boxxy.attempt.resumed': OfAttempt & {
|
|
162
|
+
readonly atcSession: AtcSessionId;
|
|
163
|
+
readonly caller: CallerIdentity | null;
|
|
164
|
+
};
|
|
165
|
+
'boxxy.attempt.closed_out': OfAttempt & {
|
|
166
|
+
readonly phase: PhaseName;
|
|
167
|
+
readonly closeOut: CloseOut;
|
|
168
|
+
readonly hash: ContentHash;
|
|
169
|
+
};
|
|
170
|
+
'boxxy.attempt.timed_out': OfAttempt & {
|
|
171
|
+
readonly phase: PhaseName;
|
|
172
|
+
readonly afterMinutes: Minutes;
|
|
173
|
+
};
|
|
174
|
+
'boxxy.attempt.turn_ended': OfAttempt & { readonly phase: PhaseName };
|
|
175
|
+
'boxxy.attempt.settled': OfAttempt & {
|
|
176
|
+
readonly phase: PhaseName;
|
|
177
|
+
readonly round: number;
|
|
178
|
+
readonly state: 'succeeded' | 'failed';
|
|
179
|
+
readonly failure: string | null;
|
|
180
|
+
|
|
181
|
+
// a name the phase kind lists, or an engine outcome
|
|
182
|
+
readonly outcome: string;
|
|
183
|
+
readonly returnedOutcome: string | null;
|
|
184
|
+
|
|
185
|
+
// null: the session was already gone
|
|
186
|
+
readonly closing: ClosingCause | null;
|
|
187
|
+
readonly asleep: boolean;
|
|
188
|
+
|
|
189
|
+
// false: settled by the give-up rule
|
|
190
|
+
readonly sessionStopped: boolean;
|
|
191
|
+
readonly endedAt: Instant;
|
|
192
|
+
readonly criteria: readonly {
|
|
193
|
+
readonly criterion: CriterionId;
|
|
194
|
+
readonly evidence: readonly FactId[];
|
|
195
|
+
}[];
|
|
196
|
+
readonly matched: readonly ItemId[];
|
|
197
|
+
readonly frictionDropped: number;
|
|
198
|
+
readonly skippedEffects: readonly {
|
|
199
|
+
readonly effect: Effect['kind'];
|
|
200
|
+
readonly reason: string;
|
|
201
|
+
}[];
|
|
202
|
+
};
|
|
203
|
+
'boxxy.proposal.recorded': OfAttempt & Friction;
|
|
204
|
+
'boxxy.evidence.recorded': OfAttempt & {
|
|
205
|
+
readonly kind: EvidenceKind;
|
|
206
|
+
readonly ref: string;
|
|
207
|
+
readonly observed: string | null;
|
|
208
|
+
};
|
|
209
|
+
'boxxy.pull_request.linked': OfAttempt & {
|
|
210
|
+
readonly repo: RepoName;
|
|
211
|
+
readonly number: number;
|
|
212
|
+
readonly url: string;
|
|
213
|
+
|
|
214
|
+
// the decimal text of GitHub's own ID of the pull request
|
|
215
|
+
readonly pullRequestId: string;
|
|
216
|
+
readonly source: 'hook' | 'watch';
|
|
217
|
+
};
|
|
218
|
+
'boxxy.commit.linked': OfAttempt & {
|
|
219
|
+
readonly repo: RepoName;
|
|
220
|
+
readonly sha: CommitSha;
|
|
221
|
+
readonly pullRequestNumber: number;
|
|
222
|
+
};
|
|
223
|
+
'boxxy.pull_request.merged': OfAttempt & {
|
|
224
|
+
readonly repo: RepoName;
|
|
225
|
+
readonly number: number;
|
|
226
|
+
readonly pullRequestId: string;
|
|
227
|
+
readonly mergedAt: Instant;
|
|
228
|
+
readonly mergeCommit: CommitSha;
|
|
229
|
+
};
|
|
230
|
+
'boxxy.pull_request.closed': OfAttempt & {
|
|
231
|
+
readonly repo: RepoName;
|
|
232
|
+
readonly number: number;
|
|
233
|
+
readonly pullRequestId: string;
|
|
234
|
+
};
|
|
235
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { contentHashSchema } from '@boxxy/content-hash';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { closeOutSchema } from '../closeouts/close-out-schema.ts';
|
|
4
|
+
import { frictionSchema } from '../closeouts/friction-schema.ts';
|
|
5
|
+
import { brandSchemas } from '../rows/brand-schemas.ts';
|
|
6
|
+
import { callerIdentitySchema } from '../rows/caller-identity-schema.ts';
|
|
7
|
+
import { criterionSchema } from '../rows/criterion-schema.ts';
|
|
8
|
+
import { decisionRowSchema } from '../rows/decision-row-schema.ts';
|
|
9
|
+
import { itemRowSchema } from '../rows/item-row-schema.ts';
|
|
10
|
+
import { leverRowSchema } from '../rows/lever-row-schema.ts';
|
|
11
|
+
import type { FactType, WorkFacts } from './types.ts';
|
|
12
|
+
|
|
13
|
+
const countSchema = z.number().int().nonnegative();
|
|
14
|
+
const roundSchema = z.number().int().positive();
|
|
15
|
+
const pullRequestNumberSchema = z.number().int().positive();
|
|
16
|
+
const pullRequestIdSchema = z.string().regex(/^[1-9]\d*$/u);
|
|
17
|
+
const ofAttempt = { attempt: brandSchemas.attemptId };
|
|
18
|
+
const seatsSchema = z.array(z.object({ limit: brandSchemas.limitName }));
|
|
19
|
+
const designModeSchema = z.enum(['agent', 'attended']);
|
|
20
|
+
const editedFieldsSchema = z.object({ designMode: designModeSchema.exactOptional() });
|
|
21
|
+
const fieldValuesSchema = z.record(z.string(), z.array(z.string()));
|
|
22
|
+
|
|
23
|
+
const relationSchema = z.object({
|
|
24
|
+
source: brandSchemas.itemId,
|
|
25
|
+
target: brandSchemas.itemId,
|
|
26
|
+
type: brandSchemas.relationTypeName,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const endedAttemptSchema = z.object({
|
|
30
|
+
attempt: brandSchemas.attemptId,
|
|
31
|
+
how: z.enum(['settled', 'closing']),
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const closingCauseSchema = z.enum([
|
|
35
|
+
'closed-out',
|
|
36
|
+
'timed-out',
|
|
37
|
+
'item-closed',
|
|
38
|
+
'stalled',
|
|
39
|
+
'skill-missing',
|
|
40
|
+
'turn-ended',
|
|
41
|
+
'usage-limit',
|
|
42
|
+
]);
|
|
43
|
+
|
|
44
|
+
const copiedEvidenceSchema = z.object({
|
|
45
|
+
criterion: brandSchemas.criterionId,
|
|
46
|
+
evidence: z.array(brandSchemas.factId),
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const effectKindSchema = z.enum([
|
|
50
|
+
'file-item',
|
|
51
|
+
'close-item',
|
|
52
|
+
'add-relation',
|
|
53
|
+
'set-kind',
|
|
54
|
+
'set-field',
|
|
55
|
+
'set-acceptance',
|
|
56
|
+
'record-proposal',
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
const skippedEffectSchema = z.object({ effect: effectKindSchema, reason: z.string().min(1) });
|
|
60
|
+
|
|
61
|
+
// One schema per fact type, with no `storeVersion`: the wire schema of the pepys package adds
|
|
62
|
+
// it. Each schema's output equals its payload type; the test of this file checks both ways.
|
|
63
|
+
export const workFactSchemas = {
|
|
64
|
+
'boxxy.item.filed': itemRowSchema.omit({ keptSession: true }),
|
|
65
|
+
'boxxy.item.noted': z.object({ seq: roundSchema, text: z.string().min(1) }),
|
|
66
|
+
'boxxy.item.edited': z.object({
|
|
67
|
+
title: z.string().min(1).exactOptional(),
|
|
68
|
+
outcome: z.string().min(1).exactOptional(),
|
|
69
|
+
acceptance: z.array(criterionSchema).exactOptional(),
|
|
70
|
+
kind: brandSchemas.itemKindName.exactOptional(),
|
|
71
|
+
fields: editedFieldsSchema.exactOptional(),
|
|
72
|
+
labels: z.array(z.string().min(1)).exactOptional(),
|
|
73
|
+
byAttempt: brandSchemas.attemptId.nullable(),
|
|
74
|
+
}),
|
|
75
|
+
'boxxy.item.closed': z.object({
|
|
76
|
+
reason: z.string().min(1),
|
|
77
|
+
byAttempt: brandSchemas.attemptId.nullable(),
|
|
78
|
+
ended: z.array(endedAttemptSchema),
|
|
79
|
+
}),
|
|
80
|
+
'boxxy.relation.added': relationSchema,
|
|
81
|
+
'boxxy.relation.removed': relationSchema,
|
|
82
|
+
'boxxy.lever.recorded': leverRowSchema,
|
|
83
|
+
'boxxy.attempt.claimed': z.object({
|
|
84
|
+
...ofAttempt,
|
|
85
|
+
phase: brandSchemas.phaseName,
|
|
86
|
+
number: roundSchema,
|
|
87
|
+
round: roundSchema,
|
|
88
|
+
mode: designModeSchema,
|
|
89
|
+
pool: brandSchemas.poolName,
|
|
90
|
+
fields: fieldValuesSchema,
|
|
91
|
+
seats: seatsSchema,
|
|
92
|
+
recipeHash: brandSchemas.recipeHash,
|
|
93
|
+
skillsRef: brandSchemas.commitSha.nullable(),
|
|
94
|
+
rulesVersion: brandSchemas.rulesVersion,
|
|
95
|
+
}),
|
|
96
|
+
'boxxy.decision.recorded': decisionRowSchema,
|
|
97
|
+
'boxxy.attempt.started': z.object({
|
|
98
|
+
...ofAttempt,
|
|
99
|
+
atcSession: brandSchemas.atcSessionId,
|
|
100
|
+
resumeFallback: z.boolean(),
|
|
101
|
+
caller: callerIdentitySchema.nullable(),
|
|
102
|
+
}),
|
|
103
|
+
'boxxy.attempt.spawn_unanswered': z.object({ ...ofAttempt, reason: z.string().min(1) }),
|
|
104
|
+
'boxxy.attempt.reconciled': z.object({
|
|
105
|
+
...ofAttempt,
|
|
106
|
+
atcSession: brandSchemas.atcSessionId,
|
|
107
|
+
caller: callerIdentitySchema.nullable(),
|
|
108
|
+
}),
|
|
109
|
+
'boxxy.attempt.session_bound': z.object({
|
|
110
|
+
...ofAttempt,
|
|
111
|
+
atcSession: brandSchemas.atcSessionId,
|
|
112
|
+
agentSession: brandSchemas.agentSessionId,
|
|
113
|
+
product: z.enum(['claude_code', 'codex']),
|
|
114
|
+
source: z.enum(['worker', 'hook']),
|
|
115
|
+
seenAt: brandSchemas.instant,
|
|
116
|
+
}),
|
|
117
|
+
'boxxy.attempt.slept': z.object({
|
|
118
|
+
...ofAttempt,
|
|
119
|
+
idleSince: brandSchemas.instant,
|
|
120
|
+
asked: z.boolean(),
|
|
121
|
+
}),
|
|
122
|
+
'boxxy.attempt.wake_requested': z.object({
|
|
123
|
+
...ofAttempt,
|
|
124
|
+
by: z.enum(['command', 'session-ran', 'host-slept-unasked']),
|
|
125
|
+
}),
|
|
126
|
+
'boxxy.attempt.woken': z.object({
|
|
127
|
+
...ofAttempt,
|
|
128
|
+
holdGen: roundSchema,
|
|
129
|
+
seats: seatsSchema,
|
|
130
|
+
overCap: z.boolean(),
|
|
131
|
+
}),
|
|
132
|
+
'boxxy.attempt.resumed': z.object({
|
|
133
|
+
...ofAttempt,
|
|
134
|
+
atcSession: brandSchemas.atcSessionId,
|
|
135
|
+
caller: callerIdentitySchema.nullable(),
|
|
136
|
+
}),
|
|
137
|
+
'boxxy.attempt.closed_out': z.object({
|
|
138
|
+
...ofAttempt,
|
|
139
|
+
phase: brandSchemas.phaseName,
|
|
140
|
+
closeOut: closeOutSchema,
|
|
141
|
+
hash: contentHashSchema,
|
|
142
|
+
}),
|
|
143
|
+
'boxxy.attempt.timed_out': z.object({
|
|
144
|
+
...ofAttempt,
|
|
145
|
+
phase: brandSchemas.phaseName,
|
|
146
|
+
afterMinutes: z.number().positive(),
|
|
147
|
+
}),
|
|
148
|
+
'boxxy.attempt.turn_ended': z.object({ ...ofAttempt, phase: brandSchemas.phaseName }),
|
|
149
|
+
'boxxy.attempt.settled': z.object({
|
|
150
|
+
...ofAttempt,
|
|
151
|
+
phase: brandSchemas.phaseName,
|
|
152
|
+
round: roundSchema,
|
|
153
|
+
state: z.enum(['succeeded', 'failed']),
|
|
154
|
+
failure: z.string().min(1).nullable(),
|
|
155
|
+
outcome: z.string().min(1),
|
|
156
|
+
returnedOutcome: z.string().min(1).nullable(),
|
|
157
|
+
closing: closingCauseSchema.nullable(),
|
|
158
|
+
asleep: z.boolean(),
|
|
159
|
+
sessionStopped: z.boolean(),
|
|
160
|
+
endedAt: brandSchemas.instant,
|
|
161
|
+
criteria: z.array(copiedEvidenceSchema),
|
|
162
|
+
matched: z.array(brandSchemas.itemId),
|
|
163
|
+
frictionDropped: countSchema,
|
|
164
|
+
skippedEffects: z.array(skippedEffectSchema),
|
|
165
|
+
}),
|
|
166
|
+
'boxxy.proposal.recorded': frictionSchema.extend(ofAttempt),
|
|
167
|
+
'boxxy.evidence.recorded': z.object({
|
|
168
|
+
...ofAttempt,
|
|
169
|
+
kind: z.enum(['pull_request', 'commit', 'test', 'ci-run', 'live-check']),
|
|
170
|
+
ref: z.string().min(1),
|
|
171
|
+
observed: z.string().nullable(),
|
|
172
|
+
}),
|
|
173
|
+
'boxxy.pull_request.linked': z.object({
|
|
174
|
+
...ofAttempt,
|
|
175
|
+
repo: brandSchemas.repoName,
|
|
176
|
+
number: pullRequestNumberSchema,
|
|
177
|
+
url: z.url(),
|
|
178
|
+
pullRequestId: pullRequestIdSchema,
|
|
179
|
+
source: z.enum(['hook', 'watch']),
|
|
180
|
+
}),
|
|
181
|
+
'boxxy.commit.linked': z.object({
|
|
182
|
+
...ofAttempt,
|
|
183
|
+
repo: brandSchemas.repoName,
|
|
184
|
+
sha: brandSchemas.commitSha,
|
|
185
|
+
pullRequestNumber: pullRequestNumberSchema,
|
|
186
|
+
}),
|
|
187
|
+
'boxxy.pull_request.merged': z.object({
|
|
188
|
+
...ofAttempt,
|
|
189
|
+
repo: brandSchemas.repoName,
|
|
190
|
+
number: pullRequestNumberSchema,
|
|
191
|
+
pullRequestId: pullRequestIdSchema,
|
|
192
|
+
mergedAt: brandSchemas.instant,
|
|
193
|
+
mergeCommit: brandSchemas.commitSha,
|
|
194
|
+
}),
|
|
195
|
+
'boxxy.pull_request.closed': z.object({
|
|
196
|
+
...ofAttempt,
|
|
197
|
+
repo: brandSchemas.repoName,
|
|
198
|
+
number: pullRequestNumberSchema,
|
|
199
|
+
pullRequestId: pullRequestIdSchema,
|
|
200
|
+
}),
|
|
201
|
+
} satisfies { readonly [T in FactType]: z.ZodType<WorkFacts[T]> };
|