@boxxy/model 0.1.0 → 0.1.2

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 (80) hide show
  1. package/README.md +27 -2
  2. package/dist/actor-ref-schema.d.ts +2 -0
  3. package/dist/brand-schemas.d.ts +26 -0
  4. package/dist/build-applied-change.d.ts +13 -0
  5. package/dist/build-close-out-schema.d.ts +3 -0
  6. package/dist/build-item-views.d.ts +2 -0
  7. package/dist/define-admission.d.ts +3 -0
  8. package/dist/define-gate.d.ts +3 -0
  9. package/dist/define-signal.d.ts +3 -0
  10. package/dist/derive-item-state.d.ts +2 -0
  11. package/dist/fact-schemas.d.ts +5 -0
  12. package/dist/find-slot-take.d.ts +5 -0
  13. package/dist/format-key-path.d.ts +1 -0
  14. package/dist/friction-schema.d.ts +3 -0
  15. package/dist/index.d.ts +24 -1
  16. package/dist/live-levers.d.ts +2 -0
  17. package/dist/outbox-fact-schema.d.ts +3 -0
  18. package/dist/row-schemas.d.ts +5 -0
  19. package/dist/signal-key.d.ts +3 -0
  20. package/dist/test-utils/build-mock-attempt-row.d.ts +2 -0
  21. package/dist/test-utils/build-mock-evidence-row.d.ts +2 -0
  22. package/dist/test-utils/build-mock-fact-id.d.ts +2 -0
  23. package/dist/test-utils/build-mock-frame-item.d.ts +2 -0
  24. package/dist/test-utils/build-mock-item-row.d.ts +2 -0
  25. package/dist/test-utils/build-mock-item-rows.d.ts +2 -0
  26. package/dist/test-utils/build-mock-item-view.d.ts +2 -0
  27. package/dist/test-utils/build-mock-lease-row.d.ts +2 -0
  28. package/dist/test-utils/build-mock-lever-row.d.ts +2 -0
  29. package/dist/test-utils/build-mock-link-row.d.ts +2 -0
  30. package/dist/test-utils/build-mock-pull-request-row.d.ts +2 -0
  31. package/dist/test-utils/build-mock-snapshot.d.ts +2 -0
  32. package/dist/test-utils/seed-faker.d.ts +1 -0
  33. package/dist/to-json-value.d.ts +2 -0
  34. package/dist/types/core.d.ts +233 -0
  35. package/dist/types/dispatch.d.ts +82 -0
  36. package/dist/types/facts.d.ts +154 -0
  37. package/dist/types/planning.d.ts +94 -0
  38. package/dist/types/ports.d.ts +218 -0
  39. package/dist/types/registries.d.ts +150 -0
  40. package/package.json +9 -2
  41. package/src/actor-ref-schema.ts +9 -0
  42. package/src/brand-schemas.ts +46 -0
  43. package/src/build-applied-change.ts +71 -0
  44. package/src/build-close-out-schema.ts +28 -0
  45. package/src/build-item-views.ts +128 -0
  46. package/src/define-admission.ts +6 -0
  47. package/src/define-gate.ts +6 -0
  48. package/src/define-signal.ts +6 -0
  49. package/src/derive-item-state.ts +76 -0
  50. package/src/fact-schemas.ts +132 -0
  51. package/src/find-slot-take.ts +12 -0
  52. package/src/format-key-path.ts +19 -0
  53. package/src/friction-schema.ts +10 -0
  54. package/src/index.ts +196 -1
  55. package/src/live-levers.ts +22 -0
  56. package/src/outbox-fact-schema.ts +25 -0
  57. package/src/row-schemas.ts +89 -0
  58. package/src/signal-key.ts +7 -0
  59. package/src/test-utils/build-mock-attempt-row.ts +37 -0
  60. package/src/test-utils/build-mock-evidence-row.ts +17 -0
  61. package/src/test-utils/build-mock-fact-id.ts +7 -0
  62. package/src/test-utils/build-mock-frame-item.ts +9 -0
  63. package/src/test-utils/build-mock-item-row.ts +22 -0
  64. package/src/test-utils/build-mock-item-rows.ts +14 -0
  65. package/src/test-utils/build-mock-item-view.ts +8 -0
  66. package/src/test-utils/build-mock-lease-row.ts +15 -0
  67. package/src/test-utils/build-mock-lever-row.ts +17 -0
  68. package/src/test-utils/build-mock-link-row.ts +15 -0
  69. package/src/test-utils/build-mock-pull-request-row.ts +16 -0
  70. package/src/test-utils/build-mock-snapshot.ts +5 -0
  71. package/src/test-utils/seed-faker.ts +3 -0
  72. package/src/to-json-value.ts +25 -0
  73. package/src/types/core.ts +299 -0
  74. package/src/types/dispatch.ts +95 -0
  75. package/src/types/facts.ts +166 -0
  76. package/src/types/planning.ts +136 -0
  77. package/src/types/ports.ts +262 -0
  78. package/src/types/registries.ts +185 -0
  79. package/dist/package-name.d.ts +0 -1
  80. package/src/package-name.ts +0 -1
package/README.md CHANGED
@@ -5,12 +5,17 @@
5
5
  <a href="https://www.npmjs.com/package/@boxxy/model"><img src="https://img.shields.io/npm/v/@boxxy/model" alt="npm version"></a>
6
6
  <a href="./LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue" alt="MIT license"></a>
7
7
  </p>
8
+
9
+ <p>
10
+ <a href="../../docs/design/boxxy/README.md">Documentation</a>
11
+ </p>
8
12
  </div>
9
13
 
10
14
  The types that boxxy's packages share, with the fact catalog and its schemas.
11
15
 
12
- This version is a placeholder that exports only its package name, as `packageName`. The
13
- [boxxy README](https://github.com/zgeoff/boxxy#workspace) lists the workspace's packages.
16
+ Every boxxy package that reads or writes a store row, a fact or a port imports its types from here.
17
+ The package does no I/O: it takes the time as an argument, and it holds only types, zod schemas and
18
+ pure functions.
14
19
 
15
20
  ## Install
16
21
 
@@ -21,3 +26,23 @@ bun add @boxxy/model
21
26
  ```
22
27
 
23
28
  The package runs on [Bun](https://bun.sh) 1.3 or newer.
29
+
30
+ ## Features
31
+
32
+ - The branded ids and names, with a zod schema for each in `brandSchemas`.
33
+ - The store rows, the port interfaces, the plug-in interfaces and the loaded rules.
34
+ - The fact catalog, with a zod schema for each fact type's payload in `factSchemas`
35
+ ([facts and the outbox](../../docs/design/boxxy/slice-1.md#facts-and-the-outbox)).
36
+ - `BuildCloseOut` and its schema, `buildCloseOutSchema`
37
+ ([the build close-out](../../docs/design/boxxy/slice-1.md#the-build-close-out)).
38
+ - `deriveItemState`, which derives an item's state from its rows
39
+ ([derived item state](../../docs/design/boxxy/slice-1.md#derived-item-state)).
40
+ - `liveLevers`, which drops the levers a later undo lever cancels and those past their expiry.
41
+ - `signalKey`, which builds a signal's key from its name and the content hash of its parameters.
42
+ - `defineSignal`, `defineGate` and `defineAdmission`, which register a plug-in with its parameter
43
+ type hidden.
44
+
45
+ ## Documentation
46
+
47
+ The [boxxy design docs](../../docs/design/boxxy/README.md) describe each type, and the
48
+ [interface sketches](../../docs/design/boxxy/sketches/README.md) give its shape.
@@ -0,0 +1,2 @@
1
+ import { z } from 'zod';
2
+ export declare const actorRefSchema: z.ZodUnion<readonly [z.ZodLiteral<"boxxy:owner:local">, z.ZodTemplateLiteral<`boxxy:runner:${string & z.$brand<"RunnerId">}`>, z.ZodTemplateLiteral<`boxxy:attempt:${string & z.$brand<"AttemptId">}`>, z.ZodTemplateLiteral<`boxxy:hook:${string & z.$brand<"AttemptId">}`>]>;
@@ -0,0 +1,26 @@
1
+ import { z } from 'zod';
2
+ export declare const brandSchemas: {
3
+ instant: z.core.$ZodBranded<z.ZodNumber, "Instant", "out">;
4
+ itemId: z.core.$ZodBranded<z.ZodString, "ItemId", "out">;
5
+ attemptId: z.core.$ZodBranded<z.ZodString, "AttemptId", "out">;
6
+ decisionId: z.core.$ZodBranded<z.ZodString, "DecisionId", "out">;
7
+ factId: z.core.$ZodBranded<z.ZodTemplateLiteral<`manual:${string}`>, "FactId", "out">;
8
+ runnerId: z.core.$ZodBranded<z.ZodString, "RunnerId", "out">;
9
+ atcSessionId: z.core.$ZodBranded<z.ZodString, "AtcSessionId", "out">;
10
+ agentSessionId: z.core.$ZodBranded<z.ZodString, "AgentSessionId", "out">;
11
+ commitSha: z.core.$ZodBranded<z.ZodString, "CommitSha", "out">;
12
+ repoName: z.core.$ZodBranded<z.ZodString, "RepoName", "out">;
13
+ criterionId: z.core.$ZodBranded<z.ZodString, "CriterionId", "out">;
14
+ itemKindName: z.core.$ZodBranded<z.ZodString, "ItemKindName", "out">;
15
+ linkTypeName: z.core.$ZodBranded<z.ZodString, "LinkTypeName", "out">;
16
+ phaseName: z.core.$ZodBranded<z.ZodString, "PhaseName", "out">;
17
+ pipelineName: z.core.$ZodBranded<z.ZodString, "PipelineName", "out">;
18
+ poolName: z.core.$ZodBranded<z.ZodString, "PoolName", "out">;
19
+ recipeName: z.core.$ZodBranded<z.ZodString, "RecipeName", "out">;
20
+ workerKindName: z.core.$ZodBranded<z.ZodString, "WorkerKindName", "out">;
21
+ sourceName: z.core.$ZodBranded<z.ZodString, "SourceName", "out">;
22
+ streamName: z.core.$ZodBranded<z.ZodString, "StreamName", "out">;
23
+ recipeHash: z.core.$ZodBranded<z.core.$ZodBranded<z.ZodString, "ContentHash", "out">, "RecipeHash", "out">;
24
+ snapshotHash: z.core.$ZodBranded<z.core.$ZodBranded<z.ZodString, "ContentHash", "out">, "SnapshotHash", "out">;
25
+ rulesVersion: z.core.$ZodBranded<z.core.$ZodBranded<z.ZodString, "ContentHash", "out">, "RulesVersion", "out">;
26
+ };
@@ -0,0 +1,13 @@
1
+ import type { AttemptId, PoolName } from './types/core.ts';
2
+ import type { StoreChange } from './types/ports.ts';
3
+ export interface TakenSlot {
4
+ readonly holder: AttemptId;
5
+ readonly pool: PoolName;
6
+ readonly slot: number;
7
+ readonly gen: number;
8
+ }
9
+ export interface ChangeAssignments {
10
+ readonly taken: TakenSlot | null;
11
+ readonly lastLeverSeq: number;
12
+ }
13
+ export declare function buildAppliedChange(change: StoreChange, assignments: ChangeAssignments): Pick<StoreChange, 'writes' | 'facts'>;
@@ -0,0 +1,3 @@
1
+ import { z } from 'zod';
2
+ import type { BuildCloseOut } from './types/facts.ts';
3
+ export declare const buildCloseOutSchema: z.ZodType<BuildCloseOut>;
@@ -0,0 +1,2 @@
1
+ import type { Instant, ItemSetRows, ItemWithLevers, MaxAttemptsByKind } from './types/core.ts';
2
+ export declare function buildItemViews(rows: ItemSetRows, now: Instant, maxAttemptsByKind: MaxAttemptsByKind): ItemWithLevers[];
@@ -0,0 +1,3 @@
1
+ import type { Admission } from './types/planning.ts';
2
+ import type { Registered } from './types/registries.ts';
3
+ export declare function defineAdmission<P>(admission: Admission<P>): Registered<'admission'>;
@@ -0,0 +1,3 @@
1
+ import type { Gate } from './types/planning.ts';
2
+ import type { Registered } from './types/registries.ts';
3
+ export declare function defineGate<P>(gate: Gate<P>): Registered<'gate'>;
@@ -0,0 +1,3 @@
1
+ import type { Signal } from './types/planning.ts';
2
+ import type { Registered } from './types/registries.ts';
3
+ export declare function defineSignal<P>(signal: Signal<P>): Registered<'signal'>;
@@ -0,0 +1,2 @@
1
+ import type { DerivedState, ItemRow, ItemRows } from './types/core.ts';
2
+ export declare function deriveItemState(item: ItemRow, rows: ItemRows): DerivedState;
@@ -0,0 +1,5 @@
1
+ import { z } from 'zod';
2
+ import type { FactType, SliceOneFacts } from './types/facts.ts';
3
+ export declare const factSchemas: {
4
+ readonly [T in FactType]: z.ZodType<SliceOneFacts[T]>;
5
+ };
@@ -0,0 +1,5 @@
1
+ import type { RowWrite } from './types/ports.ts';
2
+ export type SlotTake = Extract<RowWrite, {
3
+ op: 'take-slot';
4
+ }>;
5
+ export declare function findSlotTake(writes: readonly RowWrite[]): SlotTake | null;
@@ -0,0 +1 @@
1
+ export declare function formatKeyPath(segments: readonly PropertyKey[]): string;
@@ -0,0 +1,3 @@
1
+ import { z } from 'zod';
2
+ import type { Friction } from './types/facts.ts';
3
+ export declare const frictionSchema: z.ZodType<Friction>;
package/dist/index.d.ts CHANGED
@@ -1 +1,24 @@
1
- export { packageName } from './package-name.ts';
1
+ export type { ContentHash, JsonValue } from '@boxxy/content-hash';
2
+ export { brandSchemas } from './brand-schemas.ts';
3
+ export { buildAppliedChange, type ChangeAssignments, type TakenSlot, } from './build-applied-change.ts';
4
+ export { buildCloseOutSchema } from './build-close-out-schema.ts';
5
+ export { buildItemViews } from './build-item-views.ts';
6
+ export { defineAdmission } from './define-admission.ts';
7
+ export { defineGate } from './define-gate.ts';
8
+ export { defineSignal } from './define-signal.ts';
9
+ export { deriveItemState } from './derive-item-state.ts';
10
+ export { factSchemas } from './fact-schemas.ts';
11
+ export { findSlotTake, type SlotTake } from './find-slot-take.ts';
12
+ export { formatKeyPath } from './format-key-path.ts';
13
+ export { frictionSchema } from './friction-schema.ts';
14
+ export { liveLevers } from './live-levers.ts';
15
+ export { outboxFactSchema } from './outbox-fact-schema.ts';
16
+ export { rowSchemas } from './row-schemas.ts';
17
+ export { signalKey } from './signal-key.ts';
18
+ export { toJSONValue } from './to-json-value.ts';
19
+ export type { Actor, ActorRef, AgentSessionId, AtcSessionId, AttemptId, AttemptRow, AttemptSessionRow, AttemptState, CommitSha, ConceptPin, Criterion, CriterionId, DecisionId, DecisionRow, DerivedState, Effort, EvidenceKind, EvidenceRow, EvidenceSource, FactId, FaultRecord, ForcedFailure, Instant, ItemId, ItemKindName, ItemRow, ItemRows, ItemSetRows, ItemState, ItemView, ItemWithLevers, KnownFailure, LeaseRow, LeverKind, LeverRow, LinkRow, LinkTypeName, LiveAttemptState, LoadedRecipe, MaxAttemptsByKind, Minutes, ObservationBoundary, PhaseName, PipelineName, PoolName, PoolSlotRow, PullRequestRef, PullRequestRow, Recipe, RecipeHash, RecipeMaterial, RecipeName, RepoName, ResolvedRecipe, RulesVersion, RunnerId, RunnerRow, SnapshotHash, SourceName, StreamName, WaitingReason, WorkerKindName, } from './types/core.ts';
20
+ export type { Claim, CloseOutContext, CloseOutParse, CloseOutParser, CloseOutProblem, ReconcileAction, ReconcileTable, SettleInput, Settlement, SettleRule, SpawnContext, } from './types/dispatch.ts';
21
+ export type { BuildCloseOut, EntityRef, FactEnvelope, FactType, Friction, FrictionTargetKind, LinkPayload, NewFact, OpenItem, OutboxFact, SliceOneFacts, } from './types/facts.ts';
22
+ export type { Admission, AdmissionGrant, AdmissionName, Decision, Fault, Frame, FrameItem, FrameValues, Gate, GateName, Hold, Lift, Pick, PlanContext, Pool, PropagationLine, Signal, SignalKey, SignalName, Snapshot, View, ViewName, Waiver, WaiverName, } from './types/planning.ts';
23
+ export type { AnyNewFact, ApplyResult, ClaimStore, Clock, CostReader, CostToLandInput, CostToLandRow, FactSink, Forge, ItemDetailRows, ItemFilter, NewId, PullRequestReading, RowWrite, SessionFault, SessionReading, SpawnRequest, StartOutcome, StoreChange, StoreReader, StoreTx, TableName, Tables, WorkerKind, } from './types/ports.ts';
24
+ export type { Concept, ConceptEntry, ConceptName, FilterField, KindRules, LoadedRules, LoadRejection, LoadRejectionReason, LoadResult, ParamKindName, ParamKinds, Pipeline, PipelineStep, PlainKinds, PluginKindName, PluginRef, Registered, Registry, Resolved, RulesFile, Schema, SignalRef, } from './types/registries.ts';
@@ -0,0 +1,2 @@
1
+ import type { Instant, LeverRow } from './types/core.ts';
2
+ export declare function liveLevers(levers: readonly LeverRow[], now: Instant): LeverRow[];
@@ -0,0 +1,3 @@
1
+ import { z } from 'zod';
2
+ import type { OutboxFact } from './types/facts.ts';
3
+ export declare const outboxFactSchema: z.ZodType<OutboxFact>;
@@ -0,0 +1,5 @@
1
+ import { z } from 'zod';
2
+ import type { TableName, Tables } from './types/ports.ts';
3
+ export declare const rowSchemas: {
4
+ readonly [T in TableName]: z.ZodType<Tables[T]>;
5
+ };
@@ -0,0 +1,3 @@
1
+ import type { JsonValue } from '@boxxy/content-hash';
2
+ import type { SignalKey, SignalName } from './types/planning.ts';
3
+ export declare function signalKey(name: SignalName, params: JsonValue): SignalKey;
@@ -0,0 +1,2 @@
1
+ import type { AttemptRow } from '../types/core.ts';
2
+ export declare function buildMockAttemptRow(overrides?: Partial<AttemptRow>): AttemptRow;
@@ -0,0 +1,2 @@
1
+ import type { EvidenceRow } from '../types/core.ts';
2
+ export declare function buildMockEvidenceRow(overrides?: Partial<EvidenceRow>): EvidenceRow;
@@ -0,0 +1,2 @@
1
+ import type { FactId } from '../types/core.ts';
2
+ export declare function buildMockFactId(): FactId;
@@ -0,0 +1,2 @@
1
+ import type { FrameItem } from '../types/planning.ts';
2
+ export declare function buildMockFrameItem(overrides?: Partial<FrameItem>): FrameItem;
@@ -0,0 +1,2 @@
1
+ import type { ItemRow } from '../types/core.ts';
2
+ export declare function buildMockItemRow(overrides?: Partial<ItemRow>): ItemRow;
@@ -0,0 +1,2 @@
1
+ import type { ItemRows } from '../types/core.ts';
2
+ export declare function buildMockItemRows(overrides?: Partial<ItemRows>): ItemRows;
@@ -0,0 +1,2 @@
1
+ import type { ItemView } from '../types/core.ts';
2
+ export declare function buildMockItemView(overrides?: Partial<ItemView>): ItemView;
@@ -0,0 +1,2 @@
1
+ import type { LeaseRow } from '../types/core.ts';
2
+ export declare function buildMockLeaseRow(overrides?: Partial<LeaseRow>): LeaseRow;
@@ -0,0 +1,2 @@
1
+ import type { LeverRow } from '../types/core.ts';
2
+ export declare function buildMockLeverRow(overrides?: Partial<LeverRow>): LeverRow;
@@ -0,0 +1,2 @@
1
+ import type { LinkRow } from '../types/core.ts';
2
+ export declare function buildMockLinkRow(overrides?: Partial<LinkRow>): LinkRow;
@@ -0,0 +1,2 @@
1
+ import type { PullRequestRow } from '../types/core.ts';
2
+ export declare function buildMockPullRequestRow(overrides?: Partial<PullRequestRow>): PullRequestRow;
@@ -0,0 +1,2 @@
1
+ import type { Snapshot } from '../types/planning.ts';
2
+ export declare function buildMockSnapshot(overrides?: Partial<Snapshot>): Snapshot;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ import type { JsonValue } from '@boxxy/content-hash';
2
+ export declare function toJSONValue(value: unknown): JsonValue;
@@ -0,0 +1,233 @@
1
+ import type { ContentHash, JsonValue } from '@boxxy/content-hash';
2
+ import type { z } from 'zod';
3
+ import type { brandSchemas } from '../brand-schemas.ts';
4
+ import type { BuildCloseOut } from './facts.ts';
5
+ type BrandOf<K extends keyof typeof brandSchemas> = z.output<(typeof brandSchemas)[K]>;
6
+ export type Instant = BrandOf<'instant'>;
7
+ export type Minutes = number;
8
+ export type ItemId = BrandOf<'itemId'>;
9
+ export type AttemptId = BrandOf<'attemptId'>;
10
+ export type DecisionId = BrandOf<'decisionId'>;
11
+ export type FactId = BrandOf<'factId'>;
12
+ export type RunnerId = BrandOf<'runnerId'>;
13
+ export type AtcSessionId = BrandOf<'atcSessionId'>;
14
+ export type AgentSessionId = BrandOf<'agentSessionId'>;
15
+ export type CommitSha = BrandOf<'commitSha'>;
16
+ export type RepoName = BrandOf<'repoName'>;
17
+ export type CriterionId = BrandOf<'criterionId'>;
18
+ export interface PullRequestRef {
19
+ readonly repo: RepoName;
20
+ readonly number: number;
21
+ }
22
+ export type ItemKindName = BrandOf<'itemKindName'>;
23
+ export type LinkTypeName = BrandOf<'linkTypeName'>;
24
+ export type PhaseName = BrandOf<'phaseName'>;
25
+ export type PipelineName = BrandOf<'pipelineName'>;
26
+ export type PoolName = BrandOf<'poolName'>;
27
+ export type RecipeName = BrandOf<'recipeName'>;
28
+ export type WorkerKindName = BrandOf<'workerKindName'>;
29
+ export type SourceName = BrandOf<'sourceName'>;
30
+ export type StreamName = BrandOf<'streamName'>;
31
+ export type LeverKind = `${string}.${string}`;
32
+ export type RecipeHash = BrandOf<'recipeHash'>;
33
+ export type SnapshotHash = BrandOf<'snapshotHash'>;
34
+ export type RulesVersion = BrandOf<'rulesVersion'>;
35
+ export interface ConceptPin {
36
+ readonly ref: `${string}@${number}`;
37
+ readonly sourceHash: ContentHash;
38
+ }
39
+ export type Actor = {
40
+ readonly kind: 'owner';
41
+ } | {
42
+ readonly kind: 'attempt';
43
+ readonly attempt: AttemptId;
44
+ } | {
45
+ readonly kind: 'runner';
46
+ readonly runner: RunnerId;
47
+ } | {
48
+ readonly kind: 'hook';
49
+ readonly attempt: AttemptId;
50
+ };
51
+ 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';
53
+ export interface Criterion {
54
+ readonly id: CriterionId;
55
+ readonly text: string;
56
+ readonly evidence: readonly FactId[];
57
+ }
58
+ export interface ItemRow {
59
+ readonly id: ItemId;
60
+ readonly kind: ItemKindName;
61
+ readonly repo: RepoName;
62
+ readonly title: string;
63
+ readonly outcome: string;
64
+ readonly acceptance: readonly Criterion[];
65
+ readonly foundInAttempt: AttemptId | null;
66
+ readonly filedBy: ActorRef;
67
+ readonly filedAt: Instant;
68
+ readonly closedAt: Instant | null;
69
+ readonly closeReason: string | null;
70
+ }
71
+ export type ItemState = 'idea' | 'ready' | 'running' | 'blocked' | 'waiting' | 'done' | 'archived';
72
+ export type WaitingReason = 'PR open' | 'no PR linked' | 'attempts used up';
73
+ export type DerivedState = {
74
+ readonly state: Exclude<ItemState, 'waiting'>;
75
+ } | {
76
+ readonly state: 'waiting';
77
+ readonly reason: WaitingReason;
78
+ };
79
+ export interface ItemView extends ItemRow {
80
+ readonly derived: DerivedState;
81
+ }
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 interface ItemSetRows {
92
+ readonly items: readonly ItemRow[];
93
+ readonly links: readonly LinkRow[];
94
+ readonly levers: readonly LeverRow[];
95
+ readonly attempts: readonly AttemptRow[];
96
+ readonly liveLeases: readonly LeaseRow[];
97
+ readonly pullRequests: readonly PullRequestRow[];
98
+ }
99
+ export type MaxAttemptsByKind = ReadonlyMap<ItemKindName, ReadonlyMap<PhaseName, number>>;
100
+ export interface ItemWithLevers extends ItemView {
101
+ readonly levers: readonly LeverRow[];
102
+ }
103
+ export interface LinkRow {
104
+ readonly source: ItemId;
105
+ readonly target: ItemId;
106
+ readonly type: LinkTypeName;
107
+ readonly addedBy: ActorRef;
108
+ readonly addedAt: Instant;
109
+ readonly removedAt: Instant | null;
110
+ }
111
+ export interface LeverRow {
112
+ readonly seq: number;
113
+ readonly kind: LeverKind;
114
+ readonly item: ItemId;
115
+ readonly until: Instant | null;
116
+ readonly expiresAt: Instant | null;
117
+ readonly reason: string | null;
118
+ readonly actor: ActorRef;
119
+ readonly at: Instant;
120
+ }
121
+ export type AttemptState = 'starting' | 'running' | 'reconciling' | 'succeeded' | 'failed';
122
+ export type LiveAttemptState = Extract<AttemptState, 'starting' | 'running' | 'reconciling'>;
123
+ export type KnownFailure = 'spawn-refused' | 'session-lost' | 'spawn-lost' | 'closeout-missing';
124
+ export type ForcedFailure = Extract<KnownFailure, 'spawn-refused' | 'session-lost' | 'spawn-lost'>;
125
+ export interface AttemptRow {
126
+ readonly id: AttemptId;
127
+ readonly item: ItemId;
128
+ readonly phase: PhaseName;
129
+ readonly number: number;
130
+ readonly runner: RunnerId;
131
+ readonly recipeHash: RecipeHash;
132
+ readonly rulesVersion: RulesVersion;
133
+ readonly pool: PoolName;
134
+ readonly slot: number;
135
+ readonly slotGen: number;
136
+ readonly leaseGen: number;
137
+ readonly spawnRequest: JsonValue;
138
+ readonly spawnRequestHash: ContentHash;
139
+ readonly state: AttemptState;
140
+ readonly failure: string | null;
141
+ readonly atcSession: AtcSessionId | null;
142
+ readonly closeOut: BuildCloseOut | null;
143
+ readonly claimedAt: Instant;
144
+ readonly startedAt: Instant | null;
145
+ readonly endedAt: Instant | null;
146
+ }
147
+ export interface AttemptSessionRow {
148
+ readonly attempt: AttemptId;
149
+ readonly agentSession: AgentSessionId;
150
+ readonly atcSession: AtcSessionId;
151
+ readonly seenAt: Instant;
152
+ }
153
+ export interface LeaseRow {
154
+ readonly item: ItemId;
155
+ readonly phase: PhaseName;
156
+ readonly attempt: AttemptId;
157
+ readonly gen: number;
158
+ readonly takenAt: Instant;
159
+ readonly releasedAt: Instant | null;
160
+ }
161
+ export interface PoolSlotRow {
162
+ readonly pool: PoolName;
163
+ readonly slot: number;
164
+ readonly holder: AttemptId | null;
165
+ readonly gen: number;
166
+ readonly retired: boolean;
167
+ }
168
+ export interface ObservationBoundary {
169
+ readonly storeVersion: number;
170
+ readonly pepysOffsets: Readonly<Record<StreamName, number>>;
171
+ }
172
+ export interface DecisionRow {
173
+ readonly id: DecisionId;
174
+ readonly attempt: AttemptId;
175
+ readonly item: ItemId;
176
+ readonly pool: PoolName;
177
+ readonly rulesVersion: RulesVersion;
178
+ readonly snapshotHash: SnapshotHash;
179
+ readonly storeVersion: number;
180
+ readonly pepysOffsets: ObservationBoundary['pepysOffsets'];
181
+ readonly faults: readonly FaultRecord[];
182
+ readonly at: Instant;
183
+ }
184
+ export interface FaultRecord {
185
+ readonly plugin: string;
186
+ readonly kind: 'signal' | 'gate' | 'waiver' | 'admission' | 'propagation' | 'filter-field';
187
+ readonly item: ItemId | null;
188
+ readonly error: string;
189
+ }
190
+ export type EvidenceSource = 'hook' | 'trailer' | 'agent' | 'watch';
191
+ export interface EvidenceRow {
192
+ readonly factId: FactId;
193
+ readonly attempt: AttemptId;
194
+ readonly kind: EvidenceKind;
195
+ readonly ref: string;
196
+ readonly observed: string | null;
197
+ readonly source: EvidenceSource;
198
+ readonly at: Instant;
199
+ }
200
+ export interface PullRequestRow {
201
+ readonly repo: RepoName;
202
+ readonly number: number;
203
+ readonly attempt: AttemptId;
204
+ readonly state: 'open' | 'closed' | 'merged';
205
+ readonly mergedAt: Instant | null;
206
+ readonly mergeCommit: CommitSha | null;
207
+ readonly checkedAt: Instant;
208
+ }
209
+ export interface RunnerRow {
210
+ readonly id: RunnerId;
211
+ readonly heartbeatAt: Instant;
212
+ readonly paused: boolean;
213
+ }
214
+ export type Effort = 'low' | 'medium' | 'high' | 'xhigh' | 'max';
215
+ export interface Recipe {
216
+ readonly agent: string;
217
+ readonly model: string;
218
+ readonly effort: Effort;
219
+ readonly prompt: string;
220
+ readonly source: SourceName;
221
+ }
222
+ export interface RecipeMaterial {
223
+ readonly name: RecipeName;
224
+ readonly recipe: Recipe;
225
+ readonly promptHash: ContentHash;
226
+ readonly pluginFolderHash: ContentHash;
227
+ readonly rulesVersion: RulesVersion;
228
+ }
229
+ export type LoadedRecipe = Omit<RecipeMaterial, 'pluginFolderHash'>;
230
+ export interface ResolvedRecipe extends RecipeMaterial {
231
+ readonly hash: RecipeHash;
232
+ }
233
+ export {};
@@ -0,0 +1,82 @@
1
+ import type { ContentHash } from '@boxxy/content-hash';
2
+ import type { AttemptId, AttemptRow, CriterionId, EvidenceRow, FactId, ForcedFailure, Instant, ItemView, KnownFailure, LiveAttemptState, Minutes, RecipeName, RepoName } from './core.ts';
3
+ import type { Friction, OpenItem } from './facts.ts';
4
+ import type { SessionReading, SpawnRequest } from './ports.ts';
5
+ export interface SpawnContext {
6
+ readonly repoPaths: ReadonlyMap<RepoName, string>;
7
+ readonly pluginFolder: {
8
+ readonly path: string;
9
+ readonly hash: ContentHash;
10
+ };
11
+ readonly promptTemplates: ReadonlyMap<RecipeName, string>;
12
+ }
13
+ export interface Claim {
14
+ readonly attempt: AttemptRow;
15
+ readonly spawn: SpawnRequest;
16
+ }
17
+ export type ReconcileAction = {
18
+ readonly kind: 'move-to-running';
19
+ readonly fact: 'boxxy.attempt.started' | 'boxxy.attempt.reconciled';
20
+ } | {
21
+ readonly kind: 'bind-session';
22
+ } | {
23
+ readonly kind: 'settle';
24
+ } | {
25
+ readonly kind: 'fail';
26
+ readonly failure: Extract<KnownFailure, 'session-lost'>;
27
+ } | {
28
+ readonly kind: 'respawn';
29
+ readonly giveUpAfter: Minutes;
30
+ readonly then: Extract<KnownFailure, 'spawn-lost'>;
31
+ };
32
+ export type ReconcileTable = Readonly<Record<SessionReading['kind'], Readonly<Record<LiveAttemptState, ReconcileAction>>>>;
33
+ export interface Settlement {
34
+ readonly state: 'succeeded' | 'failed';
35
+ readonly failure: string | null;
36
+ readonly openItems: readonly OpenItem[];
37
+ readonly criteria: readonly {
38
+ readonly criterion: CriterionId;
39
+ readonly evidence: readonly FactId[];
40
+ }[];
41
+ readonly friction: readonly Friction[];
42
+ readonly frictionDropped: number;
43
+ }
44
+ export interface SettleRule<Out = unknown> {
45
+ settle: (input: SettleInput<Out>) => Settlement;
46
+ }
47
+ export interface SettleInput<Out> {
48
+ readonly attempt: AttemptRow;
49
+ readonly item: ItemView;
50
+ readonly closeOut: CloseOutParse<Out> | null;
51
+ readonly forced: ForcedFailure | null;
52
+ readonly now: Instant;
53
+ }
54
+ export interface CloseOutContext {
55
+ readonly item: ItemView;
56
+ readonly attempt: AttemptId;
57
+ readonly evidence: readonly EvidenceRow[];
58
+ }
59
+ export type CloseOutProblem = {
60
+ readonly kind: 'schema';
61
+ readonly path: string;
62
+ readonly message: string;
63
+ } | {
64
+ readonly kind: 'unknown-criterion';
65
+ readonly criterion: CriterionId;
66
+ } | {
67
+ readonly kind: 'foreign-evidence';
68
+ readonly evidence: FactId;
69
+ } | {
70
+ readonly kind: 'built-without-evidence';
71
+ readonly criteria: readonly CriterionId[];
72
+ };
73
+ export type CloseOutParse<Out> = {
74
+ readonly kind: 'valid';
75
+ readonly closeOut: Out;
76
+ } | {
77
+ readonly kind: 'invalid';
78
+ readonly problems: readonly CloseOutProblem[];
79
+ };
80
+ export interface CloseOutParser<Out> {
81
+ parse: (raw: unknown, ctx: CloseOutContext) => CloseOutParse<Out>;
82
+ }