@uchibeke/gallivant 0.2.1 → 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 (129) hide show
  1. package/README.md +38 -16
  2. package/SECURITY.md +9 -0
  3. package/bin/gallivant.mjs +33 -10
  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 +2 -0
  8. package/docs/architecture.md +11 -3
  9. package/docs/bitbucket-promotion.md +69 -0
  10. package/docs/bitbucket-review.md +330 -0
  11. package/docs/chains.md +30 -1
  12. package/docs/codex-cloud.md +7 -0
  13. package/docs/codex-review.md +50 -0
  14. package/docs/commands.md +65 -5
  15. package/docs/config.md +35 -10
  16. package/docs/first-party-review.md +266 -0
  17. package/docs/git-hosts.md +294 -0
  18. package/docs/guardrails.md +56 -0
  19. package/docs/install.md +18 -8
  20. package/docs/network-recovery.md +9 -0
  21. package/docs/openai-agents.md +2 -1
  22. package/docs/prd.md +23 -2
  23. package/docs/preparation.md +1 -1
  24. package/docs/release-qualification.md +1 -1
  25. package/docs/releasing.md +17 -2
  26. package/docs/task-delivery.md +4 -4
  27. package/docs/task-profiles.md +537 -0
  28. package/docs/tasks.md +59 -197
  29. package/lib/attribution.mjs +7 -3
  30. package/lib/block.mjs +10 -1
  31. package/lib/chains.mjs +101 -30
  32. package/lib/codex_cloud.mjs +2 -1
  33. package/lib/codex_cloud_input.mjs +15 -6
  34. package/lib/codex_cloud_result.mjs +1 -1
  35. package/lib/commands/doctor.mjs +22 -462
  36. package/lib/commands/init.mjs +72 -30
  37. package/lib/commands/register.mjs +25 -11
  38. package/lib/commands/resume.mjs +5 -1
  39. package/lib/commands/review.mjs +66 -0
  40. package/lib/commands/serve.mjs +8 -0
  41. package/lib/commands/start.mjs +30 -11
  42. package/lib/commands/status.mjs +18 -2
  43. package/lib/commands/task.mjs +9 -1
  44. package/lib/commands/up.mjs +19 -11
  45. package/lib/commands/why.mjs +7 -3
  46. package/lib/config.mjs +42 -9
  47. package/lib/context.mjs +23 -18
  48. package/lib/control.mjs +21 -6
  49. package/lib/credential.mjs +20 -14
  50. package/lib/deliverable.mjs +2 -0
  51. package/lib/events.mjs +96 -53
  52. package/lib/execution.mjs +48 -3
  53. package/lib/execution_preparation.mjs +16 -1
  54. package/lib/execution_result.mjs +26 -5
  55. package/lib/first_party_review.mjs +618 -0
  56. package/lib/gh.mjs +144 -56
  57. package/lib/git.mjs +133 -32
  58. package/lib/git_diff.mjs +121 -0
  59. package/lib/harness.mjs +14 -10
  60. package/lib/host_contract.mjs +71 -0
  61. package/lib/host_definitions.mjs +22 -0
  62. package/lib/hosts/bitbucket.mjs +553 -0
  63. package/lib/hosts/bitbucket_contract.mjs +57 -0
  64. package/lib/hosts/bitbucket_credential.mjs +62 -0
  65. package/lib/hosts/bitbucket_review.mjs +44 -0
  66. package/lib/hosts/bitbucket_review_producer.mjs +50 -0
  67. package/lib/hosts/github.mjs +57 -0
  68. package/lib/hosts/github_contract.mjs +27 -0
  69. package/lib/hosts/github_doctor.mjs +482 -0
  70. package/lib/hosts/github_review_summary.mjs +38 -0
  71. package/lib/hosts/transport_doctor.mjs +35 -0
  72. package/lib/hosts.mjs +130 -0
  73. package/lib/learning_qualification.mjs +1 -1
  74. package/lib/notify.mjs +1 -1
  75. package/lib/openai_agents_input.mjs +7 -2
  76. package/lib/openai_agents_sources.mjs +16 -8
  77. package/lib/plugin_package.mjs +13 -1
  78. package/lib/pr_operation.mjs +41 -0
  79. package/lib/prd.mjs +18 -3
  80. package/lib/preparation_codex.mjs +6 -1
  81. package/lib/probe.mjs +6 -4
  82. package/lib/process.mjs +24 -0
  83. package/lib/promotion.mjs +132 -0
  84. package/lib/promotion_git.mjs +63 -0
  85. package/lib/prompt.mjs +16 -13
  86. package/lib/provider_health.mjs +14 -3
  87. package/lib/repository.mjs +68 -0
  88. package/lib/repository_preflight.mjs +11 -0
  89. package/lib/review_evaluation.mjs +25 -0
  90. package/lib/review_evidence.mjs +500 -0
  91. package/lib/review_history.mjs +73 -0
  92. package/lib/review_image.mjs +145 -0
  93. package/lib/review_link.mjs +12 -0
  94. package/lib/review_policy.mjs +132 -0
  95. package/lib/review_policy_contract.mjs +18 -0
  96. package/lib/review_state.mjs +13 -0
  97. package/lib/review_visual.mjs +94 -0
  98. package/lib/runtime-environment.mjs +6 -0
  99. package/lib/runtime_node.mjs +3 -2
  100. package/lib/runtime_state.mjs +39 -5
  101. package/lib/sources/prd.mjs +6 -3
  102. package/lib/state.mjs +137 -24
  103. package/lib/task_completion.mjs +7 -3
  104. package/lib/task_contract.mjs +201 -27
  105. package/lib/task_delivery.mjs +9 -2
  106. package/lib/task_delivery_contract.mjs +13 -9
  107. package/lib/task_delivery_view.mjs +18 -2
  108. package/lib/task_environment.mjs +13 -1
  109. package/lib/task_limits.mjs +13 -0
  110. package/lib/task_model_config.mjs +99 -0
  111. package/lib/task_model_route.mjs +243 -0
  112. package/lib/task_prepare.mjs +21 -8
  113. package/lib/task_profile.mjs +1875 -0
  114. package/lib/task_repository_context.mjs +65 -0
  115. package/lib/tasks.mjs +252 -51
  116. package/lib/tick.mjs +353 -97
  117. package/lib/time.mjs +1 -0
  118. package/lib/tracker/pages.mjs +19 -5
  119. package/lib/tracker/review.mjs +21 -0
  120. package/lib/tracker_process.mjs +8 -1
  121. package/lib/verification_sandbox.mjs +2 -1
  122. package/lib/work_artifacts.mjs +79 -0
  123. package/npm-shrinkwrap.json +12 -3
  124. package/package.json +9 -3
  125. package/templates/plugin/task-delivery.SKILL.md +17 -10
  126. package/templates/plugin/task-intake-contract.json +18 -0
  127. package/templates/plugin/task-profile-requests.mjs +1448 -0
  128. package/templates/tracker/tracker.css +3 -0
  129. package/templates/tracker/tracker.js +38 -0
package/docs/config.md CHANGED
@@ -19,10 +19,10 @@ See [installation](install.md) for the first-run sequence.
19
19
  | Key | Default | Meaning |
20
20
  |---|---|---|
21
21
  | `poll_seconds` | 120 | GitHub review and chain-check cadence. Minimum 30. Provider progress and readiness use the separate `execution.progressMs` cadence; the daemon may tick more frequently. |
22
- | `max_iterations` | 30 | Automatic fix-round allowance per PR. A pushed fix or changed completion receipt consumes a round. At the cap, further automatic work stops with `needs-human`. Explicit operator resumes can exceed the cap; their progress still counts. |
22
+ | `max_iterations` | 60 | Automatic fix-round allowance per PR. A pushed fix or changed completion receipt consumes a round. At the cap, further automatic work stops with `needs-human`. Explicit operator resumes can exceed the cap; their progress still counts. |
23
23
  | `checks_grace_minutes` | 5 | A head younger than this with no checks reported is not green yet; GitHub shows an empty check list for the first seconds after a push. A head older than this with no checks at all counts as green. |
24
24
  | `run_timeout_minutes` | 720 | Local runs exceeding this time are killed; remote execution uses provider cancellation/reconciliation where supported and preserves unknown ownership. It is a runtime allowance, not a provider billing cap. Overridable per repository; see below and [execution](execution.md). |
25
- | `max_budget_usd` | 5 | Passed to Claude as `--max-budget-usd` and used in task preparation/authorization accounting. Other local harnesses have no equivalent enforced dollar cap. Hosted dispatch also requires its explicit provider allowance; reservations are not a billing hard cap. |
25
+ | `max_budget_usd` | 50 | Passed to Claude as `--max-budget-usd` and used in task preparation/authorization accounting. Other local harnesses have no equivalent enforced dollar cap. Hosted dispatch also requires its explicit provider allowance; reservations are not a billing hard cap. |
26
26
  | `rereview_minutes` | 6 | If the reviewer has not reviewed this long after a request, the request is posted once more. |
27
27
  | `stall_hours` | 6 | If the reviewer still has not reviewed, the PR stops with `reviewer-silent`. |
28
28
  | `trusted_authors` | required | GitHub logins whose reviews and comments may start a run. Everyone else is ignored. Your own login belongs here. |
@@ -41,9 +41,10 @@ See [installation](install.md) for the first-run sequence.
41
41
  | `harness.openai-agents` | absent | Explicit account, organization, project, model, API credential, hosted environment, network policy and allowance. See [Agents setup](openai-agents.md). |
42
42
  | `harness.codex-cloud` | absent | Recognized for configuration/recovery, but new dispatch is unavailable. See [Cloud blocker](codex-cloud.md). |
43
43
  | `execution` | bounded defaults | Transport/probe deadlines, progress cadence, concurrency, backoff and event limits. See [execution scheduling](execution.md#scheduling-and-limits). |
44
+ | `intake_model` | absent | The explicitly funded planner route for natural-language intake: `{ adapter, model, endpoint, credential_env, budget, timeout_ms }`. The key is read from the named environment variable at call time. Configurable ceilings are 12 calls, 100,000 input and 16,000 output tokens per call and a $10 allowance; configuration can lower them. Timeout defaults to two minutes, configurable up to five. Existing approved route/task budgets remain pinned. See [typed delivery profiles](task-profiles.md#configuring-the-model-route). |
44
45
  | `repos` | [] | The repositories Gallivant watches, appended by `start` and `register` and read by `up` to recover from GitHub. Each entry is either `"owner/name"` or an object: `{ "repo": "owner/name", "base": "staging", "run_timeout_minutes": 90 }`. Both object keys are optional. See below. |
45
46
 
46
- The default allows 30 rounds as an upper allowance for unattended review. It is not a target or a promise of completion:
47
+ The default allows 60 rounds as an upper allowance for unattended review. It is not a target or a promise of completion:
47
48
  large tasks can exhaust it, while missing external prerequisites cannot be solved by more rounds. Reaching the cap
48
49
  requires an operator decision, and it never increases itself.
49
50
  Existing explicit `max_iterations` settings keep their value. More rounds allow more time and model spend; they do
@@ -273,6 +274,11 @@ Gallivant was first driven against, and it is only a default:
273
274
  - `rereview_comment` is the entire text Gallivant posts to ask for another look. It is posted after every push that came from a fix run, and again as a nudge if the reviewer says nothing for `rereview_minutes`. Gallivant never inspects the string, so a bot mention, a slash command or a plain sentence all work.
274
275
  - `blocking_pattern` is a regex tested against each inline comment of the reviewer's newest review since the last request. A match, or a `CHANGES_REQUESTED` state, keeps the PR out of `ready-for-human`.
275
276
 
277
+ Pushing a commit does not automatically request Codex review for a manually
278
+ updated PR. Follow [the exact-head review procedure](codex-review.md) after each
279
+ final push; the background loop only posts its configured request after runs it
280
+ dispatches itself.
281
+
276
282
  ### Pointing it at a different reviewer
277
283
 
278
284
  Nothing beyond these three fields needs to change. Two worked examples.
@@ -303,12 +309,11 @@ account is what distinguishes a review tool from the trusted humans in `trusted_
303
309
  dispatches a fix run against rather than waiting on. So a human login in `reviewer.login` never matches, the verdict
304
310
  stays `waiting`, and the PR waits out `stall_hours` and then stops with `reviewer-silent` for a person to look at.
305
311
  That is a reasonable way to run a repo where a human gates every merge, but it is a wait, not a verdict. If you want
306
- the human's findings to drive fix rounds instead, put them in `trusted_authors` and set `reviewer` to null.
312
+ the human's findings to drive fix rounds, put them in `trusted_authors`. New tasks without an external actor also need a qualified first-party policy or the explicit legacy no-review exception.
307
313
 
308
314
  ### No automated reviewer
309
315
 
310
- `"reviewer": null` means there is no review tool: only humans and CI drive the loop, and a PR is ready as soon as
311
- checks are green. Gallivant asks nobody for a re-review, so there is no nudge and no `reviewer-silent` stop. It still
316
+ `"reviewer": null` means no external review tool is configured. For new tasks, select a qualified first-party route or set `review.legacy_no_review: true` explicitly. Legacy no-review readiness rests on checks and the configured completion gate and is labelled as absence of review, never clearance. No external re-review or nudge is requested. It still
312
317
  comments after a push, because the round comment is also how a recovery rebuilds the round count off the PR, but the
313
318
  comment says `Pushed a fix.` and mentions no one.
314
319
 
@@ -345,7 +350,9 @@ tree. That is the same rule the brief follows: the daemon judges what it recorde
345
350
  given by editing a document it was handed. Editing one in your own tree afterwards is reported by `gallivant why` the
346
351
  same way an edited brief is, and the list itself is part of the contract, so adding or removing a file is a contract
347
352
  change even though no criterion moved. Changes to either the manifest or file bytes block readiness and resume until
348
- accepted with `resume --resnapshot`; accepted snapshots are also restored when a checkout is recreated.
353
+ accepted with `resume --resnapshot`; accepted snapshots are also restored when a checkout is recreated. Carried inputs
354
+ remain local and untracked unless explicitly requested as output in the approved brief's [`publish_files`](prd.md) list.
355
+ Keep those local copies when removing accidental commits; the task still reads them.
349
356
 
350
357
  `sources` and `context_paths` answer different questions and neither replaces the other. `sources` puts named files
351
358
  INSIDE the checkout, so it works on every harness because it needs no flag at all. `context_paths` grants a session read
@@ -419,14 +426,16 @@ Every run gets the resolved credential as `GH_TOKEN`, the git settings below, an
419
426
 
420
427
  ### Git settings for a run
421
428
 
422
- No file. Git's own `GIT_CONFIG_COUNT` with numbered `GIT_CONFIG_KEY_n`/`GIT_CONFIG_VALUE_n` pairs carries four settings:
429
+ No file. Git's own `GIT_CONFIG_COUNT` with numbered `GIT_CONFIG_KEY_n`/`GIT_CONFIG_VALUE_n` pairs carries the following settings:
423
430
 
424
431
  | Key | Value |
425
432
  |---|---|
426
433
  | `user.name` | Your Git-configured name, resolved by the coordinator for each run |
427
434
  | `user.email` | Your Git-configured email, resolved by the coordinator for each run |
428
435
  | `push.default` | `current` |
429
- | `credential.helper` | a shell snippet that prints `GH_TOKEN` as the password, and prints nothing when there is no `GH_TOKEN` |
436
+ | `credential.helper` | an empty entry resets inherited helpers, followed by a helper that answers only for the bound HTTPS host and repository |
437
+ | `credential.useHttpPath` | `true` |
438
+ | `http.followRedirects` | `false` |
430
439
 
431
440
  Plus `GIT_CONFIG_NOSYSTEM=1` and `GIT_CONFIG_GLOBAL=/dev/null`.
432
441
 
@@ -434,4 +443,20 @@ Nothing in that list is a path outside the worktree, and that is the point. Unti
434
443
 
435
444
  Both isolating variables are load-bearing, and `GIT_CONFIG_NOSYSTEM` is not decoration. `GIT_CONFIG_GLOBAL` replaces only git's global file; the system one still applies, and on a Mac with the Xcode command line tools `/Library/Developer/CommandLineTools/usr/share/git-core/gitconfig` sets `credential.helper = osxkeychain`. Without `GIT_CONFIG_NOSYSTEM` a run had a path to your keychain whatever else was set. With it, `git config --get-all credential.helper` in a run's environment returns nothing but the snippet above.
436
445
 
437
- What this does not bound, said plainly because it is easy to mistake for new: a run's own `.git/config` is still read, `credential.helper` is multi-valued, and a repo-local helper is consulted before this one. That was equally true when the helper lived in a global file, since local config always won there too. A run owns its worktree, so it can always add a helper. What bounds a run is the token's scope and the branch ruleset, not how the config travels.
446
+ The helper resets repository-local credential helpers and refuses other hosts, repository paths and redirects. Runs clear inherited API tokens and SSH transport settings. A run can read its own environment, so token scope and repository rulesets remain essential. See the [Git host contract](git-hosts.md) for identity, compatibility and provider binding.
447
+
448
+ ## Bitbucket repository policy
449
+
450
+ Set `reviewer` (or explicit `null`), stable UUID `trusted_authors`, and
451
+ `required_checks` under `git_hosts["bitbucket.org"]`. A host repository entry can
452
+ override these settings, and a `repos` object takes precedence over both.
453
+ GitHub's top-level reviewer defaults are never inherited by Bitbucket.
454
+ See [configuration examples and credential scope](bitbucket-review.md).
455
+ For a deliberate no-reviewer task, set `reviewer: null` and
456
+ `review.legacy_no_review: true` on the repository entry. Readiness then reports
457
+ that no independent review was performed; it still requires configured checks
458
+ and the completion receipt.
459
+
460
+ ## Versioned review policy
461
+
462
+ `review.mode` selects `external-required`, `first-party-required`, or `both-required` for new tasks. `review.route: "codex"` requires a successful isolated live qualification. `review.specialist` allows at most one of `security` or `regression`. Defaults and bounds, per-repository settings, separate review allowances, explicit zero-check CI policy and the `legacy_no_review` exception are documented in [First-party review](first-party-review.md). A config edit cannot change an existing task policy; use `review policy <handle> --mode <mode> --reason "..."` to revoke readiness and explicitly re-evaluate. `reviewer: null` alone no longer authorizes an unattended new start.
@@ -0,0 +1,266 @@
1
+ # First-party review gate
2
+
3
+ This is an opt-in model judgement of an immutable task snapshot. It is **not Git-host bot approval**, proof that every defect was found, or authority to merge, deploy, release or advance a chain. Checks, the completion gate, trusted feedback and the existing human merge boundary still apply. The [qualification record](audit/first-party-review.md) currently records an unavailable native boundary and unmeasured live quality; do not change defaults on the strength of deterministic fixtures.
4
+
5
+ ## Select a policy
6
+
7
+ New tasks snapshot one version-1 policy:
8
+
9
+ | Mode | Required evidence |
10
+ | --- | --- |
11
+ | `external-required` | Configured external actor's clear verdict for the exact head |
12
+ | `first-party-required` | Coordinator-owned first-party clear for the exact input |
13
+ | `both-required` | Both, without unresolved disagreement |
14
+
15
+ A configured external reviewer retains `external-required` by default. There is no bot-installation detection. A repository with `reviewer: null` must opt into a qualified route, or explicitly choose the legacy exception below. Missing, slow, failed and rate-limited required reviewers never count as clear and never select another policy.
16
+
17
+ For new tasks without a remote reviewer, set these keys in the operator configuration:
18
+
19
+ ```json
20
+ {
21
+ "reviewer": null,
22
+ "review": {
23
+ "mode": "first-party-required",
24
+ "route": "codex",
25
+ "specialist": null,
26
+ "timeout_ms": 3600000,
27
+ "max_jobs": 2048,
28
+ "retries": 2,
29
+ "budget_usd": 100,
30
+ "max_input_bytes": 100000,
31
+ "zero_checks": false
32
+ }
33
+ }
34
+ ```
35
+
36
+ `review` can also be set on a `repos` object. Defaults allow 2,048 total reviewer jobs per task, including fresh-head rereviews and final synthesis, a $100 accounting allowance, two known pre-dispatch retries and 60 minutes per job. Each source piece, reduction and whole-PR synthesis has its own deadline; the limit is not a deadline for the entire PR review. Operators can select up to 8,192 jobs, $10,000 and one hour per job; explicit smaller limits remain enforced. Raising defaults does not silently rewrite saved task policies. The external actor remains the configured `reviewer` object and is copied into each task. `specialist` is either `null`, `security`, or `regression`; general correctness always applies. These are short rubrics, with no policy or requirements authority.
37
+
38
+ `zero_checks: true` is an explicit operator CI policy for a repository with no required checks. An empty Git-host response alone never establishes that policy for new version-1 tasks. Missing CI stops as `missing-ci`; a missing/disabled completion gate stops separately as `completion-gate-skipped`.
39
+
40
+ Legacy records are snapshotted as version 0 on reconciliation using their last configured external requirement. An absent reviewer is explicitly displayed as **legacy no-review**, never clearance. Existing runs do not inherit new config policy choices. For an intentional new legacy run, set both `reviewer: null` and `review: { "legacy_no_review": true }`. This grants no review evidence. Back up state before upgrading: historical configurations that were never recorded cannot be recovered from PR prose, so restore the original reviewer configuration before the first reconciliation of old records.
41
+
42
+ ## Qualification and diagnostics
43
+
44
+ The selected Git host must provide the complete review-evidence operation through
45
+ the shared host registry. An unsupported host or missing operation stops
46
+ qualification before native preparation, including when a saved clear exists.
47
+ GitHub retains `owner/repo` identities. Bitbucket uses
48
+ `bitbucket.org/workspace/repository`; its evidence adapter is implemented, but its
49
+ live private/public review matrix remains a separate qualification requirement.
50
+ No other Git host is supported by this review path.
51
+
52
+ Use the exact executable in `harness.codex.bin`. Only its restricted preparation profile is implemented as a reviewer route; other coding adapters are unqualified. The review service supplies text in a fresh isolated workspace, disables tools, MCP/plugins, hooks, skills, memories, delegation, telemetry and user/project instructions, denies escalation and network access from model tools, and verifies the effective native configuration including managed requirements. Provider authentication is confined to the native inference connection. The coding session and its context mounts are never reused.
53
+
54
+ ```sh
55
+ gallivant review qualify --repo owner/repo
56
+ gallivant review qualify --repo owner/repo --run --wait
57
+ gallivant review qualify --repo bitbucket.org/workspace/repository
58
+ gallivant review qualify --repo bitbucket.org/workspace/repository --run --wait
59
+ gallivant review status <task-handle>
60
+ gallivant doctor
61
+ ```
62
+
63
+ The run page shows a live reviewer activity feed with the current phase, job
64
+ progress, findings count and handoff state. It is separate from the coding
65
+ agent's log and updates while the page is open; it does not expose reviewer
66
+ prompts, raw output or captured source. Its visible history starts when the
67
+ page opens. The entries dashboard's last-activity time tracks a run, review or
68
+ recorded event, rather than routine coordinator writes.
69
+
70
+ The first command only reads qualification. `--run` explicitly authorizes a separate bounded live challenge. It returns a running record; repeating the command reconciles that same keyed execution. A failed qualification is retained, not silently retried as a new paid session. Repair the observed provider/native-policy failure before requalification; changed native configuration yields a different qualification identity. A credential/configuration/binary change invalidates qualification. Setup diagnostics and start preflight require qualification and recheck the effective native boundary before author launch. A version/sign-in result alone cannot qualify a route.
71
+
72
+ For recognized ChatGPT OAuth profiles, routine token refresh retains the same
73
+ qualification only when the selected account, owner, issuer, client and subject
74
+ remain consistent across the locally stored ID and access token claims. A
75
+ changed principal or provider invalidates qualification. The provider still
76
+ validates the actual credentials; unknown formats and API keys use the full
77
+ credential digest and fail closed on changes.
78
+ Unrelated absolute project trust records outside the review root do not change
79
+ the review identity. Records covering the review root and all other effective
80
+ configuration and managed policies remain bound.
81
+
82
+ `npm run test:first-party-review:live` is the opt-in disposable-repository probe. It requires `REVIEW_LIVE=1`, the normal operator configuration, and an explicit review allowance; ordinary tests never call a model. Do not run it to work around an administrator or guardrail refusal.
83
+
84
+ Codex does not expose a native USD hard cap or reliable cost receipt here. The coordinator reserves `budget_usd / max_jobs` before each review launch and consumes the reservation even when actual cost is unknown. `max_input_bytes` remains a hard per-job prompt cap (at most 100,000 bytes); it is never raised for a large PR. `max_jobs`, the reserved budget and the per-job timeout bound the complete aggregate. Job count, wall time and known pre-dispatch retries are independently bounded. This is an accounting allowance, **not a guaranteed provider billing cap**. Cost qualification and live spend measurement remain outstanding; configure a provider-side limit before relying on a monetary ceiling. Provider failure requires a person; it never spends a coding fix round by itself.
85
+
86
+ ## Evidence, fixes and migration
87
+
88
+ The GitHub and Bitbucket adapters capture exact head/base/merge-base IDs, a complete diff, full before/after content for added, modified, removed and renamed files, the immutable PRD and every criterion, checks and the full completion receipt. Bitbucket additionally binds the repository UUID and PR number, consumes every diffstat page, compares that inventory to the raw commit comparison, reads source metadata/content at the merge base and head, and rechecks the PR after capture. Oversized evidence, unsupported binaries or submodule content, omitted patches, duplicate or truncated pages, unreadable snapshots and concurrent PR changes produce incomplete review. API credentials stay in the host adapter; reviewer jobs receive neither host nor Git credentials, and redirects outside the bound API repository are refused.
89
+
90
+ The coordinator requests PNG and JPEG evidence and plans one restricted visual job per changed side alongside text slices. Captures are limited to 32 image sides, 5 MiB per side and 16 MiB total, with dimensions at most 8192 by 8192 and 16 million pixels. Corrupt, unsupported, oversized or incomplete images fail closed. Text qualification alone does not qualify image attachment, model vision or isolation. Each visual job receives a coordinator-created copy, and its exact image identity is checked again at execution; image text and metadata are untrusted data. A [disposable live screenshot review](audit/bitbucket-review-qualification.md#live-image-qualification-and-disposable-review-2026-11-03) reached a clear whole-PR verdict after recovering its owned outputs; the resend PR remains unverified. Preserve screenshots and an incomplete status when qualification or evidence is missing.
91
+
92
+ The coordinator requests link-object capture from both host adapters. Bounded UTF-8 target bytes are reviewed as untrusted Git object data at each revision; targets are never resolved or followed. Unsupported targets, ambiguous type transitions, incomplete inventories or mismatched hashes and revisions fail closed. Host and reviewer qualification still applies.
93
+
94
+ Image qualification is recorded independently for the configured executable bytes,
95
+ model and reviewer configuration. `review qualify --repo OWNER/REPO --capability image`
96
+ reads its status; adding `--run` explicitly starts one bounded image challenge and
97
+ consumes the review allowance. The challenge verifies a coordinator-created copy
98
+ at the execution boundary. It is not an end-to-end PR review or host qualification.
99
+ All image sides, text slices and the whole-PR synthesis must complete under the
100
+ same bounded allowance; missing or mismatched results cannot clear the review.
101
+ An image inspection judges its own image, while a text-only requirement may be
102
+ deferred to synthesis. The coordinator records criteria omitted by an image job
103
+ and carries its unresolved concerns through reductions. The final reviewer must
104
+ evaluate those concerns and all criteria against the combined evidence; an
105
+ unresolved need for visual evidence still blocks clearance. A previously owned
106
+ image output rejected solely for local scope can be revalidated against its
107
+ original input and qualification without launching the image job again.
108
+
109
+ When the full serialized evidence does not fit one job, the shared service creates immutable byte-bounded source and patch slices. Every piece repeats the same task, repository, PR, head, base, merge base, brief, criteria, checks, receipt, policy and aggregate digest. Long single lines and large lockfiles are sliced with absolute line/column offsets rather than omitted. Every changed path and every criterion must appear in the aggregate, every piece must return a valid matching identity, and all pieces must finish before clearance. A finding in any piece, a timeout, malformed output, missing piece, conflicting finding identity, exhausted job/budget bound or unresolved scope blocks readiness. If the configured aggregate cannot hold the evidence, the result says `review-incomplete`/`REVIEW_INCOMPLETE` with the required and configured job counts; it does not review a prefix.
110
+
111
+ Split review has two stages. Each local inspection judges only supplied slices,
112
+ records concrete defects and supplies bounded, source-quoted observations for
113
+ the final reviewer. Missing other pieces is expected and does not establish a
114
+ missing implementation. Local clear verdicts cannot clear the PR. If every local
115
+ inspection finishes without findings, a separate restricted whole-PR reviewer
116
+ receives the complete criteria, receipt and checks plus reports or validated
117
+ reductions covering every source piece. It
118
+ must resolve cross-file questions and return its own clear verdict. Empty reports,
119
+ unsupported quotes, unresolved scope and oversized synthesis never clear. Each
120
+ observation is verified against its captured source; final findings must also be
121
+ grounded in a supplied report. An incorrect line number is resolved only when the
122
+ exact single-line quote occurs at one unique line in the supplied file, side and
123
+ slice (or, for synthesis, a supplied report). The original and corrected line
124
+ and a quote digest are retained in the review ledger. Ambiguous, absent or
125
+ multiline quotes never gain clearance from this correction.
126
+ When execution sanitization masks a secret-looking value in a quote, the
127
+ coordinator compares it with the same sanitized form of the captured source
128
+ line. The review result retains the masked quote; matching still requires the
129
+ specified file, side and line or a unique source location.
130
+
131
+ Malformed output or an unverifiable citation receives up to the configured
132
+ `retries` fresh, tools-disabled reviewer attempts, using the same job, spend and
133
+ time limits. Previous attempts stay in the ledger; an ambiguous launch, tool
134
+ attempt or provider failure is never silently retried as a format error. A local
135
+ scope concern is retained in the ledger and carried through any reductions to
136
+ the final whole-PR reviewer; it is never accepted as clearance. Whole-PR
137
+ unresolved scope remains blocking. Older outputs rejected for citation numbering
138
+ or local-slice scope are revalidated once against the exact original input and
139
+ owned execution.
140
+ A confirmed, terminal Codex model-capacity response receives bounded retries
141
+ after one and five minutes, within the same reviewer job and spend allowances.
142
+ The saved evidence and completed pieces are retained. Authentication, quota,
143
+ policy denials, ambiguous ownership and unrecognized provider errors still stop
144
+ for inspection; no model or provider is switched automatically.
145
+ A new protocol identity retains old failed jobs
146
+ for audit without reusing their incomplete verdicts.
147
+
148
+ A local-scope inspection still requires final synthesis when partitioning happens
149
+ to produce only one piece; only an actual unsplit whole-PR review may clear
150
+ directly. If the combined reports exceed the prompt cap, the same restricted
151
+ review service reduces them in bounded groups over as many levels as needed.
152
+ Each node binds its child reports and a contiguous coverage range to the original
153
+ aggregate. Missing, duplicate or out-of-order coverage is refused, and the root
154
+ must cover every original piece. All original reports and intermediate jobs stay
155
+ in the durable ledger. Each reduction preserves source-grounded observations;
156
+ any concrete finding blocks instead of being summarized away. A reduction's
157
+ local clear verdict never replaces the final whole-PR verdict. Reduction and
158
+ final jobs consume the same task job, spend and timeout allowances, and restart
159
+ reuses their exact saved inputs and executions.
160
+
161
+ Source capture remains bounded to 16 MiB overall, independently of the higher
162
+ job allowance. The per-job input remains 100,000 bytes; synthesis must fit the
163
+ same bound. These are evidence and context limits, not spending defaults. Explicit
164
+ task/provider authorizations remain pinned. The intake planner has separate,
165
+ explicitly funded settings: up to 12 calls, 100,000 input and 16,000 output
166
+ tokens per call, $10 and a five-minute request timeout. Those higher ceilings
167
+ do not enlarge a saved task's approved allowance.
168
+
169
+ The model receives this material as untrusted JSON. The final output must cover all criteria, identify the route/head/input digest, leave no unresolved scope, and report either `clear` or actionable findings grounded in captured source or an exact image identity. Local concerns are carried to that final review. Invalid, partial, timed-out, failed or tool-attempting output cannot clear. The coordinator owns the ledger under `reviews/` and the separate execution namespace under `runs/review__...`. Public comments and agent-authored approval text are never an alternative source of internal clearance.
170
+
171
+ Polling reuses captured source only when the repository, head and base still match, and rechecks the live PR binding before using it. Changed head, base, checks, receipt, policy or brief invalidates the whole aggregate, not only one piece. Piece keys make restart and repeated host pages idempotent; an old-head or partial aggregate cannot clear. A delayed poll accepts a valid result whose recorded execution completion time met the deadline; missing completion times, late results and executions still running past the deadline cannot clear.
172
+
173
+ The registry caches validated reads only while the underlying file identity and
174
+ timestamps are unchanged. Returned records remain detached, and another
175
+ process's atomic write invalidates the cache. This avoids repeatedly parsing a
176
+ large registry during review polling without changing write ownership or gates.
177
+ Each review advancement also reuses immutable completed jobs from one ledger
178
+ read, while retaining the same policy, input, binding and reviewer checks.
179
+
180
+ Between host polls, the coordinator advances an already captured review on its
181
+ local progress cadence. It does not refetch the PR for every piece. Terminal
182
+ local results wake the host lane, which must reread the current binding before
183
+ readiness or author dispatch. An explicit recheck or policy change also wakes
184
+ that lane immediately instead of waiting for the old polling deadline.
185
+
186
+ Findings use the existing fix dispatch and round counter. Their disposition is recorded. A subsequent push needs fresh evidence. Repeated findings on the same input, required-reviewer disagreement and exhausted fix rounds stop for a person. `review dispute <handle> --finding <id> --reason "..."` records a pending dispute and removes readiness; it has no self-accept operation. A person must resolve the defect or deliberately change policy and re-evaluate it.
187
+
188
+ Findings remain `pending` during confirmed provider-health waits or a busy local runner. `dispatch-intent` is saved immediately before launch and becomes `dispatched` with the accepted run ID. A confirmed unsent refusal returns the findings to pending but still requires the existing explicit resume; an ambiguous launch retains its intent and requires a person before any retry. Waiting alone consumes no fix round.
189
+
190
+ Historical review records are stored in the private `reviews/history/` directory
191
+ under the Gallivant home. The registry retains compact references and dispatch
192
+ dispositions; `gallivant review status <handle>` verifies and displays the full
193
+ history. Existing inline history migrates on the next registry write. Back up and
194
+ restore the registry and the review directory together. Missing or changed archive
195
+ files are reported as errors rather than treated as review clearance. Migration
196
+ upgrades the registry format: older releases refuse it rather than changing
197
+ references they do not understand. Stop older coordinators before upgrading.
198
+
199
+ Transient Bitbucket read timeouts, rate limits and server errors during evidence
200
+ capture are retried through the bounded coordinator retry path. Authentication,
201
+ identity, incomplete evidence and uncertain write failures remain blocking; each
202
+ attempt still captures and verifies the current PR before review or readiness.
203
+
204
+ Changing head, base, checks, receipt or policy invalidates readiness. Configured external findings and trusted human feedback still enter the shared fix path, including feedback arriving after internal clearance on the same head. The external reviewer must answer again when its previously reviewed input changes. The completion gate remains independent of model opinion.
205
+
206
+ A newly observed head retains the push-based review window, so a timely exact-head approval that arrived between polls still counts. The same rule applies when an author run settles and advances the feedback cursor. Changes to base, receipt or checks on the same head start a new review window when observed and require a later external answer.
207
+
208
+ Config edits affect future tasks. For a stopped/settled existing task, use:
209
+
210
+ ```sh
211
+ gallivant review policy <handle> --mode both-required --reason "Require both reviews for this task"
212
+ gallivant review policy <handle> --mode first-party-required --reason "Enable the qualified independent local reviewer"
213
+ gallivant recheck <handle>
214
+ gallivant review retry <handle> --reason "Retry the rejected citation with exact single-line source quotes"
215
+ ```
216
+
217
+ `review retry` explicitly authorizes fresh reviewer executions for incomplete
218
+ output whose previous process exited successfully. It retains completed pieces,
219
+ original attempts, reservations and an operator-reason audit. New attempts use
220
+ the same job/spend/timeout limits and strict validation; recheck alone reuses the
221
+ old terminal record. It also accepts a reviewer cancelled by the coordinator
222
+ after a provider error only after confirming its identity, stopped process tree,
223
+ recorded cancellation reason and absence of tool attempts or denials. Ambiguous
224
+ launches, active reviewers, other provider failures, tool/boundary failures and
225
+ unresolved cancellation cannot use this shortcut.
226
+ The normal host lane rechecks the live binding before review can authorize
227
+ readiness. No author session, PR or chain merge gate is reset.
228
+
229
+ The command first proves that the selected route is qualified, then records the prior policy and reason, revokes readiness, and re-evaluates the current head. For an existing Bitbucket legacy run, this is the only path that removes `legacy_no_review`; direct config edits do not change its snapshot. The original PRD snapshot, task/run identity, PR, checkout and implementation session are retained. A failed preflight changes none of them and starts no paid review. No command here merges or advances a chain before its existing merge gate.
230
+
231
+ Policy changes and disputes share per-task process exclusion with review decisions,
232
+ including label publication and notification. If a decision is already in flight,
233
+ the command refuses without changing the policy; retry after that operation
234
+ finishes. A failed label removal leaves a durable obligation for later ticks to
235
+ retry, even while the task is stopped. Clearance stays revoked during that wait.
236
+
237
+ ### Waiting for qualification and explicitly retrying a stopped probe
238
+
239
+ Use `gallivant review qualify --repo OWNER/REPO --run --wait` to keep the CLI
240
+ alive until its bounded challenge settles. This retains the process exit
241
+ callback; a short-lived launcher can otherwise lose the precise exit time and
242
+ later reject an on-time response as a late observed completion. Normal daemon
243
+ review continues to use its existing lifecycle.
244
+
245
+ Captured local reviews advance alongside provider and Git-host polling. They
246
+ wait for their own task's decision lock, not unrelated provider reconciliation.
247
+ This progress does not clear readiness: the coordinator still fetches the
248
+ current PR head and evaluates the complete review and acceptance gates.
249
+
250
+ After inspecting a failed qualification, use
251
+ `gallivant review qualify --repo OWNER/REPO --run --wait --retry --reason "explanation"`
252
+ to authorize a fresh bounded attempt. Only a recorded timeout/provider failure
253
+ with matching ownership, confirmed process cessation and no recorded tool
254
+ attempt or policy denial qualifies for this operation. A legacy dispatch-ID
255
+ conflict rejected before launch can also recover after confirming its archived
256
+ process has stopped. Each retry uses a distinct execution identity and preserves earlier attempts and costs,
257
+ reserves another configured qualification allowance, and requires a new native
258
+ challenge to pass. It never turns failed output into clearance. Unknown or
259
+ active processes, missing completion records and boundary failures remain
260
+ blocked. The default without `--wait` still returns the running record promptly.
261
+
262
+ ## Persistence and polling
263
+
264
+ The coordinator saves changed task and reviewer records immediately. Unchanged progress polls do not rewrite the registry or refresh the task’s change timestamp. Native process liveness and output are still checked each tick; unchanged live execution observations are persisted at most once per minute, and settled executions need no heartbeat. Provider health checks, remote-provider cursors, launch/stop intents, result collection and readiness gates retain their existing persistence and polling.
265
+
266
+ Historical review evidence is kept in the private, content-addressed archive described above. Reusing an identical archived record verifies the existing file without writing another copy. No review evidence or logs are deleted by these optimizations.