@boxxy/model 0.1.1 → 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.
Files changed (222) hide show
  1. package/README.md +8 -6
  2. package/dist/closeouts/build-close-out-schema.d.ts +31 -0
  3. package/dist/closeouts/close-out-answer-schema.d.ts +3 -0
  4. package/dist/closeouts/close-out-schema.d.ts +3 -0
  5. package/dist/closeouts/design-close-out-schema.d.ts +30 -0
  6. package/dist/closeouts/friction-schema.d.ts +14 -0
  7. package/dist/closeouts/open-item-schema.d.ts +3 -0
  8. package/dist/closeouts/review-close-out-schema.d.ts +40 -0
  9. package/dist/closeouts/triage-close-out-schema.d.ts +40 -0
  10. package/dist/closeouts/types.d.ts +221 -0
  11. package/dist/dispatch/build-applied-change.d.ts +6 -0
  12. package/dist/dispatch/collect-seat-sync.d.ts +14 -0
  13. package/dist/dispatch/pick-seat-take.d.ts +10 -0
  14. package/dist/dispatch/types.d.ts +11 -0
  15. package/dist/facts/outbox-fact-schema.d.ts +3 -0
  16. package/dist/facts/parse-new-fact.d.ts +2 -0
  17. package/dist/facts/types.d.ts +191 -0
  18. package/dist/facts/work-fact-schemas.d.ts +293 -0
  19. package/dist/index.d.ts +64 -16
  20. package/dist/items/build-item-views.d.ts +4 -0
  21. package/dist/items/collect-retries.d.ts +3 -0
  22. package/dist/items/collect-settled.d.ts +3 -0
  23. package/dist/items/derive-item-state.d.ts +17 -0
  24. package/dist/{live-levers.d.ts → items/live-levers.d.ts} +1 -1
  25. package/dist/items/types.d.ts +12 -0
  26. package/dist/pipeline/advance.d.ts +10 -0
  27. package/dist/pipeline/constants.d.ts +2 -0
  28. package/dist/pipeline/count-trailing.d.ts +1 -0
  29. package/dist/pipeline/find-position.d.ts +9 -0
  30. package/dist/pipeline/find-step.d.ts +3 -0
  31. package/dist/pipeline/merge-by-time.d.ts +9 -0
  32. package/dist/pipeline/position-schema.d.ts +3 -0
  33. package/dist/pipeline/types.d.ts +28 -0
  34. package/dist/planning/define-admission.d.ts +3 -0
  35. package/dist/planning/define-gate.d.ts +3 -0
  36. package/dist/planning/define-signal.d.ts +3 -0
  37. package/dist/planning/is-filter-match.d.ts +3 -0
  38. package/dist/planning/limit-fill-schema.d.ts +3 -0
  39. package/dist/{signal-key.d.ts → planning/signal-key.d.ts} +1 -1
  40. package/dist/planning/types.d.ts +155 -0
  41. package/dist/ports/types.d.ts +289 -0
  42. package/dist/reports/constants.d.ts +3 -0
  43. package/dist/reports/cost-to-land-schema.d.ts +29 -0
  44. package/dist/reports/outbox-status.d.ts +16 -0
  45. package/dist/reports/stage-time-schema.d.ts +25 -0
  46. package/dist/reports/types.d.ts +5 -0
  47. package/dist/rows/actor-ref-schema.d.ts +2 -0
  48. package/dist/rows/attempt-row-schema.d.ts +3 -0
  49. package/dist/rows/attempt-session-row-schema.d.ts +3 -0
  50. package/dist/{brand-schemas.d.ts → rows/brand-schemas.d.ts} +5 -2
  51. package/dist/rows/caller-identity-schema.d.ts +3 -0
  52. package/dist/rows/criterion-schema.d.ts +3 -0
  53. package/dist/rows/decision-row-schema.d.ts +34 -0
  54. package/dist/rows/evidence-row-schema.d.ts +3 -0
  55. package/dist/rows/item-row-schema.d.ts +28 -0
  56. package/dist/rows/item-view-schema.d.ts +3 -0
  57. package/dist/rows/lease-row-schema.d.ts +3 -0
  58. package/dist/rows/lever-row-schema.d.ts +12 -0
  59. package/dist/rows/limit-schema.d.ts +3 -0
  60. package/dist/rows/limit-seat-row-schema.d.ts +3 -0
  61. package/dist/rows/note-row-schema.d.ts +3 -0
  62. package/dist/rows/notice-row-schema.d.ts +3 -0
  63. package/dist/rows/pull-request-row-schema.d.ts +3 -0
  64. package/dist/rows/relation-row-schema.d.ts +3 -0
  65. package/dist/rows/row-schemas.d.ts +5 -0
  66. package/dist/rows/runner-row-schema.d.ts +3 -0
  67. package/dist/rows/spawn-request-schema.d.ts +3 -0
  68. package/dist/rules/define-phase.d.ts +3 -0
  69. package/dist/rules/load-rejection-schema.d.ts +3 -0
  70. package/dist/rules/types.d.ts +244 -0
  71. package/dist/test-utils/build-mock-cost-to-land.d.ts +2 -0
  72. package/dist/test-utils/build-mock-evidence-row.d.ts +2 -0
  73. package/dist/test-utils/build-mock-fact-id.d.ts +2 -0
  74. package/dist/test-utils/build-mock-frame-item.d.ts +2 -0
  75. package/dist/test-utils/build-mock-frame.d.ts +2 -0
  76. package/dist/test-utils/build-mock-item-rules.d.ts +2 -0
  77. package/dist/test-utils/build-mock-lease-row.d.ts +1 -1
  78. package/dist/test-utils/build-mock-outbox-fact.d.ts +2 -0
  79. package/dist/test-utils/build-mock-phase-kind.d.ts +7 -0
  80. package/dist/test-utils/build-mock-pipeline.d.ts +7 -0
  81. package/dist/test-utils/build-mock-relation-row.d.ts +2 -0
  82. package/dist/test-utils/build-mock-settled.d.ts +9 -0
  83. package/dist/test-utils/build-mock-snapshot.d.ts +2 -0
  84. package/dist/test-utils/build-mock-v1-attempt-row.d.ts +2 -0
  85. package/dist/test-utils/build-mock-v1-item-row.d.ts +2 -0
  86. package/dist/test-utils/build-mock-v1-item-view.d.ts +2 -0
  87. package/dist/test-utils/build-mock-v1-lever-row.d.ts +2 -0
  88. package/dist/test-utils/build-mock-v1-pull-request-row.d.ts +2 -0
  89. package/dist/test-utils/build-mock-work-fact.d.ts +12 -0
  90. package/dist/test-utils/create-fake-notifier.d.ts +9 -0
  91. package/dist/test-utils/create-fake-pepys-reader.d.ts +13 -0
  92. package/dist/test-utils/fact-sink-contract.d.ts +14 -0
  93. package/dist/test-utils/pepys-reader-contract.d.ts +17 -0
  94. package/dist/{types/core.d.ts → types.d.ts} +94 -36
  95. package/dist/utils/format-key-path.d.ts +1 -0
  96. package/dist/utils/to-json-value.d.ts +2 -0
  97. package/package.json +14 -3
  98. package/src/{build-close-out-schema.ts → closeouts/build-close-out-schema.ts} +5 -10
  99. package/src/closeouts/close-out-answer-schema.ts +42 -0
  100. package/src/closeouts/close-out-schema.ts +13 -0
  101. package/src/closeouts/design-close-out-schema.ts +20 -0
  102. package/src/closeouts/friction-schema.ts +11 -0
  103. package/src/closeouts/open-item-schema.ts +8 -0
  104. package/src/closeouts/review-close-out-schema.ts +38 -0
  105. package/src/closeouts/triage-close-out-schema.ts +29 -0
  106. package/src/closeouts/types.ts +230 -0
  107. package/src/dispatch/build-applied-change.ts +57 -0
  108. package/src/dispatch/collect-seat-sync.ts +86 -0
  109. package/src/dispatch/pick-seat-take.ts +39 -0
  110. package/src/dispatch/types.ts +14 -0
  111. package/src/facts/outbox-fact-schema.ts +22 -0
  112. package/src/facts/parse-new-fact.ts +16 -0
  113. package/src/facts/types.ts +235 -0
  114. package/src/facts/work-fact-schemas.ts +201 -0
  115. package/src/index.ts +147 -41
  116. package/src/items/build-item-views.ts +146 -0
  117. package/src/items/collect-retries.ts +12 -0
  118. package/src/items/collect-settled.ts +20 -0
  119. package/src/items/derive-item-state.ts +95 -0
  120. package/src/{live-levers.ts → items/live-levers.ts} +1 -1
  121. package/src/items/types.ts +26 -0
  122. package/src/pipeline/advance.ts +78 -0
  123. package/src/pipeline/constants.ts +12 -0
  124. package/src/pipeline/count-trailing.ts +16 -0
  125. package/src/pipeline/find-position.ts +74 -0
  126. package/src/pipeline/find-step.ts +6 -0
  127. package/src/pipeline/merge-by-time.ts +33 -0
  128. package/src/pipeline/position-schema.ts +27 -0
  129. package/src/pipeline/types.ts +47 -0
  130. package/src/{define-admission.ts → planning/define-admission.ts} +2 -2
  131. package/src/{define-gate.ts → planning/define-gate.ts} +2 -2
  132. package/src/{define-signal.ts → planning/define-signal.ts} +2 -2
  133. package/src/planning/is-filter-match.ts +10 -0
  134. package/src/planning/limit-fill-schema.ts +12 -0
  135. package/src/{signal-key.ts → planning/signal-key.ts} +1 -1
  136. package/src/planning/types.ts +216 -0
  137. package/src/ports/types.ts +412 -0
  138. package/src/reports/constants.ts +6 -0
  139. package/src/reports/cost-to-land-schema.ts +47 -0
  140. package/src/reports/outbox-status.ts +22 -0
  141. package/src/reports/stage-time-schema.ts +21 -0
  142. package/src/reports/types.ts +7 -0
  143. package/src/rows/actor-ref-schema.ts +17 -0
  144. package/src/rows/attempt-row-schema.ts +69 -0
  145. package/src/rows/attempt-session-row-schema.ts +12 -0
  146. package/src/{brand-schemas.ts → rows/brand-schemas.ts} +5 -2
  147. package/src/rows/caller-identity-schema.ts +7 -0
  148. package/src/rows/criterion-schema.ts +9 -0
  149. package/src/rows/decision-row-schema.ts +34 -0
  150. package/src/rows/evidence-row-schema.ts +13 -0
  151. package/src/rows/item-row-schema.ts +32 -0
  152. package/src/rows/item-view-schema.ts +31 -0
  153. package/src/rows/lease-row-schema.ts +12 -0
  154. package/src/rows/lever-row-schema.ts +17 -0
  155. package/src/rows/limit-schema.ts +12 -0
  156. package/src/rows/limit-seat-row-schema.ts +12 -0
  157. package/src/rows/note-row-schema.ts +12 -0
  158. package/src/rows/notice-row-schema.ts +17 -0
  159. package/src/rows/pull-request-row-schema.ts +15 -0
  160. package/src/rows/relation-row-schema.ts +13 -0
  161. package/src/rows/row-schemas.ts +30 -0
  162. package/src/rows/runner-row-schema.ts +9 -0
  163. package/src/rows/spawn-request-schema.ts +15 -0
  164. package/src/rules/define-phase.ts +12 -0
  165. package/src/rules/load-rejection-schema.ts +51 -0
  166. package/src/rules/types.ts +291 -0
  167. package/src/test-utils/build-mock-cost-to-land.ts +31 -0
  168. package/src/test-utils/build-mock-evidence-row.ts +17 -0
  169. package/src/test-utils/build-mock-fact-id.ts +7 -0
  170. package/src/test-utils/build-mock-frame-item.ts +14 -0
  171. package/src/test-utils/build-mock-frame.ts +13 -0
  172. package/src/test-utils/build-mock-item-rules.ts +17 -0
  173. package/src/test-utils/build-mock-lease-row.ts +2 -2
  174. package/src/test-utils/build-mock-outbox-fact.ts +22 -0
  175. package/src/test-utils/build-mock-phase-kind.ts +29 -0
  176. package/src/test-utils/build-mock-pipeline.ts +52 -0
  177. package/src/test-utils/{build-mock-link-row.ts → build-mock-relation-row.ts} +4 -4
  178. package/src/test-utils/build-mock-settled.ts +18 -0
  179. package/src/test-utils/build-mock-snapshot.ts +13 -0
  180. package/src/test-utils/{build-mock-attempt-row.ts → build-mock-v1-attempt-row.ts} +28 -9
  181. package/src/test-utils/{build-mock-item-row.ts → build-mock-v1-item-row.ts} +7 -3
  182. package/src/test-utils/build-mock-v1-item-view.ts +29 -0
  183. package/src/test-utils/{build-mock-lever-row.ts → build-mock-v1-lever-row.ts} +5 -3
  184. package/src/test-utils/build-mock-v1-pull-request-row.ts +26 -0
  185. package/src/test-utils/build-mock-work-fact.ts +179 -0
  186. package/src/test-utils/create-fake-notifier.ts +54 -0
  187. package/src/test-utils/create-fake-pepys-reader.ts +73 -0
  188. package/src/test-utils/fact-sink-contract.ts +103 -0
  189. package/src/test-utils/pepys-reader-contract.ts +117 -0
  190. package/src/{types/core.ts → types.ts} +184 -48
  191. package/src/utils/format-key-path.ts +19 -0
  192. package/src/utils/to-json-value.ts +25 -0
  193. package/dist/build-close-out-schema.d.ts +0 -3
  194. package/dist/define-admission.d.ts +0 -3
  195. package/dist/define-gate.d.ts +0 -3
  196. package/dist/define-signal.d.ts +0 -3
  197. package/dist/derive-item-state.d.ts +0 -2
  198. package/dist/fact-schemas.d.ts +0 -5
  199. package/dist/friction-schema.d.ts +0 -3
  200. package/dist/test-utils/build-mock-attempt-row.d.ts +0 -2
  201. package/dist/test-utils/build-mock-item-row.d.ts +0 -2
  202. package/dist/test-utils/build-mock-item-rows.d.ts +0 -2
  203. package/dist/test-utils/build-mock-lever-row.d.ts +0 -2
  204. package/dist/test-utils/build-mock-link-row.d.ts +0 -2
  205. package/dist/test-utils/build-mock-pull-request-row.d.ts +0 -2
  206. package/dist/types/dispatch.d.ts +0 -82
  207. package/dist/types/facts.d.ts +0 -154
  208. package/dist/types/planning.d.ts +0 -94
  209. package/dist/types/ports.d.ts +0 -218
  210. package/dist/types/registries.d.ts +0 -150
  211. package/src/derive-item-state.ts +0 -76
  212. package/src/fact-schemas.ts +0 -138
  213. package/src/friction-schema.ts +0 -10
  214. package/src/test-utils/build-mock-item-rows.ts +0 -14
  215. package/src/test-utils/build-mock-pull-request-row.ts +0 -16
  216. package/src/types/dispatch.ts +0 -95
  217. package/src/types/facts.ts +0 -166
  218. package/src/types/planning.ts +0 -136
  219. package/src/types/ports.ts +0 -262
  220. package/src/types/registries.ts +0 -185
  221. /package/dist/test-utils/{seed-faker.d.ts → pin-faker-seed.d.ts} +0 -0
  222. /package/src/test-utils/{seed-faker.ts → pin-faker-seed.ts} +0 -0
@@ -1,7 +1,8 @@
1
1
  import type { ContentHash, JsonValue } from '@boxxy/content-hash';
2
2
  import type { z } from 'zod';
3
- import type { brandSchemas } from '../brand-schemas.ts';
4
- import type { BuildCloseOut } from './facts.ts';
3
+ import type { CloseOut } from './closeouts/types.ts';
4
+ import type { HoldReason, Position } from './pipeline/types.ts';
5
+ import type { brandSchemas } from './rows/brand-schemas.ts';
5
6
  type BrandOf<K extends keyof typeof brandSchemas> = z.output<(typeof brandSchemas)[K]>;
6
7
  export type Instant = BrandOf<'instant'>;
7
8
  export type Minutes = number;
@@ -20,10 +21,11 @@ export interface PullRequestRef {
20
21
  readonly number: number;
21
22
  }
22
23
  export type ItemKindName = BrandOf<'itemKindName'>;
23
- export type LinkTypeName = BrandOf<'linkTypeName'>;
24
+ export type RelationTypeName = BrandOf<'relationTypeName'>;
24
25
  export type PhaseName = BrandOf<'phaseName'>;
25
26
  export type PipelineName = BrandOf<'pipelineName'>;
26
27
  export type PoolName = BrandOf<'poolName'>;
28
+ export type LimitName = BrandOf<'limitName'>;
27
29
  export type RecipeName = BrandOf<'recipeName'>;
28
30
  export type WorkerKindName = BrandOf<'workerKindName'>;
29
31
  export type SourceName = BrandOf<'sourceName'>;
@@ -32,6 +34,7 @@ export type LeverKind = `${string}.${string}`;
32
34
  export type RecipeHash = BrandOf<'recipeHash'>;
33
35
  export type SnapshotHash = BrandOf<'snapshotHash'>;
34
36
  export type RulesVersion = BrandOf<'rulesVersion'>;
37
+ export type OutcomeName = BrandOf<'outcomeName'>;
35
38
  export interface ConceptPin {
36
39
  readonly ref: `${string}@${number}`;
37
40
  readonly sourceHash: ContentHash;
@@ -49,12 +52,22 @@ export type Actor = {
49
52
  readonly attempt: AttemptId;
50
53
  };
51
54
  export type ActorRef = 'boxxy:owner:local' | `boxxy:runner:${string}` | `boxxy:attempt:${string}` | `boxxy:hook:${string}`;
52
- export type EvidenceKind = 'pr' | 'commit' | 'test' | 'ci-run' | 'live-check';
55
+ export interface CallerIdentity {
56
+ readonly issuer: string;
57
+ readonly subject: string;
58
+ }
59
+ export type EvidenceKind = 'pull_request' | 'commit' | 'test' | 'ci-run' | 'live-check';
53
60
  export interface Criterion {
54
61
  readonly id: CriterionId;
55
62
  readonly text: string;
56
63
  readonly evidence: readonly FactId[];
57
64
  }
65
+ export type DesignMode = 'agent' | 'attended';
66
+ export type SessionMode = 'agent' | 'attended';
67
+ export type Product = 'claude_code' | 'codex';
68
+ export interface ItemFields {
69
+ readonly designMode?: DesignMode;
70
+ }
58
71
  export interface ItemRow {
59
72
  readonly id: ItemId;
60
73
  readonly kind: ItemKindName;
@@ -62,14 +75,31 @@ export interface ItemRow {
62
75
  readonly title: string;
63
76
  readonly outcome: string;
64
77
  readonly acceptance: readonly Criterion[];
78
+ readonly fields: ItemFields;
79
+ readonly labels: readonly string[];
65
80
  readonly foundInAttempt: AttemptId | null;
66
81
  readonly filedBy: ActorRef;
67
82
  readonly filedAt: Instant;
68
83
  readonly closedAt: Instant | null;
69
84
  readonly closeReason: string | null;
85
+ readonly keptSession: KeptSession | null;
86
+ }
87
+ export interface KeptSession {
88
+ readonly atcSession: AtcSessionId;
89
+ readonly target: string;
90
+ readonly attempt: AttemptId;
91
+ readonly keptAt: Instant;
92
+ readonly caller: CallerIdentity | null;
93
+ }
94
+ export interface NoteRow {
95
+ readonly item: ItemId;
96
+ readonly seq: number;
97
+ readonly text: string;
98
+ readonly by: ActorRef;
99
+ readonly at: Instant;
70
100
  }
71
101
  export type ItemState = 'idea' | 'ready' | 'running' | 'blocked' | 'waiting' | 'done' | 'archived';
72
- export type WaitingReason = 'PR open' | 'no PR linked' | 'attempts used up';
102
+ export type WaitingReason = 'pull request open' | 'no pull request linked' | 'pull request closed unmerged' | HoldReason;
73
103
  export type DerivedState = {
74
104
  readonly state: Exclude<ItemState, 'waiting'>;
75
105
  } | {
@@ -78,24 +108,12 @@ export type DerivedState = {
78
108
  };
79
109
  export interface ItemView extends ItemRow {
80
110
  readonly derived: DerivedState;
111
+ readonly position: Position;
81
112
  }
82
- export interface ItemRows {
83
- readonly links: readonly LinkRow[];
84
- readonly blockerStates: ReadonlyMap<ItemId, ItemState>;
85
- readonly levers: readonly LeverRow[];
86
- readonly attempts: readonly AttemptRow[];
87
- readonly liveLease: LeaseRow | null;
88
- readonly pullRequests: readonly PullRequestRow[];
89
- readonly maxAttempts: number;
90
- }
91
- export type MaxAttemptsByKind = ReadonlyMap<ItemKindName, ReadonlyMap<PhaseName, number>>;
92
- export interface ItemWithLevers extends ItemView {
93
- readonly levers: readonly LeverRow[];
94
- }
95
- export interface LinkRow {
113
+ export interface RelationRow {
96
114
  readonly source: ItemId;
97
115
  readonly target: ItemId;
98
- readonly type: LinkTypeName;
116
+ readonly type: RelationTypeName;
99
117
  readonly addedBy: ActorRef;
100
118
  readonly addedAt: Instant;
101
119
  readonly removedAt: Instant | null;
@@ -107,13 +125,17 @@ export interface LeverRow {
107
125
  readonly until: Instant | null;
108
126
  readonly expiresAt: Instant | null;
109
127
  readonly reason: string | null;
128
+ readonly phase: PhaseName | null;
110
129
  readonly actor: ActorRef;
111
130
  readonly at: Instant;
112
131
  }
113
- export type AttemptState = 'starting' | 'running' | 'reconciling' | 'succeeded' | 'failed';
114
- export type LiveAttemptState = Extract<AttemptState, 'starting' | 'running' | 'reconciling'>;
115
- export type KnownFailure = 'spawn-refused' | 'session-lost' | 'spawn-lost' | 'closeout-missing';
116
- export type ForcedFailure = Extract<KnownFailure, 'spawn-refused' | 'session-lost' | 'spawn-lost'>;
132
+ export type AttemptState = 'starting' | 'running' | 'reconciling' | 'sleeping' | 'waking' | 'closing' | 'succeeded' | 'failed';
133
+ export type LiveAttemptState = Exclude<AttemptState, 'succeeded' | 'failed'>;
134
+ export type ClosingCause = 'closed-out' | 'timed-out' | 'item-closed' | 'stalled' | 'skill-missing' | 'turn-ended' | 'usage-limit';
135
+ export type ForcedFailure = 'spawn-refused' | 'no-capacity' | 'spawn-lost' | 'session-lost' | 'resume-lost' | 'timed-out' | 'item-closed' | 'skill-missing' | 'stalled' | 'usage-limit';
136
+ export type KnownFailure = ForcedFailure | 'closeout-missing' | 'closeout-unsettleable';
137
+ export type EngineOutcome = 'lost' | 'unsettleable';
138
+ export type FieldValues = Readonly<Record<string, readonly string[]>>;
117
139
  export interface AttemptRow {
118
140
  readonly id: AttemptId;
119
141
  readonly item: ItemId;
@@ -123,23 +145,42 @@ export interface AttemptRow {
123
145
  readonly recipeHash: RecipeHash;
124
146
  readonly rulesVersion: RulesVersion;
125
147
  readonly pool: PoolName;
126
- readonly slot: number;
127
- readonly slotGen: number;
128
148
  readonly leaseGen: number;
129
149
  readonly spawnRequest: JsonValue;
130
150
  readonly spawnRequestHash: ContentHash;
131
151
  readonly state: AttemptState;
132
152
  readonly failure: string | null;
133
153
  readonly atcSession: AtcSessionId | null;
134
- readonly closeOut: BuildCloseOut | null;
154
+ readonly caller: CallerIdentity | null;
135
155
  readonly claimedAt: Instant;
136
156
  readonly startedAt: Instant | null;
137
157
  readonly endedAt: Instant | null;
158
+ readonly fields: FieldValues;
159
+ readonly mode: SessionMode;
160
+ readonly round: number;
161
+ readonly input: JsonValue;
162
+ readonly holdGen: number;
163
+ readonly closeOut: CloseOut | null;
164
+ readonly closeOutHash: ContentHash | null;
165
+ readonly closeOutFact: FactId | null;
166
+ readonly closing: ClosingCause | null;
167
+ readonly closingAt: Instant | null;
168
+ readonly suspendRequestedAt: Instant | null;
169
+ readonly sleptAt: Instant | null;
170
+ readonly wakeRequestedAt: Instant | null;
171
+ readonly wokenAt: Instant | null;
172
+ readonly outcome: OutcomeName | EngineOutcome | null;
173
+ readonly returnedOutcome: string | null;
174
+ readonly strayedAt: Instant | null;
175
+ readonly sessionStoppedAt: Instant | null;
176
+ readonly sessionForgottenAt: Instant | null;
138
177
  }
139
178
  export interface AttemptSessionRow {
140
179
  readonly attempt: AttemptId;
141
180
  readonly agentSession: AgentSessionId;
142
181
  readonly atcSession: AtcSessionId;
182
+ readonly product: Product;
183
+ readonly source: 'worker' | 'hook';
143
184
  readonly seenAt: Instant;
144
185
  }
145
186
  export interface LeaseRow {
@@ -150,32 +191,40 @@ export interface LeaseRow {
150
191
  readonly takenAt: Instant;
151
192
  readonly releasedAt: Instant | null;
152
193
  }
153
- export interface PoolSlotRow {
154
- readonly pool: PoolName;
155
- readonly slot: number;
156
- readonly holder: AttemptId | null;
157
- readonly gen: number;
158
- readonly retired: boolean;
194
+ export interface LimitSeatRow {
195
+ readonly limit: LimitName;
196
+ readonly attempt: AttemptId;
197
+ readonly holdGen: number;
198
+ readonly overCap: boolean;
199
+ readonly takenAt: Instant;
200
+ readonly releasedAt: Instant | null;
159
201
  }
160
202
  export interface ObservationBoundary {
161
203
  readonly storeVersion: number;
162
204
  readonly pepysOffsets: Readonly<Record<StreamName, number>>;
163
205
  }
206
+ export interface LimitCount {
207
+ readonly limit: LimitName;
208
+ readonly held: number;
209
+ readonly max: number;
210
+ }
164
211
  export interface DecisionRow {
165
212
  readonly id: DecisionId;
166
213
  readonly attempt: AttemptId;
167
214
  readonly item: ItemId;
215
+ readonly kind: 'start' | 'wake';
168
216
  readonly pool: PoolName;
169
217
  readonly rulesVersion: RulesVersion;
170
218
  readonly snapshotHash: SnapshotHash;
171
219
  readonly storeVersion: number;
172
220
  readonly pepysOffsets: ObservationBoundary['pepysOffsets'];
173
221
  readonly faults: readonly FaultRecord[];
222
+ readonly limits: readonly LimitCount[];
174
223
  readonly at: Instant;
175
224
  }
176
225
  export interface FaultRecord {
177
226
  readonly plugin: string;
178
- readonly kind: 'signal' | 'gate' | 'waiver' | 'admission' | 'propagation';
227
+ readonly kind: 'signal' | 'gate' | 'waiver' | 'admission' | 'propagation' | 'filter-field';
179
228
  readonly item: ItemId | null;
180
229
  readonly error: string;
181
230
  }
@@ -193,6 +242,8 @@ export interface PullRequestRow {
193
242
  readonly repo: RepoName;
194
243
  readonly number: number;
195
244
  readonly attempt: AttemptId;
245
+ readonly githubId: number;
246
+ readonly url: string;
196
247
  readonly state: 'open' | 'closed' | 'merged';
197
248
  readonly mergedAt: Instant | null;
198
249
  readonly mergeCommit: CommitSha | null;
@@ -203,6 +254,14 @@ export interface RunnerRow {
203
254
  readonly heartbeatAt: Instant;
204
255
  readonly paused: boolean;
205
256
  }
257
+ export interface NoticeRow {
258
+ readonly id: number;
259
+ readonly item: ItemId;
260
+ readonly reason: HoldReason;
261
+ readonly at: Instant;
262
+ readonly tries: number;
263
+ readonly sentAt: Instant | null;
264
+ }
206
265
  export type Effort = 'low' | 'medium' | 'high' | 'xhigh' | 'max';
207
266
  export interface Recipe {
208
267
  readonly agent: string;
@@ -210,15 +269,14 @@ export interface Recipe {
210
269
  readonly effort: Effort;
211
270
  readonly prompt: string;
212
271
  readonly source: SourceName;
272
+ readonly skills: readonly string[];
213
273
  }
214
274
  export interface RecipeMaterial {
215
275
  readonly name: RecipeName;
216
276
  readonly recipe: Recipe;
217
277
  readonly promptHash: ContentHash;
218
- readonly pluginFolderHash: ContentHash;
219
278
  readonly rulesVersion: RulesVersion;
220
279
  }
221
- export type LoadedRecipe = Omit<RecipeMaterial, 'pluginFolderHash'>;
222
280
  export interface ResolvedRecipe extends RecipeMaterial {
223
281
  readonly hash: RecipeHash;
224
282
  }
@@ -0,0 +1 @@
1
+ export declare function formatKeyPath(segments: readonly PropertyKey[]): string;
@@ -0,0 +1,2 @@
1
+ import type { JsonValue } from '@boxxy/content-hash';
2
+ export declare function toJSONValue(value: unknown): JsonValue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boxxy/model",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
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,10 +31,21 @@
31
31
  "typecheck": "tsrs --noEmit"
32
32
  },
33
33
  "dependencies": {
34
- "@boxxy/content-hash": "0.1.0",
35
- "@faker-js/faker": "10.6.0",
34
+ "@boxxy/content-hash": "0.1.3",
35
+ "tiny-invariant": "1.3.3",
36
36
  "zod": "4.6.7"
37
37
  },
38
+ "devDependencies": {
39
+ "@faker-js/faker": "10.6.0"
40
+ },
41
+ "peerDependencies": {
42
+ "@faker-js/faker": "10.6.0"
43
+ },
44
+ "peerDependenciesMeta": {
45
+ "@faker-js/faker": {
46
+ "optional": true
47
+ }
48
+ },
38
49
  "engines": {
39
50
  "bun": ">=1.3",
40
51
  "node": ">=24"
@@ -1,7 +1,8 @@
1
1
  import { z } from 'zod';
2
- import { brandSchemas } from './brand-schemas.ts';
2
+ import { brandSchemas } from '../rows/brand-schemas.ts';
3
3
  import { frictionSchema } from './friction-schema.ts';
4
- import type { BuildCloseOut } from './types/facts.ts';
4
+ import { openItemSchema } from './open-item-schema.ts';
5
+ import type { BuildCloseOut } from './types.ts';
5
6
 
6
7
  const reasonSchema = z.string().min(1);
7
8
  const builtSchema = z.object({ kind: z.literal('built') });
@@ -13,16 +14,10 @@ const citedEvidenceSchema = z.object({
13
14
  evidence: brandSchemas.factId,
14
15
  });
15
16
 
16
- const openItemSchema = z.object({
17
- kind: z.literal('core.issue'),
18
- title: z.string().min(1),
19
- body: z.string(),
20
- });
21
-
22
- export const buildCloseOutSchema: z.ZodType<BuildCloseOut> = z.object({
17
+ export const buildCloseOutSchema = z.strictObject({
23
18
  result: z.discriminatedUnion('kind', [builtSchema, blockedSchema, abandonedSchema]),
24
19
  criteria: z.array(citedEvidenceSchema),
25
20
  openItems: z.array(openItemSchema),
26
21
  friction: z.array(frictionSchema),
27
22
  frictionDropped: z.number().int().nonnegative(),
28
- });
23
+ }) satisfies z.ZodType<BuildCloseOut>;
@@ -0,0 +1,42 @@
1
+ import { z } from 'zod';
2
+ import { brandSchemas } from '../rows/brand-schemas.ts';
3
+ import type { CloseOutAnswer, CloseOutProblem } from './types.ts';
4
+
5
+ const closeOutProblemSchema: z.ZodType<CloseOutProblem> = z.discriminatedUnion('kind', [
6
+ z.object({ kind: z.literal('schema'), path: z.string(), message: z.string() }),
7
+ z.object({ kind: z.literal('unknown-criterion'), criterion: brandSchemas.criterionId }),
8
+ z.object({ kind: z.literal('foreign-evidence'), evidence: brandSchemas.factId }),
9
+ z.object({
10
+ kind: z.literal('built-without-evidence'),
11
+ criteria: z.array(brandSchemas.criterionId),
12
+ }),
13
+ z.object({ kind: z.literal('no-acceptance') }),
14
+ z.object({ kind: z.literal('unknown-item'), item: z.string() }),
15
+ z.object({ kind: z.literal('unknown-kind'), itemKind: z.string() }),
16
+ z.object({
17
+ kind: z.literal('refused-relation'),
18
+ type: z.string(),
19
+ target: z.string(),
20
+ reason: z.enum(['unknown-type', 'self']),
21
+ }),
22
+ z.object({ kind: z.literal('phase-rule'), message: z.string() }),
23
+ z.object({
24
+ kind: z.literal('too-large'),
25
+ bytes: z.number().int().nonnegative(),
26
+ max: z.number().int().nonnegative(),
27
+ }),
28
+ ]);
29
+
30
+ export const closeOutAnswerSchema: z.ZodType<CloseOutAnswer> = z.discriminatedUnion('kind', [
31
+ z.object({
32
+ kind: z.literal('recorded'),
33
+ attempt: brandSchemas.attemptId,
34
+ factId: brandSchemas.factId,
35
+ repeat: z.boolean(),
36
+ }),
37
+ z.object({ kind: z.literal('rejected'), problems: z.array(closeOutProblemSchema) }),
38
+ z.object({
39
+ kind: z.literal('refused'),
40
+ reason: z.enum(['no-attempt', 'already-closed-out', 'not-current']),
41
+ }),
42
+ ]);
@@ -0,0 +1,13 @@
1
+ import { z } from 'zod';
2
+ import { buildCloseOutSchema } from './build-close-out-schema.ts';
3
+ import { designCloseOutSchema } from './design-close-out-schema.ts';
4
+ import { reviewCloseOutSchema } from './review-close-out-schema.ts';
5
+ import { triageCloseOutSchema } from './triage-close-out-schema.ts';
6
+ import type { CloseOut } from './types.ts';
7
+
8
+ export const closeOutSchema: z.ZodType<CloseOut> = z.union([
9
+ reviewCloseOutSchema,
10
+ triageCloseOutSchema,
11
+ buildCloseOutSchema,
12
+ designCloseOutSchema,
13
+ ]);
@@ -0,0 +1,20 @@
1
+ import { z } from 'zod';
2
+ import { frictionSchema } from './friction-schema.ts';
3
+ import type { DesignCloseOut } from './types.ts';
4
+
5
+ const reasonSchema = z.string().min(1);
6
+
7
+ const designRefSchema = z.object({
8
+ summary: z.string().min(1),
9
+ location: z.string().min(1).nullable(),
10
+ });
11
+
12
+ const designedSchema = z.object({ kind: z.literal('designed'), design: designRefSchema });
13
+ const blockedSchema = z.object({ kind: z.literal('blocked'), reason: reasonSchema });
14
+ const abandonedSchema = z.object({ kind: z.literal('abandoned'), reason: reasonSchema });
15
+
16
+ export const designCloseOutSchema = z.strictObject({
17
+ result: z.discriminatedUnion('kind', [designedSchema, blockedSchema, abandonedSchema]),
18
+ friction: z.array(frictionSchema),
19
+ frictionDropped: z.number().int().nonnegative(),
20
+ }) satisfies z.ZodType<DesignCloseOut>;
@@ -0,0 +1,11 @@
1
+ import { z } from 'zod';
2
+ import type { Friction } from './types.ts';
3
+
4
+ // A plain object, so that the fact schema of `boxxy.proposal.recorded` can extend it.
5
+ export const frictionSchema = z.object({
6
+ target: z.object({
7
+ kind: z.enum(['skill', 'rule', 'lint', 'agents-md', 'tool']),
8
+ name: z.string().min(1),
9
+ }),
10
+ change: z.string().min(1),
11
+ }) satisfies z.ZodType<Friction>;
@@ -0,0 +1,8 @@
1
+ import { z } from 'zod';
2
+ import type { OpenItem } from './types.ts';
3
+
4
+ export const openItemSchema: z.ZodType<OpenItem> = z.object({
5
+ kind: z.literal('core.issue'),
6
+ title: z.string().min(1),
7
+ body: z.string(),
8
+ });
@@ -0,0 +1,38 @@
1
+ import { z } from 'zod';
2
+ import { brandSchemas } from '../rows/brand-schemas.ts';
3
+ import { frictionSchema } from './friction-schema.ts';
4
+ import type { ReviewCloseOut } from './types.ts';
5
+
6
+ const countSchema = z.number().int().nonnegative();
7
+
8
+ const findingSchema = z.object({
9
+ title: z.string().min(1),
10
+ body: z.string(),
11
+ path: z.string().min(1).exactOptional(),
12
+ line: z.number().int().positive().exactOptional(),
13
+ });
14
+
15
+ const passedSchema = z.object({ kind: z.literal('passed') });
16
+
17
+ const changesRequestedSchema = z.object({
18
+ kind: z.literal('changes-requested'),
19
+ findings: z.array(findingSchema),
20
+ });
21
+
22
+ const noslopSummarySchema = z.object({
23
+ version: z.number().int().positive(),
24
+ reviewID: z.string().min(1),
25
+ head: brandSchemas.commitSha,
26
+ counts: z.object({ findings: countSchema, failedCalls: countSchema, fixChecks: countSchema }),
27
+ reportBytes: countSchema,
28
+ report: z.json().nullable(),
29
+ });
30
+
31
+ // The stored form. The parser of the review phase reads noslop's whole result and builds the
32
+ // summary, so this schema never sees the raw result.
33
+ export const reviewCloseOutSchema = z.strictObject({
34
+ verdict: z.discriminatedUnion('kind', [passedSchema, changesRequestedSchema]),
35
+ noslop: noslopSummarySchema,
36
+ friction: z.array(frictionSchema),
37
+ frictionDropped: countSchema,
38
+ }) satisfies z.ZodType<ReviewCloseOut>;
@@ -0,0 +1,29 @@
1
+ import { z } from 'zod';
2
+ import { brandSchemas } from '../rows/brand-schemas.ts';
3
+ import { frictionSchema } from './friction-schema.ts';
4
+ import type { TriageCloseOut } from './types.ts';
5
+
6
+ const acceptedSchema = z.object({ kind: z.literal('accepted') });
7
+ const duplicateSchema = z.object({ kind: z.literal('duplicate'), of: brandSchemas.itemId });
8
+ const declinedSchema = z.object({ kind: z.literal('declined'), reason: z.string().min(1) });
9
+ const designModeSchema = z.enum(['agent', 'attended']);
10
+ const criterionTextSchema = z.object({ text: z.string().min(1) });
11
+
12
+ const setSchema = z.strictObject({
13
+ kind: brandSchemas.itemKindName.exactOptional(),
14
+ designMode: designModeSchema.exactOptional(),
15
+ acceptance: z.array(criterionTextSchema).exactOptional(),
16
+ });
17
+
18
+ const relationDraftSchema = z.object({
19
+ type: brandSchemas.relationTypeName,
20
+ target: brandSchemas.itemId,
21
+ });
22
+
23
+ export const triageCloseOutSchema = z.strictObject({
24
+ result: z.discriminatedUnion('kind', [acceptedSchema, duplicateSchema, declinedSchema]),
25
+ set: setSchema.exactOptional(),
26
+ relations: z.array(relationDraftSchema),
27
+ friction: z.array(frictionSchema),
28
+ frictionDropped: z.number().int().nonnegative(),
29
+ }) satisfies z.ZodType<TriageCloseOut>;