@defrex/autobuild 0.12.0 → 0.13.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 +119 -15
- package/docs/architecture.md +59 -3
- package/docs/configuration.md +41 -9
- package/docs/hosted-service.md +31 -5
- package/docs/operator-api.md +7 -0
- package/docs/remote-store-protocol.md +10 -0
- package/docs/remote-ticket-protocol.md +151 -9
- package/docs/setup.md +33 -7
- package/docs/ticket-migration.md +64 -0
- package/package.json +3 -3
- package/packages/core/src/cli/build-control.ts +12 -1
- package/packages/core/src/cli/connect.ts +141 -38
- package/packages/core/src/cli/context.ts +7 -1
- package/packages/core/src/cli/dashboard/poll.ts +1 -1
- package/packages/core/src/cli/dispatch.ts +156 -3
- package/packages/core/src/cli/harvest.ts +13 -3
- package/packages/core/src/cli/help.ts +14 -8
- package/packages/core/src/cli/installation.ts +67 -13
- package/packages/core/src/cli/main.ts +20 -2
- package/packages/core/src/cli/mcp.ts +2 -1
- package/packages/core/src/cli/self-update.ts +5 -1
- 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 +164 -34
- 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/integration/harness.ts +37 -2
- package/packages/core/src/kernel/__snapshots__/reducer-registry.test.ts.snap +15 -0
- package/packages/core/src/kernel/generators/build-log.ts +1 -1
- package/packages/core/src/kernel/incremental-fixtures.ts +13 -2
- package/packages/core/src/kernel/reducer-registry.ts +2 -0
- package/packages/core/src/ontology.ts +1 -0
- package/packages/core/src/operator/annotations.ts +12 -0
- package/packages/core/src/operator/index.ts +5 -0
- package/packages/core/src/operator/protocol.ts +19 -2
- package/packages/core/src/operator/registry.ts +61 -8
- package/packages/core/src/operator/ticket-source-backend.ts +17 -21
- package/packages/core/src/operator/tickets.ts +130 -20
- package/packages/core/src/plugin-sdk/index.ts +6 -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/dispatcher.ts +110 -32
- 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-runner.ts +24 -4
- package/packages/core/src/processes/harvest.ts +34 -14
- package/packages/core/src/processes/phase-failure-budget.ts +1 -0
- package/packages/core/src/processes/repo-view.ts +35 -0
- package/packages/core/src/store/contract.ts +32 -1
- package/packages/core/src/store/local/store.ts +1 -1
- 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 +1 -1
- package/skills/guide/SKILL.md +91 -11
- package/skills/guide/references/operator-api.md +7 -0
- package/skills/guide/references/remote-store-protocol.md +10 -0
- 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
|
|
@@ -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
|
|
@@ -2230,6 +2251,21 @@ adapter never re-cuts it from a newer base (§7.4). `ab context` rehydrates
|
|
|
2230
2251
|
scratch from the store into a fresh session. Uncommitted round-2 work is lost by
|
|
2231
2252
|
design (§7.3 — phase boundaries are the resume points).
|
|
2232
2253
|
|
|
2254
|
+
The dispatcher also applies a fixed, non-configurable limit of three consecutive
|
|
2255
|
+
executions that complete normally with exit code zero and no durable build
|
|
2256
|
+
progress. Execution start/end, runner attachment and workspace lifecycle
|
|
2257
|
+
bookkeeping do not count as progress. Pipeline, session, spec, publication/PR,
|
|
2258
|
+
observation and acknowledged operator facts reset the streak; infrastructure,
|
|
2259
|
+
budget and provider failures do not consume the allowance and retain their own
|
|
2260
|
+
retry limits. Before a fourth actionable launch, the dispatcher raises one
|
|
2261
|
+
setup-targeted `execution-no-progress` policy escalation naming the count and
|
|
2262
|
+
the next action it expected the runner to take. Waiting, paused and terminal
|
|
2263
|
+
builds are left parked, and pending operator commands remain executable.
|
|
2264
|
+
Answering that escalation with guidance or a bare `ab answer <slug>` retry grants
|
|
2265
|
+
three fresh executions. The guard is derived from durable facts, including on
|
|
2266
|
+
supervisor restart, and uses the ordinary watch, dashboard and operator API
|
|
2267
|
+
attention paths.
|
|
2268
|
+
|
|
2233
2269
|
Two liveness rules complete the picture. Within one dispatcher process,
|
|
2234
2270
|
build-runner launches are single-flighted by slug through supervised process
|
|
2235
2271
|
liveness — execution completion means the complete environment has been reaped,
|
|
@@ -2781,3 +2817,71 @@ or installs releases in the foreground or background.
|
|
|
2781
2817
|
enforcement and will colocate later session-authenticated human routes.
|
|
2782
2818
|
Artifacts remain content-by-value for now; direct-to-blob references are a
|
|
2783
2819
|
possible later protocol revision, not a second current deployment path.
|
|
2820
|
+
|
|
2821
|
+
## Revision-checked ticket writes
|
|
2822
|
+
|
|
2823
|
+
Every ticket read includes an opaque `revision`. Pass it as `expectedRevision`
|
|
2824
|
+
(on MCP/operator requests) or `--expected-revision <opaque>` on `ab ticket update`,
|
|
2825
|
+
`move`, `block` and `unblock`. A stale write fails without changing anything and
|
|
2826
|
+
reports the current revision. Omission preserves unguarded behavior. Blocker
|
|
2827
|
+
checks cover the entire batch. Dispatcher moves remain unguarded and change the
|
|
2828
|
+
revision. Sources without guarded writes, including Linear, refuse supplied
|
|
2829
|
+
revisions rather than ignoring them.
|
|
2830
|
+
|
|
2831
|
+
`ab ticket edit <id>` opens `$VISUAL`, falling back to `$EDITOR`, using TOML
|
|
2832
|
+
frontmatter and a Markdown body. Only title, body and labels are editable;
|
|
2833
|
+
id, blockers, creation key and reference comments are read-only. It saves only
|
|
2834
|
+
changed fields with the opening revision. Unchanged or formatting-only edits
|
|
2835
|
+
write nothing. On conflict, invalid input or editor failure, the error names an
|
|
2836
|
+
absolute file path containing the edited text. Read the current ticket and
|
|
2837
|
+
reapply the intended changes before retrying; conflicts are never merged.
|
|
2838
|
+
|
|
2839
|
+
File and Linear revisions fingerprint title, body, canonical label/blocker sets
|
|
2840
|
+
and state; reverting identical content restores its fingerprint. File checks
|
|
2841
|
+
re-read immediately before writing, with the existing no-lock race window.
|
|
2842
|
+
Direct file edits and state-directory moves change revisions. File revisions also
|
|
2843
|
+
cover structured comments and portable attachments. Legacy file comments change
|
|
2844
|
+
the body; structured comments preserve it. Separate hosted comments do not change
|
|
2845
|
+
ticket revisions. Hosted revisions
|
|
2846
|
+
are monotonic decimal bigint strings, and checks run under the same row lock
|
|
2847
|
+
and transaction as all requested changes. Hosted reads return a coherent
|
|
2848
|
+
snapshot of fields, blockers and revision.
|
|
2849
|
+
|
|
2850
|
+
### Independent hosted ticket service
|
|
2851
|
+
|
|
2852
|
+
`[tickets] url` selects hosted ticket transport independently of BuildStore selection;
|
|
2853
|
+
without it, tickets use the selected remote build store. Local builds require an
|
|
2854
|
+
explicit ticket URL. Project registration and ticket policy publication through
|
|
2855
|
+
`ab connect --tickets URL` work before dispatch. Policy is a durable per-registration
|
|
2856
|
+
record, outside BuildStore events/artifacts; legacy uploaded configuration remains
|
|
2857
|
+
a compatibility fallback. Hosted lifecycle defaults are triage/ready/doing/done.
|
|
2858
|
+
Independent harvest uses revocable, expiring, service-bound ticket grants with
|
|
2859
|
+
read/create runner authority and read-only child authority. Build state and harvest
|
|
2860
|
+
journals remain exclusively in the selected BuildStore.
|
|
2861
|
+
|
|
2862
|
+
### Ticket source migration
|
|
2863
|
+
|
|
2864
|
+
`ab ticket export <dir>` enumerates all states through TicketSource and writes a
|
|
2865
|
+
portable file tracker atomically to an absent or empty destination.
|
|
2866
|
+
`ab ticket import <dir>` preflights the entire tracker and target inventory, then
|
|
2867
|
+
creates or adopts tickets, maps blockers, deduplicates comments by exact body and
|
|
2868
|
+
restores current attachments. Both run sessionless without forge access.
|
|
2869
|
+
|
|
2870
|
+
TicketCreateOptions includes optional `requestedId`. Unsupported sources reject
|
|
2871
|
+
it. File keeps safe ids exactly; hosted preserves canonical own-team positive
|
|
2872
|
+
numbers and advances its counter above every occupied number. Creation-key
|
|
2873
|
+
adoption precedes collision checks. Known kept-number clashes stop import before
|
|
2874
|
+
any target mutation. Stable migration identities and atomic mapping files make
|
|
2875
|
+
interrupted imports resumable without content-based adoption.
|
|
2876
|
+
|
|
2877
|
+
File frontmatter additionally supports optional structured `comments` (body,
|
|
2878
|
+
createdAt, optional author) and `attachments` (kind, name, layout, entries with
|
|
2879
|
+
file base64 bytes or directory paths). Legacy absent fields retain old behavior;
|
|
2880
|
+
new creates use structured comments. Native file assets retain historical
|
|
2881
|
+
revisions in hidden source-local metadata and compose with legacy BuildStore
|
|
2882
|
+
assets. Build claims and spec re-pins freeze native assets into durable snapshots.
|
|
2883
|
+
|
|
2884
|
+
State normalization and the complete operator procedure are documented in
|
|
2885
|
+
[Ticket migration](docs/ticket-migration.md). The same reference is delivered in
|
|
2886
|
+
the installed guide. Export keeps lifecycle membership without inferring roles;
|
|
2887
|
+
import reuses unique case-insensitive states and creates normalized missing ones.
|
package/docs/architecture.md
CHANGED
|
@@ -364,6 +364,10 @@ once. Guidance answering the policy escalation after failed-report exhaustion
|
|
|
364
364
|
instead routes to `implement` and outranks the pending report. A bare retry carries no
|
|
365
365
|
feedback.
|
|
366
366
|
|
|
367
|
+
The dispatcher launch boundary uses `processes/execution-no-progress.ts` to
|
|
368
|
+
project clean empty execution streaks through `RepoViewStore` snapshots and
|
|
369
|
+
conditionally raise an ordinary setup policy escalation before a fourth launch.
|
|
370
|
+
|
|
367
371
|
**Launch ownership.** `packages/core/src/cli/dispatch.ts` is the kernel owner and
|
|
368
372
|
single-flights supervised build executions per slug within its process. It
|
|
369
373
|
publishes effective config into the build artifact namespace, claims the exact
|
|
@@ -771,17 +775,24 @@ selected through the plugin ticket-source registry, the real filesystem and
|
|
|
771
775
|
local-git adapters, the injected Claude and Codex CLI subprocess contracts,
|
|
772
776
|
and the injected Pi CLI/RPC contract.
|
|
773
777
|
Ticket assets (SPEC §7.1.3) are files attached to a ticket and kept in the
|
|
774
|
-
|
|
778
|
+
ticket service for hosted tickets, independently of build storage, and in the
|
|
779
|
+
BuildStore for other sources. `packages/core/src/store/ticket-assets.ts`
|
|
775
780
|
holds the types, the limits, and the one validator every adapter calls;
|
|
776
781
|
`packages/core/src/cli/ticket-assets.ts` holds the filesystem walk, the download
|
|
777
782
|
writer, and the note builder; `ab ticket attach`, `asset get`, and `asset rm`
|
|
778
|
-
live in `packages/core/src/cli/ticket.ts`. The
|
|
779
|
-
|
|
783
|
+
live in `packages/core/src/cli/ticket.ts`. The optional hosted source asset
|
|
784
|
+
capability reuses RemoteBuildStore transport with the ticket URL and credential.
|
|
785
|
+
Other sources retain the existing store path.
|
|
780
786
|
A claim freezes the ticket's current assets into the build (SPEC §6.3):
|
|
781
787
|
`build.created.assets` (and, when a spec is revised from the ticket,
|
|
782
788
|
`spec.revised.assets`) record the pinned revisions, `state.pinnedAssets` in the
|
|
783
789
|
reducer projects them, `getPinnedTicketAsset` reads them back by pinned revision,
|
|
784
790
|
and `ab context` writes them under `.ab/assets/`.
|
|
791
|
+
For hosted tickets, `store/ticket-asset-snapshots.ts` copies exact revisions
|
|
792
|
+
into chunked immutable repository artifacts in the build store before pinning.
|
|
793
|
+
Reads use explicit manifest/chunk revisions without a ticket connection. Old
|
|
794
|
+
pins retain ticket-row reads; existing service attachments need no migration,
|
|
795
|
+
and attachments in old local stores are not moved.
|
|
785
796
|
|
|
786
797
|
Both `ab dispatch` and sessionless `ab ticket` load the repository's plugins
|
|
787
798
|
before selecting their TicketSource; dispatch passes that one adapter instance
|
|
@@ -938,3 +949,48 @@ the shared `connection.ts` wire types, and Postgres `connections.ts`. Approval
|
|
|
938
949
|
commits registry membership, a credential digest, and the outcome atomically.
|
|
939
950
|
The web connection routes authenticate the existing Better Auth session and
|
|
940
951
|
reuse the sign-in/consent layout; CLI polling uses a separate private capability.
|
|
952
|
+
|
|
953
|
+
## Revision-checked ticket writes
|
|
954
|
+
|
|
955
|
+
Every ticket read includes an opaque `revision`. Pass it as `expectedRevision`
|
|
956
|
+
(on MCP/operator requests) or `--expected-revision <opaque>` on `ab ticket update`,
|
|
957
|
+
`move`, `block` and `unblock`. A stale write fails without changing anything and
|
|
958
|
+
reports the current revision. Omission preserves unguarded behavior. Blocker
|
|
959
|
+
checks cover the entire batch. Dispatcher moves remain unguarded and change the
|
|
960
|
+
revision. Sources without guarded writes, including Linear, refuse supplied
|
|
961
|
+
revisions rather than ignoring them.
|
|
962
|
+
|
|
963
|
+
`ab ticket edit <id>` opens `$VISUAL`, falling back to `$EDITOR`, using TOML
|
|
964
|
+
frontmatter and a Markdown body. Only title, body and labels are editable;
|
|
965
|
+
id, blockers, creation key and reference comments are read-only. It saves only
|
|
966
|
+
changed fields with the opening revision. Unchanged or formatting-only edits
|
|
967
|
+
write nothing. On conflict, invalid input or editor failure, the error names an
|
|
968
|
+
absolute file path containing the edited text. Read the current ticket and
|
|
969
|
+
reapply the intended changes before retrying; conflicts are never merged.
|
|
970
|
+
|
|
971
|
+
File and Linear revisions fingerprint title, body, canonical label/blocker sets
|
|
972
|
+
and state; reverting identical content restores its fingerprint. File checks
|
|
973
|
+
re-read immediately before writing, with the existing no-lock race window.
|
|
974
|
+
Direct file edits and state-directory moves change revisions. File comments
|
|
975
|
+
change the body and revision; separate hosted comments do not. Hosted revisions
|
|
976
|
+
are monotonic decimal bigint strings, and checks run under the same row lock
|
|
977
|
+
and transaction as all requested changes. Hosted reads return a coherent
|
|
978
|
+
snapshot of fields, blockers and revision.
|
|
979
|
+
|
|
980
|
+
### Independent hosted ticket service
|
|
981
|
+
|
|
982
|
+
`[tickets] url` selects hosted ticket transport independently of BuildStore selection;
|
|
983
|
+
without it, tickets use the selected remote build store. Local builds require an
|
|
984
|
+
explicit ticket URL. Project registration and ticket policy publication through
|
|
985
|
+
`ab connect --tickets URL` work before dispatch. Policy is a durable per-registration
|
|
986
|
+
record, outside BuildStore events/artifacts; legacy uploaded configuration remains
|
|
987
|
+
a compatibility fallback. Hosted lifecycle defaults are triage/ready/doing/done.
|
|
988
|
+
Independent harvest uses revocable, expiring, service-bound ticket grants with
|
|
989
|
+
read/create runner authority and read-only child authority. Build state and harvest
|
|
990
|
+
journals remain exclusively in the selected BuildStore.
|
|
991
|
+
|
|
992
|
+
Hosted ticket detail reads expose complete, oldest-first structured comments in
|
|
993
|
+
`ticket.comments`, preserving exact bodies. Scans do not fetch comments. Hosted
|
|
994
|
+
HTTP clients opt in with `x-autobuild-ticket-comments: 1` so historical strict
|
|
995
|
+
decoders retain compatible responses. File comments remain embedded in the body;
|
|
996
|
+
Linear comment reads are unchanged.
|
package/docs/configuration.md
CHANGED
|
@@ -202,6 +202,10 @@ dashboard notice row or on plain-mode stderr, and suppresses repeats while the
|
|
|
202
202
|
same failure remains. Restoring `autobuild.toml` with valid configuration clears
|
|
203
203
|
the rejection and ordinary live reload resumes without a dispatcher restart.
|
|
204
204
|
|
|
205
|
+
Dispatcher merge readiness, startup resume, and execution recovery use the same pinned
|
|
206
|
+
commands, verify, and finalize configuration as the build runner. Missing pins retain
|
|
207
|
+
the legacy live-configuration fallback.
|
|
208
|
+
|
|
205
209
|
These fields hot-reload:
|
|
206
210
|
|
|
207
211
|
| Field or table | Boundary where a new value applies |
|
|
@@ -210,8 +214,8 @@ These fields hot-reload:
|
|
|
210
214
|
| `ticketScanIntervalSeconds` | Next tick; evaluates elapsed time against the new interval. |
|
|
211
215
|
| `capacity` | Next dispatcher tick. |
|
|
212
216
|
| `[pr]` | Next build creation. |
|
|
213
|
-
| `[commands]` | Next setup, verify check, or finalize check selected for a build whose OWN branch carries it. A base-branch reload does not retarget an in-flight build. |
|
|
214
|
-
| `[verify]` and `[finalize]` | Next engine step selection for a build whose OWN branch carries it. An approved plan's stored verify selection remains authoritative, and a base-branch reload does not retarget an in-flight build. |
|
|
217
|
+
| `[commands]` | Next setup, verify check, or finalize check selected for a build whose OWN branch carries it. Dispatcher readiness, resume, and recovery use the same pin. A base-branch reload does not retarget an in-flight build. |
|
|
218
|
+
| `[verify]` and `[finalize]` | Next engine step selection for a build whose OWN branch carries it. Dispatcher readiness, resume, and recovery use the same pin. An approved plan's stored verify selection remains authoritative, and a base-branch reload does not retarget an in-flight build. |
|
|
215
219
|
| `[workspace]` provider and config (including `provisioning`) | Next launch of a build whose OWN branch carries it. A base-branch reload never re-provisions an in-flight build. |
|
|
216
220
|
| `[roles]` | Next agent invocation for that role. Runtime, model, args, alternates, and the session budget are captured together and delivered live. |
|
|
217
221
|
| `[policy]` | Next policy, convergence, or agent-session boundary, delivered live. A running session keeps its captured budget. |
|
|
@@ -1185,6 +1189,21 @@ clears the streak. Recovery-provider workspace failures belong exclusively to
|
|
|
1185
1189
|
the infrastructure budget. Exhaustion is repaired from durable facts on restart
|
|
1186
1190
|
before further dispatch work.
|
|
1187
1191
|
|
|
1192
|
+
The dispatcher also applies a fixed, non-configurable limit of three consecutive
|
|
1193
|
+
executions that complete normally with exit code zero and no durable build
|
|
1194
|
+
progress. Execution start/end, runner attachment and workspace lifecycle
|
|
1195
|
+
bookkeeping do not count as progress. Pipeline, session, spec, publication/PR,
|
|
1196
|
+
observation and acknowledged operator facts reset the streak; infrastructure,
|
|
1197
|
+
budget and provider failures do not consume the allowance and retain their own
|
|
1198
|
+
retry limits. Before a fourth actionable launch, the dispatcher raises one
|
|
1199
|
+
setup-targeted `execution-no-progress` policy escalation naming the count and
|
|
1200
|
+
the next action it expected the runner to take. Waiting, paused and terminal
|
|
1201
|
+
builds are left parked, and pending operator commands remain executable.
|
|
1202
|
+
Answering that escalation with guidance or a bare `ab answer <slug>` retry grants
|
|
1203
|
+
three fresh executions. The guard is derived from durable facts, including on
|
|
1204
|
+
supervisor restart, and uses the ordinary watch, dashboard and operator API
|
|
1205
|
+
attention paths.
|
|
1206
|
+
|
|
1188
1207
|
For each repeat conflict, Autobuild compares the base merged by the most recent
|
|
1189
1208
|
completed reconcile with a fresh authoritative base snapshot. An advanced base
|
|
1190
1209
|
proves the attempt lost a race and permits another reconcile regardless of the
|
|
@@ -1224,21 +1243,25 @@ invariants, not additional configuration fields.
|
|
|
1224
1243
|
|
|
1225
1244
|
## `[tickets]`
|
|
1226
1245
|
|
|
1246
|
+
To move an existing project between sources, follow the
|
|
1247
|
+
[ticket migration procedure](ticket-migration.md).
|
|
1248
|
+
|
|
1227
1249
|
Required in practice: `readyState` deliberately has no default, so omitting the
|
|
1228
1250
|
table fails at `tickets.readyState` rather than allowing tickets from every
|
|
1229
|
-
state. Within a present table, `source`
|
|
1251
|
+
state. Within a present table, `source` is required; hosted tickets default `readyState` to `ready`. Other sources require it.
|
|
1230
1252
|
|
|
1231
1253
|
| Field | Default | Constraints | Purpose |
|
|
1232
1254
|
|---|---:|---|---|
|
|
1233
1255
|
| `source` | — | required nonblank builtin or plugin registration name | Select the ticket adapter after configured plugins load. |
|
|
1234
1256
|
| `readyLabels` | source-aware | optional array of nonempty strings; `[]` allowed | Require every listed label in addition to the state gate. |
|
|
1235
|
-
| `
|
|
1257
|
+
| `url` | selected build service | HTTPS service URL; HTTP allowed on loopback; no credentials, query or fragment; hosted only | Ticket service independent of [store] url and AB_STORE. Required with local builds. |
|
|
1258
|
+
| `readyState` | hosted: `"ready"` | nonblank string; required for other sources | The one workflow state eligible for dispatch. |
|
|
1236
1259
|
| `readyAssignee` | — | optional; `"me"` or an email address; Linear only (rejected for file, hosted, and plugin sources) | Require the ticket to be assigned to one Linear user, in addition to the state and label gates. |
|
|
1237
1260
|
| `teamKey` | — | required for Linear and hosted; forbidden for file; optional for plugins | Backend team key such as `"ENG"`, or an existing plugin config field. |
|
|
1238
|
-
| `claimedState` | `"In Progress"` for direct Linear; `"
|
|
1239
|
-
| `doneState` | `"
|
|
1261
|
+
| `claimedState` | `"In Progress"` for direct Linear; `"doing"` for hosted | optional nonempty string; forbidden for file; allowed for plugins | Workflow state entered when a ticket is claimed. |
|
|
1262
|
+
| `doneState` | hosted: `"done"` | optional nonblank string; hosted | Project completion state and merged-ticket transition. |
|
|
1240
1263
|
| `createState` | provider default | optional nonempty string | Default state for newly created tickets when `ab ticket create` omits `--state`. |
|
|
1241
|
-
| `triageState` | Linear
|
|
1264
|
+
| `triageState` | Linear: `"Backlog"`; hosted: `"triage"`; file/plugin: `"Triage"` | optional nonempty string | State used for spec-gate bounces, aborts, and closed-unmerged PRs. |
|
|
1242
1265
|
| `proposalState` | the resolved `triageState` | optional nonempty string | State harvest files its synthesized proposals into. Setting it to `readyState` waives the human grooming gate, not dependency eligibility. |
|
|
1243
1266
|
| `dir` | file: selected local state root's `tickets/`; plugin: omitted | optional nonempty path; forbidden for Linear; allowed for plugins | Root containing file-source state directories, or an existing plugin config field. Relative file paths resolve from the repository. |
|
|
1244
1267
|
|
|
@@ -1257,7 +1280,7 @@ When `readyLabels` is absent, direct Linear uses `["autobuild"]`; hosted, file,
|
|
|
1257
1280
|
and plugin sources use `[]`, meaning no host-imposed label gate. An explicit value always
|
|
1258
1281
|
wins. A nonempty list is
|
|
1259
1282
|
conjunctive: every configured label must be present. `readyState` remains
|
|
1260
|
-
mandatory regardless of labels. Linear compares state and label names exactly
|
|
1283
|
+
mandatory regardless of labels (hosted defaults to `ready`). Linear compares state and label names exactly
|
|
1261
1284
|
and case-sensitively. The file source matches state names case-insensitively against the directories
|
|
1262
1285
|
under the tracker root: the four lifecycle directories (`triage/`, `ready/`,
|
|
1263
1286
|
`doing/`, `done/`, always present) plus any directory the repository adds, such
|
|
@@ -1279,6 +1302,15 @@ Source-specific validation is strict:
|
|
|
1279
1302
|
- Plugin sources receive the existing fields in this table unchanged and own
|
|
1280
1303
|
any additional semantic validation. No untyped plugin-options table exists.
|
|
1281
1304
|
|
|
1305
|
+
Hosted states are durable service data scoped to a project. `ab ticket states`
|
|
1306
|
+
lists configured lifecycle roles first, then custom states alphabetically, with
|
|
1307
|
+
counts and optional purposes. `ab ticket state create <name> [--about <text>]`
|
|
1308
|
+
adds a state using the file source's lowercase name grammar. Hosted duplicates
|
|
1309
|
+
in any letter case are refused; file creation remains idempotent. Configured
|
|
1310
|
+
names always exist, preserve their spelling, and remain custom states after
|
|
1311
|
+
removal from config. Any existing state supports ticket create, move, and list;
|
|
1312
|
+
unknown names report the available states. Purposes must be one nonblank line.
|
|
1313
|
+
|
|
1282
1314
|
For Linear, omitting `createState` lets the team's default state apply. For the
|
|
1283
1315
|
file source it defaults to `Triage`. A caller may override that default for one
|
|
1284
1316
|
create with `ab ticket create --state <state>`; the value is passed unchanged to
|
|
@@ -1703,7 +1735,7 @@ Secrets and store selection accompany the file through environment variables:
|
|
|
1703
1735
|
| Variable | Used for | Notes |
|
|
1704
1736
|
|---|---|---|
|
|
1705
1737
|
| `LINEAR_API_KEY` | Direct Linear ticket source | Required and nonempty when `tickets.source = "linear"`; never used by the hosted service. |
|
|
1706
|
-
| `AB_STORE` | BuildStore and hosted ticket selection | A local path or HTTP(S) remote-store URL. `tickets
|
|
1738
|
+
| `AB_STORE` | BuildStore and hosted ticket selection | A local path or HTTP(S) remote-store URL. Hosted tickets use this only when `[tickets] url` is absent; local builds with hosted tickets require `[tickets] url`. A command's explicit `--store` wins for BuildStore selection, then nonblank `AB_STORE`, then `[store] url`, then the main checkout's `.autobuild/`. Relative local paths resolve from the main checkout. |
|
|
1707
1739
|
| `AB_TOKEN` | Protected remote BuildStore and hosted tickets | Bearer credential forwarded to the service. Hosted tickets require a stored credential for a registered project. Owner admin is an explicit break-glass exception. Empty means no token; nonempty token bytes are treated as opaque. |
|
|
1708
1740
|
|
|
1709
1741
|
A local store selection relocates the state database, blobs, worktrees, and the
|
package/docs/hosted-service.md
CHANGED
|
@@ -17,8 +17,8 @@ package's `deployment/` directory and in `templates/hosted-service/`).
|
|
|
17
17
|
"build": "ab-hosted-service-build"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@defrex/autobuild-hosted-store-service": "0.
|
|
21
|
-
"@defrex/autobuild": "0.
|
|
20
|
+
"@defrex/autobuild-hosted-store-service": "0.13.0",
|
|
21
|
+
"@defrex/autobuild": "0.13.0",
|
|
22
22
|
"next": "16.1.6",
|
|
23
23
|
"react": "19.2.4",
|
|
24
24
|
"react-dom": "19.2.4"
|
|
@@ -153,9 +153,9 @@ or manual production deployment is required.
|
|
|
153
153
|
## Hosted ticket projects and v1 migration
|
|
154
154
|
|
|
155
155
|
Hosted queues are partitioned by registered repository. Credentials select the
|
|
156
|
-
project
|
|
157
|
-
|
|
158
|
-
|
|
156
|
+
project. Independent ticket policy selects lifecycle; `ab connect --tickets URL`
|
|
157
|
+
publishes it before dispatch. Older clients retain uploaded dispatcher configuration
|
|
158
|
+
as a fallback. See the [ticket protocol](remote-ticket-protocol.md). Projects using file,
|
|
159
159
|
Linear or another external source continue to access it directly through their
|
|
160
160
|
dispatcher. Service ticket surfaces refuse those projects with source feedback.
|
|
161
161
|
The service never connects to Linear.
|
|
@@ -212,3 +212,29 @@ Missing blob configuration or denied reads stop deployment before Next builds;
|
|
|
212
212
|
diagnostics never print credentials. SQL-only fresh installs, empty-v1 upgrades
|
|
213
213
|
and already-v2 reruns do not open blob storage and keep their existing database
|
|
214
214
|
requirements. Migration reruns are idempotent.
|
|
215
|
+
|
|
216
|
+
## Local builds with hosted tickets
|
|
217
|
+
|
|
218
|
+
Hosted tickets do not require hosted builds. Set `[tickets] source = "hosted"`
|
|
219
|
+
and `teamKey = "ENG"`, then run `ab connect --tickets https://your-service.example`.
|
|
220
|
+
Approve the project in the browser. This saves a service-scoped credential and
|
|
221
|
+
`[tickets] url` while leaving `[store]` unchanged. Ticket commands work immediately,
|
|
222
|
+
before any dispatcher runs. `ab connect` reports every service and whether it serves
|
|
223
|
+
builds, tickets, or both. Use `ab disconnect --tickets` to revoke ticket access;
|
|
224
|
+
when services differ use `--builds` to select build access. Shared uses share one
|
|
225
|
+
credential, so disconnecting either shared use affects both.
|
|
226
|
+
|
|
227
|
+
Ticket URL selection is `[tickets] url`, then the selected build service (including
|
|
228
|
+
AB_STORE or a supported --store override). With local builds, `[tickets] url` is
|
|
229
|
+
required. Builds, events, artifacts, and harvest journals remain in the local store.
|
|
230
|
+
The service stores ticket records, project ticket policy, and restricted ticket
|
|
231
|
+
grants. Normal project clients synchronize current `[tickets]` policy before use;
|
|
232
|
+
failed synchronization fails the operation. Harvest grants can read and create;
|
|
233
|
+
phase grants can only read. Neither can change policy or access BuildStore routes.
|
|
234
|
+
|
|
235
|
+
New hosted policy defaults to `triage`, `ready`, `doing`, `done`, with creation and
|
|
236
|
+
harvest proposals in `triage`. Explicit state names preserve their spelling.
|
|
237
|
+
To retain earlier names configure `triageState = "Backlog"`,
|
|
238
|
+
`claimedState = "Doing"`, `doneState = "Done"`, and the desired `readyState`.
|
|
239
|
+
Existing ticket rows are never renamed. Older combined-service clients continue
|
|
240
|
+
using the uploaded dispatcher configuration until independent policy is published.
|
package/docs/operator-api.md
CHANGED
|
@@ -87,6 +87,7 @@ turn runner (a later ticket) is the only producer of turn facts.
|
|
|
87
87
|
| `GET …/harvest/status` | Harvest gate, runs, steps, recovery, and attention projection. |
|
|
88
88
|
| `GET …/builds/{slug}/artifacts/{kind}?rev=N` | Raw bytes (`application/octet-stream`) plus content-disposition and `X-Autobuild-Artifact-*` metadata headers. Omit `rev` for latest. |
|
|
89
89
|
| `GET …/tickets?state=S&label=L` | `{states,tickets,diagnostics,criteria,triageState,readyState}`. The two lifecycle names come from effective repository configuration (including provider fallback). With no `state`, `criteria.state` is `triageState`; repeated `label` parameters narrow that state with AND filters. An explicit `state` selects that exact backend workflow state. |
|
|
90
|
+
| `GET …/tickets/states` | Full state metadata `{name,tickets,about?}[]`, including empty states (`tickets.states` in MCP). |
|
|
90
91
|
| `GET …/tickets/{id}` | `{ticket,blockers,build}`. Blockers include native `exists`/`resolved` status; `build` prefers an active matching repository build, otherwise the most recently updated one. |
|
|
91
92
|
|
|
92
93
|
For artifact reads, an absent `rev` selects the latest revision. A supplied value
|
|
@@ -119,6 +120,7 @@ JSON bodies are strict: unknown fields are rejected.
|
|
|
119
120
|
| `POST …/settings/auto-merge-default/toggle` | Empty body. |
|
|
120
121
|
| `POST …/bulk-control` | `{"action":"pause"\|"resume"}`. The hold fact, intake fact, then eligible build events are written in that order. |
|
|
121
122
|
| `POST …/harvest/control` | `{"action":"toggle-gate"}` or `{"action":"run","run":"…"}`. A run action is bound to that concrete projected run. |
|
|
123
|
+
| `POST …/tickets/states` | `{name,about?}` → `{state,created}`; requires attributed operator identity (`tickets.state.create` in MCP). Hosted duplicate names are refused case-insensitively. |
|
|
122
124
|
| `POST …/tickets` | `{"title":"…","body":"…","labels"?:[],"state"?:"…","blockedBy"?:[]}`; omitted state preserves the backend default. |
|
|
123
125
|
| `PATCH …/tickets/{id}` | Any nonempty subset of `title`, `body`, and complete-replacement `labels`. Body bytes are not normalized. |
|
|
124
126
|
| `POST …/tickets/{id}/move` | `{"state":"backend state name"}`. |
|
|
@@ -284,3 +286,8 @@ even with `--since`; live and backlog matches ignore routine outcomes and
|
|
|
284
286
|
self-healing failures. A merge match uses the watch observation with
|
|
285
287
|
`condition: "attention"`. Explicit `--event` globs remain event-only.
|
|
286
288
|
Watch and wait preserve each other's cursor notification metadata.
|
|
289
|
+
|
|
290
|
+
Hosted ticket tools resolve independent project ticket policy before legacy uploaded
|
|
291
|
+
configuration. Queue, detail, state discovery and mutations work before any build
|
|
292
|
+
or dispatcher run; detail reports a null matching build. Ticket policy publication
|
|
293
|
+
never creates synthetic build or repository history.
|
|
@@ -485,6 +485,16 @@ does not apply. `{repo}` and `{id}` are percent-encoded path segments. Token
|
|
|
485
485
|
authorization requires a credential for that registered project, or owner admin.
|
|
486
486
|
The family is additive, so `REMOTE_STORE_PROTOCOL_VERSION` did not change.
|
|
487
487
|
|
|
488
|
+
Hosted ticket attachments use the ticket service's existing repository-keyed
|
|
489
|
+
asset routes with the ticket connection's URL and credential, independently
|
|
490
|
+
of the build store. Names, revisions, tombstones and service limits are
|
|
491
|
+
unchanged. Existing service attachments need no migration; old local
|
|
492
|
+
attachments are not moved or used as a fallback. A claim or ticket spec re-pin
|
|
493
|
+
copies exact revisions into immutable chunked repository artifacts in the
|
|
494
|
+
destination build store. Build pins reference explicit snapshot manifests;
|
|
495
|
+
build-scoped asset reads need no ticket credentials. Old pins without snapshot
|
|
496
|
+
references keep their existing ticket-row lookup.
|
|
497
|
+
|
|
488
498
|
A build also reads the assets it froze at its claim through its own build-scoped
|
|
489
499
|
routes, authorized against the build's actual project. The
|
|
490
500
|
server reduces the build's events to find the pinned revision, then returns that
|