@defrex/autobuild 0.12.0 → 0.14.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/README.md +1 -1
- package/SPEC.md +138 -16
- package/bin/ab-dispatch-kernel.ts +4 -6
- package/docs/architecture.md +155 -73
- package/docs/configuration.md +41 -9
- package/docs/hosted-service.md +31 -5
- package/docs/operator-api.md +8 -1
- package/docs/remote-store-protocol.md +94 -2
- package/docs/remote-ticket-protocol.md +151 -9
- package/docs/setup.md +33 -7
- package/docs/ticket-migration.md +64 -0
- package/package.json +4 -3
- package/packages/core/src/cli/attention.ts +18 -164
- package/packages/core/src/cli/build-control.ts +23 -16
- package/packages/core/src/cli/bulk-control.ts +3 -2
- package/packages/core/src/cli/connect.ts +141 -38
- package/packages/core/src/cli/context.ts +23 -79
- package/packages/core/src/cli/dashboard/model.ts +36 -22
- package/packages/core/src/cli/dashboard/poll.ts +1 -1
- package/packages/core/src/cli/dispatch-frontend.ts +24 -67
- package/packages/core/src/cli/dispatch-process.ts +14 -7
- package/packages/core/src/cli/dispatch-repository-feed.ts +196 -0
- package/packages/core/src/cli/dispatch.ts +304 -82
- package/packages/core/src/cli/dispatcher-liveness.ts +26 -19
- package/packages/core/src/cli/harvest.ts +84 -42
- package/packages/core/src/cli/help.ts +14 -8
- package/packages/core/src/cli/historical-build-state.ts +27 -0
- package/packages/core/src/cli/installation.ts +67 -13
- package/packages/core/src/cli/main.ts +23 -5
- package/packages/core/src/cli/mcp.ts +2 -1
- package/packages/core/src/cli/pr-attachments.ts +10 -13
- package/packages/core/src/cli/pr-summary-publication.ts +27 -60
- package/packages/core/src/cli/pr-summary.ts +43 -13
- package/packages/core/src/cli/publication-settlement.ts +10 -20
- package/packages/core/src/cli/repository-status.ts +38 -2
- package/packages/core/src/cli/self-update.ts +5 -1
- package/packages/core/src/cli/status.ts +62 -32
- package/packages/core/src/cli/terminals.ts +25 -142
- package/packages/core/src/cli/ticket-assets.ts +7 -2
- package/packages/core/src/cli/ticket-editor.ts +82 -0
- package/packages/core/src/cli/ticket.ts +166 -36
- package/packages/core/src/cli/wait.ts +91 -84
- package/packages/core/src/cli/watch.ts +60 -97
- package/packages/core/src/config/pipeline-source.ts +4 -3
- package/packages/core/src/config/schema.ts +35 -3
- package/packages/core/src/connection.ts +3 -3
- package/packages/core/src/events/catalog.ts +3 -2
- package/packages/core/src/events/payloads.ts +6 -0
- package/packages/core/src/events/repository.ts +7 -3
- package/packages/core/src/integration/harness.ts +38 -4
- package/packages/core/src/kernel/__snapshots__/reducer-registry.test.ts.snap +2444 -9
- package/packages/core/src/kernel/auto-merge.ts +19 -3
- package/packages/core/src/kernel/dispatcher-liveness.ts +10 -4
- package/packages/core/src/kernel/generators/build-log.ts +1 -1
- package/packages/core/src/kernel/generators/repository-journals.ts +14 -3
- package/packages/core/src/kernel/harvest.ts +25 -23
- package/packages/core/src/kernel/incremental-fixtures.ts +13 -2
- package/packages/core/src/kernel/log-index-value.ts +38 -0
- package/packages/core/src/kernel/read-facts.ts +637 -0
- package/packages/core/src/kernel/reducer-registry.ts +139 -3
- package/packages/core/src/kernel/repository-attention.ts +179 -0
- package/packages/core/src/kernel/service-facts.ts +135 -0
- package/packages/core/src/kernel/terminal-guard.ts +133 -0
- package/packages/core/src/ontology.ts +1 -0
- package/packages/core/src/operator/annotations.ts +12 -0
- package/packages/core/src/operator/control.ts +5 -6
- package/packages/core/src/operator/index.ts +7 -0
- package/packages/core/src/operator/protocol.ts +19 -2
- package/packages/core/src/operator/query.ts +37 -20
- package/packages/core/src/operator/read-view.ts +4 -13
- package/packages/core/src/operator/registry.ts +61 -8
- package/packages/core/src/operator/requests.ts +2 -14
- package/packages/core/src/operator/sandbox.ts +10 -9
- package/packages/core/src/operator/ticket-source-backend.ts +17 -21
- package/packages/core/src/operator/tickets.ts +132 -22
- package/packages/core/src/plugin-sdk/index.ts +19 -0
- package/packages/core/src/plugins/runtimes.ts +5 -1
- package/packages/core/src/ports/runner/session-env.ts +2 -0
- package/packages/core/src/ports/tickets/contract.ts +66 -1
- package/packages/core/src/ports/tickets/create.ts +48 -12
- package/packages/core/src/ports/tickets/fake.ts +30 -1
- package/packages/core/src/ports/tickets/file-assets.ts +159 -0
- package/packages/core/src/ports/tickets/file-codec.ts +90 -0
- package/packages/core/src/ports/tickets/file.ts +114 -120
- package/packages/core/src/ports/tickets/grants.ts +47 -0
- package/packages/core/src/ports/tickets/hosted-index.ts +17 -0
- package/packages/core/src/ports/tickets/identity.ts +20 -0
- package/packages/core/src/ports/tickets/lifecycle.ts +18 -0
- package/packages/core/src/ports/tickets/linear.ts +74 -9
- package/packages/core/src/ports/tickets/migration.ts +336 -0
- package/packages/core/src/ports/tickets/operations.ts +38 -7
- package/packages/core/src/ports/tickets/portable-assets.ts +54 -0
- package/packages/core/src/ports/tickets/remote-protocol.ts +95 -0
- package/packages/core/src/ports/tickets/remote.ts +60 -3
- package/packages/core/src/ports/tickets/requested-id.ts +46 -0
- package/packages/core/src/ports/tickets/revision.ts +62 -0
- package/packages/core/src/ports/tickets/states.ts +61 -0
- package/packages/core/src/ports/types.ts +40 -3
- package/packages/core/src/ports/workspace/build-execution.ts +1 -0
- package/packages/core/src/ports/workspace/create.ts +5 -1
- package/packages/core/src/ports/workspace/operator-sandbox.ts +2 -0
- package/packages/core/src/ports/workspace/vercel-sandbox.ts +8 -4
- package/packages/core/src/processes/build-child.ts +6 -6
- package/packages/core/src/processes/build-runner.ts +62 -70
- package/packages/core/src/processes/dispatch-failure-budget.ts +5 -4
- package/packages/core/src/processes/dispatcher.ts +223 -205
- package/packages/core/src/processes/execution-no-progress.ts +176 -0
- package/packages/core/src/processes/harvest-child.ts +30 -4
- package/packages/core/src/processes/harvest-execution-state.ts +15 -9
- package/packages/core/src/processes/harvest-runner.ts +58 -74
- package/packages/core/src/processes/harvest.ts +72 -29
- package/packages/core/src/processes/infrastructure-failure-budget.ts +13 -15
- package/packages/core/src/processes/orchestrator-tick.ts +2 -2
- package/packages/core/src/processes/phase-failure-budget.ts +1 -0
- package/packages/core/src/processes/publication-loss.ts +35 -21
- package/packages/core/src/processes/repo-view.ts +229 -1099
- package/packages/core/src/processes/tick-publication.ts +110 -0
- package/packages/core/src/store/adapter.ts +23 -0
- package/packages/core/src/store/build-scope.ts +17 -0
- package/packages/core/src/store/contract.ts +283 -1
- package/packages/core/src/store/local/schema.ts +1 -0
- package/packages/core/src/store/local/store.ts +180 -55
- package/packages/core/src/store/memory.ts +119 -29
- package/packages/core/src/store/phase-session.ts +17 -0
- package/packages/core/src/store/reduced-reads.ts +239 -0
- package/packages/core/src/store/reducer-value-shapes.json +14056 -0
- package/packages/core/src/store/reducer-value-validation.ts +96 -0
- package/packages/core/src/store/reducer-values.ts +145 -0
- package/packages/core/src/store/remote/client.ts +41 -0
- package/packages/core/src/store/remote/compatibility.ts +2 -0
- package/packages/core/src/store/remote/index.ts +19 -0
- package/packages/core/src/store/remote/protocol.ts +16 -0
- package/packages/core/src/store/remote/version.ts +3 -1
- package/packages/core/src/store/repo-state-events.ts +1 -1
- package/packages/core/src/store/repo-tick.ts +72 -0
- package/packages/core/src/store/session-handle.ts +19 -0
- package/packages/core/src/store/snapshots.ts +10 -0
- package/packages/core/src/store/ticket-asset-snapshots.ts +192 -0
- package/packages/core/src/store/ticket-assets.ts +86 -8
- package/packages/core/src/store/types.ts +40 -3
- package/packages/core/src/testing/dispatch-read-budget.ts +215 -0
- package/packages/core/src/testing/index.ts +8 -0
- package/packages/core/src/testing/reduced-read-budget.ts +462 -0
- package/skills/guide/SKILL.md +97 -12
- package/skills/guide/references/operator-api.md +8 -1
- package/skills/guide/references/remote-store-protocol.md +94 -2
- package/skills/guide/references/remote-ticket-protocol.md +151 -9
- package/skills/guide/references/setup.md +33 -7
- package/skills/guide/references/ticket-migration.md +64 -0
- package/skills/tickets/SKILL.md +71 -0
- package/templates/hosted-service/package.json +2 -2
package/README.md
CHANGED
package/SPEC.md
CHANGED
|
@@ -432,6 +432,13 @@ body file leaves the pinned assets unchanged. The one case this cannot cover is
|
|
|
432
432
|
a record an older dispatcher created with an empty stream: recovery can only
|
|
433
433
|
sample the ticket's current assets for it.
|
|
434
434
|
|
|
435
|
+
For hosted tickets, exact sampled revisions are copied into immutable repository
|
|
436
|
+
artifacts in the destination build store before pins are published. Pins carry
|
|
437
|
+
explicit manifest references; bounded binary chunks preserve files and empty
|
|
438
|
+
directories without contacting the ticket service during build reads. Original
|
|
439
|
+
ticket revision numbers are preserved. Old pins without snapshot references
|
|
440
|
+
continue reading their existing ticket rows.
|
|
441
|
+
|
|
435
442
|
## 7. The build store
|
|
436
443
|
|
|
437
444
|
The v1 repo-bloat and no-observability problems share one root cause: the
|
|
@@ -450,7 +457,7 @@ builds id/slug, ticket ref, repo, branch, status (derived), created/update
|
|
|
450
457
|
lease + heartbeat (mutable liveness columns — §15.2.6, never events)
|
|
451
458
|
events build_id, seq, timestamp, actor, type, payload (JSON) — append-only
|
|
452
459
|
artifacts build_id, kind, revision, blobRef, metadata
|
|
453
|
-
repo_streams repo, created/updated, lease + heartbeat
|
|
460
|
+
repo_streams repo, created/updated, lease + heartbeat, bounded tick observation
|
|
454
461
|
repo_events repo, seq, timestamp, actor, type, payload (JSON) — append-only
|
|
455
462
|
repo_artifacts repo, kind, revision, blobRef, metadata
|
|
456
463
|
ticket_assets repo, ticket_id, kind, name, revision, layout, manifest (JSON), size,
|
|
@@ -618,15 +625,23 @@ resume or turn — no second turn, no concurrent turns, no subagents.
|
|
|
618
625
|
|
|
619
626
|
A **ticket asset** is a named, versioned bundle of files attached to a ticket —
|
|
620
627
|
a design export, a reference screenshot, a sample payload — that shapes a change
|
|
621
|
-
but belongs
|
|
622
|
-
ships) nor in the ticket tool (which build agents cannot reach). It is keyed by
|
|
628
|
+
but belongs outside the repository, where it would go stale once the change ships. It is keyed by
|
|
623
629
|
`(repo, ticketId, kind, name)` and works identically whichever ticket source is
|
|
624
630
|
configured. It is a fourth resource family beside builds, repository journals,
|
|
625
631
|
and sessions, but a deliberately thin one: no event log, because nothing here
|
|
626
632
|
needs reduction, and no retention pruning, because assets live as long as the
|
|
627
633
|
ticket's other durable data and never expire on their own.
|
|
628
634
|
|
|
629
|
-
|
|
635
|
+
Hosted ticket assets live in the ticket service's repository-keyed storage,
|
|
636
|
+
regardless of where builds run or which BuildStore is selected. File tickets use
|
|
637
|
+
native portable storage composed with legacy BuildStore attachments; Linear
|
|
638
|
+
tickets retain BuildStore storage. Existing service assets need no migration;
|
|
639
|
+
old local hosted-ticket attachments are not moved or used as a fallback.
|
|
640
|
+
|
|
641
|
+
Each put creates a new increasing **revision**; earlier revisions stay retrievable.
|
|
642
|
+
Adapters normally start at 0. Native file assets reserve revisions from
|
|
643
|
+
1,000,000,000 upward so explicit reads of old BuildStore revisions remain
|
|
644
|
+
unambiguous when native and legacy assets are composed.
|
|
630
645
|
An asset is a `file` (exactly one file) or a `tree` (a folder: its root is
|
|
631
646
|
implicit, so a tree with zero entries is a valid empty folder). The manifest is
|
|
632
647
|
a list of entries — `file` entries with size and content address, and `dir`
|
|
@@ -1071,9 +1086,9 @@ kind and operation.
|
|
|
1071
1086
|
|
|
1072
1087
|
Ticket admission uses the credential project. Hosted tickets, comments, blockers, creation-key
|
|
1073
1088
|
deduplication and assets are partitioned by registered repository, never team.
|
|
1074
|
-
Lifecycle comes from
|
|
1075
|
-
|
|
1076
|
-
|
|
1089
|
+
Lifecycle comes from independent project ticket policy (triage, ready, doing, done
|
|
1090
|
+
by default; configurable doneState). Legacy projects without independent policy
|
|
1091
|
+
use their uploaded configuration with Backlog / Doing / Done defaults. Owner admin ticket requests explicitly select a registered
|
|
1077
1092
|
repository. The service has no Linear ticket backend: external tracker and
|
|
1078
1093
|
file sources remain dispatcher-side, and service ticket surfaces refuse those
|
|
1079
1094
|
projects with actionable source feedback. Legacy team queues migrate atomically
|
|
@@ -1273,9 +1288,10 @@ implementer: ab context (findings.json now materialized) → …
|
|
|
1273
1288
|
|
|
1274
1289
|
Human/pre-build ticket grooming uses one configured-source namespace
|
|
1275
1290
|
(`ab ticket create|update|block|unblock|list|show|move`, plus the ticket-asset
|
|
1276
|
-
forms below).
|
|
1291
|
+
forms below). Migration adds `ab ticket export <dir>` and `ab ticket import <dir>`
|
|
1292
|
+
(see [Ticket source migration](#ticket-source-migration)). These commands are
|
|
1277
1293
|
sessionless, source-agnostic, and never available as a mid-build spec
|
|
1278
|
-
mutation path.
|
|
1294
|
+
mutation path. The CRUD subcommands accept `--json` and then writes exactly one
|
|
1279
1295
|
bare value: `list` emits `Ticket[]`; every other form emits the complete
|
|
1280
1296
|
created, read, or post-mutation `Ticket`. Human-readable confirmations are not
|
|
1281
1297
|
a data format and callers must not parse ids from them.
|
|
@@ -1290,8 +1306,10 @@ creates tickets directly in its ready state must therefore create a dependency
|
|
|
1290
1306
|
chain in dependency order, carrying each predecessor id into the next create,
|
|
1291
1307
|
before a later ticket can be claimed.
|
|
1292
1308
|
|
|
1293
|
-
**Ticket assets** (§7.1) attach files to a ticket
|
|
1294
|
-
|
|
1309
|
+
**Ticket assets** (§7.1) attach files to a ticket. Hosted tickets use their
|
|
1310
|
+
ticket service storage independently of the selected build store; file tickets use
|
|
1311
|
+
native storage with legacy fallback, and sources without native assets use the
|
|
1312
|
+
selected BuildStore:
|
|
1295
1313
|
|
|
1296
1314
|
- `ab ticket attach <id> <kind> <path> [--name <name>] [--store <ref>] [--json]`
|
|
1297
1315
|
stores a file or a whole folder (its relative tree preserved) as an asset.
|
|
@@ -1762,9 +1780,10 @@ event-level mechanics live in the repository catalog and reducer tests):
|
|
|
1762
1780
|
repository; an owner selects a registered repository explicitly. Team and state
|
|
1763
1781
|
fields from clients convey no authority or lifecycle policy. Tickets, comments,
|
|
1764
1782
|
blockers, creation-key deduplication and assets are isolated by repository.
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1783
|
+
Independent project ticket policy supplies hosted lifecycle names: triage, ready,
|
|
1784
|
+
doing, done (`doneState`), and create/proposal equal to triage by default. Hosted
|
|
1785
|
+
readyState defaults to ready; other sources require it. Legacy clients without
|
|
1786
|
+
independent policy use uploaded dispatcher config and its old defaults. Configured roles may overlap.
|
|
1768
1787
|
The service has no Linear backend and never relays external ticket sources.
|
|
1769
1788
|
Projects using Linear, files or plugins keep their direct dispatcher connection;
|
|
1770
1789
|
service ticket surfaces refuse with project/source feedback instead of empty data.
|
|
@@ -1780,14 +1799,16 @@ This keeps the abstraction honest: a file-based TicketSource with nowhere to
|
|
|
1780
1799
|
put blobs must be fully workable.
|
|
1781
1800
|
|
|
1782
1801
|
**Ticket assets follow the same rule.** The contents of a ticket asset (§7.1)
|
|
1783
|
-
live in the
|
|
1802
|
+
live in the ticket service for hosted tickets, independently of build storage;
|
|
1803
|
+
file sources keep portable bundles and source-local history, while sources without
|
|
1804
|
+
native assets keep them in the BuildStore. Attaching,
|
|
1784
1805
|
replacing, or removing an asset instead leaves a note on the ticket through the
|
|
1785
1806
|
existing `comment()` port — the outward projection every source, including the
|
|
1786
1807
|
plugin surface, already supports. The note names the asset, its revision, file
|
|
1787
1808
|
count, and size, and gives the `ab ticket asset get` command that fetches it, so
|
|
1788
1809
|
a person reading the ticket in Linear, the hosted service, or a local file knows
|
|
1789
1810
|
the asset exists. The note is a projection outward only; nothing reads it back,
|
|
1790
|
-
and
|
|
1811
|
+
and existing sources and plugins need no asset capability.
|
|
1791
1812
|
|
|
1792
1813
|
**Claim lifecycle.** Claim acquires nonterminal work: it returns `true` and
|
|
1793
1814
|
moves a claimable ticket to the source's claimed state. It returns `false` for
|
|
@@ -1905,6 +1926,24 @@ head (or an explicit commit) to a deterministic operator branch and a pull
|
|
|
1905
1926
|
request against the base branch and records published/publish-failed journal
|
|
1906
1927
|
facts.
|
|
1907
1928
|
|
|
1929
|
+
Successful dispatcher ticks with no effects, counters, diagnostics, queue change,
|
|
1930
|
+
or attention transition append no tick boundary events. The first queue baseline,
|
|
1931
|
+
failed ticks, meaningful ticks, diagnostic clearing, failure recovery, and the
|
|
1932
|
+
first retry after a source cooldown remain recorded. Recorded starts may arrive
|
|
1933
|
+
with completion; optional `startedAt` preserves the actual start time, falling
|
|
1934
|
+
back to envelope time for historical journals.
|
|
1935
|
+
|
|
1936
|
+
Repository tick telemetry is bounded mutable operational metadata, like leases.
|
|
1937
|
+
`beginRepoTick` persists the open boundary before unsafe work; `finishRepoTick`
|
|
1938
|
+
atomically replaces it with actual completion time and outcome and appends any
|
|
1939
|
+
validated tick boundaries. Both are fenced by the unexpired repository lease,
|
|
1940
|
+
and neither renews it. Quiet completions advance telemetry without advancing the
|
|
1941
|
+
journal. Readers refresh telemetry independently of event cursors, correlate it
|
|
1942
|
+
by run, and merge with historical completions by actual time; heartbeat never
|
|
1943
|
+
stands in for tick completion. Telemetry survives lease release. Safe shutdown
|
|
1944
|
+
uses the matching run's open observation, historical journal boundaries when
|
|
1945
|
+
absent, and refuses forced termination when the observation cannot be read.
|
|
1946
|
+
|
|
1908
1947
|
The operator's job across many concurrent builds: see status at a glance,
|
|
1909
1948
|
act on a selected build, find blocked builds, answer escalations, and inspect
|
|
1910
1949
|
any build's trail. Each dashboard build row spends its header on identity and
|
|
@@ -2230,6 +2269,21 @@ adapter never re-cuts it from a newer base (§7.4). `ab context` rehydrates
|
|
|
2230
2269
|
scratch from the store into a fresh session. Uncommitted round-2 work is lost by
|
|
2231
2270
|
design (§7.3 — phase boundaries are the resume points).
|
|
2232
2271
|
|
|
2272
|
+
The dispatcher also applies a fixed, non-configurable limit of three consecutive
|
|
2273
|
+
executions that complete normally with exit code zero and no durable build
|
|
2274
|
+
progress. Execution start/end, runner attachment and workspace lifecycle
|
|
2275
|
+
bookkeeping do not count as progress. Pipeline, session, spec, publication/PR,
|
|
2276
|
+
observation and acknowledged operator facts reset the streak; infrastructure,
|
|
2277
|
+
budget and provider failures do not consume the allowance and retain their own
|
|
2278
|
+
retry limits. Before a fourth actionable launch, the dispatcher raises one
|
|
2279
|
+
setup-targeted `execution-no-progress` policy escalation naming the count and
|
|
2280
|
+
the next action it expected the runner to take. Waiting, paused and terminal
|
|
2281
|
+
builds are left parked, and pending operator commands remain executable.
|
|
2282
|
+
Answering that escalation with guidance or a bare `ab answer <slug>` retry grants
|
|
2283
|
+
three fresh executions. The guard is derived from durable facts, including on
|
|
2284
|
+
supervisor restart, and uses the ordinary watch, dashboard and operator API
|
|
2285
|
+
attention paths.
|
|
2286
|
+
|
|
2233
2287
|
Two liveness rules complete the picture. Within one dispatcher process,
|
|
2234
2288
|
build-runner launches are single-flighted by slug through supervised process
|
|
2235
2289
|
liveness — execution completion means the complete environment has been reaped,
|
|
@@ -2781,3 +2835,71 @@ or installs releases in the foreground or background.
|
|
|
2781
2835
|
enforcement and will colocate later session-authenticated human routes.
|
|
2782
2836
|
Artifacts remain content-by-value for now; direct-to-blob references are a
|
|
2783
2837
|
possible later protocol revision, not a second current deployment path.
|
|
2838
|
+
|
|
2839
|
+
## Revision-checked ticket writes
|
|
2840
|
+
|
|
2841
|
+
Every ticket read includes an opaque `revision`. Pass it as `expectedRevision`
|
|
2842
|
+
(on MCP/operator requests) or `--expected-revision <opaque>` on `ab ticket update`,
|
|
2843
|
+
`move`, `block` and `unblock`. A stale write fails without changing anything and
|
|
2844
|
+
reports the current revision. Omission preserves unguarded behavior. Blocker
|
|
2845
|
+
checks cover the entire batch. Dispatcher moves remain unguarded and change the
|
|
2846
|
+
revision. Sources without guarded writes, including Linear, refuse supplied
|
|
2847
|
+
revisions rather than ignoring them.
|
|
2848
|
+
|
|
2849
|
+
`ab ticket edit <id>` opens `$VISUAL`, falling back to `$EDITOR`, using TOML
|
|
2850
|
+
frontmatter and a Markdown body. Only title, body and labels are editable;
|
|
2851
|
+
id, blockers, creation key and reference comments are read-only. It saves only
|
|
2852
|
+
changed fields with the opening revision. Unchanged or formatting-only edits
|
|
2853
|
+
write nothing. On conflict, invalid input or editor failure, the error names an
|
|
2854
|
+
absolute file path containing the edited text. Read the current ticket and
|
|
2855
|
+
reapply the intended changes before retrying; conflicts are never merged.
|
|
2856
|
+
|
|
2857
|
+
File and Linear revisions fingerprint title, body, canonical label/blocker sets
|
|
2858
|
+
and state; reverting identical content restores its fingerprint. File checks
|
|
2859
|
+
re-read immediately before writing, with the existing no-lock race window.
|
|
2860
|
+
Direct file edits and state-directory moves change revisions. File revisions also
|
|
2861
|
+
cover structured comments and portable attachments. Legacy file comments change
|
|
2862
|
+
the body; structured comments preserve it. Separate hosted comments do not change
|
|
2863
|
+
ticket revisions. Hosted revisions
|
|
2864
|
+
are monotonic decimal bigint strings, and checks run under the same row lock
|
|
2865
|
+
and transaction as all requested changes. Hosted reads return a coherent
|
|
2866
|
+
snapshot of fields, blockers and revision.
|
|
2867
|
+
|
|
2868
|
+
### Independent hosted ticket service
|
|
2869
|
+
|
|
2870
|
+
`[tickets] url` selects hosted ticket transport independently of BuildStore selection;
|
|
2871
|
+
without it, tickets use the selected remote build store. Local builds require an
|
|
2872
|
+
explicit ticket URL. Project registration and ticket policy publication through
|
|
2873
|
+
`ab connect --tickets URL` work before dispatch. Policy is a durable per-registration
|
|
2874
|
+
record, outside BuildStore events/artifacts; legacy uploaded configuration remains
|
|
2875
|
+
a compatibility fallback. Hosted lifecycle defaults are triage/ready/doing/done.
|
|
2876
|
+
Independent harvest uses revocable, expiring, service-bound ticket grants with
|
|
2877
|
+
read/create runner authority and read-only child authority. Build state and harvest
|
|
2878
|
+
journals remain exclusively in the selected BuildStore.
|
|
2879
|
+
|
|
2880
|
+
### Ticket source migration
|
|
2881
|
+
|
|
2882
|
+
`ab ticket export <dir>` enumerates all states through TicketSource and writes a
|
|
2883
|
+
portable file tracker atomically to an absent or empty destination.
|
|
2884
|
+
`ab ticket import <dir>` preflights the entire tracker and target inventory, then
|
|
2885
|
+
creates or adopts tickets, maps blockers, deduplicates comments by exact body and
|
|
2886
|
+
restores current attachments. Both run sessionless without forge access.
|
|
2887
|
+
|
|
2888
|
+
TicketCreateOptions includes optional `requestedId`. Unsupported sources reject
|
|
2889
|
+
it. File keeps safe ids exactly; hosted preserves canonical own-team positive
|
|
2890
|
+
numbers and advances its counter above every occupied number. Creation-key
|
|
2891
|
+
adoption precedes collision checks. Known kept-number clashes stop import before
|
|
2892
|
+
any target mutation. Stable migration identities and atomic mapping files make
|
|
2893
|
+
interrupted imports resumable without content-based adoption.
|
|
2894
|
+
|
|
2895
|
+
File frontmatter additionally supports optional structured `comments` (body,
|
|
2896
|
+
createdAt, optional author) and `attachments` (kind, name, layout, entries with
|
|
2897
|
+
file base64 bytes or directory paths). Legacy absent fields retain old behavior;
|
|
2898
|
+
new creates use structured comments. Native file assets retain historical
|
|
2899
|
+
revisions in hidden source-local metadata and compose with legacy BuildStore
|
|
2900
|
+
assets. Build claims and spec re-pins freeze native assets into durable snapshots.
|
|
2901
|
+
|
|
2902
|
+
State normalization and the complete operator procedure are documented in
|
|
2903
|
+
[Ticket migration](docs/ticket-migration.md). The same reference is delivered in
|
|
2904
|
+
the installed guide. Export keeps lifecycle membership without inferring roles;
|
|
2905
|
+
import reuses unique case-insensitive states and creates normalized missing ones.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
+
import { readDispatcherRunFacts } from '../packages/core/src/store/reduced-reads'
|
|
2
3
|
/** Private, shipped child for the interactive `ab dispatch` kernel. It owns no
|
|
3
4
|
* terminal handles; the public command launches it with immutable options. */
|
|
4
5
|
import { abDispatch } from '../packages/core/src/cli/dispatch'
|
|
@@ -61,12 +62,9 @@ try {
|
|
|
61
62
|
const opened = openStoreForRepoState(state, { env: process.env })
|
|
62
63
|
try {
|
|
63
64
|
await opened.store.ensureRepo(state.repo)
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
(event) => event.type === 'dispatcher.run-stopped' && event.payload.run === options.run,
|
|
68
|
-
)
|
|
69
|
-
) {
|
|
65
|
+
const facts = (await readDispatcherRunFacts(opened.store, state.repo, options.run, false))
|
|
66
|
+
.value
|
|
67
|
+
if (!facts.stop) {
|
|
70
68
|
await opened.store.appendRepo(state.repo, {
|
|
71
69
|
actor: DISPATCHER,
|
|
72
70
|
type: 'dispatcher.run-stopped',
|
package/docs/architecture.md
CHANGED
|
@@ -145,9 +145,9 @@ by a later advance. Each reducer publishes a `version`; bump it whenever the
|
|
|
145
145
|
accumulator shape or the fold semantics change, because a cached accumulator is
|
|
146
146
|
only valid for the version that wrote it. `kernel/reducer-registry.ts` lists
|
|
147
147
|
every reducer with its version, and its snapshot test fails when an accumulator
|
|
148
|
-
shape changes without a bump.
|
|
149
|
-
|
|
150
|
-
|
|
148
|
+
shape changes without a bump. Current-state consumers use the typed persisted
|
|
149
|
+
read helpers in `store/reduced-reads.ts`; whole-array reducers remain pure
|
|
150
|
+
reference projections for tests and explicit historical output.
|
|
151
151
|
|
|
152
152
|
**Reducer snapshots.** The `BuildStore` port can keep, per scope (one build log
|
|
153
153
|
or the repository journal) and registered reducer, that reducer's accumulator as
|
|
@@ -173,72 +173,86 @@ reads every snapshot as missing and replays (SQLSTATE `42P01` is never an
|
|
|
173
173
|
error), and an older client never asks. Run `bun run postgres:migrate` once to
|
|
174
174
|
gain the table; until then the dispatcher and every other reader replay in full.
|
|
175
175
|
|
|
176
|
-
**
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
the
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
176
|
+
**Named reducer values.** `BuildStore.getReducerValue(scope, {reducer, args?})`
|
|
177
|
+
returns `{version, cursor, value}` for each eligible entry in the executable
|
|
178
|
+
reducer registry. Eligible reducers consume build or repository events and finish
|
|
179
|
+
as plain JSON; raw journal-event lists, operator-session reducers, collections,
|
|
180
|
+
selector functions, and top-level optional results are explicitly excluded with
|
|
181
|
+
reasons. Factory arguments are validated and participate in a bounded digest
|
|
182
|
+
cache key. The persisted envelope also records the canonical scope, arguments,
|
|
183
|
+
name and version, and nested accumulator shapes are validated before restore.
|
|
184
|
+
The `value.*` namespace is reserved: public snapshot reads and writes reject it,
|
|
185
|
+
and the engine persists through private adapter hooks. Versioned cache keys
|
|
186
|
+
exclude checkpoints produced while the old namespace was publicly writable.
|
|
187
|
+
`tools/reducer-value-shapes.ts` regenerates those structural validators from the
|
|
188
|
+
declared accumulator types.
|
|
189
|
+
|
|
190
|
+
Memory, SQLite and Postgres use the same algorithm: capture the authoritative
|
|
191
|
+
high-water, load persisted state on every call, fold the indexed contiguous delta
|
|
192
|
+
through that boundary, persist, and return an independent JSON value. There is
|
|
193
|
+
no process-local accumulator cache. A foreign checkpoint newer than the initial
|
|
194
|
+
boundary causes a fresh high-water check. Normal writes are monotone; corrupt,
|
|
195
|
+
wrong-version or ahead-of-log rows are repaired only by comparing the exact row
|
|
196
|
+
observed, atomically with the log boundary. A losing writer still returns its
|
|
197
|
+
correct prefix. Missing or unreadable cache state replays; log failures propagate.
|
|
198
|
+
|
|
199
|
+
The remote adapter makes one value request; only the finished answer crosses the
|
|
200
|
+
wire. The service uses named effective-configuration references for hosted ticket
|
|
201
|
+
operations (including policy publication) and semantic build/harvest lifecycle
|
|
202
|
+
facts for delegated authentication and issuance. Lifecycle snapshots keep session,
|
|
203
|
+
execution and terminal evidence, including historical endings, without dispatcher
|
|
204
|
+
tick tails. Anchor membership follows the contiguous log prefix. The legacy
|
|
205
|
+
state-events route remains a deprecated compatibility endpoint. Public generic
|
|
206
|
+
snapshot routes remain compatible, but current consumer reads do not restore the
|
|
207
|
+
former dispatcher work bundles.
|
|
208
|
+
|
|
209
|
+
**Dispatcher repository view.** `RepoViewStore`
|
|
210
|
+
(`packages/core/src/processes/repo-view.ts`) coordinates repository metadata and
|
|
211
|
+
source promise chains. Its build and journal facts come from persisted reduced
|
|
212
|
+
values. Reads after an append or lost conditional append consult that boundary
|
|
213
|
+
again, so no process-local memo suppresses a required delta. The adapter owns
|
|
214
|
+
cache persistence and recovery; the view neither writes work bundles nor hydrates
|
|
215
|
+
whole logs for decisions. Discovery uses persisted build digests, including for
|
|
216
|
+
settled builds. Raw methods forward actual cursor event output.
|
|
217
|
+
|
|
218
|
+
JSON-safe companion projections preserve collection and optional-value contracts.
|
|
219
|
+
The build facts projection returns one prefix for engine routing; its log-index
|
|
220
|
+
rounds and finalize steps reconstruct Maps and Sets explicitly, while publication
|
|
221
|
+
selectors reconstruct from a JSON ledger. Repository facts retain configuration,
|
|
222
|
+
control, Harvest, and dispatcher run correlations. Lease metadata and clocks stay
|
|
223
|
+
outside event reducers: liveness combines durable run facts with the current
|
|
224
|
+
repository record and observation time, including an older lease holder hidden
|
|
225
|
+
by a newer run. The shared repository value keeps a bounded recent-run window, including the
|
|
226
|
+
latest started and stopped runs. Fresh invocations use those shared facts for
|
|
227
|
+
first-tick publication, liveness and supervision without creating a cold
|
|
228
|
+
parameterized cache. Older holder correlations can use `dispatcherRunFacts` for
|
|
229
|
+
the requested historical run. A never-started fresh invocation does not request
|
|
230
|
+
historical correlation. Stopped dispatcher history is not copied into every
|
|
231
|
+
current read.
|
|
232
|
+
|
|
233
|
+
**Operator and CLI reads.** Build listings and details, repository and Harvest
|
|
234
|
+
status, dispatcher decisions, operator API queries, MCP delegation and web
|
|
235
|
+
dashboard refreshes use the same typed persisted read helpers. Shared projection
|
|
236
|
+
functions render those facts; whole-array overloads remain reference oracles.
|
|
237
|
+
Operator passes are single-flight per repository, with requests arriving during a
|
|
238
|
+
pass queued for one trailing pass. Fresh readers use persisted cache rows too;
|
|
239
|
+
steady-state event-row cost depends on newly appended events at fixed build/run
|
|
240
|
+
cardinality, not on log length. Reduced collections may legitimately grow in JSON
|
|
241
|
+
size. Cache loss or corruption can replay history once to recover the same answer.
|
|
242
|
+
|
|
243
|
+
Watch and wait register from a compound persisted `buildStreamSeed` at cursor C.
|
|
244
|
+
Its build accumulator, deferral ledger and insertion-ordered historical PR
|
|
245
|
+
eligibility describe that same prefix. Ordinary polling, including the first
|
|
246
|
+
batch on an old build, reads only events after the cursor and advances that seed
|
|
247
|
+
event by event, preserving state at event N in each emitted record. Watch uses
|
|
248
|
+
historical eligibility for baseline suppression; wait retains its separate
|
|
249
|
+
current-attention registration policy. Only an explicit `--since` older than C
|
|
250
|
+
reconstructs a historical prefix once in `cli/historical-build-state.ts`.
|
|
251
|
+
Actual event listings, transcripts and cursor streams remain raw reads. The
|
|
252
|
+
interactive terminal frontend retains its independently established incremental
|
|
253
|
+
feed. `tools/persisted-reduced-reads.test.ts` scans production TypeScript calls
|
|
254
|
+
and maintains precise, reason-bearing exceptions for these boundaries and pure
|
|
255
|
+
reference projections; stale exceptions fail the check.
|
|
242
256
|
|
|
243
257
|
**Session Store authority.** `packages/core/src/cli/binary.ts` validates a complete build or
|
|
244
258
|
Harvest ambient tuple before opening its phase Store through
|
|
@@ -364,6 +378,10 @@ once. Guidance answering the policy escalation after failed-report exhaustion
|
|
|
364
378
|
instead routes to `implement` and outranks the pending report. A bare retry carries no
|
|
365
379
|
feedback.
|
|
366
380
|
|
|
381
|
+
The dispatcher launch boundary uses `processes/execution-no-progress.ts` to
|
|
382
|
+
project clean empty execution streaks through `RepoViewStore` snapshots and
|
|
383
|
+
conditionally raise an ordinary setup policy escalation before a fourth launch.
|
|
384
|
+
|
|
367
385
|
**Launch ownership.** `packages/core/src/cli/dispatch.ts` is the kernel owner and
|
|
368
386
|
single-flights supervised build executions per slug within its process. It
|
|
369
387
|
publishes effective config into the build artifact namespace, claims the exact
|
|
@@ -383,7 +401,19 @@ SIGTERM restore terminal modes immediately and begin one supervised drain;
|
|
|
383
401
|
persistent frontend and child handlers keep repeated signals graceful until the
|
|
384
402
|
kernel child is reaped, after which a non-SIGINT terminating signal is replayed
|
|
385
403
|
in the frontend. A parent-liveness watch remains the detached-kernel fallback.
|
|
386
|
-
|
|
404
|
+
The repository record carries constant-size, lease-holder-fenced tick telemetry:
|
|
405
|
+
`beginRepoTick` opens the unsafe boundary, and `finishRepoTick` atomically closes
|
|
406
|
+
it and appends selected tick facts. Successful unchanged ticks append nothing;
|
|
407
|
+
queue transitions, counters, diagnostics, attention resets/retries, and failures
|
|
408
|
+
retain their journal evidence. Buffered starts preserve actual `startedAt` for
|
|
409
|
+
attention cooldowns; old starts use their envelope time. Liveness reads refresh
|
|
410
|
+
the repository record even with an unchanged event cursor, merging matching-run
|
|
411
|
+
completion samples with journal ticks. Heartbeat renewal cannot invent progress.
|
|
412
|
+
The memory, SQLite, Postgres and remote adapters share this contract, including
|
|
413
|
+
no mutation after lease expiry and no partial publication on validation failure.
|
|
414
|
+
|
|
415
|
+
Timeout escalation is held while the matching repository tick observation is open
|
|
416
|
+
(with historical `tick-started` journal fallback when no observation exists),
|
|
387
417
|
because force-killing the ticket claim before build creation would not be
|
|
388
418
|
recoverable. After a build child claims a takeover lease, it reduces one
|
|
389
419
|
captured event prefix and appends transcriptless reclaimed `session.ended`
|
|
@@ -771,17 +801,24 @@ selected through the plugin ticket-source registry, the real filesystem and
|
|
|
771
801
|
local-git adapters, the injected Claude and Codex CLI subprocess contracts,
|
|
772
802
|
and the injected Pi CLI/RPC contract.
|
|
773
803
|
Ticket assets (SPEC §7.1.3) are files attached to a ticket and kept in the
|
|
774
|
-
|
|
804
|
+
ticket service for hosted tickets, independently of build storage, and in the
|
|
805
|
+
BuildStore for other sources. `packages/core/src/store/ticket-assets.ts`
|
|
775
806
|
holds the types, the limits, and the one validator every adapter calls;
|
|
776
807
|
`packages/core/src/cli/ticket-assets.ts` holds the filesystem walk, the download
|
|
777
808
|
writer, and the note builder; `ab ticket attach`, `asset get`, and `asset rm`
|
|
778
|
-
live in `packages/core/src/cli/ticket.ts`. The
|
|
779
|
-
|
|
809
|
+
live in `packages/core/src/cli/ticket.ts`. The optional hosted source asset
|
|
810
|
+
capability reuses RemoteBuildStore transport with the ticket URL and credential.
|
|
811
|
+
Other sources retain the existing store path.
|
|
780
812
|
A claim freezes the ticket's current assets into the build (SPEC §6.3):
|
|
781
813
|
`build.created.assets` (and, when a spec is revised from the ticket,
|
|
782
814
|
`spec.revised.assets`) record the pinned revisions, `state.pinnedAssets` in the
|
|
783
815
|
reducer projects them, `getPinnedTicketAsset` reads them back by pinned revision,
|
|
784
816
|
and `ab context` writes them under `.ab/assets/`.
|
|
817
|
+
For hosted tickets, `store/ticket-asset-snapshots.ts` copies exact revisions
|
|
818
|
+
into chunked immutable repository artifacts in the build store before pinning.
|
|
819
|
+
Reads use explicit manifest/chunk revisions without a ticket connection. Old
|
|
820
|
+
pins retain ticket-row reads; existing service attachments need no migration,
|
|
821
|
+
and attachments in old local stores are not moved.
|
|
785
822
|
|
|
786
823
|
Both `ab dispatch` and sessionless `ab ticket` load the repository's plugins
|
|
787
824
|
before selecting their TicketSource; dispatch passes that one adapter instance
|
|
@@ -938,3 +975,48 @@ the shared `connection.ts` wire types, and Postgres `connections.ts`. Approval
|
|
|
938
975
|
commits registry membership, a credential digest, and the outcome atomically.
|
|
939
976
|
The web connection routes authenticate the existing Better Auth session and
|
|
940
977
|
reuse the sign-in/consent layout; CLI polling uses a separate private capability.
|
|
978
|
+
|
|
979
|
+
## Revision-checked ticket writes
|
|
980
|
+
|
|
981
|
+
Every ticket read includes an opaque `revision`. Pass it as `expectedRevision`
|
|
982
|
+
(on MCP/operator requests) or `--expected-revision <opaque>` on `ab ticket update`,
|
|
983
|
+
`move`, `block` and `unblock`. A stale write fails without changing anything and
|
|
984
|
+
reports the current revision. Omission preserves unguarded behavior. Blocker
|
|
985
|
+
checks cover the entire batch. Dispatcher moves remain unguarded and change the
|
|
986
|
+
revision. Sources without guarded writes, including Linear, refuse supplied
|
|
987
|
+
revisions rather than ignoring them.
|
|
988
|
+
|
|
989
|
+
`ab ticket edit <id>` opens `$VISUAL`, falling back to `$EDITOR`, using TOML
|
|
990
|
+
frontmatter and a Markdown body. Only title, body and labels are editable;
|
|
991
|
+
id, blockers, creation key and reference comments are read-only. It saves only
|
|
992
|
+
changed fields with the opening revision. Unchanged or formatting-only edits
|
|
993
|
+
write nothing. On conflict, invalid input or editor failure, the error names an
|
|
994
|
+
absolute file path containing the edited text. Read the current ticket and
|
|
995
|
+
reapply the intended changes before retrying; conflicts are never merged.
|
|
996
|
+
|
|
997
|
+
File and Linear revisions fingerprint title, body, canonical label/blocker sets
|
|
998
|
+
and state; reverting identical content restores its fingerprint. File checks
|
|
999
|
+
re-read immediately before writing, with the existing no-lock race window.
|
|
1000
|
+
Direct file edits and state-directory moves change revisions. File comments
|
|
1001
|
+
change the body and revision; separate hosted comments do not. Hosted revisions
|
|
1002
|
+
are monotonic decimal bigint strings, and checks run under the same row lock
|
|
1003
|
+
and transaction as all requested changes. Hosted reads return a coherent
|
|
1004
|
+
snapshot of fields, blockers and revision.
|
|
1005
|
+
|
|
1006
|
+
### Independent hosted ticket service
|
|
1007
|
+
|
|
1008
|
+
`[tickets] url` selects hosted ticket transport independently of BuildStore selection;
|
|
1009
|
+
without it, tickets use the selected remote build store. Local builds require an
|
|
1010
|
+
explicit ticket URL. Project registration and ticket policy publication through
|
|
1011
|
+
`ab connect --tickets URL` work before dispatch. Policy is a durable per-registration
|
|
1012
|
+
record, outside BuildStore events/artifacts; legacy uploaded configuration remains
|
|
1013
|
+
a compatibility fallback. Hosted lifecycle defaults are triage/ready/doing/done.
|
|
1014
|
+
Independent harvest uses revocable, expiring, service-bound ticket grants with
|
|
1015
|
+
read/create runner authority and read-only child authority. Build state and harvest
|
|
1016
|
+
journals remain exclusively in the selected BuildStore.
|
|
1017
|
+
|
|
1018
|
+
Hosted ticket detail reads expose complete, oldest-first structured comments in
|
|
1019
|
+
`ticket.comments`, preserving exact bodies. Scans do not fetch comments. Hosted
|
|
1020
|
+
HTTP clients opt in with `x-autobuild-ticket-comments: 1` so historical strict
|
|
1021
|
+
decoders retain compatible responses. File comments remain embedded in the body;
|
|
1022
|
+
Linear comment reads are unchanged.
|