@defrex/autobuild 0.8.0
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/LICENSE +201 -0
- package/README.md +192 -0
- package/SPEC.md +2269 -0
- package/bin/ab-build-runner.ts +47 -0
- package/bin/ab-dev.ts +27 -0
- package/bin/ab-dispatch-kernel.ts +92 -0
- package/bin/ab-harvest-runner.ts +29 -0
- package/bin/ab-init-probe.ts +19 -0
- package/bin/ab-process-group-reaper.ts +32 -0
- package/bin/ab.ts +6 -0
- package/bin/agent/ab +3 -0
- package/docs/answering-blocked-builds.md +89 -0
- package/docs/architecture.md +726 -0
- package/docs/assets/headline-wide.png +0 -0
- package/docs/configuration.md +1623 -0
- package/docs/hosted-dispatcher-cutover-validation.md +178 -0
- package/docs/hosted-dispatcher.md +204 -0
- package/docs/mcp.md +119 -0
- package/docs/operator-api.md +186 -0
- package/docs/remote-store-protocol.md +972 -0
- package/docs/remote-ticket-protocol.md +79 -0
- package/docs/setup.md +289 -0
- package/docs/spec-standard.md +63 -0
- package/docs/ticket-dependencies.md +59 -0
- package/docs/vercel-sandbox-rollout-probe.md +7 -0
- package/package.json +135 -0
- package/packages/core/src/cli/args.ts +74 -0
- package/packages/core/src/cli/artifact.ts +182 -0
- package/packages/core/src/cli/binary.ts +198 -0
- package/packages/core/src/cli/build-control.ts +789 -0
- package/packages/core/src/cli/build-progress.ts +55 -0
- package/packages/core/src/cli/bulk-control.ts +385 -0
- package/packages/core/src/cli/context.ts +470 -0
- package/packages/core/src/cli/dashboard/actions.ts +59 -0
- package/packages/core/src/cli/dashboard/cells.ts +92 -0
- package/packages/core/src/cli/dashboard/composer.ts +230 -0
- package/packages/core/src/cli/dashboard/detail.ts +100 -0
- package/packages/core/src/cli/dashboard/frame-image.ts +373 -0
- package/packages/core/src/cli/dashboard/live.ts +152 -0
- package/packages/core/src/cli/dashboard/model.ts +1173 -0
- package/packages/core/src/cli/dashboard/poll.ts +196 -0
- package/packages/core/src/cli/dashboard/render.ts +1568 -0
- package/packages/core/src/cli/dashboard/selection.ts +66 -0
- package/packages/core/src/cli/dashboard/session-feed.ts +244 -0
- package/packages/core/src/cli/dashboard/session-view.ts +506 -0
- package/packages/core/src/cli/dashboard/transcript.ts +108 -0
- package/packages/core/src/cli/dev.ts +46 -0
- package/packages/core/src/cli/dispatch-frontend.ts +1045 -0
- package/packages/core/src/cli/dispatch-process.ts +259 -0
- package/packages/core/src/cli/dispatch.ts +3692 -0
- package/packages/core/src/cli/dotenv.ts +48 -0
- package/packages/core/src/cli/env.ts +206 -0
- package/packages/core/src/cli/harvest.ts +698 -0
- package/packages/core/src/cli/help.ts +713 -0
- package/packages/core/src/cli/init-agent.ts +106 -0
- package/packages/core/src/cli/init-validation.ts +583 -0
- package/packages/core/src/cli/init.ts +756 -0
- package/packages/core/src/cli/installation.ts +333 -0
- package/packages/core/src/cli/keyboard.ts +261 -0
- package/packages/core/src/cli/main.ts +1399 -0
- package/packages/core/src/cli/mcp.ts +279 -0
- package/packages/core/src/cli/models.ts +65 -0
- package/packages/core/src/cli/observe.ts +55 -0
- package/packages/core/src/cli/plugin.ts +227 -0
- package/packages/core/src/cli/pr-attachments.ts +138 -0
- package/packages/core/src/cli/pr-summary.ts +124 -0
- package/packages/core/src/cli/publication-settlement.ts +188 -0
- package/packages/core/src/cli/repo-state.ts +213 -0
- package/packages/core/src/cli/repository-status.ts +80 -0
- package/packages/core/src/cli/self-update.ts +443 -0
- package/packages/core/src/cli/status.ts +895 -0
- package/packages/core/src/cli/store-opening.contract.ts +289 -0
- package/packages/core/src/cli/store-opening.ts +167 -0
- package/packages/core/src/cli/store-ref.ts +33 -0
- package/packages/core/src/cli/terminal-restore.ts +174 -0
- package/packages/core/src/cli/terminal.ts +361 -0
- package/packages/core/src/cli/terminals.ts +995 -0
- package/packages/core/src/cli/testkit.ts +194 -0
- package/packages/core/src/cli/ticket.ts +484 -0
- package/packages/core/src/cli/upgrade-agent.ts +180 -0
- package/packages/core/src/cli/upgrade-commit.ts +468 -0
- package/packages/core/src/cli/upgrade-notice.ts +91 -0
- package/packages/core/src/cli/upgrade-progress.ts +110 -0
- package/packages/core/src/cli/upgrade.ts +888 -0
- package/packages/core/src/cli/wait.ts +587 -0
- package/packages/core/src/cli/watch.ts +932 -0
- package/packages/core/src/config/live.ts +255 -0
- package/packages/core/src/config/load.ts +98 -0
- package/packages/core/src/config/roles.ts +438 -0
- package/packages/core/src/config/schema.ts +774 -0
- package/packages/core/src/distribution.ts +24 -0
- package/packages/core/src/events/catalog.ts +201 -0
- package/packages/core/src/events/envelope.ts +59 -0
- package/packages/core/src/events/payloads.ts +618 -0
- package/packages/core/src/events/repository.ts +559 -0
- package/packages/core/src/events/sessions.ts +180 -0
- package/packages/core/src/harvest/schema.ts +147 -0
- package/packages/core/src/ids.ts +45 -0
- package/packages/core/src/integration/harness.ts +681 -0
- package/packages/core/src/kernel/auto-merge.ts +259 -0
- package/packages/core/src/kernel/converge.ts +117 -0
- package/packages/core/src/kernel/dispatch-settings.ts +60 -0
- package/packages/core/src/kernel/dispatch-status.ts +141 -0
- package/packages/core/src/kernel/engine.ts +1047 -0
- package/packages/core/src/kernel/harvest.ts +823 -0
- package/packages/core/src/kernel/origin.ts +69 -0
- package/packages/core/src/kernel/phases.ts +196 -0
- package/packages/core/src/kernel/plan-verify-selection.ts +105 -0
- package/packages/core/src/kernel/pr-attachments.ts +82 -0
- package/packages/core/src/kernel/reducer.ts +752 -0
- package/packages/core/src/kernel/stall.ts +155 -0
- package/packages/core/src/kernel/verify-applicability.ts +52 -0
- package/packages/core/src/markdown.ts +67 -0
- package/packages/core/src/ontology.ts +288 -0
- package/packages/core/src/open-map.ts +203 -0
- package/packages/core/src/operator/annotations.ts +187 -0
- package/packages/core/src/operator/client.ts +311 -0
- package/packages/core/src/operator/control.ts +117 -0
- package/packages/core/src/operator/index.ts +62 -0
- package/packages/core/src/operator/presentation.ts +22 -0
- package/packages/core/src/operator/protocol.ts +98 -0
- package/packages/core/src/operator/query.ts +201 -0
- package/packages/core/src/operator/registry.ts +1043 -0
- package/packages/core/src/operator/requests.ts +138 -0
- package/packages/core/src/operator/sandbox.ts +458 -0
- package/packages/core/src/operator/server.ts +616 -0
- package/packages/core/src/operator/sessions.ts +223 -0
- package/packages/core/src/operator/tickets.ts +177 -0
- package/packages/core/src/plugin-sdk/index.ts +174 -0
- package/packages/core/src/plugins/contract-entry.ts +74 -0
- package/packages/core/src/plugins/contract-env.ts +3 -0
- package/packages/core/src/plugins/load.ts +259 -0
- package/packages/core/src/plugins/manifest.ts +236 -0
- package/packages/core/src/plugins/registry.ts +274 -0
- package/packages/core/src/plugins/runtimes.ts +75 -0
- package/packages/core/src/ports/forge/contract.ts +258 -0
- package/packages/core/src/ports/forge/create.ts +74 -0
- package/packages/core/src/ports/forge/fake.ts +488 -0
- package/packages/core/src/ports/forge/github-pr-attachments.ts +351 -0
- package/packages/core/src/ports/forge/github-transport.ts +352 -0
- package/packages/core/src/ports/forge/github.ts +1162 -0
- package/packages/core/src/ports/forge/local-git.ts +568 -0
- package/packages/core/src/ports/runner/claude.ts +873 -0
- package/packages/core/src/ports/runner/cli-stream.ts +90 -0
- package/packages/core/src/ports/runner/codex.ts +873 -0
- package/packages/core/src/ports/runner/contract.ts +492 -0
- package/packages/core/src/ports/runner/fake.ts +213 -0
- package/packages/core/src/ports/runner/json-record.ts +2 -0
- package/packages/core/src/ports/runner/live-contract-fixture.ts +176 -0
- package/packages/core/src/ports/runner/one-shot.ts +29 -0
- package/packages/core/src/ports/runner/pi-bridge-core.ts +136 -0
- package/packages/core/src/ports/runner/pi-bridge.js +6 -0
- package/packages/core/src/ports/runner/pi-rpc.ts +454 -0
- package/packages/core/src/ports/runner/pi.ts +617 -0
- package/packages/core/src/ports/runner/production.ts +74 -0
- package/packages/core/src/ports/runner/provider-error.ts +121 -0
- package/packages/core/src/ports/runner/routing.ts +234 -0
- package/packages/core/src/ports/runner/runtime.ts +214 -0
- package/packages/core/src/ports/runner/session-env.ts +34 -0
- package/packages/core/src/ports/runner/stream-parts.ts +103 -0
- package/packages/core/src/ports/tickets/contract.ts +570 -0
- package/packages/core/src/ports/tickets/create.ts +135 -0
- package/packages/core/src/ports/tickets/fake.ts +215 -0
- package/packages/core/src/ports/tickets/file.ts +559 -0
- package/packages/core/src/ports/tickets/linear.ts +811 -0
- package/packages/core/src/ports/tickets/operations.ts +161 -0
- package/packages/core/src/ports/tickets/remote-index.ts +13 -0
- package/packages/core/src/ports/tickets/remote-protocol.ts +80 -0
- package/packages/core/src/ports/tickets/remote-server.ts +185 -0
- package/packages/core/src/ports/tickets/remote.ts +130 -0
- package/packages/core/src/ports/tickets/update.ts +51 -0
- package/packages/core/src/ports/types.ts +528 -0
- package/packages/core/src/ports/workspace/build-execution.ts +123 -0
- package/packages/core/src/ports/workspace/contract.ts +136 -0
- package/packages/core/src/ports/workspace/create.ts +132 -0
- package/packages/core/src/ports/workspace/distribution-archive.ts +317 -0
- package/packages/core/src/ports/workspace/fake.ts +432 -0
- package/packages/core/src/ports/workspace/git-worktree.ts +848 -0
- package/packages/core/src/ports/workspace/harvest-execution.ts +111 -0
- package/packages/core/src/ports/workspace/in-process-build-execution.ts +30 -0
- package/packages/core/src/ports/workspace/local-build-execution.ts +88 -0
- package/packages/core/src/ports/workspace/operator-sandbox.ts +142 -0
- package/packages/core/src/ports/workspace/phase-scratch.ts +156 -0
- package/packages/core/src/ports/workspace/vercel-sandbox.ts +2541 -0
- package/packages/core/src/processes/build-child-exit.ts +78 -0
- package/packages/core/src/processes/build-child.ts +119 -0
- package/packages/core/src/processes/build-execution-state.ts +95 -0
- package/packages/core/src/processes/build-parent-watch.ts +35 -0
- package/packages/core/src/processes/build-runner.ts +2614 -0
- package/packages/core/src/processes/dispatcher.ts +2825 -0
- package/packages/core/src/processes/execution-settlement.ts +171 -0
- package/packages/core/src/processes/harvest-child.ts +115 -0
- package/packages/core/src/processes/harvest-execution-state.ts +121 -0
- package/packages/core/src/processes/harvest-runner.ts +1656 -0
- package/packages/core/src/processes/harvest.ts +595 -0
- package/packages/core/src/processes/infrastructure-failure-budget.ts +146 -0
- package/packages/core/src/processes/phase-failure-budget.ts +52 -0
- package/packages/core/src/processes/process-group-reaper.ts +35 -0
- package/packages/core/src/processes/process-group.ts +65 -0
- package/packages/core/src/processes/publication-loss.ts +62 -0
- package/packages/core/src/processes/publication-state.ts +93 -0
- package/packages/core/src/processes/sandbox-state.ts +101 -0
- package/packages/core/src/registry.ts +24 -0
- package/packages/core/src/sessions/reducer.ts +185 -0
- package/packages/core/src/skills.ts +7 -0
- package/packages/core/src/spec-standard.ts +47 -0
- package/packages/core/src/store/adapter.ts +80 -0
- package/packages/core/src/store/build-scope.ts +272 -0
- package/packages/core/src/store/contract.ts +2581 -0
- package/packages/core/src/store/local/blobs.ts +38 -0
- package/packages/core/src/store/local/schema.ts +180 -0
- package/packages/core/src/store/local/store.ts +1713 -0
- package/packages/core/src/store/memory.ts +1138 -0
- package/packages/core/src/store/phase-session.ts +425 -0
- package/packages/core/src/store/remote/client.ts +780 -0
- package/packages/core/src/store/remote/index.ts +12 -0
- package/packages/core/src/store/remote/protocol.ts +348 -0
- package/packages/core/src/store/remote/server.ts +923 -0
- package/packages/core/src/store/remote/token.ts +137 -0
- package/packages/core/src/store/remote/version.ts +10 -0
- package/packages/core/src/store/retention.ts +91 -0
- package/packages/core/src/store/session-handle.ts +265 -0
- package/packages/core/src/store/streams/assemble.ts +79 -0
- package/packages/core/src/store/streams/lock.ts +42 -0
- package/packages/core/src/store/streams/session-writer.ts +306 -0
- package/packages/core/src/store/streams/types.ts +171 -0
- package/packages/core/src/store/streams/wait.ts +127 -0
- package/packages/core/src/store/subscribe.ts +105 -0
- package/packages/core/src/store/types.ts +466 -0
- package/packages/core/src/testing/fixed.ts +44 -0
- package/packages/core/src/testing/store-failures.ts +32 -0
- package/packages/core/src/zod-issues.ts +91 -0
- package/skills/code-review/SKILL.md +100 -0
- package/skills/finalize/SKILL.md +44 -0
- package/skills/guide/SKILL.md +1781 -0
- package/skills/guide/references/operator-api.md +164 -0
- package/skills/guide/references/plugin-authoring.md +354 -0
- package/skills/guide/references/remote-store-protocol.md +972 -0
- package/skills/guide/references/remote-ticket-protocol.md +79 -0
- package/skills/guide/references/setup.md +289 -0
- package/skills/guide/references/spec-standard.md +63 -0
- package/skills/guide/references/ticket-dependencies.md +59 -0
- package/skills/harvest/SKILL.md +66 -0
- package/skills/harvest-review/SKILL.md +63 -0
- package/skills/implement/SKILL.md +82 -0
- package/skills/plan/SKILL.md +123 -0
- package/skills/plan-review/SKILL.md +121 -0
- package/skills/reconcile/SKILL.md +65 -0
- package/skills/spec/SKILL.md +132 -0
- package/skills/tickets/SKILL.md +139 -0
- package/templates/autobuild.toml +36 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { dirname, resolve } from 'node:path'
|
|
2
|
+
import { fileURLToPath } from 'node:url'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Directory of this module. Bun exposes `import.meta.dir`; bundlers that
|
|
6
|
+
* embed the module (Next.js/Turbopack for the hosted service) provide only
|
|
7
|
+
* `import.meta.url`, so fall back to it rather than resolving from undefined
|
|
8
|
+
* at module evaluation time.
|
|
9
|
+
*/
|
|
10
|
+
function moduleDir(): string {
|
|
11
|
+
const dir = (import.meta as { dir?: unknown }).dir
|
|
12
|
+
if (typeof dir === 'string' && dir !== '') return dir
|
|
13
|
+
return dirname(fileURLToPath(import.meta.url))
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Root of the installable `autobuild` compatibility distribution. */
|
|
17
|
+
export function distributionRoot(): string {
|
|
18
|
+
return resolve(moduleDir(), '..', '..', '..')
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Resolve a path owned by the root distribution. */
|
|
22
|
+
export function distributionPath(...segments: string[]): string {
|
|
23
|
+
return resolve(distributionRoot(), ...segments)
|
|
24
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The event catalog: envelope + payload schemas + per-type actor rules, and
|
|
3
|
+
* the single validation entry point every store adapter calls at append.
|
|
4
|
+
* This is where the ontology is *enforced*, not just described (SPEC §8).
|
|
5
|
+
*/
|
|
6
|
+
import {
|
|
7
|
+
actorSchema,
|
|
8
|
+
VIA_ACTOR_RULE,
|
|
9
|
+
viaOnNonHumanActor,
|
|
10
|
+
type Actor,
|
|
11
|
+
type ActorKind,
|
|
12
|
+
} from './envelope'
|
|
13
|
+
import { eventPayloadSchemas, isEventType, type EventPayload, type EventType } from './payloads'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* A stored event: envelope (SPEC §15.1) with a known type. `seq` is per-build
|
|
17
|
+
* and monotonic, `ts` is ISO-8601; both are store-assigned on append.
|
|
18
|
+
*/
|
|
19
|
+
export interface EventEnvelope<T extends EventType = EventType> {
|
|
20
|
+
build: string
|
|
21
|
+
seq: number
|
|
22
|
+
ts: string
|
|
23
|
+
actor: Actor
|
|
24
|
+
type: T
|
|
25
|
+
payload: EventPayload<T>
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** The discriminated union over every event type — what reducers consume. */
|
|
29
|
+
export type AbEvent = { [T in EventType]: EventEnvelope<T> }[EventType]
|
|
30
|
+
|
|
31
|
+
/** What a producer submits; the store assigns `seq`/`ts` (§15.1). */
|
|
32
|
+
export interface EventWrite<T extends EventType = EventType> {
|
|
33
|
+
actor: Actor
|
|
34
|
+
type: T
|
|
35
|
+
payload: EventPayload<T>
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Which actor kinds may emit each event type — the Actor column of the
|
|
40
|
+
* catalog tables in SPEC §15.3.
|
|
41
|
+
*/
|
|
42
|
+
export const allowedActorKinds: Record<EventType, readonly ActorKind[]> = {
|
|
43
|
+
'build.created': ['dispatcher', 'human'],
|
|
44
|
+
'build.completed': ['dispatcher'],
|
|
45
|
+
'runner.attached': ['kernel'],
|
|
46
|
+
'runner.setup-failed': ['kernel'],
|
|
47
|
+
'workspace.provisioned': ['dispatcher', 'kernel'],
|
|
48
|
+
'workspace.provision-started': ['dispatcher'],
|
|
49
|
+
'workspace.released': ['dispatcher', 'kernel'],
|
|
50
|
+
'execution.started': ['dispatcher'],
|
|
51
|
+
'execution.ended': ['dispatcher'],
|
|
52
|
+
'infrastructure.failed': ['dispatcher'],
|
|
53
|
+
'infrastructure.cleanup-attempted': ['dispatcher'],
|
|
54
|
+
'publication.requested': ['agent', 'kernel'],
|
|
55
|
+
// Only the dispatcher releases workspaces and settles publications (§15.7);
|
|
56
|
+
// the kernel never destroys one, so it never records a loss.
|
|
57
|
+
'publication.lost': ['dispatcher'],
|
|
58
|
+
'abort.remote-branch-deleted': ['dispatcher'],
|
|
59
|
+
'abort.local-branch-deleted': ['dispatcher'],
|
|
60
|
+
'abort.ticket-returned': ['dispatcher'],
|
|
61
|
+
'dispatch.failed': ['dispatcher'],
|
|
62
|
+
'dispatch.comment-posted': ['dispatcher'],
|
|
63
|
+
|
|
64
|
+
'build.pause-requested': ['human'],
|
|
65
|
+
'build.resume-requested': ['human'],
|
|
66
|
+
'build.abort-requested': ['human'],
|
|
67
|
+
'build.discard-requested': ['human'],
|
|
68
|
+
'build.auto-merge-requested': ['human'],
|
|
69
|
+
'build.auto-merge-cancelled': ['human'],
|
|
70
|
+
'build.paused': ['kernel'],
|
|
71
|
+
'build.resumed': ['kernel'],
|
|
72
|
+
'build.aborted': ['kernel', 'dispatcher'],
|
|
73
|
+
|
|
74
|
+
'spec.imported': ['dispatcher'],
|
|
75
|
+
'spec.authored': ['agent'],
|
|
76
|
+
'spec.revised': ['kernel'],
|
|
77
|
+
|
|
78
|
+
'session.started': ['kernel'],
|
|
79
|
+
'session.ended': ['kernel'],
|
|
80
|
+
|
|
81
|
+
'plan.started': ['kernel'],
|
|
82
|
+
'plan.completed': ['agent'],
|
|
83
|
+
'plan-review.started': ['kernel'],
|
|
84
|
+
'plan-review.verdict': ['agent'],
|
|
85
|
+
'implement.started': ['kernel'],
|
|
86
|
+
'implement.completed': ['agent', 'dispatcher'],
|
|
87
|
+
'code-review.started': ['kernel'],
|
|
88
|
+
'code-review.verdict': ['agent'],
|
|
89
|
+
|
|
90
|
+
'verify.started': ['kernel'],
|
|
91
|
+
'verify.completed': ['kernel', 'agent'],
|
|
92
|
+
'finalize.started': ['kernel'],
|
|
93
|
+
'finalize.completed': ['kernel'],
|
|
94
|
+
'finalize.step-completed': ['kernel', 'agent'],
|
|
95
|
+
'pr-attachment.designated': ['agent'],
|
|
96
|
+
'pr-attachment.hosted': ['kernel'],
|
|
97
|
+
'pr-attachment.reclaimed': ['dispatcher'],
|
|
98
|
+
'pr-attachment.reclaim-failed': ['dispatcher'],
|
|
99
|
+
|
|
100
|
+
'pr.auto-merge-enabled': ['kernel', 'dispatcher'],
|
|
101
|
+
'pr.auto-merge-disabled': ['kernel', 'dispatcher'],
|
|
102
|
+
'pr.merged': ['dispatcher'],
|
|
103
|
+
'pr.closed': ['dispatcher'],
|
|
104
|
+
'pr.conflicted': ['dispatcher'],
|
|
105
|
+
'reconcile.progress-checked': ['kernel'],
|
|
106
|
+
'reconcile.started': ['kernel'],
|
|
107
|
+
'reconcile.completed': ['agent', 'dispatcher'],
|
|
108
|
+
|
|
109
|
+
'observation.recorded': ['kernel', 'agent'],
|
|
110
|
+
'escalation.raised': ['agent', 'kernel', 'dispatcher'],
|
|
111
|
+
// Answering an escalation is always a deliberate human act. Historical
|
|
112
|
+
// dispatcher-authored retries remain reducible because replay does not
|
|
113
|
+
// revalidate already-persisted envelopes.
|
|
114
|
+
'escalation.answered': ['human'],
|
|
115
|
+
'phase.failed': ['kernel'],
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Validation failures are agent feedback (D6): the message carries what was
|
|
120
|
+
* wrong and what would be accepted, so the in-session correction loop is
|
|
121
|
+
* immediate and cheap.
|
|
122
|
+
*/
|
|
123
|
+
export class EventValidationError extends Error {
|
|
124
|
+
constructor(
|
|
125
|
+
message: string,
|
|
126
|
+
readonly issues?: unknown,
|
|
127
|
+
) {
|
|
128
|
+
super(message)
|
|
129
|
+
this.name = 'EventValidationError'
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* The single validation gate. Every store adapter MUST pass writes through
|
|
135
|
+
* here before appending — the contract tests enforce that they do.
|
|
136
|
+
*/
|
|
137
|
+
export function validateEventWrite(input: {
|
|
138
|
+
actor: unknown
|
|
139
|
+
type: string
|
|
140
|
+
payload: unknown
|
|
141
|
+
}): EventWrite {
|
|
142
|
+
if (!isEventType(input.type)) {
|
|
143
|
+
throw new EventValidationError(
|
|
144
|
+
`unknown event type "${input.type}" — known types: ${Object.keys(eventPayloadSchemas).join(', ')}`,
|
|
145
|
+
)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (viaOnNonHumanActor(input.actor)) {
|
|
149
|
+
throw new EventValidationError(VIA_ACTOR_RULE)
|
|
150
|
+
}
|
|
151
|
+
const actorResult = actorSchema.safeParse(input.actor)
|
|
152
|
+
if (!actorResult.success) {
|
|
153
|
+
throw new EventValidationError(
|
|
154
|
+
`invalid actor for "${input.type}": ${actorResult.error.message}`,
|
|
155
|
+
actorResult.error.issues,
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
const actor = actorResult.data
|
|
159
|
+
|
|
160
|
+
const allowed = allowedActorKinds[input.type]
|
|
161
|
+
if (!allowed.includes(actor.kind)) {
|
|
162
|
+
throw new EventValidationError(
|
|
163
|
+
`actor kind "${actor.kind}" may not emit "${input.type}" (allowed: ${allowed.join(', ')})`,
|
|
164
|
+
)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const schema = eventPayloadSchemas[input.type]
|
|
168
|
+
const payloadResult = schema.safeParse(input.payload)
|
|
169
|
+
if (!payloadResult.success) {
|
|
170
|
+
throw new EventValidationError(
|
|
171
|
+
`invalid payload for "${input.type}": ${payloadResult.error.message}`,
|
|
172
|
+
payloadResult.error.issues,
|
|
173
|
+
)
|
|
174
|
+
}
|
|
175
|
+
if (input.type === 'escalation.raised') {
|
|
176
|
+
const escalation = payloadResult.data as EventPayload<'escalation.raised'>
|
|
177
|
+
if (
|
|
178
|
+
actor.kind === 'dispatcher' &&
|
|
179
|
+
(escalation.source !== 'policy' || escalation.policyCause !== 'infrastructure-failure-limit')
|
|
180
|
+
) {
|
|
181
|
+
throw new EventValidationError(
|
|
182
|
+
'invalid dispatcher escalation: only policy/infrastructure-failure-limit may be raised outside the kernel',
|
|
183
|
+
)
|
|
184
|
+
}
|
|
185
|
+
if (escalation.source === 'policy' && escalation.policyCause === undefined) {
|
|
186
|
+
throw new EventValidationError(
|
|
187
|
+
'invalid payload for "escalation.raised": source "policy" requires a recognized policyCause',
|
|
188
|
+
)
|
|
189
|
+
}
|
|
190
|
+
if (escalation.source !== 'policy' && escalation.policyCause !== undefined) {
|
|
191
|
+
throw new EventValidationError(
|
|
192
|
+
`invalid payload for "escalation.raised": policyCause is only allowed when source is "policy", not ${JSON.stringify(escalation.source)}`,
|
|
193
|
+
)
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return {
|
|
197
|
+
actor,
|
|
198
|
+
type: input.type,
|
|
199
|
+
payload: payloadResult.data,
|
|
200
|
+
} as EventWrite
|
|
201
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The event envelope (SPEC §15.1). Every event in a build's append-only log
|
|
3
|
+
* shares this shape; the store assigns `seq` and `ts` so producers can't fake
|
|
4
|
+
* ordering.
|
|
5
|
+
*/
|
|
6
|
+
import { z } from 'zod'
|
|
7
|
+
|
|
8
|
+
/** Delegated-write attribution (SPEC §15.1): when an agent acts for a person,
|
|
9
|
+
* the event still names the person as the human actor and may name the
|
|
10
|
+
* delegate, so an audit trail can distinguish "the operator did this" from
|
|
11
|
+
* "the operator's orchestrator session did this" or "an MCP client did this"
|
|
12
|
+
* forever. Only human actors may carry `via`, and only on build and
|
|
13
|
+
* repository events; session events are the delegate's own log. */
|
|
14
|
+
export const viaSchema = z.discriminatedUnion('kind', [
|
|
15
|
+
z.strictObject({ kind: z.literal('session'), id: z.string().min(1) }),
|
|
16
|
+
z.strictObject({ kind: z.literal('mcp'), client: z.string().min(1) }),
|
|
17
|
+
])
|
|
18
|
+
export type Via = z.infer<typeof viaSchema>
|
|
19
|
+
|
|
20
|
+
export const actorSchema = z.discriminatedUnion('kind', [
|
|
21
|
+
z.strictObject({ kind: z.literal('kernel') }),
|
|
22
|
+
z.strictObject({
|
|
23
|
+
kind: z.literal('agent'),
|
|
24
|
+
role: z.string().min(1),
|
|
25
|
+
session: z.string().min(1),
|
|
26
|
+
}),
|
|
27
|
+
z.strictObject({
|
|
28
|
+
kind: z.literal('human'),
|
|
29
|
+
user: z.string().min(1),
|
|
30
|
+
via: viaSchema.optional(),
|
|
31
|
+
}),
|
|
32
|
+
z.strictObject({ kind: z.literal('dispatcher') }),
|
|
33
|
+
z.strictObject({ kind: z.literal('ingester'), source: z.string().min(1) }),
|
|
34
|
+
])
|
|
35
|
+
export type Actor = z.infer<typeof actorSchema>
|
|
36
|
+
export type ActorKind = Actor['kind']
|
|
37
|
+
|
|
38
|
+
export const KERNEL: Actor = { kind: 'kernel' }
|
|
39
|
+
export const DISPATCHER: Actor = { kind: 'dispatcher' }
|
|
40
|
+
|
|
41
|
+
export function agentActor(role: string, session: string): Actor {
|
|
42
|
+
return { kind: 'agent', role, session }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function humanActor(user: string, via?: Via): Actor {
|
|
46
|
+
return via === undefined ? { kind: 'human', user } : { kind: 'human', user, via }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** The validation rule every catalog's gate names when a `via` rides on a
|
|
50
|
+
* non-human actor (the strict variants reject the key themselves, but their
|
|
51
|
+
* parse error would not say why it is forbidden). */
|
|
52
|
+
export const VIA_ACTOR_RULE = 'only human actors may carry via'
|
|
53
|
+
|
|
54
|
+
/** Raw-input check used before actor parsing: `via` on any non-human actor. */
|
|
55
|
+
export function viaOnNonHumanActor(actor: unknown): boolean {
|
|
56
|
+
if (typeof actor !== 'object' || actor === null) return false
|
|
57
|
+
const candidate = actor as { kind?: unknown; via?: unknown }
|
|
58
|
+
return candidate.kind !== 'human' && candidate.via !== undefined
|
|
59
|
+
}
|