@uchibeke/gallivant 0.2.0 → 0.3.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 (133) hide show
  1. package/README.md +120 -60
  2. package/SECURITY.md +9 -0
  3. package/bin/gallivant.mjs +41 -14
  4. package/bin/promote-bitbucket.mjs +40 -0
  5. package/bin/task-pr.mjs +9 -0
  6. package/bin/task-review.mjs +15 -0
  7. package/docs/README.md +6 -2
  8. package/docs/agent-setup.md +55 -41
  9. package/docs/architecture.md +11 -3
  10. package/docs/bitbucket-promotion.md +69 -0
  11. package/docs/bitbucket-review.md +330 -0
  12. package/docs/chains.md +30 -1
  13. package/docs/codex-cloud.md +7 -0
  14. package/docs/codex-review.md +50 -0
  15. package/docs/commands.md +103 -14
  16. package/docs/config.md +45 -13
  17. package/docs/execution.md +1 -1
  18. package/docs/first-party-review.md +266 -0
  19. package/docs/git-hosts.md +294 -0
  20. package/docs/guardrails.md +56 -0
  21. package/docs/install.md +137 -67
  22. package/docs/launch.md +7 -4
  23. package/docs/network-recovery.md +9 -0
  24. package/docs/openai-agents.md +3 -2
  25. package/docs/prd.md +23 -2
  26. package/docs/preparation.md +2 -2
  27. package/docs/release-qualification.md +1 -1
  28. package/docs/releasing.md +46 -22
  29. package/docs/task-delivery.md +5 -5
  30. package/docs/task-profiles.md +537 -0
  31. package/docs/tasks.md +59 -197
  32. package/lib/attribution.mjs +7 -3
  33. package/lib/block.mjs +10 -1
  34. package/lib/chains.mjs +101 -30
  35. package/lib/codex_cloud.mjs +2 -1
  36. package/lib/codex_cloud_input.mjs +15 -6
  37. package/lib/codex_cloud_result.mjs +1 -1
  38. package/lib/commands/doctor.mjs +22 -453
  39. package/lib/commands/init.mjs +281 -28
  40. package/lib/commands/register.mjs +81 -13
  41. package/lib/commands/resume.mjs +5 -1
  42. package/lib/commands/review.mjs +66 -0
  43. package/lib/commands/serve.mjs +8 -0
  44. package/lib/commands/start.mjs +30 -11
  45. package/lib/commands/status.mjs +18 -2
  46. package/lib/commands/task.mjs +9 -1
  47. package/lib/commands/up.mjs +19 -11
  48. package/lib/commands/why.mjs +7 -3
  49. package/lib/config.mjs +42 -9
  50. package/lib/context.mjs +28 -21
  51. package/lib/control.mjs +21 -6
  52. package/lib/credential.mjs +20 -14
  53. package/lib/deliverable.mjs +2 -0
  54. package/lib/events.mjs +96 -53
  55. package/lib/execution.mjs +132 -11
  56. package/lib/execution_preparation.mjs +16 -1
  57. package/lib/execution_result.mjs +26 -5
  58. package/lib/first_party_review.mjs +618 -0
  59. package/lib/fs.mjs +10 -3
  60. package/lib/gh.mjs +144 -56
  61. package/lib/git.mjs +133 -32
  62. package/lib/git_diff.mjs +121 -0
  63. package/lib/harness.mjs +14 -10
  64. package/lib/host_contract.mjs +71 -0
  65. package/lib/host_definitions.mjs +22 -0
  66. package/lib/hosts/bitbucket.mjs +553 -0
  67. package/lib/hosts/bitbucket_contract.mjs +57 -0
  68. package/lib/hosts/bitbucket_credential.mjs +62 -0
  69. package/lib/hosts/bitbucket_review.mjs +44 -0
  70. package/lib/hosts/bitbucket_review_producer.mjs +50 -0
  71. package/lib/hosts/github.mjs +57 -0
  72. package/lib/hosts/github_contract.mjs +27 -0
  73. package/lib/hosts/github_doctor.mjs +482 -0
  74. package/lib/hosts/github_review_summary.mjs +38 -0
  75. package/lib/hosts/transport_doctor.mjs +35 -0
  76. package/lib/hosts.mjs +130 -0
  77. package/lib/learning_qualification.mjs +1 -1
  78. package/lib/notify.mjs +1 -1
  79. package/lib/openai_agents_input.mjs +7 -2
  80. package/lib/openai_agents_sources.mjs +16 -8
  81. package/lib/plugin_package.mjs +13 -1
  82. package/lib/pr_operation.mjs +41 -0
  83. package/lib/prd.mjs +18 -3
  84. package/lib/preparation_codex.mjs +6 -1
  85. package/lib/probe.mjs +6 -4
  86. package/lib/process.mjs +24 -0
  87. package/lib/promotion.mjs +132 -0
  88. package/lib/promotion_git.mjs +63 -0
  89. package/lib/prompt.mjs +16 -13
  90. package/lib/provider_health.mjs +14 -3
  91. package/lib/repository.mjs +68 -0
  92. package/lib/repository_preflight.mjs +11 -0
  93. package/lib/review_evaluation.mjs +25 -0
  94. package/lib/review_evidence.mjs +500 -0
  95. package/lib/review_history.mjs +73 -0
  96. package/lib/review_image.mjs +145 -0
  97. package/lib/review_link.mjs +12 -0
  98. package/lib/review_policy.mjs +132 -0
  99. package/lib/review_policy_contract.mjs +18 -0
  100. package/lib/review_state.mjs +13 -0
  101. package/lib/review_visual.mjs +94 -0
  102. package/lib/runtime-environment.mjs +6 -0
  103. package/lib/runtime_node.mjs +3 -2
  104. package/lib/runtime_state.mjs +39 -5
  105. package/lib/sources/prd.mjs +6 -3
  106. package/lib/state.mjs +137 -24
  107. package/lib/task_completion.mjs +7 -3
  108. package/lib/task_contract.mjs +201 -27
  109. package/lib/task_delivery.mjs +9 -2
  110. package/lib/task_delivery_contract.mjs +13 -9
  111. package/lib/task_delivery_view.mjs +18 -2
  112. package/lib/task_environment.mjs +13 -1
  113. package/lib/task_limits.mjs +13 -0
  114. package/lib/task_model_config.mjs +99 -0
  115. package/lib/task_model_route.mjs +243 -0
  116. package/lib/task_prepare.mjs +21 -8
  117. package/lib/task_profile.mjs +1875 -0
  118. package/lib/task_repository_context.mjs +65 -0
  119. package/lib/tasks.mjs +252 -51
  120. package/lib/tick.mjs +373 -98
  121. package/lib/time.mjs +1 -0
  122. package/lib/tracker/pages.mjs +19 -5
  123. package/lib/tracker/review.mjs +21 -0
  124. package/lib/tracker_process.mjs +8 -1
  125. package/lib/verification_sandbox.mjs +2 -1
  126. package/lib/work_artifacts.mjs +79 -0
  127. package/npm-shrinkwrap.json +12 -3
  128. package/package.json +9 -3
  129. package/templates/plugin/task-delivery.SKILL.md +17 -10
  130. package/templates/plugin/task-intake-contract.json +18 -0
  131. package/templates/plugin/task-profile-requests.mjs +1448 -0
  132. package/templates/tracker/tracker.css +3 -0
  133. package/templates/tracker/tracker.js +38 -0
@@ -1,9 +1,10 @@
1
1
  # Let an agent set up Gallivant
2
2
 
3
- Give the prompt below to your coding agent. It can inspect prerequisites, install
4
- the CLI, create a private config and validate a first task. You handle account
5
- login and any required trust prompts. Setup does not need access to every private
6
- repository, and installing the CLI does not start a paid session.
3
+ Give the prompt below to your coding agent. It can inspect prerequisites, run
4
+ the published setup command, read the resulting report and validate a first task.
5
+ You handle account login and any required trust prompts. Setup does not need
6
+ access to every private repository, and running the setup command does not start
7
+ a paid session.
7
8
 
8
9
  Start with **Codex or Claude and one repository**. Those are the harnesses supported
9
10
  by `gallivant init`. [Hosted Agents API](openai-agents.md) uses an explicit config
@@ -24,12 +25,15 @@ CLI --help and the docs matching the installed version. Prefer an already workin
24
25
  Codex or Claude setup. Preserve existing credentials, settings, running jobs,
25
26
  worktrees and uncommitted changes. Report proposed config changes without secrets.
26
27
 
27
- Install/configure the CLI and run the setup checks. If Gallivant is not yet
28
- published on npm, use the documented source installation. Do not overwrite an
29
- existing config, weaken security settings, install global hooks, change repository
30
- protections, sign into accounts or elevate privileges without the relevant user
31
- authorization. Never ask me to paste API keys or tokens into this conversation.
32
- Use the provider's login flow or a private credential file instead.
28
+ From inside the target checkout, run the published setup command:
29
+ npx --yes @uchibeke/gallivant init --harness codex (or --harness claude), then
30
+ read its report. Do not clone the Gallivant repository or install it globally
31
+ unless I ask. If the command stops because gh or the harness is signed out, tell
32
+ me the exact login command it printed and wait; do not sign in for me. Do not
33
+ overwrite an existing config, weaken security settings, install hooks, change
34
+ repository protections or elevate privileges without my authorization. Never ask
35
+ me to paste API keys or tokens into this conversation. Use the provider's login
36
+ flow or a private credential file instead.
33
37
 
34
38
  Ask only for missing decisions: target repository and checkout, approved base
35
39
  branch, preferred available harness, first task scope, and allowed spending.
@@ -88,38 +92,45 @@ automatically commit, or switch a dirty checkout. Confirm which GitHub repositor
88
92
  and base branch the task should use; the current branch is not necessarily the
89
93
  approved PR target. Account login and Git identity belong to the user.
90
94
 
91
- ## 2. Install and initialize
95
+ ## 2. Run the setup command
92
96
 
93
- Use the [current installation instructions](install.md#1-the-command). Before
94
- the first npm publication, install from source; `npm install -g @uchibeke/gallivant` is only
95
- an option after the package is published. Avoid `sudo npm install`; use a
96
- user-owned Node installation or prefix when global installation is not writable.
97
- Do not silently replace a different installed version while its daemon is running.
98
-
99
- After GitHub and the selected harness are signed in:
97
+ Use the [current installation instructions](install.md#2-the-command). After
98
+ GitHub and the selected harness are signed in, from inside the target checkout:
100
99
 
101
100
  ```sh
102
- gallivant --version
103
- gallivant --help
104
- gallivant init --harness codex
105
- gallivant doctor
101
+ npx --yes @uchibeke/gallivant init --harness codex # or: --harness claude
106
102
  ```
107
103
 
108
- Use `--harness claude` for Claude. `init` is noninteractive; it creates a config
109
- only when none exists. It does not log in, install hooks or fix permissions.
110
- If a config exists, skip `init` and preserve its unrelated keys. The normal path
111
- is `~/.gallivant/config.json`; use `$GALLIVANT_HOME/config.json` if that variable is
112
- already set. Keep it private (mode `600`). Choose a worktrees directory outside
113
- the config home, using `init --worktrees /absolute/path` if needed.
114
-
115
- Before a real run, finish the [harness guardrail setup](install.md#6-aport-on-claude-code)
104
+ `npx` runs the published package on demand; it installs nothing globally and
105
+ does not clone this repository. `init` is noninteractive. It refuses, writing
106
+ nothing, when the directory is not a GitHub checkout, `gh` or the harness is
107
+ signed out, or the login cannot push to the repository; report the printed
108
+ command to the user instead of working around it. Otherwise it creates
109
+ `~/.gallivant/config.json` (mode 600) when none exists, records the current
110
+ repository in `repos` once, creates the worktrees directory and prints the
111
+ `doctor` report. Exit status `1` means checks remain, not that setup failed.
112
+
113
+ With an existing config, `init` keeps every key as written and adds only the
114
+ current repository. Do not edit unrelated keys. The normal path is
115
+ `~/.gallivant/config.json`; use `$GALLIVANT_HOME/config.json` if that variable is
116
+ already set. Pass `--worktrees /absolute/path` only on first creation; later
117
+ runs refuse a different directory.
118
+
119
+ If the user prefers a persistent command, `npm install -g @uchibeke/gallivant`
120
+ is the documented option; ask before installing globally. Avoid `sudo npm
121
+ install`; use a user-owned Node installation or prefix. Do not silently replace
122
+ a different installed version while its daemon is running.
123
+
124
+ Before a real run, finish the [harness guardrail setup](install.md#7-aport-on-claude-code)
116
125
  for the selected harness. Some steps require human interaction: for example,
117
126
  Codex's initial `/hooks` trust prompt cannot be automated. Report such a blocker
118
127
  instead of changing the enforcement level or bypassing it.
119
128
 
120
- Add the authorized repository to `repos` and its approved base where necessary,
121
- following [configuration](config.md#the-base-branch). Review the config diff without
122
- printing credentials. Confirm these decisions before dispatch:
129
+ `init` records the repository without a base branch; its pull requests target
130
+ the default branch unless the user chooses otherwise with `start --base` or a
131
+ `{ "repo", "base" }` entry, following [configuration](config.md#the-base-branch).
132
+ Review the config diff without printing credentials. Confirm these decisions
133
+ before dispatch:
123
134
 
124
135
  | Decision | What must be established |
125
136
  |---|---|
@@ -129,8 +140,9 @@ printing credentials. Confirm these decisions before dispatch:
129
140
  | Completion evaluator | Default APort hosted confirmation needs network access. A local evaluator is an explicit user choice, not an automatic workaround for a failure. |
130
141
  | Cost | Confirm `max_iterations`, provider budget controls and allowed spend. `max_budget_usd` is a native per-run dollar cap for Claude; other local harnesses have no equivalent enforced dollar cap. |
131
142
 
132
- Run `gallivant doctor` again and report every failure. Do not treat “signed in
133
- (API unchecked)” as proof of inference access. `doctor` without extra flags checks
143
+ Run `gallivant doctor` (or `npx --yes @uchibeke/gallivant doctor`) again and
144
+ report every failure. Do not treat “signed in (API unchecked)” as proof of
145
+ inference access. `doctor` without extra flags checks
134
146
  configuration, credentials and repository access without launching a model run.
135
147
  `doctor --probe` launches a real Claude sandbox test when Claude is configured;
136
148
  `doctor --send` sends a real notification. Use those only when authorized.
@@ -206,9 +218,11 @@ review and merge.
206
218
 
207
219
  ## What setup verification proves
208
220
 
209
- The package's `npm run test:install` smoke test installs the tarball into a
210
- throwaway directory, uses fixture CLI credentials, initializes a private config,
211
- loads the packaged PRD template, and checks an offline brief. It does not use a
212
- real account, invoke a model or certify a provider's current availability.
213
- A first authorized end-to-end task is still needed to verify the user's actual
214
- repository permissions, provider entitlement, sandbox, CI and review integration.
221
+ The package's `npm run test:install` check packs the tarball and runs the
222
+ README's `npx` setup command against it from a disposable repository, with
223
+ fixture `gh` and `codex` commands and a throwaway home. It proves which binary
224
+ ran, the config and directory permissions, repository registration, repeat
225
+ safety and the printed next steps. It does not use a real account, invoke a
226
+ model or certify a provider's current availability. A first authorized
227
+ end-to-end task is still needed to verify the user's actual repository
228
+ permissions, provider entitlement, sandbox, CI and review integration.
@@ -38,6 +38,10 @@ lib/events.mjs pure rules: what counts as an event, trust, reviewer ve
38
38
  lib/prompt.mjs start, register and fix prompts; quoting and caps
39
39
  lib/harness.mjs capability registry plus local argv, session, outcome and sign-in adapters
40
40
  lib/tasks.mjs natural-language intake, revisions, validation, readiness and explicit execution consent
41
+ lib/task_profile.mjs portable typed delivery profile, deterministic delivery screen and planner tag coverage (vendored by Agent Passport)
42
+ lib/task_model_route.mjs bounded text-only model route for drafting; pre-call allowance checks, usage-derived cost
43
+ lib/task_model_config.mjs operator configuration and absolute ceilings for that route
44
+ lib/task_repository_context.mjs read-only, bounded repository snapshot pinned to the prepared revision
41
45
  lib/task_delivery.mjs authenticated host operation boundary; delegates to the same task service
42
46
  lib/execution.mjs durable local/remote dispatch, ownership, observations and recovery
43
47
  lib/execution_result.mjs owned hosted artifact verification and coordinator publication
@@ -72,10 +76,10 @@ templates/ passport, Claude sandbox settings, PRD, tracker/{tracke
72
76
 
73
77
  ## Design rules
74
78
 
75
- New intake tasks targeting `delivery_ready` stop automatic observation and fixing
79
+ Legacy review policies on intake tasks targeting `delivery_ready` stop automatic observation and fixing
76
80
  at the qualified saved handoff. Explicit queued recheck/resume/message controls
77
81
  reopen the workflow. `integrated` targets and legacy written-PRD runs retain
78
- monitoring. `completionStopsAutomation` and the exported `coordinatorEntryActive`
82
+ monitoring. Version-1 review policies keep ready deliveries monitored so late trusted feedback and changed input can revoke readiness. `completionStopsAutomation` and the exported `coordinatorEntryActive`
79
83
  keep core and host schedulers aligned. The review transitions below apply while
80
84
  an entry is monitored; malformed or incomplete delivery proof cannot mark it
81
85
  finished or suppress work.
@@ -215,7 +219,7 @@ For each registry entry that is not `done`:
215
219
  6. **Dispatch.** Past the cap, stop with `iterations`. Otherwise recreate the checkout if it is gone, merge the base branch into the work branch, build the fix prompt, resume the session (or start one for a registered PR), move the cursor to the newest event and record the ids dispatched at that instant, record the run.
216
220
 
217
221
  The merge is where a round of work starts from the current base rather than from wherever the base was when the branch was cut, and it is a merge rather than a rebase for three reasons that all live in this codebase. A rebase of a pushed branch can only move with a force-push, which the rules every session is given forbid. `reviewerVerdict` clears a head only when the commit the reviewer named is that head, so a rewrite makes every prior clearance describe a commit that no longer exists, and the reviewer's inline comments are anchored to those same commits. And step 7 reads a head the loop did not put there as a person's push, so a daemon force-push would look to the daemon itself like a stranger pushing. A merge moves the head forward, keeps every reviewed commit an ancestor, and needs no `--force`. An outstanding review therefore does not hold it up, which is the point: a rebase would have had to wait for the review, and that is a deadlock where the reviewer waits for a fix and the fix waits for the reviewer. The merge commit stays local until the session pushes, so nothing on GitHub moves, the reviewer clock is not reset and the round is still counted from the session's own push. It is recorded the moment it succeeds rather than by the save at the end of this step, because four things after it can return early and a merge nobody recorded is a change to a checkout with nothing to explain it. A conflict is aborted and the entry stops with `base-conflict` naming the base, because a half-merged checkout handed to a session as if it were clean is the worst thing this step could leave, and a conflict does not resolve on its own so retrying every tick would loop forever. Four things that would refuse identically on every poll stop the entry instead of looping: a checkout that cannot be recreated (`no-worktree`, with the cause as the event), a harness that refuses the configured `context_paths` (`context-paths`), no GitHub credential (`no-credential`) and no git identity on the machine (`no-identity`, whose event is the two `git config --global` commands that fix it). None of them resolves on its own, and the entry would otherwise redispatch the same feedback every poll with nothing notified. One invariant orders the rest of this step: **a spawned run must be recorded before anything else can fail.** Everything that can throw, the checkout and the ready-label removal included, happens before the spawn, and the registry write that owns the run comes immediately after it with no `await` in between. A process the registry does not know about is the worst state the dispatch can leave, because the settle step reads it as an unrelated leftover and the feedback that caused it is still new, so the same feedback spawns a second fixer when the first one exits. The label removal is the one write that can therefore hold a dispatch back, and holding it back is bounded: five consecutive failures stop the entry with `stuck`. `gh.removeLabel` throws by default and swallows only gh's own "label not found", which is what makes that bound reachable at all: the lenient behaviour was once the default, one of the two callers omitted the flag, and a GitHub that refused the write resolved as though the label had merely been absent.
218
- 7. **Ready.** First, a head nobody told the loop about. Both watching states go through the same check, in one place: `fixed_sha` follows the head, the reviewer clock resets to the push and the nudge becomes available again, because the reviewer has not seen this commit. A `ready` entry also leaves ready with the label off, since its verdict, its green checks and its accepted receipt all describe a commit that is not the head any more. Handling it for `ready` alone used to leave a `pr-open` entry judging the new head with the old head's age, so the same tick that noticed the push could stop it as `reviewer-silent` on a wait that expired before the commit existed, and the nudge already spent on the old head was never reissued. Then, for a `pr-open` entry: no events, no run, not a draft, every check green (none counts as green), reviewer clear or absent. Then the brief, compared with the operator's own copy: this is the only place the daemon reads their working tree, and it is here because this is where the contract is about to be used to certify something. A contract that moved stops the entry with `prd-changed` and the difference named, before the gate runs and without setting `gate_skipped`, which describes the other thing entirely (a PR that reached READY with the gate unrun, where this entry is not reaching ready at all). An edit outside the contract re-takes the snapshot, notifies nobody and carries on. Then the completion gate (`deliverable.mjs`): the PR body's receipt must attest every acceptance criterion of the PRD with evidence; a deny starts a receipt round. A receipt whose shape is wrong is one of those denies, not an exception. The output scan needs the whole diff, so a diff that cannot be read or reaches the 16 MiB scan cap is no decision at all. Large hosted payloads are sent in overlapping pieces within the API request limit, with full criteria and attestations on each; every piece must allow. Unreadable diffs and unavailable evaluators use the same bounded `entry.retry` mechanism as writes, with the cause visible in `status` and `why`; five consecutive failures stop as `needs-human`, without a fixer run or iteration. The label goes on before the registry says ready, so a label write that fails leaves the entry in `pr-open` to be retried rather than a ready PR carrying no label, and those retries are counted on the same `entry.retry` as every other declining write: a token that cannot write labels at all used to repeat the readiness judgement, the completion gate included, on every poll forever, while `status` said the entry was waiting on a reviewer who had already answered. Only then notify, once.
222
+ 7. **Ready.** First, a head nobody told the loop about. Both watching states go through the same check, in one place: `fixed_sha` follows the head, the reviewer clock resets to the push and the nudge becomes available again, because the reviewer has not seen this commit. A `ready` entry also leaves ready with the label off, since its verdict, its green checks and its accepted receipt all describe a commit that is not the head any more. Handling it for `ready` alone used to leave a `pr-open` entry judging the new head with the old head's age, so the same tick that noticed the push could stop it as `reviewer-silent` on a wait that expired before the commit existed, and the nudge already spent on the old head was never reissued. Then, for a `pr-open` entry: no events, no run, not a draft, checks settled and the pinned review policy satisfied. Version-1 policies require explicit zero-check CI authorization for an empty check response; legacy no-review is disclosed as absence of review. Then the brief, compared with the operator's own copy: this is the only place the daemon reads their working tree, and it is here because this is where the contract is about to be used to certify something. A contract that moved stops the entry with `prd-changed` and the difference named, before the gate runs and without setting `gate_skipped`, which describes the other thing entirely (a PR that reached READY with the gate unrun, where this entry is not reaching ready at all). An edit outside the contract re-takes the snapshot, notifies nobody and carries on. Then the completion gate (`deliverable.mjs`): the PR body's receipt must attest every acceptance criterion of the PRD with evidence; a deny starts a receipt round. A receipt whose shape is wrong is one of those denies, not an exception. The output scan needs the whole diff, so a diff that cannot be read or reaches the 16 MiB scan cap is no decision at all. Large hosted payloads are sent in overlapping pieces within the API request limit, with full criteria and attestations on each; every piece must allow. Unreadable diffs and unavailable evaluators use the same bounded `entry.retry` mechanism as writes, with the cause visible in `status` and `why`; five consecutive failures stop as `needs-human`, without a fixer run or iteration. The label goes on before the registry says ready, so a label write that fails leaves the entry in `pr-open` to be retried rather than a ready PR carrying no label, and those retries are counted on the same `entry.retry` as every other declining write: a token that cannot write labels at all used to repeat the readiness judgement, the completion gate included, on every poll forever, while `status` said the entry was waiting on a reviewer who had already answered. Only then notify, once.
219
223
  8. **Silence.** Reviewer configured and quiet since the last request: nudge once after `rereview_minutes`, stop with `reviewer-silent` after `stall_hours`. Draft conversion in step 3 starts a fresh reviewer window, so time spent as a draft does not count as reviewer silence.
220
224
 
221
225
  The reviewer clock (`rereview.at`) is when the reviewer was last asked about the current head, and all three of those timers measure from it. Its best available value is the head commit's committer date, which is when the commit was made and not when it arrived on the branch, so it is floored at `rereview_minutes` ago: a commit made on Monday and pushed on Thursday must not stop the PR for a silence the reviewer was never given a chance to break. The rule is `reviewerClock` in `events.mjs`, pure and in one place because the tick is not its only writer: `reconcile` sets the same field on a recovered entry and goes through the same function, so a PR whose last round comment is older than `stall_hours` is not stopped `reviewer-silent` on the first tick after a crash recovery for silence that accrued while no daemon was running to ask.
@@ -263,3 +267,7 @@ a successful version probe alone cannot establish unattended support.
263
267
  ## Adding a reviewer
264
268
 
265
269
  No code. Set `reviewer.login`, `reviewer.rereview_comment` and `reviewer.blocking_pattern` in config.
270
+
271
+ ## Coordinator-owned first-party review
272
+
273
+ `review_policy.mjs` owns versioned task policy and input bindings; `review_evidence.mjs` captures complete snapshots and validates structured judgement. `first_party_review.mjs` advances keyed review jobs through the existing execution registry, in a separate session and allowance. The shared tick handles readiness, trusted external feedback and fix rounds. Review jobs do not create a second scheduler or publish independent approvals. Host adapters provide the same normalized evidence contract; only the existing GitHub boundary is implemented here. See [policy and recovery behavior](first-party-review.md), including native qualification and measured rollout limitations.
@@ -0,0 +1,69 @@
1
+ # Review on GitHub, deliver through Bitbucket
2
+
3
+ `npm run promote:bitbucket` transfers an accepted GitHub PR's **original commits** to Bitbucket Cloud and creates or updates its Bitbucket PR. It uses Git transport, the existing host adapters and the same review/check policy as the coordinator. It does not copy files, create commits, force-push, merge, enable CI or deploy.
4
+
5
+ This is an operator command from a Gallivant source checkout. Install dependencies with `npm ci`. Configure both hosts using the [Git host guide](git-hosts.md); Git push access and Bitbucket API repository/PR access are both required. The command uses the existing scoped credentials, including a configured Bitbucket SSH key. Never put a token in a repository URL or a plan file.
6
+
7
+ ## Before promotion
8
+
9
+ - Register and finish the GitHub run. It must retain an exact accepted completion and review binding under an explicit review policy. A label, green CI or the PR author's statement alone is insufficient.
10
+ - Stopped dispatch and queued/applying operator controls block promotion. Cancellation, messages, resume and recheck requests must be reconciled before accepted work can be delivered. These controls are checked again after plan validation and after a push; a cancellation during an already-running push can leave the branch updated, but prevents subsequent PR publication when observed.
11
+ - Only the exact remotely reviewed commit is transferred. Local checkout edits, untracked carried research inputs, environment files and session logs are neither read nor included. The transfer uses its own disposable bare Git repository, so an operator checkout may remain dirty or may already have been removed after merge.
12
+ - Specify the destination repository explicitly. No organization or repository mapping is inferred.
13
+ - For an existing Bitbucket PR, supply its number. This updates that PR rather than creating a duplicate.
14
+ - The Bitbucket base must have the same Git tree as the reviewed GitHub base. Its commit hash may differ because the two hosts merged earlier changes separately. Promote dependent work in order, after the preceding Bitbucket change has merged. Reconcile differing trees on GitHub and obtain review again.
15
+ - An existing destination branch must be an ancestor of the reviewed source head. Divergence is not resolved automatically.
16
+
17
+ GitHub Actions may remain disabled for a review-only mirror. Zero CI checks are accepted **only** when the source run's operator-approved review policy explicitly allows zero checks. Configured required checks still must exist and pass. Local test results and production release requirements are not replaced by that setting. Missing required external or first-party review blocks promotion.
18
+
19
+ ## Preview, approve and apply
20
+
21
+ For an existing mapped PR:
22
+
23
+ ```sh
24
+ npm run promote:bitbucket -- \
25
+ --github-pr https://github.com/example/app/pull/1 \
26
+ --bitbucket-repo bitbucket.org/example/app \
27
+ --bitbucket-pr 93 \
28
+ --out accepted-promotion.json
29
+ ```
30
+
31
+ The default is a remote read-only dry run. It fetches into a disposable temporary Git repository and prints the source and destination heads, bases, exact title/body, review policy, check count and a SHA-256 `digest`. `--out` saves that plan locally with mode 600 and refuses to overwrite an existing file. Keep private plans outside your repository; they contain private PR prose and the previous destination PR text, which may include its task metadata. Transport credentials are never added to the plan.
32
+
33
+ Inspect the complete plan, then rerun the same mapping with its digest:
34
+
35
+ ```sh
36
+ npm run promote:bitbucket -- \
37
+ --github-pr https://github.com/example/app/pull/1 \
38
+ --bitbucket-repo bitbucket.org/example/app \
39
+ --bitbucket-pr 93 \
40
+ --apply --expected-plan DIGEST_FROM_THE_DRY_RUN
41
+ ```
42
+
43
+ The digest is an exact human approval pin, not a substitute for fresh review evidence. Changed source code, review, checks, public text, destination branch, base or existing PR text requires another dry run. The command reads accepted state and operator controls from the run registry; it never writes that registry or starts another agent.
44
+
45
+ For a new PR, omit `--bitbucket-pr`. The default destination branch is `work/github-OWNER-REPO-pr-N`; `--branch` and `--base` select explicit alternatives. Subsequent runs reuse an existing PR only when its repository, branch/base and source-review provenance match. Otherwise supply an explicit PR mapping. Closed, cross-repository or duplicate targets are rejected.
46
+
47
+ The Bitbucket title and human-readable body come from the GitHub PR, with a source-review link and original commit SHA appended. Source task receipts and recovery/session metadata are removed because they do not authorize a new host/task. The source GitHub PR retains the complete evidence.
48
+
49
+ ## After merging on GitHub
50
+
51
+ Run the same dry-run command after merge. When GitHub still supplies the original reviewed base, the coordinator's retained acceptance hash is checked directly against the original head, base, body, checks and policy. No pre-merge plan file is required. The accepted local record and fresh clear reviewer/check evidence remain mandatory; merging a PR before it was accepted does not manufacture that authority.
52
+
53
+ Optionally save `--out accepted-promotion.json` while the PR is accepted and still open. If GitHub later reports a different base, that archived plan can reconstruct the original base using:
54
+
55
+ ```sh
56
+ --accepted-plan /absolute/path/to/accepted-promotion.json
57
+ ```
58
+
59
+ Use the new printed digest for `--apply --expected-plan ...`, keeping `--accepted-plan` on that command too when using the fallback. The reconstructed binding must exactly match the coordinator's retained acceptance hash. The plan cannot replace a missing local acceptance record or authorize changed code, body, checks or policy.
60
+
61
+ The transferred head is the original reviewed PR head even when GitHub used squash or merge commits. The GitHub merge/squash commit is never described as reviewed or silently substituted. Squash merges can make subsequent branch histories diverge between hosts; prefer history-preserving merges for this bridge. A future branch that is not a fast-forward of its mapped Bitbucket branch must be reconciled and reviewed, not force-pushed.
62
+
63
+ ## Races and retries
64
+
65
+ Apply rechecks the plan before pushing. A native pre-push guard checks the server-advertised old branch SHA; Git's ordinary fast-forward update then compares that SHA on the server. No force or force-with-lease option is used.
66
+
67
+ There is no atomic transaction across GitHub and Bitbucket. The command rechecks evidence and destination after the push, before publishing the PR, and verifies the returned PR head/base. The publication adapter's final reconciliation read also enforces the approved PR absence or exact existing number and previous title/body. An observed concurrent creation or text edit stops publication. This adapter has no atomic conditional-update contract with Bitbucket: an edit between that final read and the write can still be overwritten without detection, so avoid concurrent PR editing during apply. If an operation fails, including a lost push response, the branch or PR may already have been updated; the error states that possibility. Inspect the target and rerun a dry run. Never respond with a force push. Bitbucket merge and deployment remain separate operator decisions and retain their normal release controls.
68
+
69
+ This bridge supports GitHub to Bitbucket Cloud only. It does not automatically schedule promotion, accept unregistered PRs, establish live production readiness, or migrate CI/secrets/deployment configuration.
@@ -0,0 +1,330 @@
1
+ # Bitbucket Cloud review setup and qualification
2
+
3
+ Bitbucket Cloud dispatch and complete first-party evidence capture are implemented.
4
+ The independent local review route is still **live-unqualified** until the public
5
+ and private disposable repository matrix records a genuine blocking verdict,
6
+ same-session correction and fresh exact-head clearance. Earlier disposable runs
7
+ proved regular PR publication and receipt acceptance with **no reviewer
8
+ configured**; they are not review evidence. The private coding session could also
9
+ read the coordinator's merge-capable API-token file by path, so that historical
10
+ coding-credential hold remains separate from reviewer credential isolation. Do
11
+ not migrate an existing legacy run or start unattended work on the strength of
12
+ offline fixtures. See the [qualification record](audit/bitbucket-review-qualification.md).
13
+
14
+ ## First setup, including a checkout with no existing configuration
15
+
16
+ Use Node 22 or later, Git, and an explicitly selected installed local Codex or
17
+ Claude executable. Bitbucket setup does not require `gh` or GitHub sign-in.
18
+ Version/sign-in diagnostics do not prove model access. Existing GitHub defaults
19
+ and runs retain their previous review semantics.
20
+
21
+ 1. Obtain an Atlassian **account API token** scoped to the intended workspace,
22
+ with `read:repository:bitbucket`, `write:repository:bitbucket`,
23
+ `read:pullrequest:bitbucket`, and `write:pullrequest:bitbucket`. Save it in a
24
+ private file (`chmod 600`). Supply the account email separately. An account
25
+ API token can be used with a free-plan repository; this does not require a
26
+ workspace/repository access-token subscription or Agentic Pipelines.
27
+ 2. For HTTPS Git, the coordinator uses the selected token as
28
+ `x-bitbucket-api-token-auth`; the API uses account email/token Basic auth.
29
+ For SSH Git, keep the API token and select the explicit SSH key/verified
30
+ known-hosts file described in [Git host setup](git-hosts.md). SSH authentication
31
+ alone cannot read or write PRs. The coding session receives neither token nor
32
+ SSH key through environment variables: its bounded PR mailbox asks the
33
+ coordinator to push and publish. A same-user coding process can still read
34
+ the configured private files unless a separate boundary denies those reads.
35
+ HTTPS and Cloud SSH checkout origins identify
36
+ the same repository; self-hosted servers and SSH aliases remain unsupported.
37
+ 3. Write a host settings file outside the coding checkout. Example:
38
+
39
+ ```json
40
+ {
41
+ "api": {
42
+ "email": "operator@example.com",
43
+ "token_file": "~/.config/repository-access/bitbucket-api-token"
44
+ },
45
+ "git": { "transport": "https" },
46
+ "trusted_authors": ["{11111111-1111-1111-1111-111111111111}"],
47
+ "reviewer": null,
48
+ "required_checks": ["Tests"]
49
+ }
50
+ ```
51
+
52
+ Replace the example UUID with the operator's stable Bitbucket UUID, not a nickname.
53
+ Select `reviewer: null` deliberately; the local first-party path needs no separate
54
+ Bitbucket reviewer account. After `init`, configure the repository entry for a
55
+ new reviewed run:
56
+
57
+ ```json
58
+ {
59
+ "repo": "bitbucket.org/workspace/repository",
60
+ "reviewer": null,
61
+ "review": {
62
+ "mode": "first-party-required",
63
+ "route": "codex",
64
+ "max_input_bytes": 100000,
65
+ "max_jobs": 2048,
66
+ "budget_usd": 100,
67
+ "zero_checks": false
68
+ }
69
+ }
70
+ ```
71
+
72
+ Keep `review.legacy_no_review: true` only for a deliberately unreviewed legacy
73
+ run while live qualification is unavailable. That mode still enforces configured
74
+ CI, trusted commands, unresolved required feedback and the completion receipt,
75
+ but its readiness record says `none`; it is never independently reviewed. The
76
+ example check name must exactly match the repository's build status name. An
77
+ empty `required_checks` list does not waive CI for a version-1 policy: a repository
78
+ with no checks must explicitly set `review.zero_checks: true`. Missing/partial
79
+ responses, rate limits, outages and pending checks never pass.
80
+
81
+ From the intended checkout:
82
+
83
+ ```sh
84
+ gallivant init --harness codex --host-config /absolute/path/bitbucket-host.json --base release/v2
85
+ gallivant doctor
86
+ ```
87
+
88
+ `--host-config` imports settings for the verified checkout's host. It creates a
89
+ new config, or accepts unchanged settings while preserving UUID bindings added
90
+ by setup. JSON member order does not matter; changed or omitted policy and
91
+ conflicting identity bindings are refused. `--base` is validated and saved on the repository entry.
92
+ `init` binds repository/workspace UUIDs, reads the selected base and account push
93
+ role, and verifies Git's base SHA against the API. `doctor` distinguishes unknown
94
+ write scopes from observed read access. Only an actual write can prove Git push,
95
+ PR creation and comment write permission. Setup never installs a pipeline,
96
+ creates a credential, changes repository protection, or makes a paid model call.
97
+ It reports dispatch availability separately from transport access.
98
+
99
+ Host settings live under `git_hosts["bitbucket.org"]`. `repositories["workspace/repo"]`
100
+ may override `api`, `git`, `reviewer`, `trusted_authors`, and `required_checks`,
101
+ alongside the UUID binding. Each override replaces that setting, not another
102
+ host's credentials. A `repos` object may override reviewer/trust/check policy;
103
+ precedence is repository entry, host repository binding, host settings. Historical
104
+ top-level reviewer/trust defaults apply only to GitHub. Reviewer objects for
105
+ Bitbucket must supply every required field; the GitHub mention is rejected.
106
+
107
+ ## Independent local Codex reviewer
108
+
109
+ The host adapter binds the repository UUID, PR number, full head and base object
110
+ IDs, and merge base. It paginates `diffstat/<head>..<base>?topic=true`, compares
111
+ that changed-path inventory to the complete raw comparison, and reads regular
112
+ UTF-8 source at the merge base and head through `src/{commit}/{path}`. Added,
113
+ modified, removed and renamed files all carry before/after text as applicable.
114
+ Unsupported binary, subrepository, missing-patch, duplicate, truncated, stale,
115
+ rate-limited, redirected and oversized evidence is refused. The coordinator
116
+ captures bounded symlink target data as untrusted Git objects without following
117
+ the link. Unsupported targets or ambiguous type transitions block review.
118
+ The PR binding is read again after capture. The API token stays behind the host boundary and is not
119
+ part of the reviewer prompt or environment.
120
+
121
+ The coordinator requests bounded PNG and JPEG sides at the exact revisions and
122
+ requires a separate image-capability qualification before launching visual jobs.
123
+ It combines their validated reports with text review and whole-PR synthesis.
124
+ The image qualification does not itself qualify the host or complete a PR review;
125
+ the [disposable live screenshot review](audit/bitbucket-review-qualification.md#live-image-qualification-and-disposable-review-2026-11-03)
126
+ reached a clear verdict after its owned outputs were recovered; the resend PR
127
+ has not been rechecked. Preserve the original files and incomplete state when any
128
+ capability or evidence is unavailable.
129
+
130
+ Qualify the exact configured executable/provider route only after authorizing its
131
+ separate paid challenge:
132
+
133
+ ```sh
134
+ gallivant review qualify --repo bitbucket.org/workspace/repository
135
+ gallivant review qualify --repo bitbucket.org/workspace/repository --run --wait
136
+ gallivant review qualify --repo bitbucket.org/workspace/repository
137
+ ```
138
+
139
+ The first and last commands are read-only. `--run` starts at most the one durable
140
+ qualification job for that fingerprint; CLI version and sign-in checks alone do
141
+ not prove selected-model access. Start refuses before author dispatch if the route
142
+ cannot qualify.
143
+
144
+ Qualification fingerprints use the adapter's selected provider environment,
145
+ configuration, credentials and executable. Parent-agent session and tool-call
146
+ IDs do not invalidate an existing qualification. The private Codex profile drops
147
+ the desktop-only `daybreak` flag for CLI compatibility; strict inspection of
148
+ effective permissions and managed policy remains required.
149
+
150
+ For a settled existing run that still has the explicit legacy snapshot, use the
151
+ audited transition and then recheck the same PR:
152
+
153
+ ```sh
154
+ gallivant review policy HANDLE --mode first-party-required \
155
+ --reason "Enable the qualified independent local reviewer"
156
+ gallivant recheck HANDLE
157
+ ```
158
+
159
+ This is the only path that removes the saved legacy policy. It retains the task
160
+ identity, original PRD snapshot, PR, checkout and implementation session. A
161
+ failed route preflight changes nothing and launches no review. Do not edit an
162
+ active WebBabyShower brief or local policy as an implementation test.
163
+
164
+ Each reviewer job is a fresh restricted Codex execution with no implementation
165
+ session, context mounts, tools, network, host/Git credential or publication
166
+ authority. The 100,000-byte input cap applies to every job. Large evidence is
167
+ split into immutable source/patch slices, including a single large lockfile or
168
+ line; every slice repeats the aggregate identities and all acceptance criteria.
169
+ Clearance requires every piece to complete and match. `max_jobs`, `budget_usd`
170
+ and per-job timeout bound the aggregate. If the full change does not fit those
171
+ bounds, the run stops with `review-incomplete`; no path or suffix is omitted.
172
+
173
+ ## External Bitbucket reviewer account
174
+
175
+ This is an alternative external-review setup, not required by the local path.
176
+ Use a separate Bitbucket account for the automated reviewer. Configure its stable
177
+ UUID, never its display name, nickname, the coding account, or a Pipeline label:
178
+
179
+ ```json
180
+ {
181
+ "reviewer": {
182
+ "actor_id": "{22222222-2222-2222-2222-222222222222}",
183
+ "rereview_comment": "Review the current commit and post a work-review verdict.",
184
+ "blocking_pattern": "\\bP[01]\\b"
185
+ }
186
+ }
187
+ ```
188
+
189
+ This fragment belongs in the coding coordinator's host/repository policy. The
190
+ reviewer token does **not** belong there. On a separate operator-controlled
191
+ reviewer machine, OS account, or isolated container, store another private config
192
+ with the same policy and the **reviewer** account email/token in `api`. Its token
193
+ needs repository read and PR read/write. The coding agent must have no filesystem,
194
+ environment, secret-store or container access to that credential. A private file
195
+ in a directory readable by the coding identity is not isolation. The review model
196
+ needs only the prepared input and a read-only checkout, never publication secrets.
197
+ Codex requires its own supported sign-in or provider credentials and actual model
198
+ access; CLI installation/sign-in alone cannot qualify it.
199
+
200
+ The installed `task-review` tool separates preparation and publication from
201
+ inference. It never invokes a model, changes model/provider settings, or posts a
202
+ review request. These review transport steps are covered by offline tests; the
203
+ intervening Codex execution and end-to-end publication are still unqualified:
204
+
205
+ ```sh
206
+ task-review prepare --config /private/reviewer-config.json \
207
+ --url https://bitbucket.org/workspace/repo/pull-requests/7 > review-input.json
208
+ ```
209
+
210
+ In the isolated reviewer checkout, use the operator-selected Codex executable
211
+ under the existing read-only review permissions to inspect the input's exact
212
+ head and diff. Follow `review-input.json.instructions`. Save its actual response
213
+ as `review-result.json`, containing only this JSON shape:
214
+
215
+ ```json
216
+ {
217
+ "head_sha": "0123456789012345678901234567890123456789",
218
+ "verdict": "blocking",
219
+ "summary": "Concrete findings from reviewing this exact commit."
220
+ }
221
+ ```
222
+
223
+ A successful model execution is not a verdict. Outside the model process, publish
224
+ its response with the separate reviewer credential:
225
+
226
+ ```sh
227
+ task-review publish --config /private/reviewer-config.json \
228
+ --url https://bitbucket.org/workspace/repo/pull-requests/7 \
229
+ --input review-input.json --result review-result.json
230
+ ```
231
+
232
+ Publication verifies the authenticated actor differs from the coding author and
233
+ matches `reviewer.actor_id`. It rechecks repository UUIDs, PR number, branches,
234
+ base, full head SHA and diff hash against the prepared input. An explicit retry
235
+ reuses an identical verdict only while it remains the reviewer's latest decision.
236
+ A superseded match causes a new publication, so blocking/clear/blocking decisions
237
+ take effect even on the same head. Uncertain comment writes are not silently
238
+ retried. Keep the real model transcript/run ID with qualification
239
+ artifacts: a manually authored fixture result cannot prove a Codex review.
240
+ An ordinary Pipeline can orchestrate these steps when an operator explicitly
241
+ installs it, enables Pipelines, and configures provider and reviewer secrets in an
242
+ isolated trusted job. Do not expose those secrets to arbitrary PR code or the
243
+ coding step. No paid Agentic Pipelines capability is assumed or installed.
244
+
245
+ The posted comment contains a `work-review` fenced JSON block. Only the configured
246
+ actor and a complete exact current SHA can clear readiness. Abbreviations, old-head
247
+ approvals, prose claiming a successful Pipeline, or a run with no posted verdict
248
+ are silence. Native Bitbucket approvals do not identify a reviewed commit and
249
+ cannot clear an automated-review gate. Native change requests and unresolved tasks
250
+ remain blockers until their authors remove/resolve them, including after one fix
251
+ round has consumed their events.
252
+
253
+ Trusted humans can post `/fix ...`. Inline findings use a verified code link to
254
+ the full source SHA or a standalone `Reviewed commit: <40-character-sha>` line.
255
+ Unknown inline heads stop readiness with the source link rather than silently
256
+ approving or dispatching a guessed head. A command explicitly naming an older head
257
+ is ignored. Replies authored by the coding account do not become new fix requests.
258
+
259
+ ## Session PR operations and recovery
260
+
261
+ `task-pr` is the bounded PR CLI used by Bitbucket start/fix/resume prompts. In a
262
+ task session it writes a bounded request to the checkout's mailbox; the daemon
263
+ verifies the saved repository, branch, base and PR identity, then uses its own
264
+ Git and API credentials. `push`, `create`, `edit` and `comment` push committed
265
+ HEAD through the coordinator before publication. `view` and `diff` are read
266
+ operations. The agent receives no Git or PR token and no SSH key in its
267
+ environment. Its observed ability to read the token file remains a dispatch
268
+ blocker. The
269
+ coordinator disables checkout hooks when running Git, so an agent-written
270
+ pre-push hook cannot run with coordinator authority. The mailbox has no merge,
271
+ deployment or repository-settings operation. Direct `task-pr` use outside an
272
+ agent session still requires an explicitly bound API credential.
273
+ The PR CLI created and reconciled a disposable private PR, read its exact head,
274
+ posted a comment and updated its body. A separate live public task also used it
275
+ to open and update a regular PR. See the [qualification record](audit/bitbucket-review-qualification.md).
276
+
277
+ After the credential boundary is qualified, local PRD commands use the verified
278
+ checkout, and `register` uses the exact PR
279
+ URL. Host-qualified state/worktree keys
280
+ prevent a same-named GitHub repository controlling a Bitbucket PR. Base overrides
281
+ flow through clone, PR publication and later base updates. Use `gallivant doctor`
282
+ to confirm access and policy before `gallivant start <prd> --base <branch>`.
283
+ Hosted providers with a GitHub-bound environment are incompatible. A snapshot
284
+ provider must pass the same publication and qualification checks as a local one.
285
+
286
+ Bitbucket snapshots supply one coherent set of paginated comments, participants,
287
+ required tasks and statuses for the head. The shared event cursor, bounded fix
288
+ round, session continuation, completion gate and chain engine consume those
289
+ records. Unreadable snapshots preserve cursors. A changed PR branch/base or a
290
+ replacement repository stops with `pr-identity`. Declined/superseded PRs cannot
291
+ become done. A merged PR must match the recorded head and its merge commit must
292
+ be an ancestor of the intended base before completion or chain advancement.
293
+ No command merges the PR, force-pushes, deploys or alters protections.
294
+
295
+ ## Troubleshooting
296
+
297
+ - `NO_CREDENTIAL`: select the account email and private API-token file under the
298
+ correct host/repository. An SSH key, GitHub token or token file without an email
299
+ is insufficient. Restore scopes before retrying; do not broaden another host.
300
+ - `reviewer.actor_id` / explicit reviewer errors: use the actual UUID and producer
301
+ configuration, or explicitly choose no-reviewer mode. Do not use `@codex review`.
302
+ - `BB_INCOMPLETE`, `BB_STALE`, HTTP 429/5xx: restore API access or wait for the read
303
+ retry. Never clear a cursor or turn missing evidence into an empty collection.
304
+ - `REVIEW_UNQUALIFIED`: confirm the exact `harness.codex.bin`, selected model and
305
+ provider access, then explicitly run `review qualify --repo ... --run`. Do not
306
+ substitute `--version`, sign-in status or an offline fixture.
307
+ - `review-incomplete` / `REVIEW_INCOMPLETE`: inspect the named missing identity,
308
+ path, patch or required job count. For a large complete text change, raise
309
+ `max_jobs` and `budget_usd` only within an operator-approved bound, then select
310
+ the new policy explicitly. Unsupported binary, subrepository, malformed link, rate-limited,
311
+ redirected or stale evidence must be corrected; increasing a byte cap is not a
312
+ workaround.
313
+ - Screenshot evidence: check `review qualify --repo ... --capability image` for
314
+ the exact route. Repair the reported native or provider issue before a separately
315
+ authorized `--run`; do not repeat an unchanged failed launch. PNG/JPEG limits
316
+ and all image sides still apply. Unsupported formats remain incomplete.
317
+ - `pr-identity`: inspect source/base/repository/head and restore the recorded
318
+ identity. A decline or unproven merge needs operator reconciliation, not a new
319
+ paid run or an automatic chain advance.
320
+ - Access probe fails: check the selected coordinator SSH key or HTTPS token and
321
+ the account API token for PR operations. The coding session receives neither.
322
+ Re-run `doctor`, then resume the existing task rather than starting a duplicate.
323
+ - PR mailbox timeout: confirm the daemon is running and can read the selected
324
+ repository; retry the same `task-pr` operation. Do not give the coding session
325
+ a token to work around the mailbox.
326
+
327
+ API semantics are based on Atlassian's [PR APIs](https://developer.atlassian.com/cloud/bitbucket/rest/api-group-pullrequests/),
328
+ [commit ancestry API](https://developer.atlassian.com/cloud/bitbucket/rest/api-group-commits/),
329
+ [source metadata](https://developer.atlassian.com/cloud/bitbucket/rest/api-group-source/),
330
+ and [account API-token guidance](https://support.atlassian.com/bitbucket-cloud/docs/using-api-tokens/).