@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,31 @@
|
|
|
1
|
+
import { faker } from '@faker-js/faker';
|
|
2
|
+
import type { CostToLand } from '../reports/types.ts';
|
|
3
|
+
|
|
4
|
+
// The cost of a landed item: one build line with a reported cost.
|
|
5
|
+
export function buildMockCostToLand(overrides: Partial<CostToLand> = {}): CostToLand {
|
|
6
|
+
const costUSD = faker.number.float({ min: 0.5, max: 20, fractionDigits: 2 });
|
|
7
|
+
const requests = faker.number.int({ min: 1, max: 80 });
|
|
8
|
+
|
|
9
|
+
return {
|
|
10
|
+
item: `boxxy:item:${faker.string.uuid({ version: 7 })}`,
|
|
11
|
+
landedAt: '2026-11-11T06:00:00Z',
|
|
12
|
+
attempts: 1,
|
|
13
|
+
lines: [
|
|
14
|
+
{
|
|
15
|
+
phase: 'build',
|
|
16
|
+
rework: false,
|
|
17
|
+
product: 'claude_code',
|
|
18
|
+
model: 'model-large',
|
|
19
|
+
requests,
|
|
20
|
+
inputTokens: requests * 10,
|
|
21
|
+
cacheReadTokens: requests * 1000,
|
|
22
|
+
cacheCreationTokens: requests * 50,
|
|
23
|
+
outputTokens: requests * 300,
|
|
24
|
+
costUSD,
|
|
25
|
+
costBasis: 'reported',
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
totals: { requests, costUSD, reworkCostUSD: 0, requestsWithoutCost: 0 },
|
|
29
|
+
...overrides,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { faker } from '@faker-js/faker';
|
|
2
|
-
import { brandSchemas } from '../brand-schemas.ts';
|
|
3
|
-
import type { EvidenceRow } from '../types
|
|
2
|
+
import { brandSchemas } from '../rows/brand-schemas.ts';
|
|
3
|
+
import type { EvidenceRow } from '../types.ts';
|
|
4
4
|
import { buildMockFactId } from './build-mock-fact-id.ts';
|
|
5
5
|
|
|
6
6
|
export function buildMockEvidenceRow(overrides: Partial<EvidenceRow> = {}): EvidenceRow {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { faker } from '@faker-js/faker';
|
|
2
|
-
import { brandSchemas } from '../brand-schemas.ts';
|
|
3
|
-
import type { FactId } from '../types
|
|
2
|
+
import { brandSchemas } from '../rows/brand-schemas.ts';
|
|
3
|
+
import type { FactId } from '../types.ts';
|
|
4
4
|
|
|
5
5
|
export function buildMockFactId(): FactId {
|
|
6
|
-
return brandSchemas.factId.parse(
|
|
6
|
+
return brandSchemas.factId.parse(faker.string.uuid({ version: 7 }));
|
|
7
7
|
}
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
1
|
+
import type { FrameItem } from '../planning/types.ts';
|
|
2
|
+
import { brandSchemas } from '../rows/brand-schemas.ts';
|
|
3
|
+
import { buildMockV1ItemView } from './build-mock-v1-item-view.ts';
|
|
4
4
|
|
|
5
|
+
// The item's position is the phase and round of the frame item, unless an override sets it.
|
|
5
6
|
export function buildMockFrameItem(overrides: Partial<FrameItem> = {}): FrameItem {
|
|
6
|
-
const { phase, ...view } = overrides;
|
|
7
|
+
const { phase = brandSchemas.phaseName.parse('build'), round = 1, ...view } = overrides;
|
|
7
8
|
|
|
8
|
-
return {
|
|
9
|
+
return {
|
|
10
|
+
...buildMockV1ItemView({ position: { kind: 'phase', phase, round }, ...view }),
|
|
11
|
+
phase,
|
|
12
|
+
round,
|
|
13
|
+
};
|
|
9
14
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Frame } from '../planning/types.ts';
|
|
2
|
+
|
|
3
|
+
export function buildMockFrame(overrides: Partial<Frame> = {}): Frame {
|
|
4
|
+
return {
|
|
5
|
+
candidates: [],
|
|
6
|
+
fields: new Map(),
|
|
7
|
+
values: new Map(),
|
|
8
|
+
holds: new Map(),
|
|
9
|
+
lifted: new Map(),
|
|
10
|
+
faults: [],
|
|
11
|
+
...overrides,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { brandSchemas } from '../rows/brand-schemas.ts';
|
|
2
|
+
import type { ItemRules } from '../rules/types.ts';
|
|
3
|
+
import { buildMockPipeline } from './build-mock-pipeline.ts';
|
|
4
|
+
|
|
5
|
+
// `core.issue` and `core.task` run the build phase alone; no phase needs acceptance criteria.
|
|
6
|
+
export function buildMockItemRules(overrides: Partial<ItemRules> = {}): ItemRules {
|
|
7
|
+
const pipeline = buildMockPipeline({ phases: ['build'] });
|
|
8
|
+
|
|
9
|
+
return {
|
|
10
|
+
kinds: new Map([
|
|
11
|
+
[brandSchemas.itemKindName.parse('core.issue'), { pipeline }],
|
|
12
|
+
[brandSchemas.itemKindName.parse('core.task'), { pipeline }],
|
|
13
|
+
]),
|
|
14
|
+
phases: new Map(),
|
|
15
|
+
...overrides,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { faker } from '@faker-js/faker';
|
|
2
|
-
import { brandSchemas } from '../brand-schemas.ts';
|
|
3
|
-
import type { LeaseRow } from '../types
|
|
2
|
+
import { brandSchemas } from '../rows/brand-schemas.ts';
|
|
3
|
+
import type { LeaseRow } from '../types.ts';
|
|
4
4
|
|
|
5
5
|
export function buildMockLeaseRow(overrides: Partial<LeaseRow> = {}): LeaseRow {
|
|
6
6
|
return {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { OutboxFact } from '../facts/types.ts';
|
|
2
|
+
import { brandSchemas } from '../rows/brand-schemas.ts';
|
|
3
|
+
import { buildMockFactId } from './build-mock-fact-id.ts';
|
|
4
|
+
|
|
5
|
+
// An unsent, unparked `boxxy.item.noted` row for the item `i-<seq>`.
|
|
6
|
+
export function buildMockOutboxFact(overrides: Partial<OutboxFact> = {}): OutboxFact {
|
|
7
|
+
const seq = overrides.seq ?? 1;
|
|
8
|
+
|
|
9
|
+
return {
|
|
10
|
+
seq,
|
|
11
|
+
factId: buildMockFactId(),
|
|
12
|
+
type: 'boxxy.item.noted',
|
|
13
|
+
entity: `boxxy:item:i-${seq}`,
|
|
14
|
+
actor: 'boxxy:owner:local',
|
|
15
|
+
at: brandSchemas.instant.parse(1_800_000_000_000 + seq),
|
|
16
|
+
payload: { seq, text: 'a note' },
|
|
17
|
+
sentAt: null,
|
|
18
|
+
parkedAt: null,
|
|
19
|
+
parkedReason: null,
|
|
20
|
+
...overrides,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { brandSchemas } from '../rows/brand-schemas.ts';
|
|
2
|
+
import { definePhase } from '../rules/define-phase.ts';
|
|
3
|
+
import type { PhaseKind } from '../rules/types.ts';
|
|
4
|
+
|
|
5
|
+
interface MockPhaseKindInput {
|
|
6
|
+
readonly name: string;
|
|
7
|
+
readonly outcomes: readonly string[];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// A phase kind with only a name and an outcome list: its close-out is any value, and it settles
|
|
11
|
+
// with its first outcome.
|
|
12
|
+
export function buildMockPhaseKind(input: MockPhaseKindInput): PhaseKind {
|
|
13
|
+
return definePhase({
|
|
14
|
+
name: brandSchemas.phaseName.parse(input.name),
|
|
15
|
+
version: 1,
|
|
16
|
+
worker: brandSchemas.workerKindName.parse('atc.session'),
|
|
17
|
+
outcomes: input.outcomes,
|
|
18
|
+
needsAcceptance: false,
|
|
19
|
+
input: () => ({}),
|
|
20
|
+
closeOut: { parse: (raw) => ({ kind: 'valid', closeOut: raw }), jsonSchema: {} },
|
|
21
|
+
settle: () => ({
|
|
22
|
+
state: 'succeeded',
|
|
23
|
+
failure: null,
|
|
24
|
+
outcome: input.outcomes[0] ?? '',
|
|
25
|
+
effects: [],
|
|
26
|
+
frictionDropped: 0,
|
|
27
|
+
}),
|
|
28
|
+
});
|
|
29
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { brandSchemas } from '../rows/brand-schemas.ts';
|
|
2
|
+
import type { Edge, Pipeline, PipelineStep } from '../rules/types.ts';
|
|
3
|
+
|
|
4
|
+
const standardOrder = ['triage', 'design', 'build', 'review'];
|
|
5
|
+
|
|
6
|
+
const standardEdges: Readonly<Record<string, Readonly<Record<string, Edge>>>> = {
|
|
7
|
+
triage: {
|
|
8
|
+
accepted: 'next',
|
|
9
|
+
duplicate: { hold: brandSchemas.rulesHoldReason.parse('duplicate') },
|
|
10
|
+
declined: { hold: brandSchemas.rulesHoldReason.parse('declined') },
|
|
11
|
+
},
|
|
12
|
+
design: {
|
|
13
|
+
designed: 'next',
|
|
14
|
+
blocked: { hold: brandSchemas.rulesHoldReason.parse('blocked') },
|
|
15
|
+
abandoned: 'again',
|
|
16
|
+
},
|
|
17
|
+
build: {
|
|
18
|
+
built: 'next',
|
|
19
|
+
blocked: { hold: brandSchemas.rulesHoldReason.parse('blocked') },
|
|
20
|
+
abandoned: 'again',
|
|
21
|
+
},
|
|
22
|
+
review: {
|
|
23
|
+
passed: { end: 'reviewed' },
|
|
24
|
+
'changes-requested': { to: brandSchemas.phaseName.parse('build'), max: 3, resume: true },
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
interface MockPipelineInput {
|
|
29
|
+
// the phases in order; the four standard phases when left out
|
|
30
|
+
readonly phases?: readonly string[];
|
|
31
|
+
|
|
32
|
+
// fields to replace on the step of a phase; `on` is replaced whole
|
|
33
|
+
readonly steps?: Readonly<Record<string, Partial<PipelineStep>>>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// The `standard` pipeline of the v1 rules file: triage, design, build and review, with two
|
|
37
|
+
// attempts in a row for each step.
|
|
38
|
+
export function buildMockPipeline(input: MockPipelineInput = {}): Pipeline {
|
|
39
|
+
const steps: PipelineStep[] = [];
|
|
40
|
+
|
|
41
|
+
for (const phase of input.phases ?? standardOrder) {
|
|
42
|
+
steps.push({
|
|
43
|
+
phase: brandSchemas.phaseName.parse(phase),
|
|
44
|
+
maxAttempts: 2,
|
|
45
|
+
timeoutMinutes: 30,
|
|
46
|
+
on: standardEdges[phase] ?? {},
|
|
47
|
+
...input.steps?.[phase],
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return { name: brandSchemas.pipelineName.parse('standard'), steps };
|
|
52
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { faker } from '@faker-js/faker';
|
|
2
|
-
import { brandSchemas } from '../brand-schemas.ts';
|
|
3
|
-
import type {
|
|
2
|
+
import { brandSchemas } from '../rows/brand-schemas.ts';
|
|
3
|
+
import type { RelationRow } from '../types.ts';
|
|
4
4
|
|
|
5
|
-
export function
|
|
5
|
+
export function buildMockRelationRow(overrides: Partial<RelationRow> = {}): RelationRow {
|
|
6
6
|
return {
|
|
7
7
|
source: brandSchemas.itemId.parse(faker.string.uuid({ version: 7 })),
|
|
8
8
|
target: brandSchemas.itemId.parse(faker.string.uuid({ version: 7 })),
|
|
9
|
-
type: brandSchemas.
|
|
9
|
+
type: brandSchemas.relationTypeName.parse('blocks'),
|
|
10
10
|
addedBy: 'boxxy:owner:local',
|
|
11
11
|
addedAt: brandSchemas.instant.parse(faker.number.int({ max: 1_800_000_000_000 })),
|
|
12
12
|
removedAt: null,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Settled } from '../pipeline/types.ts';
|
|
2
|
+
import { brandSchemas } from '../rows/brand-schemas.ts';
|
|
3
|
+
|
|
4
|
+
interface MockSettledInput {
|
|
5
|
+
readonly phase: string;
|
|
6
|
+
readonly outcome: string;
|
|
7
|
+
readonly endedAt: number;
|
|
8
|
+
readonly failure?: string | null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function buildMockSettled(input: MockSettledInput): Settled {
|
|
12
|
+
return {
|
|
13
|
+
phase: brandSchemas.phaseName.parse(input.phase),
|
|
14
|
+
outcome: input.outcome,
|
|
15
|
+
endedAt: brandSchemas.instant.parse(input.endedAt),
|
|
16
|
+
failure: input.failure ?? null,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
import type { Snapshot } from '../types
|
|
1
|
+
import type { Snapshot } from '../planning/types.ts';
|
|
2
2
|
|
|
3
3
|
export function buildMockSnapshot(overrides: Partial<Snapshot> = {}): Snapshot {
|
|
4
|
-
return {
|
|
4
|
+
return {
|
|
5
|
+
storeVersion: 1,
|
|
6
|
+
items: [],
|
|
7
|
+
relations: [],
|
|
8
|
+
levers: [],
|
|
9
|
+
limits: [],
|
|
10
|
+
wakes: [],
|
|
11
|
+
...overrides,
|
|
12
|
+
};
|
|
5
13
|
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { contentHash } from '@boxxy/content-hash';
|
|
2
2
|
import { faker } from '@faker-js/faker';
|
|
3
|
-
import { brandSchemas } from '../brand-schemas.ts';
|
|
4
|
-
import type { AttemptRow } from '../types
|
|
3
|
+
import { brandSchemas } from '../rows/brand-schemas.ts';
|
|
4
|
+
import type { AttemptRow } from '../types.ts';
|
|
5
5
|
|
|
6
6
|
const hashOptions = { length: 64, casing: 'lower', prefix: '' } as const;
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
// A running agent-mode build attempt of round 1. `buildMockAttemptRow` still builds the slice 1
|
|
9
|
+
// row that the store reads and writes.
|
|
10
|
+
export function buildMockV1AttemptRow(overrides: Partial<AttemptRow> = {}): AttemptRow {
|
|
9
11
|
const spawnRequest =
|
|
10
12
|
overrides.spawnRequest === undefined
|
|
11
13
|
? { prompt: faker.lorem.sentence() }
|
|
@@ -19,19 +21,36 @@ export function buildMockAttemptRow(overrides: Partial<AttemptRow> = {}): Attemp
|
|
|
19
21
|
runner: brandSchemas.runnerId.parse('runner-1'),
|
|
20
22
|
recipeHash: brandSchemas.recipeHash.parse(faker.string.hexadecimal(hashOptions)),
|
|
21
23
|
rulesVersion: brandSchemas.rulesVersion.parse(faker.string.hexadecimal(hashOptions)),
|
|
22
|
-
pool: brandSchemas.poolName.parse('
|
|
23
|
-
slot: 1,
|
|
24
|
-
slotGen: 1,
|
|
24
|
+
pool: brandSchemas.poolName.parse('main'),
|
|
25
25
|
leaseGen: 1,
|
|
26
26
|
spawnRequest,
|
|
27
27
|
spawnRequestHash: contentHash(spawnRequest),
|
|
28
|
-
state: '
|
|
28
|
+
state: 'running',
|
|
29
29
|
failure: null,
|
|
30
30
|
atcSession: brandSchemas.atcSessionId.parse(faker.string.uuid()),
|
|
31
|
-
|
|
31
|
+
caller: null,
|
|
32
32
|
claimedAt: brandSchemas.instant.parse(faker.number.int({ max: 1_800_000_000_000 })),
|
|
33
33
|
startedAt: brandSchemas.instant.parse(faker.number.int({ max: 1_800_000_000_000 })),
|
|
34
|
-
endedAt:
|
|
34
|
+
endedAt: null,
|
|
35
|
+
fields: {},
|
|
36
|
+
mode: 'agent',
|
|
37
|
+
round: 1,
|
|
38
|
+
input: {},
|
|
39
|
+
holdGen: 1,
|
|
40
|
+
closeOut: null,
|
|
41
|
+
closeOutHash: null,
|
|
42
|
+
closeOutFact: null,
|
|
43
|
+
closing: null,
|
|
44
|
+
closingAt: null,
|
|
45
|
+
suspendRequestedAt: null,
|
|
46
|
+
sleptAt: null,
|
|
47
|
+
wakeRequestedAt: null,
|
|
48
|
+
wokenAt: null,
|
|
49
|
+
outcome: null,
|
|
50
|
+
returnedOutcome: null,
|
|
51
|
+
strayedAt: null,
|
|
52
|
+
sessionStoppedAt: null,
|
|
53
|
+
sessionForgottenAt: null,
|
|
35
54
|
...overrides,
|
|
36
55
|
};
|
|
37
56
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { faker } from '@faker-js/faker';
|
|
2
|
-
import { brandSchemas } from '../brand-schemas.ts';
|
|
3
|
-
import type { ItemRow } from '../types
|
|
2
|
+
import { brandSchemas } from '../rows/brand-schemas.ts';
|
|
3
|
+
import type { ItemRow } from '../types.ts';
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
// An open issue with one acceptance criterion, no labels and no kept session.
|
|
6
|
+
export function buildMockV1ItemRow(overrides: Partial<ItemRow> = {}): ItemRow {
|
|
6
7
|
return {
|
|
7
8
|
id: brandSchemas.itemId.parse(faker.string.uuid({ version: 7 })),
|
|
8
9
|
kind: brandSchemas.itemKindName.parse('core.issue'),
|
|
@@ -12,11 +13,14 @@ export function buildMockItemRow(overrides: Partial<ItemRow> = {}): ItemRow {
|
|
|
12
13
|
acceptance: [
|
|
13
14
|
{ id: brandSchemas.criterionId.parse('a1'), text: faker.lorem.sentence(), evidence: [] },
|
|
14
15
|
],
|
|
16
|
+
fields: {},
|
|
17
|
+
labels: [],
|
|
15
18
|
foundInAttempt: null,
|
|
16
19
|
filedBy: 'boxxy:owner:local',
|
|
17
20
|
filedAt: brandSchemas.instant.parse(faker.number.int({ max: 1_800_000_000_000 })),
|
|
18
21
|
closedAt: null,
|
|
19
22
|
closeReason: null,
|
|
23
|
+
keptSession: null,
|
|
20
24
|
...overrides,
|
|
21
25
|
};
|
|
22
26
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { faker } from '@faker-js/faker';
|
|
2
|
+
import { brandSchemas } from '../rows/brand-schemas.ts';
|
|
3
|
+
import type { ItemView } from '../types.ts';
|
|
4
|
+
|
|
5
|
+
// A ready item at the build phase of round 1. `buildMockItemView` still builds the slice 1 view
|
|
6
|
+
// that the store reads.
|
|
7
|
+
export function buildMockV1ItemView(overrides: Partial<ItemView> = {}): ItemView {
|
|
8
|
+
return {
|
|
9
|
+
id: brandSchemas.itemId.parse(faker.string.uuid({ version: 7 })),
|
|
10
|
+
kind: brandSchemas.itemKindName.parse('core.issue'),
|
|
11
|
+
repo: brandSchemas.repoName.parse(`${faker.word.noun()}/${faker.word.noun()}`),
|
|
12
|
+
title: faker.lorem.sentence(),
|
|
13
|
+
outcome: faker.lorem.sentence(),
|
|
14
|
+
acceptance: [
|
|
15
|
+
{ id: brandSchemas.criterionId.parse('a1'), text: faker.lorem.sentence(), evidence: [] },
|
|
16
|
+
],
|
|
17
|
+
fields: {},
|
|
18
|
+
labels: [],
|
|
19
|
+
foundInAttempt: null,
|
|
20
|
+
filedBy: 'boxxy:owner:local',
|
|
21
|
+
filedAt: brandSchemas.instant.parse(faker.number.int({ max: 1_800_000_000_000 })),
|
|
22
|
+
closedAt: null,
|
|
23
|
+
closeReason: null,
|
|
24
|
+
keptSession: null,
|
|
25
|
+
derived: { state: 'ready' },
|
|
26
|
+
position: { kind: 'phase', phase: brandSchemas.phaseName.parse('build'), round: 1 },
|
|
27
|
+
...overrides,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { faker } from '@faker-js/faker';
|
|
2
|
-
import { brandSchemas } from '../brand-schemas.ts';
|
|
3
|
-
import type { LeverRow } from '../types
|
|
2
|
+
import { brandSchemas } from '../rows/brand-schemas.ts';
|
|
3
|
+
import type { LeverRow } from '../types.ts';
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
// A defer lever with no phase.
|
|
6
|
+
export function buildMockV1LeverRow(overrides: Partial<LeverRow> = {}): LeverRow {
|
|
6
7
|
return {
|
|
7
8
|
seq: faker.number.int({ min: 1, max: 10_000 }),
|
|
8
9
|
kind: 'plan.defer',
|
|
@@ -10,6 +11,7 @@ export function buildMockLeverRow(overrides: Partial<LeverRow> = {}): LeverRow {
|
|
|
10
11
|
until: null,
|
|
11
12
|
expiresAt: null,
|
|
12
13
|
reason: faker.lorem.sentence(),
|
|
14
|
+
phase: null,
|
|
13
15
|
actor: 'boxxy:owner:local',
|
|
14
16
|
at: brandSchemas.instant.parse(faker.number.int({ max: 1_800_000_000_000 })),
|
|
15
17
|
...overrides,
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { faker } from '@faker-js/faker';
|
|
2
|
+
import { brandSchemas } from '../rows/brand-schemas.ts';
|
|
3
|
+
import type { PullRequestRow } from '../types.ts';
|
|
4
|
+
|
|
5
|
+
// An open pull request, with its URL built from its repo and number. `buildMockPullRequestRow`
|
|
6
|
+
// still builds the slice 1 row.
|
|
7
|
+
export function buildMockV1PullRequestRow(overrides: Partial<PullRequestRow> = {}): PullRequestRow {
|
|
8
|
+
const repo =
|
|
9
|
+
overrides.repo ??
|
|
10
|
+
brandSchemas.repoName.parse(`${faker.string.alpha(8)}/${faker.string.alpha(8)}`);
|
|
11
|
+
|
|
12
|
+
const number = overrides.number ?? faker.number.int({ min: 1, max: 10_000 });
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
repo,
|
|
16
|
+
number,
|
|
17
|
+
attempt: brandSchemas.attemptId.parse(faker.string.uuid({ version: 7 })),
|
|
18
|
+
githubId: faker.number.int({ min: 1, max: 2_000_000_000 }),
|
|
19
|
+
url: `https://github.com/${repo}/pull/${number}`,
|
|
20
|
+
state: 'open',
|
|
21
|
+
mergedAt: null,
|
|
22
|
+
mergeCommit: null,
|
|
23
|
+
checkedAt: brandSchemas.instant.parse(faker.number.int({ max: 1_800_000_000_000 })),
|
|
24
|
+
...overrides,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { contentHash } from '@boxxy/content-hash';
|
|
2
|
+
import { faker } from '@faker-js/faker';
|
|
3
|
+
import type { z } from 'zod';
|
|
4
|
+
import type { EntityRef, OutboxFact, WorkFacts } from '../facts/types.ts';
|
|
5
|
+
import { workFactSchemas } from '../facts/work-fact-schemas.ts';
|
|
6
|
+
import { brandSchemas } from '../rows/brand-schemas.ts';
|
|
7
|
+
import type { Instant } from '../types.ts';
|
|
8
|
+
import { toJSONValue } from '../utils/to-json-value.ts';
|
|
9
|
+
import { buildMockFactId } from './build-mock-fact-id.ts';
|
|
10
|
+
|
|
11
|
+
// The fact types that the pepys consumer reads.
|
|
12
|
+
export type MockedFactType =
|
|
13
|
+
| 'boxxy.item.filed'
|
|
14
|
+
| 'boxxy.item.edited'
|
|
15
|
+
| 'boxxy.item.closed'
|
|
16
|
+
| 'boxxy.attempt.claimed'
|
|
17
|
+
| 'boxxy.attempt.started'
|
|
18
|
+
| 'boxxy.attempt.reconciled'
|
|
19
|
+
| 'boxxy.attempt.resumed'
|
|
20
|
+
| 'boxxy.attempt.session_bound'
|
|
21
|
+
| 'boxxy.attempt.slept'
|
|
22
|
+
| 'boxxy.attempt.woken'
|
|
23
|
+
| 'boxxy.attempt.closed_out'
|
|
24
|
+
| 'boxxy.attempt.settled'
|
|
25
|
+
| 'boxxy.pull_request.linked';
|
|
26
|
+
|
|
27
|
+
// The payload's values are checked by the schema, so a test may give a plain string for a brand.
|
|
28
|
+
interface WorkFactOverrides<Type extends MockedFactType> {
|
|
29
|
+
readonly payload?: { readonly [Key in keyof WorkFacts[Type]]?: unknown };
|
|
30
|
+
readonly at?: number;
|
|
31
|
+
readonly entity?: EntityRef;
|
|
32
|
+
readonly seq?: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const hashOptions = { length: 64, casing: 'lower', prefix: '' } as const;
|
|
36
|
+
|
|
37
|
+
const defaultPayloads: { readonly [Type in MockedFactType]: () => WorkFacts[Type] } = {
|
|
38
|
+
'boxxy.item.filed': () => ({
|
|
39
|
+
id: brandSchemas.itemId.parse(faker.string.uuid({ version: 7 })),
|
|
40
|
+
kind: brandSchemas.itemKindName.parse('core.issue'),
|
|
41
|
+
repo: brandSchemas.repoName.parse('shoal/charts'),
|
|
42
|
+
title: faker.lorem.sentence(),
|
|
43
|
+
outcome: faker.lorem.sentence(),
|
|
44
|
+
acceptance: [],
|
|
45
|
+
fields: {},
|
|
46
|
+
labels: [],
|
|
47
|
+
foundInAttempt: null,
|
|
48
|
+
filedBy: 'boxxy:owner:local',
|
|
49
|
+
filedAt: toInstant(1_800_000_000_000),
|
|
50
|
+
closedAt: null,
|
|
51
|
+
closeReason: null,
|
|
52
|
+
}),
|
|
53
|
+
'boxxy.item.edited': () => ({ byAttempt: null }),
|
|
54
|
+
'boxxy.item.closed': () => ({ reason: 'done', byAttempt: null, ended: [] }),
|
|
55
|
+
'boxxy.attempt.claimed': () => ({
|
|
56
|
+
attempt: buildAttemptId(),
|
|
57
|
+
phase: brandSchemas.phaseName.parse('build'),
|
|
58
|
+
number: 1,
|
|
59
|
+
round: 1,
|
|
60
|
+
mode: 'agent',
|
|
61
|
+
pool: brandSchemas.poolName.parse('main'),
|
|
62
|
+
fields: {},
|
|
63
|
+
seats: [],
|
|
64
|
+
recipeHash: brandSchemas.recipeHash.parse(faker.string.hexadecimal(hashOptions)),
|
|
65
|
+
skillsRef: null,
|
|
66
|
+
rulesVersion: brandSchemas.rulesVersion.parse(faker.string.hexadecimal(hashOptions)),
|
|
67
|
+
}),
|
|
68
|
+
'boxxy.attempt.started': () => ({
|
|
69
|
+
attempt: buildAttemptId(),
|
|
70
|
+
atcSession: buildAtcSession(),
|
|
71
|
+
resumeFallback: false,
|
|
72
|
+
caller: null,
|
|
73
|
+
}),
|
|
74
|
+
'boxxy.attempt.reconciled': () => ({
|
|
75
|
+
attempt: buildAttemptId(),
|
|
76
|
+
atcSession: buildAtcSession(),
|
|
77
|
+
caller: null,
|
|
78
|
+
}),
|
|
79
|
+
'boxxy.attempt.resumed': () => ({
|
|
80
|
+
attempt: buildAttemptId(),
|
|
81
|
+
atcSession: buildAtcSession(),
|
|
82
|
+
caller: null,
|
|
83
|
+
}),
|
|
84
|
+
'boxxy.attempt.session_bound': () => ({
|
|
85
|
+
attempt: buildAttemptId(),
|
|
86
|
+
atcSession: buildAtcSession(),
|
|
87
|
+
agentSession: brandSchemas.agentSessionId.parse(`agent-${faker.string.alphanumeric(8)}`),
|
|
88
|
+
product: 'claude_code',
|
|
89
|
+
source: 'hook',
|
|
90
|
+
seenAt: toInstant(1_800_000_000_000),
|
|
91
|
+
}),
|
|
92
|
+
'boxxy.attempt.slept': () => ({
|
|
93
|
+
attempt: buildAttemptId(),
|
|
94
|
+
idleSince: toInstant(1_800_000_000_000),
|
|
95
|
+
asked: true,
|
|
96
|
+
}),
|
|
97
|
+
'boxxy.attempt.woken': () => ({
|
|
98
|
+
attempt: buildAttemptId(),
|
|
99
|
+
holdGen: 1,
|
|
100
|
+
seats: [],
|
|
101
|
+
overCap: false,
|
|
102
|
+
}),
|
|
103
|
+
'boxxy.attempt.closed_out': () => {
|
|
104
|
+
const closeOut = {
|
|
105
|
+
result: { kind: 'accepted' as const },
|
|
106
|
+
relations: [],
|
|
107
|
+
friction: [],
|
|
108
|
+
frictionDropped: 0,
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
attempt: buildAttemptId(),
|
|
113
|
+
phase: brandSchemas.phaseName.parse('triage'),
|
|
114
|
+
closeOut,
|
|
115
|
+
hash: contentHash(closeOut),
|
|
116
|
+
};
|
|
117
|
+
},
|
|
118
|
+
'boxxy.attempt.settled': () => ({
|
|
119
|
+
attempt: buildAttemptId(),
|
|
120
|
+
phase: brandSchemas.phaseName.parse('build'),
|
|
121
|
+
round: 1,
|
|
122
|
+
state: 'succeeded',
|
|
123
|
+
failure: null,
|
|
124
|
+
outcome: 'built',
|
|
125
|
+
returnedOutcome: null,
|
|
126
|
+
closing: 'closed-out',
|
|
127
|
+
asleep: false,
|
|
128
|
+
sessionStopped: true,
|
|
129
|
+
endedAt: toInstant(1_800_000_000_000),
|
|
130
|
+
criteria: [],
|
|
131
|
+
matched: [],
|
|
132
|
+
frictionDropped: 0,
|
|
133
|
+
skippedEffects: [],
|
|
134
|
+
}),
|
|
135
|
+
'boxxy.pull_request.linked': () => ({
|
|
136
|
+
attempt: buildAttemptId(),
|
|
137
|
+
repo: brandSchemas.repoName.parse('shoal/charts'),
|
|
138
|
+
number: 14,
|
|
139
|
+
url: 'https://github.com/shoal/charts/pull/14',
|
|
140
|
+
pullRequestId: '9001',
|
|
141
|
+
source: 'hook',
|
|
142
|
+
}),
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// An unsent outbox row of the type, with every payload field the test does not give filled with a
|
|
146
|
+
// valid value. The payload passes the type's schema, or the factory throws.
|
|
147
|
+
export function buildMockWorkFact<Type extends MockedFactType>(
|
|
148
|
+
type: Type,
|
|
149
|
+
overrides: WorkFactOverrides<Type> = {},
|
|
150
|
+
): OutboxFact {
|
|
151
|
+
const schema: z.ZodType = workFactSchemas[type];
|
|
152
|
+
const payload = schema.parse({ ...defaultPayloads[type](), ...overrides.payload });
|
|
153
|
+
const seq = overrides.seq ?? 1;
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
seq,
|
|
157
|
+
factId: buildMockFactId(),
|
|
158
|
+
type,
|
|
159
|
+
entity: overrides.entity ?? `boxxy:item:${faker.string.uuid({ version: 7 })}`,
|
|
160
|
+
actor: 'boxxy:owner:local',
|
|
161
|
+
at: toInstant(overrides.at ?? 1_800_000_000_000),
|
|
162
|
+
payload: toJSONValue(payload),
|
|
163
|
+
sentAt: null,
|
|
164
|
+
parkedAt: null,
|
|
165
|
+
parkedReason: null,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function toInstant(at: number): Instant {
|
|
170
|
+
return brandSchemas.instant.parse(at);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function buildAttemptId() {
|
|
174
|
+
return brandSchemas.attemptId.parse(faker.string.uuid({ version: 7 }));
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function buildAtcSession() {
|
|
178
|
+
return brandSchemas.atcSessionId.parse(`s-${faker.string.alphanumeric(8)}`);
|
|
179
|
+
}
|