@defrex/autobuild 0.11.0 → 0.12.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.
Files changed (96) hide show
  1. package/README.md +3 -1
  2. package/SPEC.md +222 -22
  3. package/docs/architecture.md +66 -4
  4. package/docs/configuration.md +105 -16
  5. package/docs/hosted-dispatcher.md +17 -2
  6. package/docs/hosted-service.md +214 -0
  7. package/docs/mcp.md +8 -2
  8. package/docs/operator-api.md +90 -7
  9. package/docs/remote-store-protocol.md +189 -144
  10. package/docs/remote-ticket-protocol.md +107 -19
  11. package/docs/setup.md +173 -16
  12. package/docs/ticket-dependencies.md +1 -1
  13. package/package.json +7 -6
  14. package/packages/core/src/cli/attention.ts +209 -0
  15. package/packages/core/src/cli/configured-store.ts +17 -0
  16. package/packages/core/src/cli/connect.ts +261 -0
  17. package/packages/core/src/cli/dashboard/model.ts +4 -5
  18. package/packages/core/src/cli/dispatch.ts +183 -41
  19. package/packages/core/src/cli/help.ts +39 -10
  20. package/packages/core/src/cli/init-validation.ts +27 -2
  21. package/packages/core/src/cli/main.ts +41 -15
  22. package/packages/core/src/cli/mcp.ts +7 -1
  23. package/packages/core/src/cli/pr-summary-publication.ts +220 -0
  24. package/packages/core/src/cli/pr-summary.ts +2 -0
  25. package/packages/core/src/cli/project-credentials.ts +132 -0
  26. package/packages/core/src/cli/repo-state.ts +15 -2
  27. package/packages/core/src/cli/self-update.ts +10 -0
  28. package/packages/core/src/cli/store-opening.ts +22 -14
  29. package/packages/core/src/cli/terminals.ts +0 -10
  30. package/packages/core/src/cli/ticket.ts +8 -1
  31. package/packages/core/src/cli/upgrade-compatibility.ts +80 -0
  32. package/packages/core/src/cli/wait.ts +84 -17
  33. package/packages/core/src/cli/watch.ts +197 -60
  34. package/packages/core/src/config/live.ts +3 -0
  35. package/packages/core/src/config/schema.ts +56 -9
  36. package/packages/core/src/connection.ts +86 -0
  37. package/packages/core/src/events/catalog.ts +10 -2
  38. package/packages/core/src/events/payloads.ts +44 -0
  39. package/packages/core/src/events/repository.ts +13 -0
  40. package/packages/core/src/kernel/__snapshots__/reducer-registry.test.ts.snap +130 -83
  41. package/packages/core/src/kernel/engine.ts +24 -0
  42. package/packages/core/src/kernel/generators/build-log.ts +10 -0
  43. package/packages/core/src/kernel/log-index.ts +17 -0
  44. package/packages/core/src/kernel/pr-summary.ts +89 -0
  45. package/packages/core/src/kernel/reducer-registry.ts +8 -0
  46. package/packages/core/src/kernel/reducer.ts +8 -0
  47. package/packages/core/src/ontology.ts +1 -0
  48. package/packages/core/src/operator/index.ts +7 -0
  49. package/packages/core/src/operator/query.ts +38 -16
  50. package/packages/core/src/operator/ticket-source-backend.ts +1 -0
  51. package/packages/core/src/operator/tickets.ts +6 -8
  52. package/packages/core/src/plugin-sdk/index.ts +1 -0
  53. package/packages/core/src/plugins/manifest.ts +5 -3
  54. package/packages/core/src/plugins/runtimes.ts +3 -1
  55. package/packages/core/src/ports/forge/fake.ts +13 -1
  56. package/packages/core/src/ports/forge/github-transport.ts +36 -1
  57. package/packages/core/src/ports/forge/github.ts +29 -5
  58. package/packages/core/src/ports/forge/local-git.ts +12 -4
  59. package/packages/core/src/ports/forge/summary-marker.ts +8 -0
  60. package/packages/core/src/ports/runner/session-env.ts +1 -0
  61. package/packages/core/src/ports/tickets/create.ts +11 -3
  62. package/packages/core/src/ports/tickets/hosted-index.ts +0 -3
  63. package/packages/core/src/ports/tickets/remote-protocol.ts +1 -0
  64. package/packages/core/src/ports/tickets/remote.ts +1 -0
  65. package/packages/core/src/ports/workspace/build-execution.ts +5 -1
  66. package/packages/core/src/ports/workspace/create.ts +11 -2
  67. package/packages/core/src/ports/workspace/distribution-archive.ts +3 -5
  68. package/packages/core/src/ports/workspace/harvest-execution.ts +3 -1
  69. package/packages/core/src/ports/workspace/local-build-execution.ts +8 -1
  70. package/packages/core/src/ports/workspace/vercel-sandbox.ts +47 -19
  71. package/packages/core/src/processes/build-execution-state.ts +1 -1
  72. package/packages/core/src/processes/build-runner.ts +87 -26
  73. package/packages/core/src/processes/dispatch-failure-budget.ts +83 -0
  74. package/packages/core/src/processes/dispatcher.ts +59 -10
  75. package/packages/core/src/processes/harvest-child.ts +1 -0
  76. package/packages/core/src/processes/harvest-execution-state.ts +19 -2
  77. package/packages/core/src/processes/harvest-runner.ts +142 -100
  78. package/packages/core/src/processes/phase-failure-budget.ts +1 -0
  79. package/packages/core/src/processes/publication-loss.ts +18 -1
  80. package/packages/core/src/store/remote/client.ts +1 -1
  81. package/packages/core/src/store/remote/compatibility.ts +90 -0
  82. package/packages/core/src/store/remote/credentials.ts +28 -0
  83. package/packages/core/src/store/remote/index.ts +14 -1
  84. package/packages/core/src/store/remote/protocol.ts +25 -0
  85. package/packages/core/src/store/remote/token.ts +74 -13
  86. package/packages/core/src/testing/index.ts +7 -0
  87. package/skills/guide/SKILL.md +144 -26
  88. package/skills/guide/references/operator-api.md +135 -13
  89. package/skills/guide/references/plugin-authoring.md +10 -2
  90. package/skills/guide/references/remote-store-protocol.md +189 -144
  91. package/skills/guide/references/remote-ticket-protocol.md +111 -18
  92. package/skills/guide/references/setup.md +173 -16
  93. package/skills/guide/references/ticket-dependencies.md +1 -1
  94. package/skills/operate/SKILL.md +126 -36
  95. package/templates/hosted-service/package.json +13 -0
  96. package/templates/hosted-service/vercel.json +7 -0
package/README.md CHANGED
@@ -24,7 +24,7 @@ needs an authenticated [`gh` CLI](https://cli.github.com) or an exported
24
24
  <!-- release-install:start -->
25
25
 
26
26
  ```sh
27
- bun add -g @defrex/autobuild@0.11.0
27
+ bun add -g @defrex/autobuild@0.12.0
28
28
  ```
29
29
 
30
30
  <!-- release-install:end -->
@@ -174,3 +174,5 @@ routine escalations, leaving you only the real product calls.
174
174
  ## License
175
175
 
176
176
  [Apache License 2.0](LICENSE).
177
+
178
+ Deploy your own store and dashboard with the [hosted service setup](docs/hosted-service.md).
package/SPEC.md CHANGED
@@ -581,9 +581,8 @@ registry already exposes bounded repository reads). Each source's cursor
581
581
  advances only through a recorded trigger naming that source, so a crash
582
582
  between scan and start cannot skip or duplicate a wake, and other builds' —
583
583
  and the journal's — matching events re-trigger on later ticks. Sessions with
584
- empty wake settings are never woken. The default wake settings span both
585
- halves of the attention set: the build events `ab watch` filters on by
586
- default plus the repository-journal events `ab watch --repository` follows.
584
+ empty wake settings are never woken. The legacy hosted wake settings retain their event defaults independently of
585
+ the actionable CLI watch projection.
587
586
 
588
587
  **Crash recovery.** A turn invocation that dies without an outcome leaves the
589
588
  session `running` with a silent open stream; the tick's reaper fails such a
@@ -701,7 +700,8 @@ conformance suite):
701
700
  hosted HTTP service, selected by an `http(s)://` reference. Kernels,
702
701
  sandboxes, terminal dashboards, and later human-facing pages share this
703
702
  service tier; it owns token authorization, protocol write validation,
704
- artifact policy, and exact package/protocol version-skew enforcement. The
703
+ artifact policy, release-line compatibility, and independent protocol
704
+ enforcement. The
705
705
  later human routes share its deployment so a browser or second service never
706
706
  receives the machine signing secret. Artifacts remain content-by-value. The
707
707
  documented [remote store protocol](docs/remote-store-protocol.md) is the
@@ -710,6 +710,24 @@ conformance suite):
710
710
  client, is the conformance bar. Autobuild does not load in-process BuildStore
711
711
  plugins. Git worktrees and default file tickets necessarily remain local.
712
712
 
713
+ A service accepts stable clients from its own `major.minor` release line and
714
+ the two preceding minor lines in the same major. A major starts a new family:
715
+ X.0 accepts only X.0, X.1 accepts X.0/X.1, and X.2 onward accepts three lines.
716
+ Patch versions are interchangeable in both directions and must never change
717
+ the protocol. Upgrade the service first, then projects independently within
718
+ its window. Supported release lines retain their wire handlers and known
719
+ protocol identities; an unknown protocol is refused independently of version.
720
+ Malformed, missing, and prerelease identities are refused with HTTP 409.
721
+ A newer client is told to upgrade the service; a client below the window is
722
+ told to upgrade the project's Autobuild. Diagnostics name the service version
723
+ and supported range.
724
+
725
+ Unauthenticated `GET /health` publishes `ok`, `autobuildVersion`,
726
+ `protocolVersion`, and `supportedClientRange: { minVersion, maxVersionExclusive }`.
727
+ The range is inclusive at the minimum and exclusive at the maximum; a 0.11.x
728
+ service publishes `>=0.9.0 <0.12.0`. Health needs no credentials, version
729
+ headers, or available backend.
730
+
713
731
  `subscribe` is specced in the interface; the v2.0 implementation is polling
714
732
  `getEvents(since)`. True push comes later.
715
733
 
@@ -734,6 +752,43 @@ longer grows with the number of past dispatcher invocations. The journal
734
752
  itself stays append-only: full replay remains the normative truth, and
735
753
  `ab watch` still sees every recorded fact.
736
754
 
755
+ #### Hosted connected projects
756
+
757
+ The product's hosted service keeps a durable PostgreSQL project registry,
758
+ independent of BuildStore repository journals and ticket data. Entries record
759
+ normalized repository origin, addition timestamp and adding identity. An
760
+ append-only journal records additions/removals; latest sequence determines
761
+ membership. Removal never deletes build, event, artifact or ticket history;
762
+ re-registration restores access and records fresh addition metadata.
763
+
764
+ Database-authorized owners administer it without redeploying through
765
+ `ab-hosted-store projects list`, `projects add REPOSITORY --user IDENTITY`, and
766
+ `projects remove REPOSITORY --user IDENTITY`. Attribution is declared by the
767
+ administrator; ordinary store/project tokens cannot administer registration.
768
+ All allowlisted signed-in users own every registered project (single-owner
769
+ model). Per-project memberships and machine credential boundaries are deferred.
770
+
771
+ Dashboard discovery, MCP `repositories.list` and every repository tool call,
772
+ and all operator API routes for every operator credential consult current
773
+ membership. Unregistered operator paths return not-found before execution.
774
+ Registry failures fail closed and transient initialization can retry.
775
+ The dashboard selection lives at `/?repo=<URL-encoded normalized origin>`;
776
+ missing/invalid selections canonicalize to the first active entry, and an
777
+ empty registry issues no project data/control requests.
778
+
779
+ The hosted dispatcher queries the registry each authorized invocation when
780
+ `AB_DISPATCHER_REPOSITORIES` is unset. An explicit list is intersected with
781
+ current registration in its configured order. Empty registration is a
782
+ successful zero-project tick. Removal stops later invocations, without
783
+ cancelling already-started work or changing machine-route token authority.
784
+
785
+ `AB_WEB_REPOSITORIES` is deprecated: the first initialization with a nonempty
786
+ CSV imports absent projects once per database as `system:AB_WEB_REPOSITORIES`.
787
+ The import and durable marker share one transaction and mutation lock across
788
+ processes. Absence does not consume the marker. Restarts or later variable
789
+ edits cannot resurrect removals. Deployments migrate the pinned schema before
790
+ starting services; runtime initialization never runs DDL.
791
+
737
792
  ### 7.3 Persistence granularity
738
793
 
739
794
  Required phase outputs persist at **phase/round boundaries**; a killed phase
@@ -781,8 +836,27 @@ Four base-selection invariants make this safe with Git:
781
836
 
782
837
  ### 7.5 What the PR gets
783
838
 
784
- A summary comment — verdict history, verification results, links into the
785
- store. The full audit trail is queryable, not committed to the branch.
839
+ One marked summary comment contains verdict history, verification results,
840
+ and links into the store. Built-in forges discover its per-build marker on
841
+ every refresh and edit it, recreating it only after confirmed absence. The
842
+ full audit trail is queryable, not committed to the branch.
843
+
844
+ Summary publication is best effort, once per completed phase occurrence,
845
+ after sessions end; attaching artifacts performs no summary write. Durable
846
+ claim-before-write facts consume the occurrence budget even across crashes.
847
+ Rate limits stop that occurrence and persist a cooldown (provider headers or
848
+ at least one minute) before a later phase may catch up. Failures never fail
849
+ artifact designation or phase completion. Bodies are capped at 65,536 UTF-16
850
+ code units. Oversized projections are deposited as a non-attached `pr-summary`
851
+ artifact; a compact comment provides the exact pinned download command.
852
+ Current-API plugins retain `commentOnPr` and receive the same bounded calls;
853
+ legacy plugins may append instead of editing.
854
+
855
+ Local runners publish under their build lease. Remote guests record durable
856
+ summary boundary requests and yield; only the credentialed dispatcher settles
857
+ those requests, after guest execution ends and under exclusive ownership,
858
+ before replacement execution or workspace cleanup. Attempts and request
859
+ dispositions survive restart and do not alter pipeline routing.
786
860
 
787
861
  Any agent session can explicitly designate an exact deposited artifact as a PR
788
862
  attachment through `ab artifact put <kind> <file> --attach`. Designation is a
@@ -802,8 +876,8 @@ dispatcher reclaims them after the build reaches a terminal outcome, while
802
876
  store artifacts remain under the store's retention policy. Upload/validation/timeout failures record follow-up
803
877
  observations and preserve the complete text projection; they never fail
804
878
  verification or block finalize. Agents receive no forge credentials. A
805
- designation after the PR exists publishes a new complete summary, so finalize
806
- post-steps and post-reconcile verifiers need no custom phase.
879
+ designation after the PR exists is included at the completed phase boundary,
880
+ so finalize post-steps and post-reconcile verifiers need no custom phase.
807
881
 
808
882
  ### 7.6 Streams (the third primitive)
809
883
 
@@ -925,7 +999,7 @@ AB_STORE # store URL or local path
925
999
  AB_BUILD # build slug
926
1000
  AB_PHASE # current phase (+ round)
927
1001
  AB_SESSION # session id
928
- AB_TOKEN # transports the scoped handle's authority to a remote store
1002
+ AB_TOKEN # signed credential for this exact phase session (remote store)
929
1003
  ```
930
1004
 
931
1005
  A harvest session instead carries `AB_REPO`, `AB_HARVEST`, and an `AB_PHASE`
@@ -933,14 +1007,18 @@ of `synthesize@N` or `review@N`. The AgentRunner invocation argument is
933
1007
  opaque: a build skill receives its slug; a harvest skill receives its run id.
934
1008
  The CLI resolves identity from ambient auth. Every build process holds an
935
1009
  interface-enforced build-scoped Store handle. At the phase CLI opening boundary,
936
- a remote handle forwards the runner-minted token unchanged, while a local handle
937
- is wrapped with authority over exactly `AB_BUILD` or `AB_REPO`. Build and
1010
+ both local and remote handles are wrapped with authority over exactly
1011
+ `AB_BUILD` or `AB_REPO`. Before launch, the dispatcher exchanges its project credential with the service
1012
+ for a build or prepared harvest-execution grant. After recording a session start,
1013
+ the runner exchanges that grant for an exact phase-session grant. The remote
1014
+ handle forwards only this delegated credential; the service enforces its project,
1015
+ resource and session boundaries on the wire. Build and
938
1016
  repository resources cannot cross, and naming another resource to a Store
939
1017
  operation cannot widen either handle. Event-bearing writes attributed to an
940
1018
  agent must name the ambient `AB_SESSION`; non-agent writes remain allowed so the
941
1019
  CLI can perform its existing trusted kernel plumbing, including finalize.
942
- Operator and kernel processes with no agent identity markers retain unscoped
943
- Store access. Three read-only forms are also valid inside a phase: `ab build
1020
+ Operator and kernel processes with no agent identity markers retain interface-unscoped
1021
+ Store handles; remote authorization still limits access to the credential project. Three read-only forms are also valid inside a phase: `ab build
944
1022
  status` and `ab artifact download` may read only `AB_BUILD`, while `ab builds`
945
1023
  is denied because collection access cannot represent one build. A complete
946
1024
  Harvest identity has repository scope and cannot use those build/admin reads.
@@ -949,10 +1027,60 @@ If any build or Harvest identity marker is present, the corresponding
949
1027
  partial, empty, malformed, shared-only, or mixed identity fails before Store
950
1028
  access rather than falling back to operator authority. `AB_STORE` and
951
1029
  `AB_TOKEN` alone remain operator selection and credentials, not identity.
952
- Remote tokens transport the corresponding resource and session authority over
953
- the wire; build-process resource scope is already enforced by the Store
954
- interface. Least privilege comes from the Store and runner, not prompt
955
- instructions.
1030
+ Dispatcher machine authority is an opaque, revocable credential for exactly one
1031
+ registered project. The service keeps only a digest of its random secret and
1032
+ credential metadata (creator, creation, last use, expiry and revocation), and
1033
+ checks both credential status and project registration on each request. It
1034
+ checks actual build/session/stream ownership and filters collections server-side.
1035
+ Explicit project mismatch is 403; missing and foreign indirect IDs share 404.
1036
+ Remote project build creation allocates a fresh slug and branch; the returned
1037
+ record is authoritative. Local adapters retain exact-slug behavior.
1038
+
1039
+ Owners issue/list/revoke credentials with deployment-local `ab-hosted-store
1040
+ credentials` commands. Retired deployment-wide and repository-less operator
1041
+ tokens are rejected with migration guidance. An explicit versioned owner-only
1042
+ break-glass admin is the sole machine cross-project exception. Internal signed
1043
+ owner delegation is short-lived, repository-bound and operator-only. The hosted
1044
+ dispatcher issues stored credentials with immutable dispatcher purpose (raw
1045
+ store and tickets only) per invocation and keeps them valid through configured
1046
+ expiry. Already issued delegated grants do not depend on that parent expiry.
1047
+ Owner-issued project credentials attribute operator writes to their recorded
1048
+ creator. Agents never receive the dispatcher's project credential. Delegated
1049
+ reads retain access to same-project repository state; build mutations target only
1050
+ that build, and harvest mutations target only the prepared run and execution,
1051
+ its artifacts and streams, with heartbeat authority for its adopted lease holder.
1052
+ Phase grants also enforce agent session attribution. They cannot create builds or
1053
+ operator sessions, administer repositories, invoke operator routes, or delegate.
1054
+ A runner can delegate only to a recorded session within its own authority.
1055
+
1056
+ Delegated grants have no fixed wall-clock expiry. The service checks signed
1057
+ bindings against authoritative durable lifecycle facts on every request and
1058
+ fails closed if those reads fail. Active, paused and escalated builds may outlive
1059
+ a dispatcher restart or a week-long parent credential. Build termination,
1060
+ harvest execution/run termination, or the phase's own session end retires the
1061
+ corresponding grant after a 60-second evidence grace window. A durable ending
1062
+ permanently closes that grant; recovered harvest executions use fresh durable
1063
+ authorizations and fresh grants. Project removal denies all its grants immediately.
1064
+ Local-store projects require no exchange.
1065
+
1066
+ Hosted ticket operations are gated by grant kind: build-runner and build-phase
1067
+ grants have no access; harvest-phase grants can only list-ready, get and read
1068
+ dependency-states; harvest-runner grants can also create proposals. All other
1069
+ ticket mutations require project or admin authority. Refusals name the grant
1070
+ kind and operation.
1071
+
1072
+ Ticket admission uses the credential project. Hosted tickets, comments, blockers, creation-key
1073
+ deduplication and assets are partitioned by registered repository, never team.
1074
+ Lifecycle comes from that project's latest durable effective configuration
1075
+ (triage Backlog, claim Doing, completion Done by default; configurable
1076
+ `doneState`). Owner admin ticket requests explicitly select a registered
1077
+ repository. The service has no Linear ticket backend: external tracker and
1078
+ file sources remain dispatcher-side, and service ticket surfaces refuse those
1079
+ projects with actionable source feedback. Legacy team queues migrate atomically
1080
+ to their sole configured claimant; conflicts stop unchanged for an owner
1081
+ assignment and rerun. See the hosted service migration procedure.
1082
+ See the remote store, remote ticket and operator protocol references for wire
1083
+ and revocation details. Least privilege comes from code, not prompt instructions.
956
1084
 
957
1085
  Every phase and harvest turn also receives a runner-controlled `PATH` prefix
958
1086
  containing a private `ab` launcher from the same Autobuild distribution that
@@ -1219,6 +1347,17 @@ be narrowed to the ambient build — and `--repo` constrains every call to one
1219
1347
  repository. Mutating tools attribute their writes to the sessionless operator
1220
1348
  identity, exactly as the other operator commands do.
1221
1349
 
1350
+ ### 8.10 Hosted project connection
1351
+
1352
+ `ab connect <service-url>` requests owner browser approval for the normalized
1353
+ origin, registers the project, and saves a project credential outside the
1354
+ checkout. `ab connect` reports its status; `ab disconnect` revokes and removes
1355
+ only that credential, retaining project data. Store precedence is `--store`,
1356
+ nonblank `AB_STORE`, `[store] url`, then local state. `AB_TOKEN` overrides saved
1357
+ credentials. Configured services without credentials fail closed. Connection
1358
+ commands require a network origin and are unavailable in phase sessions.
1359
+
1360
+
1222
1361
  ## 9. AgentRunner
1223
1362
 
1224
1363
  Session-based, because review loops need memory:
@@ -1619,6 +1758,18 @@ event-level mechanics live in the repository catalog and reducer tests):
1619
1758
 
1620
1759
  ## 13. Ticket source policy
1621
1760
 
1761
+ **Hosted tickets are project-scoped.** A project credential selects one registered
1762
+ repository; an owner selects a registered repository explicitly. Team and state
1763
+ fields from clients convey no authority or lifecycle policy. Tickets, comments,
1764
+ blockers, creation-key deduplication and assets are isolated by repository.
1765
+ The project's latest effective configuration supplies hosted lifecycle names:
1766
+ triage Backlog, claimed Doing, completion Done (`doneState`) and create/proposal
1767
+ equal to triage by default; `readyState` is required. Configured roles may overlap.
1768
+ The service has no Linear backend and never relays external ticket sources.
1769
+ Projects using Linear, files or plugins keep their direct dispatcher connection;
1770
+ service ticket surfaces refuse with project/source feedback instead of empty data.
1771
+
1772
+
1622
1773
  The TicketSource **initiates and receives projections; it is never consulted
1623
1774
  mid-build and never used as artifact storage.** Dispatch reads the ticket
1624
1775
  (including the spec) as part of initiation — at claim time, or on a later tick
@@ -1871,7 +2022,8 @@ with illustrative members:
1871
2022
  | Spec | `spec.imported`, `spec.authored`, `spec.revised` (optionally carrying `assets`, a re-pin of the ticket's assets, §6.3) |
1872
2023
  | Sessions | `session.started`; `session.ended` with transcript ref and usage (ordinary completion — the analysis corpus), or `session.ended {outcome: reclaimed, reclaimedBy: {instance, resumedFromSeq}}` (explicit transcriptless takeover) |
1873
2024
  | Plan/code loops | `plan.started` … `plan-review.verdict`; `implement.started` … `code-review.verdict` |
1874
- | Verify/finalize | `verify.started {step, attempt, feedback?}`, `verify.completed {step, outcome}`, `finalize.completed {pr}`, `finalize.step-completed {step, ok, headSha?}` |
2025
+ | Verify/finalize | `verify.started {step, attempt, feedback?}`, `verify.completed {step, outcome, skipCause?}`, `verify.reconcile-policy-captured {reconcileSeq, steps}`, `finalize.completed {pr}`, `finalize.step-started {step}`, `finalize.step-completed {step, ok, headSha?}` |
2026
+ | PR summary | Kernel-authored `pr-summary.requested {occurrence, boundary}`, `pr-summary.attempted {occurrence, boundary, pr}`, `pr-summary.result {attempt, outcome, eligibleAfter?}`, `pr-summary.settled {request, disposition}`; sequence identities correlate durable starts, completed boundaries, attempts, and handoffs (§7.5) |
1875
2027
  | PR attachments | `pr-attachment.designated`, `pr-attachment.hosted`, `pr-attachment.reclaimed`, `pr-attachment.reclaim-failed` |
1876
2028
  | Post-PR [D1] | `pr.merged`, `pr.conflicted`, `reconcile.progress-checked`, `reconcile.started`, `reconcile.completed` |
1877
2029
  | Cross-cutting | `observation.recorded`, `escalation.raised`, `phase.failed` |
@@ -1975,8 +2127,18 @@ ordinary dispatcher tick provisions the workspace, atomically imports the spec,
1975
2127
  posts the ticket notice once, and launches the runner. Claim-time auto-merge
1976
2128
  attribution retained by `build.created` is materialized as the ordinary
1977
2129
  human-authored request before launch. A failed boundary appends `dispatch.failed
1978
- {stage,attempt,error}` and stays queued for another tick. A discard request is
1979
- honored only while the build remains queued; one that races with runner
2130
+ {stage,attempt,error}` and stays queued for another tick until its budget is
2131
+ exhausted. Dispatch failures share a `[policy].maxDispatchAttempts` budget
2132
+ (default 3) across
2133
+ create, workspace, spec, comment, and launch stages. Exhaustion raises one
2134
+ `dispatch-failure-limit` policy escalation naming the latest stage and error,
2135
+ and parks dispatch until answered. Both bare `ab answer <slug>` retries and
2136
+ text guidance grant a fresh budget; abort does not. Confirmed runner attachment
2137
+ clears the streak. Recovery-provider workspace failures belong exclusively to
2138
+ the infrastructure budget. Exhaustion is repaired from durable facts on restart
2139
+ before further dispatch work.
2140
+
2141
+ A discard request is honored only while the build remains queued; one that races with runner
1980
2142
  attachment is inert and cannot tear down live work. A human discard waits out
1981
2143
  any unexpired execution lease, then releases a partial workspace and stale
1982
2144
  lease, returns the ticket to Ready, and appends `build.completed {outcome:
@@ -2182,7 +2344,8 @@ fresh from `origin`, and records the resolved SHA on `reconcile.started` — kno
2182
2344
  used (§15.3). The agent merges that base into the branch guided by the spec,
2183
2345
  plan, and implement-notes, with the explicit charge to regress against
2184
2346
  neither; the resolution lands as a merge commit, and because reconciliation
2185
- changed code, **`verify:*` re-runs in full**. A resolution the agent judges
2347
+ changed code, **`verify:*` starts a fresh cycle**, subject to the captured
2348
+ post-reconcile policy (default: re-run all applicable steps). A resolution the agent judges
2186
2349
  risky — semantic conflicts, spec-relevant choices — escalates rather than
2187
2350
  guesses. Reconcile skips `code-review` by default (escalation covers the
2188
2351
  judgment cases; policy can force it).
@@ -2314,6 +2477,7 @@ sessionBudgetSeconds = 7200 # optional role override
2314
2477
  sessionBudgetSeconds = 3600 # non-infinite default for build agent sessions
2315
2478
  stallRounds = 3
2316
2479
  maxVerifyAttempts = 3
2480
+ maxDispatchAttempts = 3
2317
2481
  maxSetupAttempts = 3
2318
2482
  maxInfrastructureAttempts = 3
2319
2483
  maxReconcileAttempts = 3
@@ -2386,9 +2550,12 @@ artifact deposited on reload changes only those sections. In-flight
2386
2550
  environments are never re-provisioned; a fresh build from the new base is the
2387
2551
  path for a changed provisioning definition.
2388
2552
 
2389
- Two configurable narrowing mechanisms govern which verify steps run, both
2553
+ Three configurable narrowing mechanisms govern which verify steps run, all
2390
2554
  resolving to the ordinary `skipped` outcome so exclusions stay queryable:
2391
2555
 
2556
+ - **Post-reconcile policy.** The cycle snapshot resolves repository and step
2557
+ `afterReconcile` settings before any plan or path exclusions, including for
2558
+ `always` steps. It applies only after a completed reconcile.
2392
2559
  - **Plan selection.** An approved plan may declare the complete subset of
2393
2560
  optional verify steps warranted by the spec, in strict front matter
2394
2561
  validated at deposit. The selection paired with the approving review
@@ -2402,6 +2569,30 @@ resolving to the ordinary `skipped` outcome so exclusions stay queryable:
2402
2569
  match skips without launching anything; a Git failure is infrastructure and
2403
2570
  fails closed, never a synthetic skip.
2404
2571
 
2572
+
2573
+ #### Post-reconcile verification policy
2574
+
2575
+ Post-reconcile verification defaults to enabled: `[verify].afterReconcile = true`.
2576
+ Set it to `false` to retain pre-reconcile verification and skip all steps after
2577
+ reconciliation. An optional boolean `[verify.<step>].afterReconcile` overrides
2578
+ the repository setting in either direction; overrides require a configured step.
2579
+ For example, set `afterReconcile = false` in `[verify]` and
2580
+ `afterReconcile = true` in `[verify.types]` to keep only that step re-running.
2581
+
2582
+ The kernel freezes the resolved ordered policy in
2583
+ `verify.reconcile-policy-captured` at the next engine action after reconcile
2584
+ completion. Live configuration changes apply at that boundary; a cycle already
2585
+ started keeps its policy through recovery. Historical cycles already started
2586
+ without a captured policy retain the rerun-all behavior. Initial verification
2587
+ and verification after subsequent code review always use ordinary applicability.
2588
+ Policy exclusion precedes plan selection and paths, including `always = true`.
2589
+ Enabled steps still follow plan selection and path rules. Excluded steps record
2590
+ `verify.completed` with outcome `skipped`, `skipCause = "post-reconcile-policy"`,
2591
+ and a reason naming the setting. Dashboards and PR summaries call this
2592
+ "skipped by post-reconcile policy"; it is never a pass. Forge-side required
2593
+ checks and branch protections still gate merge. For excluded steps, merged code
2594
+ is not re-verified, so breakage that only exists in the combination can land.
2595
+
2405
2596
  ### 16.3 Skill installation: vendored, namespaced, editable [D11]
2406
2597
 
2407
2598
  This project ships 11 canonical default skills for the fixed phases, the
@@ -2483,6 +2674,15 @@ install failure is fatal and does not merge against the wrong defaults.
2483
2674
  `--no-self-update` always selects merge-only
2484
2675
  behavior. An exact version may be older than the installed version.
2485
2676
 
2677
+ Before installation or project writes, upgrades targeting a hosted store probe
2678
+ its public health range. An incompatible target produces a directional warning
2679
+ (service first for a newer target, project upgrade for a stale target) and
2680
+ continues. A legacy health response has an exact-version contract; different
2681
+ targets warn that the service needs the compatibility-window release. Failed,
2682
+ timed-out, or malformed probes warn that connectivity could not be verified
2683
+ and may fail after upgrade, then continue. Merge-only and replacement-process
2684
+ handoffs check the distribution actually applied before skill writes.
2685
+
2486
2686
  Upgrade records its successful work in one local commit on the target's current
2487
2687
  HEAD by default. The exact ownership boundary is the reported skills' canonical
2488
2688
  `.agents` trees, pristine records, and `.claude` discovery paths, plus
@@ -333,7 +333,19 @@ head is a no-op; Git/Forge failures stay failure-tolerant observations.
333
333
  **Verify gating.** `packages/core/src/ontology.ts` owns the canonical
334
334
  `pass | fail | skipped` outcome (only `fail` routes back to implement or
335
335
  consumes attempts; a skip satisfies one step without being passing
336
- evidence). Two kernel-authored skip sources narrow the configured universe:
336
+ evidence). Three kernel-authored skip sources narrow the configured universe:
337
+ post-reconcile policy, approved plan selection, and changed paths.
338
+ The engine captures the ordered effective `afterReconcile` policy in
339
+ `verify.reconcile-policy-captured` at the action after reconciliation completes,
340
+ before verification starts. Log-index replay keeps it scoped to that completion;
341
+ subsequent config changes cannot replace it mid-cycle. Historical already-started
342
+ cycles without a snapshot retain rerun-all behavior. A later code-review approval
343
+ restores ordinary verification. Policy exclusions precede plan/path applicability
344
+ and carry `skipCause: "post-reconcile-policy"` plus a setting-specific reason.
345
+ The shared dashboard model renders that reason, as does the PR summary.
346
+ Excluded steps do not re-verify merged code, so combination-only breakage can
347
+ land; forge requirements and reconcile budgets remain independent.
348
+ For enabled steps,
337
349
  `packages/core/src/kernel/plan-verify-selection.ts` resolves an approved plan's front-matter
338
350
  selection (applied at the planner's `ab done` in `packages/core/src/cli/terminals.ts`,
339
351
  snapshotted by the engine at approval), and
@@ -341,7 +353,7 @@ snapshotted by the engine at approval), and
341
353
  selectors, resolved by the build runner via `git diff` against the initial
342
354
  branch-cut base (or the refreshed base promoted by a completed reconcile).
343
355
  This verify-only base is deliberately independent from implementation's
344
- focused review range. Both narrowing mechanisms produce the ordinary
356
+ focused review range. All narrowing mechanisms produce the ordinary
345
357
  queryable skipped outcome; Git failure is infrastructure and fails closed,
346
358
  never a synthetic skip. Verify escalation routing is also explicit in the
347
359
  engine: guidance answering an agent verifier's own `ab escalate` returns to the
@@ -579,7 +591,7 @@ slug routing. Upgrade performs the same composition lazily at its first merge
579
591
  conflict.
580
592
 
581
593
  `packages/core/src/cli/repo-state.ts` owns repository identity and store precedence
582
- (`--store` > `AB_STORE` > `.autobuild/`); `packages/core/src/cli/store-opening.ts` is the
594
+ (`--store` > `AB_STORE` > `[store] url` > `.autobuild/`); `packages/core/src/cli/store-opening.ts` is the
583
595
  production store composition boundary shared by finite sessionless queries and
584
596
  phase sessions. Its shared scoping primitive preserves remote token composition
585
597
  and adds local ambient authority only for filesystem stores. The dedicated
@@ -599,7 +611,15 @@ phase-only commands report their complete runner context when run by hand.
599
611
  correlations, and pending cleanup without coupling to a producer or verify-step
600
612
  name. `packages/core/src/cli/pr-attachments.ts` performs optional image hosting through the
601
613
  narrow Forge capability, while `packages/core/src/cli/pr-summary.ts` renders the same complete
602
- text projection for finalize and late designations. The GitHub release transport
614
+ text projection for finalize and late designations. `cli/pr-summary-publication.ts`
615
+ coalesces these at completed phase boundaries with durable attempt, result,
616
+ cooldown, request, and disposition facts. Built-in forges upsert one hidden
617
+ per-build marker; legacy plugins keep the existing bounded `commentOnPr` API.
618
+ Oversized bodies become a compact pinned download of a full `pr-summary`
619
+ store artifact. Local runners publish under their lease; remote guests request
620
+ and yield, and dispatcher settlement fences ended execution and owns the
621
+ publication lease before launching replacement work. Summary failure never
622
+ changes phase outcomes. The GitHub release transport
603
623
  lives in `packages/core/src/ports/forge/github-pr-attachments.ts`; terminal-build reclamation
604
624
  and retry facts remain dispatcher janitor duty.
605
625
 
@@ -876,3 +896,45 @@ because they cannot be manufactured safely against a live account.
876
896
 
877
897
  Provisioning or scheduling these credentials/resources in CI is deliberately
878
898
  out of scope; live runs remain explicit.
899
+
900
+ ## Hosted project registry
901
+
902
+ `packages/postgres-store/src/projects.ts` owns a narrow project registry port
903
+ beside BuildStore. Schema v10 adds an independent append-only project journal
904
+ and singleton mutation/bootstrap lock and marker, with no build/ticket foreign
905
+ keys. Active entries reduce the latest sequence per origin; timestamps are
906
+ metadata, not ordering. Runtime opens assert schema and never run DDL.
907
+ `ab-hosted-store projects` administers registrations using database authority.
908
+ The service exposes one lazy live reader to the operator server, web gateway,
909
+ MCP and server-rendered repository picker. Initialization failures clear the
910
+ cached promise for retry. The dispatcher opens its own shared pool and queries
911
+ membership each invocation. See [owner workflow](setup.md#connected-projects).
912
+
913
+ ## Delegated execution authority
914
+
915
+ `store/remote/credentials.ts` owns the credential exchange client independently
916
+ of the BuildStore persistence port. The hosted service's `delegated-authority.ts`
917
+ validates issuance, durable lifecycle bindings and the 60-second terminal grace;
918
+ `machine-auth.ts` authenticates these signed version-2 grants as delegated
919
+ principals. `remote-store-server.ts` enforces resource mutations before deposits,
920
+ including body-selected and addressed-stream resources. Operator routes reject
921
+ these principals. Ticket routes deny build grants and allow harvest grants only the reads and
922
+ runner filing operations they require. Ticket sources and assets are partitioned
923
+ by the authenticated project.
924
+
925
+ Dispatch prepares harvest claims using `HarvestRunner.run(true)` before issuing
926
+ an execution grant. `harvest.execution.authorized` binds the selected run,
927
+ execution and adopted lease holder; the guest resumes only that prepared run.
928
+ Local completion records `harvest.execution.ended`; hosted completion retains
929
+ its provider release fact. Recovery controls remain trusted dispatcher work.
930
+ Execution launch auth is transient and separate from serialized identity. Runners
931
+ request exact phase grants after session-start facts and before runtime calls.
932
+ Workspace plugin factories receive an exchange callback and a scrubbed environment,
933
+ while local children and sandbox bootstrap/launch replace inherited authority.
934
+ Service requests reread durable state; detached executions need neither renewal
935
+ secrets nor their original dispatcher. Local stores retain their existing path.
936
+ Project onboarding uses `cli/connect.ts`, user-level `cli/project-credentials.ts`,
937
+ the shared `connection.ts` wire types, and Postgres `connections.ts`. Approval
938
+ commits registry membership, a credential digest, and the outcome atomically.
939
+ The web connection routes authenticate the existing Better Auth session and
940
+ reuse the sign-in/consent layout; CLI polling uses a separate private capability.