@defrex/autobuild 0.11.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 +3 -1
- package/SPEC.md +335 -31
- package/docs/architecture.md +125 -7
- package/docs/configuration.md +142 -21
- package/docs/hosted-dispatcher.md +17 -2
- package/docs/hosted-service.md +240 -0
- package/docs/mcp.md +8 -2
- package/docs/operator-api.md +97 -7
- package/docs/remote-store-protocol.md +199 -144
- package/docs/remote-ticket-protocol.md +249 -19
- package/docs/setup.md +199 -16
- package/docs/ticket-dependencies.md +1 -1
- package/docs/ticket-migration.md +64 -0
- package/package.json +7 -6
- package/packages/core/src/cli/attention.ts +209 -0
- package/packages/core/src/cli/build-control.ts +12 -1
- package/packages/core/src/cli/configured-store.ts +17 -0
- package/packages/core/src/cli/connect.ts +364 -0
- package/packages/core/src/cli/context.ts +7 -1
- package/packages/core/src/cli/dashboard/model.ts +4 -5
- package/packages/core/src/cli/dashboard/poll.ts +1 -1
- package/packages/core/src/cli/dispatch.ts +336 -41
- package/packages/core/src/cli/harvest.ts +13 -3
- package/packages/core/src/cli/help.ts +51 -16
- package/packages/core/src/cli/init-validation.ts +27 -2
- package/packages/core/src/cli/installation.ts +67 -13
- package/packages/core/src/cli/main.ts +60 -16
- package/packages/core/src/cli/mcp.ts +9 -2
- package/packages/core/src/cli/pr-summary-publication.ts +220 -0
- package/packages/core/src/cli/pr-summary.ts +2 -0
- package/packages/core/src/cli/project-credentials.ts +132 -0
- package/packages/core/src/cli/repo-state.ts +15 -2
- package/packages/core/src/cli/self-update.ts +15 -1
- package/packages/core/src/cli/store-opening.ts +22 -14
- package/packages/core/src/cli/terminals.ts +0 -10
- 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 +172 -35
- package/packages/core/src/cli/upgrade-compatibility.ts +80 -0
- package/packages/core/src/cli/wait.ts +84 -17
- package/packages/core/src/cli/watch.ts +197 -60
- package/packages/core/src/config/live.ts +3 -0
- package/packages/core/src/config/schema.ts +90 -11
- package/packages/core/src/connection.ts +86 -0
- package/packages/core/src/events/catalog.ts +11 -2
- package/packages/core/src/events/payloads.ts +50 -0
- package/packages/core/src/events/repository.ts +13 -0
- package/packages/core/src/integration/harness.ts +37 -2
- package/packages/core/src/kernel/__snapshots__/reducer-registry.test.ts.snap +145 -83
- package/packages/core/src/kernel/engine.ts +24 -0
- package/packages/core/src/kernel/generators/build-log.ts +11 -1
- package/packages/core/src/kernel/incremental-fixtures.ts +13 -2
- package/packages/core/src/kernel/log-index.ts +17 -0
- package/packages/core/src/kernel/pr-summary.ts +89 -0
- package/packages/core/src/kernel/reducer-registry.ts +10 -0
- package/packages/core/src/kernel/reducer.ts +8 -0
- package/packages/core/src/ontology.ts +2 -0
- package/packages/core/src/operator/annotations.ts +12 -0
- package/packages/core/src/operator/index.ts +12 -0
- package/packages/core/src/operator/protocol.ts +19 -2
- package/packages/core/src/operator/query.ts +38 -16
- package/packages/core/src/operator/registry.ts +61 -8
- package/packages/core/src/operator/ticket-source-backend.ts +17 -20
- package/packages/core/src/operator/tickets.ts +136 -28
- package/packages/core/src/plugin-sdk/index.ts +7 -0
- package/packages/core/src/plugins/manifest.ts +5 -3
- package/packages/core/src/plugins/runtimes.ts +7 -1
- package/packages/core/src/ports/forge/fake.ts +13 -1
- package/packages/core/src/ports/forge/github-transport.ts +36 -1
- package/packages/core/src/ports/forge/github.ts +29 -5
- package/packages/core/src/ports/forge/local-git.ts +12 -4
- package/packages/core/src/ports/forge/summary-marker.ts +8 -0
- package/packages/core/src/ports/runner/session-env.ts +3 -0
- package/packages/core/src/ports/tickets/contract.ts +66 -1
- package/packages/core/src/ports/tickets/create.ts +54 -10
- 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 -3
- 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 +96 -0
- package/packages/core/src/ports/tickets/remote.ts +61 -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 +6 -1
- package/packages/core/src/ports/workspace/create.ts +15 -2
- package/packages/core/src/ports/workspace/distribution-archive.ts +3 -5
- package/packages/core/src/ports/workspace/harvest-execution.ts +3 -1
- package/packages/core/src/ports/workspace/local-build-execution.ts +8 -1
- package/packages/core/src/ports/workspace/operator-sandbox.ts +2 -0
- package/packages/core/src/ports/workspace/vercel-sandbox.ts +51 -19
- package/packages/core/src/processes/build-execution-state.ts +1 -1
- package/packages/core/src/processes/build-runner.ts +87 -26
- package/packages/core/src/processes/dispatch-failure-budget.ts +83 -0
- package/packages/core/src/processes/dispatcher.ts +168 -41
- package/packages/core/src/processes/execution-no-progress.ts +176 -0
- package/packages/core/src/processes/harvest-child.ts +31 -4
- package/packages/core/src/processes/harvest-execution-state.ts +19 -2
- package/packages/core/src/processes/harvest-runner.ts +166 -104
- package/packages/core/src/processes/harvest.ts +34 -14
- package/packages/core/src/processes/phase-failure-budget.ts +2 -0
- package/packages/core/src/processes/publication-loss.ts +18 -1
- 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/remote/client.ts +1 -1
- package/packages/core/src/store/remote/compatibility.ts +90 -0
- package/packages/core/src/store/remote/credentials.ts +28 -0
- package/packages/core/src/store/remote/index.ts +14 -1
- package/packages/core/src/store/remote/protocol.ts +25 -0
- package/packages/core/src/store/remote/token.ts +74 -13
- 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/packages/core/src/testing/index.ts +7 -0
- package/skills/guide/SKILL.md +232 -34
- package/skills/guide/references/operator-api.md +142 -13
- package/skills/guide/references/plugin-authoring.md +10 -2
- package/skills/guide/references/remote-store-protocol.md +199 -144
- package/skills/guide/references/remote-ticket-protocol.md +253 -18
- package/skills/guide/references/setup.md +199 -16
- package/skills/guide/references/ticket-dependencies.md +1 -1
- package/skills/guide/references/ticket-migration.md +64 -0
- package/skills/operate/SKILL.md +126 -36
- package/skills/tickets/SKILL.md +71 -0
- package/templates/hosted-service/package.json +13 -0
- package/templates/hosted-service/vercel.json +7 -0
|
@@ -2,22 +2,81 @@
|
|
|
2
2
|
|
|
3
3
|
The hosted ticket protocol exposes the complete `TicketSource` port without
|
|
4
4
|
exposing backend credentials. It shares the Autobuild and remote protocol
|
|
5
|
-
version headers with the remote BuildStore.
|
|
6
|
-
|
|
5
|
+
version headers with the remote BuildStore. The version must be in the
|
|
6
|
+
published service window and the protocol must
|
|
7
|
+
match its known release-line identity (`3` for 0.9, 0.10, and 0.11).
|
|
8
|
+
|
|
9
|
+
A service accepts stable clients from its own `major.minor` release line and
|
|
10
|
+
the two preceding minor lines in the same major. A major starts a new family:
|
|
11
|
+
X.0 accepts only X.0, X.1 accepts X.0/X.1, and X.2 onward accepts three lines.
|
|
12
|
+
Patch versions are interchangeable in both directions and must never change
|
|
13
|
+
the protocol. Upgrade the service first, then projects independently within
|
|
14
|
+
its window. Supported release lines retain their wire handlers and known
|
|
15
|
+
protocol identities; an unknown protocol is refused independently of version.
|
|
16
|
+
Malformed, missing, and prerelease identities are refused with HTTP 409.
|
|
17
|
+
A newer client is told to upgrade the service; a client below the window is
|
|
18
|
+
told to upgrade the project's Autobuild. Diagnostics name the service version
|
|
19
|
+
and supported range.
|
|
20
|
+
|
|
21
|
+
Unauthenticated `GET /health` publishes `ok`, `autobuildVersion`,
|
|
22
|
+
`protocolVersion`, and `supportedClientRange: { minVersion, maxVersionExclusive }`.
|
|
23
|
+
The range is inclusive at the minimum and exclusive at the maximum; a 0.11.x
|
|
24
|
+
service publishes `>=0.9.0 <0.12.0`. Health needs no credentials, version
|
|
25
|
+
headers, or available backend.
|
|
7
26
|
|
|
8
27
|
## Authentication and context
|
|
9
28
|
|
|
10
|
-
Every request is `POST /tickets/<operation>`, has `Content-Type:
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
29
|
+
Every request is `POST /tickets/<operation>`, has `Content-Type: application/json`,
|
|
30
|
+
and requires `Authorization: Bearer <project credential>`. Authentication and
|
|
31
|
+
registration checks precede body parsing and source construction. Owner admin
|
|
32
|
+
is the explicit cross-project exception; internal operator signatures have no
|
|
33
|
+
ticket authority.
|
|
34
|
+
|
|
35
|
+
Project credentials are opaque `abp_1_<id>_<secret>` bearer values bound to one
|
|
36
|
+
registered normalized repository. The service stores only a SHA-256 digest of
|
|
37
|
+
the random secret, plus project, creator, creation time, last use, expiry and
|
|
38
|
+
revocation metadata. It checks credential status and project registration on
|
|
39
|
+
every request. Revocation takes effect on the next request without affecting
|
|
40
|
+
other credentials. Unknown, expired or revoked credentials receive `401 auth`;
|
|
41
|
+
removed projects receive `403 auth` with `project not registered`.
|
|
42
|
+
|
|
43
|
+
The deployment owner runs these commands locally with database access:
|
|
16
44
|
|
|
17
45
|
```sh
|
|
18
|
-
|
|
46
|
+
ab-hosted-store credentials issue https://github.com/acme/app --user owner@example.com
|
|
47
|
+
ab-hosted-store credentials list https://github.com/acme/app
|
|
48
|
+
ab-hosted-store credentials revoke https://github.com/acme/app --id ID --user owner@example.com
|
|
19
49
|
```
|
|
20
50
|
|
|
51
|
+
Issue prints the secret once; list contains metadata only. Issue optionally
|
|
52
|
+
accepts `--ttl-seconds N` or `--expires-at ISO-8601`. For administrative/non-interactive issuance, set the returned token as
|
|
53
|
+
`AB_TOKEN`. Interactive project onboarding uses `ab connect <service-url>`;
|
|
54
|
+
it saves the credential outside the repository and commits no secret. Previous `AB_TOKEN` values and `mint operator` / `mint build` are
|
|
55
|
+
retired: the service responds that the credential format changed and points
|
|
56
|
+
to `credentials issue`. Supported old protocol shapes still work with a new
|
|
57
|
+
credential; protocol compatibility does not restore retired authentication.
|
|
58
|
+
|
|
59
|
+
`mint admin --ttl-seconds N` creates an explicit versioned, attributed owner
|
|
60
|
+
break-glass credential. It can cross project boundaries. Keep it owner-only:
|
|
61
|
+
never give it or `AB_STORE_SECRET` to a dispatcher or build agent.
|
|
62
|
+
|
|
63
|
+
Hosted tickets, comments, blockers, creation-key deduplication and assets belong
|
|
64
|
+
to exactly one registered project, even when projects use the same team key.
|
|
65
|
+
Project credentials select that repository. An optional `context.repo` selector
|
|
66
|
+
must match the credential's project; mismatches are 403. Owner admin requests
|
|
67
|
+
require this selector and registration is checked before configuration is read.
|
|
68
|
+
Internal operator credentials remain forbidden on machine ticket routes.
|
|
69
|
+
|
|
70
|
+
Hosted ticket attachments use the ticket service's existing repository-keyed
|
|
71
|
+
asset routes with the ticket connection's URL and credential, independently
|
|
72
|
+
of the build store. Names, revisions, tombstones and service limits are
|
|
73
|
+
unchanged. Existing service attachments need no migration; old local
|
|
74
|
+
attachments are not moved or used as a fallback. A claim or ticket spec re-pin
|
|
75
|
+
copies exact revisions into immutable chunked repository artifacts in the
|
|
76
|
+
destination build store. Build pins reference explicit snapshot manifests;
|
|
77
|
+
build-scoped asset reads need no ticket credentials. Old pins without snapshot
|
|
78
|
+
references keep their existing ticket-row lookup.
|
|
79
|
+
|
|
21
80
|
The strict request envelope is:
|
|
22
81
|
|
|
23
82
|
```json
|
|
@@ -31,12 +90,51 @@ The strict request envelope is:
|
|
|
31
90
|
}
|
|
32
91
|
```
|
|
33
92
|
|
|
34
|
-
`teamKey`
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
93
|
+
`teamKey` remains required for older client compatibility. It and the optional
|
|
94
|
+
`claimedState` / `createState` fields are ignored as policy inputs. The service
|
|
95
|
+
loads the project's durable independent ticket policy. Project authority publishes
|
|
96
|
+
version 1 policy through `POST /tickets/policy`, using the usual context/input
|
|
97
|
+
envelope. The input contains only `version` and `tickets`: source, teamKey,
|
|
98
|
+
readyState, triageState, claimedState, doneState, createState, proposalState and
|
|
99
|
+
optional readyLabels. URL, secrets, and pipeline configuration are rejected.
|
|
100
|
+
Only project or owner authority can publish. This does not append BuildStore
|
|
101
|
+
history. Registration removal invalidates policy and grants from that registration.
|
|
102
|
+
|
|
103
|
+
For compatibility, projects without independent policy use their latest uploaded
|
|
104
|
+
dispatcher configuration with the old `Backlog`, `Doing`, `Done` defaults.
|
|
105
|
+
New policy defaults are `triage`, `ready`, `doing`, `done`; create/proposal follow
|
|
106
|
+
triage. States are persistent project data, including empty states and optional
|
|
107
|
+
one-line purposes. Configured role names always exist; removed roles remain as
|
|
108
|
+
custom states and keep their tickets. Explicit settings preserve state spelling.
|
|
109
|
+
State lookup prefers an exact match, then a unique case-insensitive match;
|
|
110
|
+
unknown or ambiguous names are refused. Lists order configured triage, ready,
|
|
111
|
+
doing, done first (deduplicated), then other names alphabetically.
|
|
112
|
+
|
|
113
|
+
`[tickets] url` selects the ticket service independently of the build store;
|
|
114
|
+
otherwise the selected remote build store is used. A local build store requires
|
|
115
|
+
an explicit ticket URL. Credentials are resolved for that selected service.
|
|
116
|
+
`ab connect --tickets URL` registers and publishes policy before any dispatcher run.
|
|
117
|
+
|
|
118
|
+
`POST /tickets/grants` issues, renews or revokes short-lived, digest-stored ticket
|
|
119
|
+
grants. Project authority issues runner grants scoped to project and execution;
|
|
120
|
+
runners may issue only read-only phase children bound to themselves. Runner grants
|
|
121
|
+
allow read and create; phase grants allow read only. Policy, claim, moves, comments,
|
|
122
|
+
updates, blocker changes, BuildStore, and credential administration are denied.
|
|
123
|
+
AB_TICKET_URL and AB_TICKET_TOKEN carry this authority separately from AB_STORE and
|
|
124
|
+
AB_TOKEN. Revocation, expiry, parent revocation and registration changes invalidate
|
|
125
|
+
grants. Existing combined-service BuildStore delegation remains supported.
|
|
126
|
+
|
|
127
|
+
The service never contacts Linear or relays external trackers. If the project's
|
|
128
|
+
source is Linear, file or another non-hosted source, machine HTTP, operator and
|
|
129
|
+
MCP ticket surfaces refuse with a message naming that project and source: its
|
|
130
|
+
tickets live in its own source, accessed directly by its dispatcher. This is a
|
|
131
|
+
409 conflict, not an empty queue. The dispatcher's direct adapters are unchanged.
|
|
132
|
+
|
|
133
|
+
`AB_TICKET_BACKEND` and `LINEAR_API_KEY` are removed service settings. Their
|
|
134
|
+
presence (even blank or unknown values) is ignored and emits one startup removal
|
|
135
|
+
message. `AB_TICKET_TRIAGE_STATE`, `AB_TICKET_READY_STATE`,
|
|
136
|
+
`AB_TICKET_DOING_STATE` and `AB_TICKET_DONE_STATE` are removed and ignored,
|
|
137
|
+
including malformed values. These retired settings do not prevent startup.
|
|
40
138
|
|
|
41
139
|
## Operations
|
|
42
140
|
|
|
@@ -44,6 +142,8 @@ The operation names and `input` values are:
|
|
|
44
142
|
|
|
45
143
|
| Operation | Input | Successful response |
|
|
46
144
|
|---|---|---|
|
|
145
|
+
| `states` | `{}` | `{name, tickets, about?}[]`, including empty states |
|
|
146
|
+
| `add-state` | `{name, about?: string}` | `{state: {name,tickets,about?}, created: boolean}` |
|
|
47
147
|
| `list-ready` | `{labels?: string[], state?: string}` | `TicketListing` |
|
|
48
148
|
| `get` | `{id}` | `Ticket \| null` |
|
|
49
149
|
| `claim` | `{id}` | `{claimed: boolean}` |
|
|
@@ -65,6 +165,35 @@ Ticket body strings are opaque. Clients, JSON handling, the service, and the
|
|
|
65
165
|
database backend must not trim or normalize bytes, newlines, Unicode, blank
|
|
66
166
|
lines, or trailing whitespace.
|
|
67
167
|
|
|
168
|
+
## Readable ticket identity
|
|
169
|
+
|
|
170
|
+
New hosted tickets use `<teamKey>-<n>`, for example `ENG-1`. The effective
|
|
171
|
+
project configuration supplies the literal prefix; the request's `teamKey`
|
|
172
|
+
does not choose it. Numbers start at 1 in each project, increase atomically
|
|
173
|
+
across concurrent creates, and are never reused after deletion. Projects sharing
|
|
174
|
+
a team key have independent counters. Changing `teamKey` affects only future
|
|
175
|
+
ids and continues the same numbering; existing ids retain their captured prefix.
|
|
176
|
+
|
|
177
|
+
Every ticket operation, CLI command, MCP tool and blocker input accepts readable
|
|
178
|
+
ids in any letter case. Legacy storage ids (such as `ticket-<uuid>`) remain
|
|
179
|
+
aliases, including references in existing builds, harvest records and assets.
|
|
180
|
+
Current ticket and blocker output uses the canonical readable id. The exception
|
|
181
|
+
is `dependency-states`: each result's `id` echoes the requested id for correlation,
|
|
182
|
+
while its `blockedBy` edges are canonical. Raw historical events and artifacts
|
|
183
|
+
remain unchanged. These rules apply only to hosted tickets, not file or Linear ids.
|
|
184
|
+
|
|
185
|
+
Upgrade the service with its environment-aware migration command before serving
|
|
186
|
+
requests. The transactional migration preserves storage keys and assigns existing
|
|
187
|
+
tickets numbers in `(created_at, id)` order within each project. It first resolves
|
|
188
|
+
legacy team ownership, then reads each populated project's current independent
|
|
189
|
+
ticket policy. Projects without that policy use their selected effective
|
|
190
|
+
configuration through the configured blob backend. Independent-policy projects
|
|
191
|
+
need no uploaded config or blob access. Missing or invalid fallback config,
|
|
192
|
+
missing `teamKey`, or inaccessible required blobs abort the entire migration
|
|
193
|
+
unchanged with a project diagnostic. Restore that config/blob access and rerun;
|
|
194
|
+
an ownership assignment alone cannot supply a readable prefix. Empty projects
|
|
195
|
+
need no config lookup. Re-running a completed migration does not renumber tickets.
|
|
196
|
+
|
|
68
197
|
## Errors and conformance
|
|
69
198
|
|
|
70
199
|
Errors are JSON `{ "error": string, "kind": "validation" | "not-found" |
|
|
@@ -74,11 +203,112 @@ environment values, or credentials. Client 401/403 responses become
|
|
|
74
203
|
`AuthError`; other backend messages remain actionable.
|
|
75
204
|
|
|
76
205
|
The shared `TicketSource` contract is normative for the database adapter and
|
|
77
|
-
the hosted client/server pair.
|
|
78
|
-
|
|
79
|
-
|
|
206
|
+
the hosted client/server pair. PostgreSQL migration and isolation tests prove
|
|
207
|
+
project partitions. The direct Linear client retains its separate opt-in
|
|
208
|
+
GraphQL contract; no Linear adapter ships through the hosted ticket entry point.
|
|
80
209
|
|
|
81
210
|
Every ticket returned by list, get, or create requires a boolean `resolved`,
|
|
82
211
|
with the same source-native completion semantics as `DependencyState.resolved`.
|
|
83
212
|
The client preserves it when remapping ticket references. Missing or non-boolean
|
|
84
|
-
values fail wire validation. Client and service
|
|
213
|
+
values fail wire validation. Client and service follow the published compatibility window.
|
|
214
|
+
|
|
215
|
+
Legacy 0.9.x and 0.10.x ticket responses omit `resolved` and `blockersResolved`
|
|
216
|
+
because those clients use strict decoders without these fields. This projection
|
|
217
|
+
applies to list-ready, get, and create responses. Current clients retain the
|
|
218
|
+
current required resolution fields; domain and storage types are unchanged.
|
|
219
|
+
|
|
220
|
+
## Delegated execution credentials
|
|
221
|
+
|
|
222
|
+
Build and harvest runners exchange project authority for signed, project-bound
|
|
223
|
+
execution and phase credentials through `/credentials/delegate` (see the remote
|
|
224
|
+
store protocol). Build-runner and build-phase credentials cannot call any ticket
|
|
225
|
+
operation. Harvest-phase credentials permit only list-ready, get and
|
|
226
|
+
dependency-states. Harvest-runner credentials permit those reads plus create
|
|
227
|
+
for filing proposals. Claim, comment, transition, update, add-blocker and
|
|
228
|
+
remove-blocker require project or admin authority; their access is unchanged.
|
|
229
|
+
Denied delegated calls return 403 with an error naming the grant kind and
|
|
230
|
+
operation before body parsing or source construction. Lifecycle retirement and
|
|
231
|
+
project removal are also checked before parsing or source construction.
|
|
232
|
+
|
|
233
|
+
Ticket admission and assets use the authenticated project, including for
|
|
234
|
+
delegated harvest grants.
|
|
235
|
+
|
|
236
|
+
Custom state creation uses `/^[a-z][a-z0-9-]{0,39}$/`; an optional purpose must
|
|
237
|
+
be one nonblank line. A duplicate in any letter case is refused without
|
|
238
|
+
changing purpose. `add-state` requires project or owner machine authority;
|
|
239
|
+
ticket grants and harvest delegations can read states but cannot create them.
|
|
240
|
+
Request context cannot supply lifecycle policy or insert another project's
|
|
241
|
+
states. These operations use the existing wire version and strict envelopes.
|
|
242
|
+
|
|
243
|
+
## Revision-checked ticket writes
|
|
244
|
+
|
|
245
|
+
Every ticket read includes an opaque `revision`. Pass it as `expectedRevision`
|
|
246
|
+
(on MCP/operator requests) or `--expected-revision <opaque>` on `ab ticket update`,
|
|
247
|
+
`move`, `block` and `unblock`. A stale write fails without changing anything and
|
|
248
|
+
reports the current revision. Omission preserves unguarded behavior. Blocker
|
|
249
|
+
checks cover the entire batch. Dispatcher moves remain unguarded and change the
|
|
250
|
+
revision. Sources without guarded writes, including Linear, refuse supplied
|
|
251
|
+
revisions rather than ignoring them.
|
|
252
|
+
|
|
253
|
+
`ab ticket edit <id>` opens `$VISUAL`, falling back to `$EDITOR`, using TOML
|
|
254
|
+
frontmatter and a Markdown body. Only title, body and labels are editable;
|
|
255
|
+
id, blockers, creation key and reference comments are read-only. It saves only
|
|
256
|
+
changed fields with the opening revision. Unchanged or formatting-only edits
|
|
257
|
+
write nothing. On conflict, invalid input or editor failure, the error names an
|
|
258
|
+
absolute file path containing the edited text. Read the current ticket and
|
|
259
|
+
reapply the intended changes before retrying; conflicts are never merged.
|
|
260
|
+
|
|
261
|
+
File and Linear revisions fingerprint title, body, canonical label/blocker sets
|
|
262
|
+
and state; reverting identical content restores its fingerprint. File checks
|
|
263
|
+
re-read immediately before writing, with the existing no-lock race window.
|
|
264
|
+
Direct file edits and state-directory moves change revisions. File revisions also
|
|
265
|
+
cover structured comments and portable attachments. Legacy file comments change
|
|
266
|
+
the body; structured comments preserve it. Separate hosted comments do not change
|
|
267
|
+
ticket revisions. Hosted revisions
|
|
268
|
+
are monotonic decimal bigint strings, and checks run under the same row lock
|
|
269
|
+
and transaction as all requested changes. Hosted reads return a coherent
|
|
270
|
+
snapshot of fields, blockers and revision.
|
|
271
|
+
|
|
272
|
+
### Guarded mutation transport
|
|
273
|
+
|
|
274
|
+
`POST /tickets/mutate-if-revision` accepts the usual authenticated context and
|
|
275
|
+
`input: { id, expectedRevision, mutation }`. Mutation is one of
|
|
276
|
+
`{ kind: "update", patch: { title?, body?, labels? } }`,
|
|
277
|
+
`{ kind: "transition", state }`, or
|
|
278
|
+
`{ kind: "blockers", operation: "block" | "unblock", ids: string[] }`.
|
|
279
|
+
Unknown keys and empty patches are refused. Success returns `{ ok: true }`.
|
|
280
|
+
A revision conflict returns HTTP 409 with `kind: "conflict"`, `error`, `id`,
|
|
281
|
+
`expectedRevision` and `currentRevision`. Delegated credentials retain existing
|
|
282
|
+
permissions: none of the guarded mutation variants grants additional access.
|
|
283
|
+
Ticket responses include `revision` only when the request advertises
|
|
284
|
+
`x-autobuild-ticket-revisions: 1`. The current hosted client sends this header
|
|
285
|
+
on every request and requires revision-bearing responses. Released clients
|
|
286
|
+
through 0.12.x omit the header and retain their strict decoder's original
|
|
287
|
+
response shape on get, list-ready and create. This explicit capability also
|
|
288
|
+
supports new source checkouts that still report version 0.12.0; version alone
|
|
289
|
+
cannot distinguish them from released clients. Unknown capability values do
|
|
290
|
+
not opt in. Clients before 0.11 also omit the existing resolution projections.
|
|
291
|
+
The capability does not change authentication, authorization or the remote
|
|
292
|
+
BuildStore protocol version.
|
|
293
|
+
|
|
294
|
+
## Requested ids for migration
|
|
295
|
+
|
|
296
|
+
Create options accept optional `requestedId: string` alongside `state` and
|
|
297
|
+
`idempotencyKey`. Older clients omit it and responses are unchanged. Unsupported
|
|
298
|
+
sources reject supplied ids; Linear is not an import target. File sources keep
|
|
299
|
+
filesystem-safe ids exactly and never overwrite an occupied id.
|
|
300
|
+
|
|
301
|
+
Hosted sources preserve only literal own-team `<teamKey>-<n>` ids, where `n` is a
|
|
302
|
+
positive canonical decimal within PostgreSQL bigint bounds. For example,
|
|
303
|
+
`AUT-706` in team `AUT` keeps 706; `OTHER-706`, `AUT-01` and `AUT-0` use ordinary
|
|
304
|
+
allocation. Overflow canonical numbers are rejected. A matching creation key is
|
|
305
|
+
adopted before occupancy checks. A kept number belonging to a different ticket
|
|
306
|
+
fails without replacing it. Creation and counter advancement share the existing
|
|
307
|
+
project transaction and counter lock. Later automatic numbers exceed both the
|
|
308
|
+
counter and highest occupied number; importing a lower number never lowers the
|
|
309
|
+
counter. Requested ids require project or owner authority. Ticket grants and
|
|
310
|
+
delegated credentials receive 403 for create options containing `requestedId`,
|
|
311
|
+
before source construction. Their ordinary create grants remain unchanged.
|
|
312
|
+
|
|
313
|
+
See the [migration procedure](ticket-migration.md) for preflight, state mapping,
|
|
314
|
+
resumption and portable file records.
|
package/docs/setup.md
CHANGED
|
@@ -28,7 +28,7 @@ maintainer before selecting it:
|
|
|
28
28
|
- a dispatcher-side push-capable `GITHUB_TOKEN` or `GH_TOKEN`;
|
|
29
29
|
- for a private repository, a separate read-only clone identity named by
|
|
30
30
|
`gitUsernameEnv` and `gitPasswordEnv`;
|
|
31
|
-
- an HTTPS hosted
|
|
31
|
+
- an HTTPS hosted service reachable from Vercel, configured through `ab connect <url>`;
|
|
32
32
|
- each selected role and alternate's runtime/model, its pinned
|
|
33
33
|
`[workspace.config.runtimeProvisioning.<runtime>]` commands, and the API
|
|
34
34
|
credential names it needs in `[workspace.config].environmentVariables`.
|
|
@@ -177,7 +177,7 @@ ab dispatch --repository https://github.com/owner/repository \\
|
|
|
177
177
|
```
|
|
178
178
|
|
|
179
179
|
`--repository` (or `AB_REPOSITORY`) is the normalized origin. Origin mode
|
|
180
|
-
requires an HTTPS `
|
|
180
|
+
requires an HTTPS service selected through `[store] url` or `AB_STORE`, a saved project credential or `AB_TOKEN`, an exported `GITHUB_TOKEN` or
|
|
181
181
|
`GH_TOKEN`, and `forge = "github"`; the interactive dashboard is unavailable
|
|
182
182
|
(`--plain` or no TTY). Origin mode never consults the gh CLI: a checkout-less
|
|
183
183
|
host has no gh and no keyring, and the only workspace provider it can run,
|
|
@@ -208,17 +208,34 @@ sources agree with the running system by construction:
|
|
|
208
208
|
**running dispatcher's version** (read from the deployed distribution's
|
|
209
209
|
`package.json`), so the guest runs the dispatcher's own release.
|
|
210
210
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
211
|
+
A service accepts stable clients from its own `major.minor` release line and
|
|
212
|
+
the two preceding minor lines in the same major. A major starts a new family:
|
|
213
|
+
X.0 accepts only X.0, X.1 accepts X.0/X.1, and X.2 onward accepts three lines.
|
|
214
|
+
Patch versions are interchangeable in both directions and must never change
|
|
215
|
+
the protocol. Upgrade the service first, then projects independently within
|
|
216
|
+
its window. Supported release lines retain their wire handlers and known
|
|
217
|
+
protocol identities; an unknown protocol is refused independently of version.
|
|
218
|
+
Malformed, missing, and prerelease identities are refused with HTTP 409.
|
|
219
|
+
A newer client is told to upgrade the service; a client below the window is
|
|
220
|
+
told to upgrade the project's Autobuild. Diagnostics name the service version
|
|
221
|
+
and supported range.
|
|
222
|
+
|
|
223
|
+
Unauthenticated `GET /health` publishes `ok`, `autobuildVersion`,
|
|
224
|
+
`protocolVersion`, and `supportedClientRange: { minVersion, maxVersionExclusive }`.
|
|
225
|
+
The range is inclusive at the minimum and exclusive at the maximum; a 0.11.x
|
|
226
|
+
service publishes `>=0.9.0 <0.12.0`. Health needs no credentials, version
|
|
227
|
+
headers, or available backend.
|
|
228
|
+
|
|
229
|
+
`ab upgrade` probes this public range before installation or project changes.
|
|
230
|
+
It warns and continues when the target is outside the range, naming the
|
|
231
|
+
required service upgrade for a newer target or a compatible project range for
|
|
232
|
+
an older one. An unavailable or malformed probe warns that connectivity may
|
|
233
|
+
fail after upgrade. Legacy health without a range means exact-version matching;
|
|
234
|
+
upgrade that service to the compatibility-window release first.
|
|
235
|
+
|
|
236
|
+
A distribution fix reaches origin-mode guests after a release is cut and the
|
|
237
|
+
dispatcher is upgraded. Guests continue to run the dispatcher's own version;
|
|
238
|
+
the hosted service must support that release line.
|
|
222
239
|
|
|
223
240
|
Provisioning records the installed distribution's identity — package version
|
|
224
241
|
and remote-store protocol version — in the guest's
|
|
@@ -229,10 +246,10 @@ against the identity the current system would deliver and, when they disagree
|
|
|
229
246
|
(which includes every guest provisioned before the marker existed), refreshes
|
|
230
247
|
it in place (archive re-fetched, extracted, and production-installed) first,
|
|
231
248
|
so an upgraded dispatcher retrofits its existing guests instead of resuming a
|
|
232
|
-
stale distribution
|
|
249
|
+
stale distribution. A refresh failure deletes
|
|
233
250
|
the sandbox so the next provisioning pass rematerializes it from scratch.
|
|
234
251
|
|
|
235
|
-
After a
|
|
252
|
+
After a dispatcher upgrade, confirm a fix-bearing guest from the guest
|
|
236
253
|
perspective:
|
|
237
254
|
|
|
238
255
|
1. `ab build status <slug> --json` with the ambient build identity for a
|
|
@@ -250,7 +267,7 @@ apart from the identity change, `ab dispatch` behaves as it did.
|
|
|
250
267
|
A hosted-store deployment configures its web/auth variables once — see the
|
|
251
268
|
hosted service README and the complete environment reference in the pinned
|
|
252
269
|
distribution checkout: `BETTER_AUTH_URL`, `AB_WEB_ALLOWED_EMAILS`,
|
|
253
|
-
|
|
270
|
+
and the optional `AB_WEB_MCP_RESOURCE` — the protected
|
|
254
271
|
resource the hosted MCP server (docs/mcp.md) binds its OAuth tokens to,
|
|
255
272
|
defaulting to `<BETTER_AUTH_URL>/mcp`. Set it only when a proxy or custom
|
|
256
273
|
domain fronts the deployment under a different public URL than
|
|
@@ -258,6 +275,93 @@ domain fronts the deployment under a different public URL than
|
|
|
258
275
|
production) or every MCP client's discovery binds tokens to the wrong
|
|
259
276
|
resource.
|
|
260
277
|
|
|
278
|
+
|
|
279
|
+
## Connect a project
|
|
280
|
+
|
|
281
|
+
From a checkout with an origin remote, run `ab connect https://YOUR_ORIGIN`.
|
|
282
|
+
The CLI prints a verification URL and short code and attempts to open a browser.
|
|
283
|
+
Sign in as an allowed owner, check the full repository identity and code, and
|
|
284
|
+
approve or deny. Another device can open the printed URL, or visit `/connect`
|
|
285
|
+
and enter the code. Approval requires the web-enabled service origin; a
|
|
286
|
+
standalone machine-only listener cannot present browser consent. Requests
|
|
287
|
+
expire after ten minutes. Denial and timeout leave local configuration unchanged.
|
|
288
|
+
|
|
289
|
+
On approval the service registers the project and issues a project credential.
|
|
290
|
+
The CLI keeps it in `$XDG_CONFIG_HOME/autobuild/credentials` (or
|
|
291
|
+
`~/.config/autobuild/credentials`), keyed by normalized service and origin,
|
|
292
|
+
with directory mode 0700 and file mode 0600. Credentials never belong in the
|
|
293
|
+
repository. It adds the non-secret `[store] url` to `autobuild.toml` when
|
|
294
|
+
absent; review and commit that change yourself. An existing different URL
|
|
295
|
+
must be changed explicitly before connecting. Reconnecting replaces the saved
|
|
296
|
+
credential only after approval and revokes the previous credential.
|
|
297
|
+
|
|
298
|
+
All worktrees share the main checkout's configuration and the user's saved
|
|
299
|
+
credential. A service manager running as that user uses the same HOME and
|
|
300
|
+
XDG_CONFIG_HOME, with no AB_STORE or AB_TOKEN exports. A fresh clone with
|
|
301
|
+
committed store configuration but no saved credential fails with `ab connect`
|
|
302
|
+
guidance; it never silently creates local state. Run connect on each host/user.
|
|
303
|
+
|
|
304
|
+
`ab connect` without a URL reports service, project, and credential status:
|
|
305
|
+
accepted, rejected, missing, or unreachable. `ab disconnect` revokes the saved
|
|
306
|
+
credential remotely before removing it locally, keeping the project registered,
|
|
307
|
+
its data, and store configuration. A network/server failure retains the local
|
|
308
|
+
entry for retry; an already revoked credential can be removed. If saving a new
|
|
309
|
+
connection fails, the CLI cancels/revokes it and retains the previous entry.
|
|
310
|
+
If remote cleanup cannot be confirmed, check the printed credential id with
|
|
311
|
+
the owner's administrative tools before retrying.
|
|
312
|
+
|
|
313
|
+
Store selection is `--store` > nonblank `AB_STORE` > `[store] url` > the
|
|
314
|
+
main checkout's `.autobuild/`. `AB_TOKEN` overrides the exact service/project's
|
|
315
|
+
saved credential for CI and other non-interactive hosts. A service override
|
|
316
|
+
never borrows another service's credential. Build and harvest sessions keep
|
|
317
|
+
their explicit scoped authority.
|
|
318
|
+
|
|
319
|
+
## Connected projects
|
|
320
|
+
|
|
321
|
+
Migrate PostgreSQL from the pinned release before deploying (`bun run
|
|
322
|
+
postgres:migrate`). The service keeps an independent, durable project registry;
|
|
323
|
+
existing build or ticket data does not register a project. An administrator
|
|
324
|
+
with deployment database credentials manages it without redeploying:
|
|
325
|
+
|
|
326
|
+
```sh
|
|
327
|
+
ab-hosted-store projects list
|
|
328
|
+
ab-hosted-store projects add https://github.com/owner/project --user owner@example.com
|
|
329
|
+
ab-hosted-store projects remove https://github.com/owner/project --user owner@example.com
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
From a source checkout, substitute `bun packages/hosted-store-service/src/bin.ts`
|
|
333
|
+
for `ab-hosted-store`. Configure `AB_POSTGRES_URL` or `DATABASE_URL` in that
|
|
334
|
+
process. Database possession grants administration; `--user` is declared audit
|
|
335
|
+
attribution, not a verified login. Ordinary project/store tokens cannot manage
|
|
336
|
+
registrations. Each entry records the normalized origin URL, addition time,
|
|
337
|
+
and adding identity. SSH git spellings normalize to HTTPS; local paths and
|
|
338
|
+
credential-bearing HTTPS URLs are rejected. Duplicate adds preserve metadata;
|
|
339
|
+
remove is idempotent, and re-adding records a fresh addition.
|
|
340
|
+
|
|
341
|
+
Every allowlisted signed-in user owns every registered project. The dashboard,
|
|
342
|
+
MCP discovery and calls, and every operator API route consult current
|
|
343
|
+
registration. Removal hides a project from all these surfaces and subsequent
|
|
344
|
+
hosted dispatcher invocations; builds, events, artifacts and tickets remain,
|
|
345
|
+
and re-registration restores access. Already-started work is not cancelled.
|
|
346
|
+
Project credentials issued by connect authorize only their registered project. Administrative credential issuance remains available for non-interactive hosts.
|
|
347
|
+
|
|
348
|
+
Link directly to `/?repo=<URL-encoded normalized origin>`. The page selects the
|
|
349
|
+
first registered origin when the requested one is missing or removed, and an
|
|
350
|
+
empty registry shows no project data or controls. Registry errors fail closed;
|
|
351
|
+
there is no environment fallback on database failure.
|
|
352
|
+
|
|
353
|
+
`AB_WEB_REPOSITORIES` is deprecated. A nonempty CSV is imported exactly once per
|
|
354
|
+
database, on the first registry initialization with that variable configured,
|
|
355
|
+
with actor `system:AB_WEB_REPOSITORIES`. The import and durable marker commit
|
|
356
|
+
atomically across concurrent starts. An absent variable does not consume the
|
|
357
|
+
marker. Later restarts or edits to the variable never re-add removed projects;
|
|
358
|
+
use the owner commands for subsequent administration.
|
|
359
|
+
|
|
360
|
+
The hosted dispatcher queries current registrations on every authorized
|
|
361
|
+
invocation. With `AB_DISPATCHER_REPOSITORIES` unset, it serves all registered
|
|
362
|
+
projects; an explicit list preserves its order and is intersected with current
|
|
363
|
+
registration. An empty registry is a successful zero-project invocation.
|
|
364
|
+
|
|
261
365
|
## Authoring an agent verifier
|
|
262
366
|
|
|
263
367
|
A repository-owned agent-verify skill is a verifier, not a reviewer: it drives
|
|
@@ -290,3 +394,82 @@ explanation, never a skip or silent pass. Use `skip` only when the complete step
|
|
|
290
394
|
does not apply. If guidance still cannot make a verdict possible, escalate and
|
|
291
395
|
explain what remains unresolved. Record out-of-scope work with `ab observe`;
|
|
292
396
|
the verifier does not fix it.
|
|
397
|
+
|
|
398
|
+
### Project-scoped hosted tickets
|
|
399
|
+
|
|
400
|
+
Hosted ticket queues belong to the credential's registered repository, even
|
|
401
|
+
when projects share a team key. Independent project ticket policy owns lifecycle:
|
|
402
|
+
new defaults are triage / ready / doing / done, with create/proposal following
|
|
403
|
+
triage. Explicit names retain their spelling; doneState customizes completion.
|
|
404
|
+
`ab connect --tickets URL` publishes policy before dispatch. Older clients without
|
|
405
|
+
independent policy retain their uploaded dispatcher configuration and legacy defaults.
|
|
406
|
+
Owner admin requests require an explicit registered context.repo; project credentials
|
|
407
|
+
cannot select another project. See [local builds with hosted tickets](#local-builds-with-hosted-tickets).
|
|
408
|
+
|
|
409
|
+
The service never contacts Linear. Projects with external sources (including
|
|
410
|
+
file and Linear) keep using those sources directly through their dispatcher;
|
|
411
|
+
service ticket HTTP, operator and MCP surfaces refuse with project/source
|
|
412
|
+
feedback rather than returning an empty queue. Removed `AB_TICKET_BACKEND` and
|
|
413
|
+
`LINEAR_API_KEY` values are ignored with one startup removal message, including
|
|
414
|
+
blank/unknown values. Removed `AB_TICKET_TRIAGE_STATE`, `AB_TICKET_READY_STATE`,
|
|
415
|
+
`AB_TICKET_DOING_STATE` and `AB_TICKET_DONE_STATE` values are ignored even when
|
|
416
|
+
malformed. None of these retired settings prevents startup.
|
|
417
|
+
|
|
418
|
+
The environment-aware migration imports `AB_WEB_REPOSITORIES` once before
|
|
419
|
+
ownership preflight, including released main-v9 deployments without registry
|
|
420
|
+
tables. A failed migration rolls back the import, main-schema promotion and
|
|
421
|
+
ticket changes together. Owner `projects add` and `tickets assign-team` commands
|
|
422
|
+
bootstrap only the registry/recovery journals and work while the main marker
|
|
423
|
+
is still v9. Without the retired environment, first register the intended
|
|
424
|
+
project with `ab-hosted-store projects add REPOSITORY --user IDENTITY`, then
|
|
425
|
+
assign the team and rerun migration. A successful one-time import is never
|
|
426
|
+
reapplied from later environment edits.
|
|
427
|
+
|
|
428
|
+
Ticket schema v1 migration assigns each whole legacy team to its sole claimant
|
|
429
|
+
among registered projects' latest effective configs, reading their actual blob
|
|
430
|
+
bytes. Projects with no dispatcher run or no effective-config reference make
|
|
431
|
+
no team claim and do not block other projects. Unclaimed teams still fail closed.
|
|
432
|
+
When inferring ownership, a selected configuration whose revision/blob is missing,
|
|
433
|
+
unreadable or invalid stops unchanged with recovery guidance. Restore the selected
|
|
434
|
+
configuration or assign every remaining legacy team explicitly; complete owner
|
|
435
|
+
assignments to registered projects bypass unrelated configuration reads. Conflicts
|
|
436
|
+
and asset ownership mismatches also stop unchanged. Resolve ownership, then rerun:
|
|
437
|
+
|
|
438
|
+
```sh
|
|
439
|
+
ab-hosted-store tickets assign-team TEAM https://github.com/acme/app --user owner@example.com
|
|
440
|
+
ab-postgres-store migrate
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
The assignment journal works before v2 assertion, retains the actor, and grants
|
|
444
|
+
no future cross-project access. Migration preserves ids, states, comments,
|
|
445
|
+
blockers, timestamps and assets. Populated-v1 migration and deployment builds
|
|
446
|
+
require the running service's blob backend, access mode, credentials and prefix
|
|
447
|
+
(`AB_BLOB_PREFIX`), not just PostgreSQL access. `deploy:build` inherits this
|
|
448
|
+
environment and migration failure stops Next build. Fresh databases, empty v1
|
|
449
|
+
queues and v2 reruns stay SQL-only and do not initialize blob storage.
|
|
450
|
+
|
|
451
|
+
## Local builds with hosted tickets
|
|
452
|
+
|
|
453
|
+
Hosted tickets do not require hosted builds. Set `[tickets] source = "hosted"`
|
|
454
|
+
and `teamKey = "ENG"`, then run `ab connect --tickets https://your-service.example`.
|
|
455
|
+
Approve the project in the browser. This saves a service-scoped credential and
|
|
456
|
+
`[tickets] url` while leaving `[store]` unchanged. Ticket commands work immediately,
|
|
457
|
+
before any dispatcher runs. `ab connect` reports every service and whether it serves
|
|
458
|
+
builds, tickets, or both. Use `ab disconnect --tickets` to revoke ticket access;
|
|
459
|
+
when services differ use `--builds` to select build access. Shared uses share one
|
|
460
|
+
credential, so disconnecting either shared use affects both.
|
|
461
|
+
|
|
462
|
+
Ticket URL selection is `[tickets] url`, then the selected build service (including
|
|
463
|
+
AB_STORE or a supported --store override). With local builds, `[tickets] url` is
|
|
464
|
+
required. Builds, events, artifacts, and harvest journals remain in the local store.
|
|
465
|
+
The service stores ticket records, project ticket policy, and restricted ticket
|
|
466
|
+
grants. Normal project clients synchronize current `[tickets]` policy before use;
|
|
467
|
+
failed synchronization fails the operation. Harvest grants can read and create;
|
|
468
|
+
phase grants can only read. Neither can change policy or access BuildStore routes.
|
|
469
|
+
|
|
470
|
+
New hosted policy defaults to `triage`, `ready`, `doing`, `done`, with creation and
|
|
471
|
+
harvest proposals in `triage`. Explicit state names preserve their spelling.
|
|
472
|
+
To retain earlier names configure `triageState = "Backlog"`,
|
|
473
|
+
`claimedState = "Doing"`, `doneState = "Done"`, and the desired `readyState`.
|
|
474
|
+
Existing ticket rows are never renamed. Older combined-service clients continue
|
|
475
|
+
using the uploaded dispatcher configuration until independent policy is published.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
`ab ticket create --blocked-by` validates prerequisite ids and records blocking
|
|
4
4
|
relationships, but a single CLI command is **not an atomic publication guarantee**.
|
|
5
|
-
In particular, direct Linear
|
|
5
|
+
In particular, direct Linear creates the issue first and adds
|
|
6
6
|
its blocker relationships in separate requests. If the issue is already in the
|
|
7
7
|
ready state, a dispatcher can see it before those relationships exist. A
|
|
8
8
|
successful create response containing every blocker does not prove that no build
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Moving a project between ticket sources
|
|
2
|
+
|
|
3
|
+
Export and import use the ordinary file ticket layout. They operate on tickets
|
|
4
|
+
and current attachments through the ticket source; neither command contacts the
|
|
5
|
+
forge. File and hosted sources support import. Linear supports export only.
|
|
6
|
+
|
|
7
|
+
1. Pause intake and stop other ticket writers for the cutover. Import preflight
|
|
8
|
+
does not reserve numbers against concurrent writers.
|
|
9
|
+
2. With the old `[tickets]` configuration, run `ab ticket export /path/to/export`.
|
|
10
|
+
The destination must be absent or empty. Export reads every state, including
|
|
11
|
+
archived Linear tickets and empty discoverable states, and publishes the
|
|
12
|
+
directory only after all reads succeed. Back up the target tracker too.
|
|
13
|
+
3. Configure the new `[tickets]` source, or use `ab connect --tickets URL` for a
|
|
14
|
+
hosted ticket service. Keep the export directory intact.
|
|
15
|
+
4. Run `ab ticket import /path/to/export`. Inspect its printed ticket and state
|
|
16
|
+
mappings and `/path/to/export/.ab-import-map.json`.
|
|
17
|
+
5. Inspect ticket bodies, labels, blockers, comments and attachments in the new
|
|
18
|
+
source. Confirm lifecycle configuration and the ready gate, then resume intake.
|
|
19
|
+
|
|
20
|
+
Both commands also accept
|
|
21
|
+
`--store <ref>` to reach legacy BuildStore attachments. Keep the old store available
|
|
22
|
+
through export when file or Linear tickets have attachments there.
|
|
23
|
+
|
|
24
|
+
State directory names use lowercase letters, digits and hyphens, start with a
|
|
25
|
+
letter and contain at most forty characters. Export maps `In Progress` to
|
|
26
|
+
`in-progress`, `Backlog` to `backlog`, and `Done` to `done`. It retains each ticket's
|
|
27
|
+
state rather than assigning lifecycle roles. Distinct names that collapse to the
|
|
28
|
+
same directory fail before publication. The hidden `.ab-migration.json` records
|
|
29
|
+
original display names and the state map. Import also accepts ordinary legacy
|
|
30
|
+
file layouts: it reuses exact or unique case-insensitive target states before
|
|
31
|
+
normalizing new names. A seeded `done` satisfies `Done`; absent `In Progress`
|
|
32
|
+
creates `in-progress`. Ambiguous matches and colliding state maps fail preflight.
|
|
33
|
+
|
|
34
|
+
File targets retain source ids. Hosted targets keep canonical own-team ids:
|
|
35
|
+
`AUT-706` imported into team `AUT` stays `AUT-706`. Other ids receive numbers above
|
|
36
|
+
all existing and preserved incoming numbers. Known clashes with unrelated tickets
|
|
37
|
+
are reported together before any target state, ticket, comment or asset write.
|
|
38
|
+
Content similarity and stale mapping files never establish identity.
|
|
39
|
+
|
|
40
|
+
Creation keys establish identity. Exports retain existing keys and assign keys to
|
|
41
|
+
legacy tickets. Importing an ordinary file layout first saves a hidden migration
|
|
42
|
+
identity and keys in that input directory. Preserve this file and the input across
|
|
43
|
+
retries. After interruption, rerun the same command: committed creates are adopted
|
|
44
|
+
by key even if their mapping write failed. Adopted bodies and other fields are not
|
|
45
|
+
overwritten. Missing blockers and comments are replayed, and unchanged attachments
|
|
46
|
+
do not create another revision. Comments are deduplicated by exact body, so two
|
|
47
|
+
identical source comment bodies produce one target comment. Original authors and
|
|
48
|
+
timestamps remain in the export; imported comments use the target's metadata.
|
|
49
|
+
|
|
50
|
+
Portable records use TOML frontmatter between `+++` fences and an unchanged
|
|
51
|
+
Markdown body. Alongside `id`, `title`, `labels`, `blockedBy` and `idempotencyKey`,
|
|
52
|
+
optional `comments` contain `body`, `createdAt` and optional `author`. Optional
|
|
53
|
+
`attachments` contain `kind`, `name`, `layout` (`file` or `tree`) and `entries`:
|
|
54
|
+
`{ type = "dir", path = "empty" }` or
|
|
55
|
+
`{ type = "file", path = "image.png", base64 = "…" }`. Common asset limits and
|
|
56
|
+
path validators apply. Only current attachment contents travel, including binary
|
|
57
|
+
files and empty directories; historical revisions do not. The exported directory
|
|
58
|
+
works directly as a file source, without its migration manifest or original store.
|
|
59
|
+
File source revision history stays in its hidden `.ab-assets` directory.
|
|
60
|
+
|
|
61
|
+
Legacy records without `comments` retain their Markdown comment append behavior;
|
|
62
|
+
export never interprets Markdown headings as structured history. New file tickets
|
|
63
|
+
use structured comments and preserve their body when a comment is added. There is
|
|
64
|
+
no continuous sync, assignee migration, state history or build-history migration.
|