@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
@@ -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.
@@ -0,0 +1,294 @@
1
+ # Git host boundary
2
+
3
+ For a GitHub review mirror that delivers through Bitbucket, see the [explicit branch promotion workflow](bitbucket-promotion.md). It preserves reviewed commits and uses the existing host/review services.
4
+
5
+ `github.com` supports task dispatch. Bitbucket's explicit no-reviewer path
6
+ completed live local Codex tasks through PR publication and receipt acceptance
7
+ on disposable public and private repositories, but its coding session could
8
+ read the selected merge-capable token file. General Bitbucket dispatch remains
9
+ unqualified while credential isolation is repaired. Independent Bitbucket
10
+ review and clean Linux installation also remain unvalidated. Other hosts remain
11
+ unsupported. The synthetic adapter in
12
+ `test/git-host.test.mjs` is an offline contract fixture, not a supported host.
13
+
14
+ `lib/host_definitions.mjs` owns the static host catalogue. `lib/hosts.mjs` binds
15
+ its declarations to Node transport implementations. Portable views and task
16
+ profiles read the same declarations without importing Node or credential code. It is independent of both the harness
17
+ registry and execution transports. Shared code obtains `hostApi(context)` and
18
+ selects a repository for dispatch through `context.hosts.select(...)`. Setup and
19
+ transport tools use `inspect(...)` or `inspectRemote(...)`; these do not qualify
20
+ the host for dispatch. The old `context.gh`
21
+ property is retained as an integration/test compatibility seam. New lifecycle
22
+ code must not use it. GitHub CLI commands, wire normalization, prompt commands,
23
+ learning endpoints and rulesets belong to `lib/gh.mjs`, `lib/hosts/github.mjs`
24
+ and the GitHub diagnostics feature module.
25
+
26
+ ## Identity and compatibility
27
+
28
+ `repository.mjs` parses HTTPS, HTTP (historical GitHub input, upgraded before use),
29
+ scp-style SSH and `ssh://` input. It rejects ambiguous authorities, ports,
30
+ queries, fragments, encoded path characters, traversal and unsupported schemes.
31
+ It never embeds rejected input in errors. HTTPS userinfo is discarded; it is
32
+ never a credential source. Canonical records contain `host`, `path`,
33
+ `remoteIdentity` (`host/owner/repository`) and `key`.
34
+
35
+ The historical GitHub key remains `owner/repository`; another qualified host's
36
+ key is `host/owner/repository`. Entry IDs, worktree paths and run folder names
37
+ include that key. Existing GitHub IDs, branch prefixes, cursors, receipt hashes,
38
+ PR metadata and chain ownership tokens are read without rewriting them.
39
+ Review/inline/comment IDs keep their old cursor keys, such as `review:42`.
40
+ A short handle still works when it identifies exactly one entry. Ambiguity
41
+ requires `host/owner/repository#number`. Contradictory saved identities and duplicate
42
+ PR ownership stop with a backup/reconciliation instruction; no automatic
43
+ migration, cursor reset or redispatch repairs them.
44
+
45
+ ## Adapter declaration
46
+
47
+ Each registry declaration supplies:
48
+
49
+ | Field | Contract |
50
+ | --- | --- |
51
+ | `host`, `id` | Canonical authority and stable completion-evidence adapter ID |
52
+ | `capabilities` | Required evidence and optional decoration, separately declared |
53
+ | `credential(config, repository)` | Resolve current API/HTTPS authorization for the bound host; never cache at daemon boot |
54
+ | `remote(repository)` | Verified clone URL, protocol, host and repository path |
55
+ | `create(options)` | Repository/API operations with injected transport and credentials |
56
+ | `parsePr(url)`, `prUrl(repository, number)` | Strict PR routing and canonical UI links |
57
+ | `prompts` | Host-specific create, inspect, CI-log and receipt-edit instructions |
58
+ | `dataContract` | `host-records-v1` |
59
+
60
+ Required capabilities are `pullRequests`, `reviews`, `comments`, `checks`,
61
+ `diff`, `mergeProof` and `recovery`. Missing required capabilities fail closed.
62
+ `labels` is optional: an adapter without labels does not block readiness.
63
+ GitHub retains its existing retry semantics for label writes. Learning and
64
+ ruleset operations are GitHub features, not mandatory adapter methods.
65
+
66
+ Repository operations cover branch/default-branch and permission reads, exact
67
+ ref/ancestry proof, file reads, PR view/list/diff, review/comment pages, comments,
68
+ body/title/recovery writes, ready-for-review and idempotent publication.
69
+ `fileAtStrict` distinguishes a missing file from inaccessible or incomplete
70
+ content. The shared chain engine requires the exact merge commit to be an
71
+ ancestor of the intended base; a closed PR never authorizes a successor.
72
+
73
+ First-party review additionally requires `reviewEvidence(repo, pr, head, base,
74
+ maxBytes)`: complete diff and before/after changed-file content, including
75
+ deletions, bound to exact head, base and merge-base IDs. Qualification and
76
+ reconciliation refuse adapters without this operation before launching a
77
+ first-party reviewer or reusing its clearance. External-only and explicit
78
+ no-reviewer policies do not require this method. Evidence reads and policy/dispute label writes
79
+ use the same repository registry and credential binding as other lifecycle
80
+ operations. Review jobs and verdicts remain coordinator-owned.
81
+
82
+ ## Domain records and completeness
83
+
84
+ Every normalized record carries `source` (host and adapter), `actor` (login and
85
+ bot flag), `eventId`, `headSha`, `createdAt` and `updatedAt`. Unknown optional
86
+ values are explicit nulls. Review/comment records also carry `at`, `reviewId`
87
+ and `replyTo`. Their original numeric `id` remains stable for saved cursors.
88
+ CI records expose `outcome: passed | failed | pending`, name, URL and optional
89
+ run ID. Wire-specific CI classification exists only in the adapter.
90
+
91
+ PRs retain the established domain field names (`headRefOid`, `headRefName`,
92
+ `baseRefName`, `state`, `mergeCommit`, `mergedAt`, `statusCheckRollup`, body,
93
+ author and URL). These are contract fields, not permission to import a host
94
+ client. The GitHub adapter keeps legacy event aliases for existing consumers;
95
+ the review engine accepts the canonical actor, head and timestamp fields too.
96
+
97
+ A list is either a complete array or `{ items, complete: true }`. Incomplete
98
+ pages, absent CI, rate limits, authentication failures and unreadable diffs
99
+ throw before a readiness decision. GitHub pagination uses bounded subprocess
100
+ output; PR list/check limits are refused at their cap. Shared retries preserve
101
+ cursors, dispatch ownership and the last known decision. Optional decorations
102
+ never supply review, CI or merge evidence. The shared loop has one reviewer
103
+ verdict and one CI outcome predicate for every qualified host.
104
+
105
+ ## Transport and provider binding
106
+
107
+ The shared Git layer clones with native `git clone --filter=blob:none`. The
108
+ GitHub policy converts accepted GitHub SSH/HTTP inputs to verified HTTPS; no
109
+ shared Git method constructs a GitHub URL. Existing fetch, base selection,
110
+ operator commit identity, isolated configuration and push behavior remain.
111
+ Origin and push destinations are checked against the repository identity before
112
+ credentialed network operations.
113
+
114
+ The HTTPS helper reads Git's requested protocol, host and repository path before
115
+ returning the bound token. It resets repository credential helpers, refuses
116
+ redirects and receives secrets only through environment variables. Clone URLs,
117
+ argv, committed files and public diagnostics contain no token. A run clears
118
+ inherited API tokens and SSH channels. Bitbucket supports an explicitly selected
119
+ SSH key for coordinator Git operations; an SSH key alone cannot authorize the PR
120
+ API. The coordinator may clone and push over selected SSH or HTTPS. The coding
121
+ session receives neither the repository API token nor the SSH key. Its bounded
122
+ checkout mailbox requests validated push and PR operations from the coordinator.
123
+ Coordinator Git disables checkout hooks before using a privileged credential.
124
+ Setup never grants a sandbox extra key paths.
125
+ GitHub resolution order remains configured token file, daemon environment,
126
+ then `gh auth token`, with explicit-file failure refusing fallback. Resolution
127
+ happens for each operation so reauthentication works without restarting.
128
+
129
+ Providers declare `repositoryAccess`: `local-worktree`, `snapshot`, or
130
+ `bound-host` with allowed authorities. The shared pre-dispatch check enforces it
131
+ before clone or paid preparation. A local-worktree provider needs no adapter
132
+ change to use another qualified host. No host-by-harness switch table exists.
133
+
134
+ ## Regression evidence
135
+
136
+ `test/git-host.test.mjs` exercises canonical identity, saved state, collisions,
137
+ normalized feedback, provider access, native clone, token isolation, failure
138
+ preservation and a synthetic host through readiness and chain merge proof.
139
+ `test/git-host-architecture.test.mjs` rejects direct host CLI/API imports or
140
+ prompt commands and a second host-specific review/CI branch in shared modules.
141
+ The existing review, recovery, receipt, chain and execution suites retain
142
+ coverage for bounded retries and idempotent writes. All these tests are offline
143
+ and make no model calls.
144
+
145
+
146
+ ## Bitbucket Cloud setup
147
+
148
+ Configure credentials explicitly in `git_hosts["bitbucket.org"]`. Existing
149
+ `github_token_file` resolution is unchanged and is never tried for Bitbucket.
150
+ No `gh` installation or GitHub sign-in is required for a Bitbucket-only config.
151
+ Use an Atlassian account API token; repository access tokens are not required.
152
+ Request `read:repository:bitbucket`, `write:repository:bitbucket`,
153
+ `read:pullrequest:bitbucket` and `write:pullrequest:bitbucket`, limited to the
154
+ selected workspace where available. Reads do not prove write scopes: diagnostics
155
+ report them as unknown until the corresponding write, which surfaces permission
156
+ errors and never silently switches credentials.
157
+
158
+ ```json
159
+ {
160
+ "git_hosts": {
161
+ "bitbucket.org": {
162
+ "api": {
163
+ "email": "operator@example.com",
164
+ "token_file": "~/.config/repository-access/bitbucket-api-token"
165
+ },
166
+ "git": { "transport": "https" }
167
+ }
168
+ },
169
+ "repos": [{ "repo": "bitbucket.org/workspace/repository", "base": "release/v2" }]
170
+ }
171
+ ```
172
+
173
+ Keep the existing harness, operator identity, worktrees and other config settings.
174
+ Token files must be private (`chmod 600`). HTTPS Git uses the selected API token
175
+ unless `git.token_file` explicitly selects a separate private token file. Git's
176
+ helper returns the token only for HTTPS on `bitbucket.org` and the exact repository;
177
+ it uses the account-token Git username `x-bitbucket-api-token-auth`. API requests
178
+ use account email plus token over HTTPS to `api.bitbucket.org`, with redirects
179
+ refused. API and Git authorization may differ, but the base commit observed through
180
+ Git must match the API repository and base.
181
+
182
+ For SSH, use this `git` block instead:
183
+
184
+ ```json
185
+ {
186
+ "transport": "ssh",
187
+ "ssh_key": "~/.config/repository-access/bitbucket-key",
188
+ "known_hosts": "~/.config/repository-access/bitbucket-known-hosts"
189
+ }
190
+ ```
191
+
192
+ Select an unencrypted dedicated key that the coordinator can read, with mode 600.
193
+ No SSH agent or global SSH configuration is used. The dedicated known-hosts file
194
+ must contain only `ssh.bitbucket.org` entries matching Atlassian's published
195
+ SHA256 fingerprints. Get candidate public keys from `https://bitbucket.org/site/ssh`,
196
+ select the `ssh.bitbucket.org` lines and independently check their fingerprints
197
+ against [Atlassian's SSH host-key documentation](https://support.atlassian.com/bitbucket-cloud/docs/configure-ssh-and-two-step-verification/).
198
+ Do not accept an unverified `ssh-keyscan` result. A host-key rotation stops access
199
+ until the published pins and selected file are reviewed. Strict verification is
200
+ always enabled. Existing `git@bitbucket.org:workspace/repo.git` origins and the
201
+ new `git@ssh.bitbucket.org:workspace/repo.git` origins resolve to one Cloud identity;
202
+ clones use the new endpoint described in [Atlassian's SSH migration notice](https://developer.atlassian.com/cloud/bitbucket/changelog/).
203
+ Self-hosted servers, custom SSH aliases and alternate ports are unsupported.
204
+
205
+ Run `init` from the checkout to bind the API repository UUID and workspace UUID
206
+ under the host's `repositories` map, or run `doctor` for read-only diagnostics.
207
+ Setup checks repository access, the selected base, effective account push role,
208
+ PR reads, comments when a PR exists, branch restrictions where visible, and native
209
+ Git access to the same base. The account role comes from the
210
+ [authenticated user's repository permissions](https://developer.atlassian.com/cloud/bitbucket/rest/api-group-repositories/#api-user-workspaces-workspace-permissions-repositories-get),
211
+ filtered by repository UUID, using repository read scope without workspace-admin access.
212
+ An archive flag, if supplied, is enforced; the Cloud
213
+ repository schema does not currently expose that flag consistently, so absence
214
+ is reported as unknown. A missing API credential reports missing PR/comment
215
+ capability even when an SSH key is configured. A successful transport check is
216
+ followed by an explicit failed dispatch check. No paid model probe is needed for
217
+ this milestone, and `init` does not recommend starting a task on an unqualified host.
218
+
219
+ API credentials are reread for every operation. A changed email, account UUID on
220
+ successive permission reads, repository UUID,
221
+ workspace UUID, canonical slug or API clone target stops access. Restore the
222
+ previous binding, or inspect the new identity and explicitly edit the binding;
223
+ setup never silently migrates a renamed or transferred repository.
224
+
225
+ ## Bitbucket evidence and publication bounds
226
+
227
+ `lib/hosts/bitbucket.mjs` owns API shape and pagination differences. PR snapshots
228
+ include source/destination UUIDs, branches and commits, draft state, host state
229
+ (`OPEN`, `MERGED`, `DECLINED` or `SUPERSEDED`), title/description, diff, comments,
230
+ reviewer participants, tasks and statuses tied to the current head. Declined and
231
+ superseded PRs normalize to `CLOSED`, preserving `hostState`. UUID-based actor
232
+ identity avoids nickname ambiguity. These observations do not qualify reviewer
233
+ trust, CI policy, recovery or merge proof for dispatch.
234
+ Build statuses use the [documented commit link](https://developer.atlassian.com/cloud/bitbucket/rest/api-group-commit-statuses/#api-repositories-workspace-repo-slug-commit-commit-statuses-get)
235
+ to confirm the queried repository and head; missing or mismatched links stop the snapshot.
236
+ PR list responses omit reviewer and participant collections. Bounded list results
237
+ are expanded through repository-scoped PR detail reads before normalization;
238
+ preflight also reads the selected PR's details before checking comment access.
239
+ Missing or inaccessible detail records stop the operation, and a failed read after
240
+ publication preserves the unresolved write until reconciliation succeeds.
241
+
242
+ Reads are bounded to 100 pages and 10,000 items per collection, 4 MiB per JSON
243
+ response, a diff smaller than 16 MiB, and 20 seconds per request. Missing fields,
244
+ cycles, changed filters, size inconsistencies, rate limits, foreign pagination,
245
+ redirects and changed PR identity/head during a snapshot produce explicit errors.
246
+ The documented diff redirect is allowed only into the same repository's diff
247
+ endpoint. Failures never become empty reviews or successful checks.
248
+
249
+ Publication uses the existing public-text validator, exact repository UUIDs and
250
+ source/base names. It checks PRs in all states before every publication, updates one matching open PR,
251
+ and refuses forks, closed predecessors, conflicting bases or duplicate ownership.
252
+ Writes address immutable workspace/repository UUIDs so a concurrent slug change
253
+ cannot redirect a write into a replacement repository. Every write is
254
+ followed by reconciliation, including timeouts after acceptance. An unresolved
255
+ create remains blocked in that adapter instance until a matching PR is observed;
256
+ a restart still reads before any write. Concurrent publication in one instance
257
+ is refused. There is no fork creation, merge, force push or repository-settings API.
258
+ Comments are never automatically retried after an uncertain write.
259
+
260
+ Offline coverage: `test/bitbucket.test.mjs`, `test/bitbucket-fixture.mjs` and
261
+ `test/host-transport-contract.test.mjs`. The shared contract assertions run against
262
+ both production adapters with injected wire responses. No fixture test calls a
263
+ model or writes to a live repository. Live review-loop qualification remains a
264
+ separate milestone.
265
+
266
+ API references: [repositories](https://developer.atlassian.com/cloud/bitbucket/rest/api-group-repositories/),
267
+ [pull requests](https://developer.atlassian.com/cloud/bitbucket/rest/api-group-pullrequests/),
268
+ and [account-token authentication](https://support.atlassian.com/bitbucket-cloud/docs/using-api-tokens/).
269
+
270
+ ## Review-loop implementation and ship gate
271
+
272
+ The [Bitbucket review guide](bitbucket-review.md) supersedes transport-only setup
273
+ examples for reviewer/trust/check policy. `init --host-config <json> --base <branch>`
274
+ can bootstrap an empty config, with an explicit reviewer (or `null`) and stable
275
+ trusted UUIDs. The adapter now implements review normalization, required task
276
+ blockers, recovery operations and merge ancestry. The explicit no-reviewer
277
+ dispatch path has [disposable live observations](audit/bitbucket-review-qualification.md),
278
+ but credential isolation failed; independent review and clean Linux installation
279
+ remain unvalidated. Do not enable general dispatch from these observations.
280
+
281
+ `prView` may include `feedback: { complete: true, headSha, reviews, inline, comments }`.
282
+ The shared loop consumes this one coherent snapshot; adapters without it retain
283
+ the previous collection methods. Strict records declare `headBinding: "exact"`
284
+ and an explicit `verdict`; PR-wide required tasks declare `required: true` and
285
+ `headBinding: "pull-request"`. Stable `sequence` values disambiguate verdicts that
286
+ share a timestamp. `strictIdentity` requests recorded branch/base/head and terminal
287
+ merge checks. These are domain contract fields, not host-name branches in the
288
+ scheduler. GitHub's historical event keys and review interpretation are retained.
289
+
290
+ A future GitLab adapter must implement the same complete records, explicit policy,
291
+ strict URL/credential binding, publication, file reads, and merge proof. Add its
292
+ static definition/implementation and shared-contract tests, then qualify it live
293
+ with a compatible provider. Until then GitLab and unregistered hosts fail before
294
+ dispatch. Host, harness and inference provider remain separate configuration axes.
@@ -309,3 +309,59 @@ that a tool call was denied. The historical findings are linked below.
309
309
  ## Follow-ups filed against APort
310
310
 
311
311
  The historical [decision record](https://github.com/uchibeke/gallivant/blob/main/docs/audit/DECISIONS.md) lists: multi-file `apply_patch` in the Codex hook, `git push` refspec parsing, control-plane paths blocked by default, a non-interactive local passport install, and a Repository Guard slice that blocks pushes rather than reporting merges.
312
+
313
+ ## Reviewer authority
314
+
315
+ The opt-in first-party reviewer uses the restricted native preparation boundary in a fresh session with supplied evidence only. Image jobs additionally require their own capability qualification and a verified coordinator-created copy. Its profile denies tools, escalation, delegation and tool network access; setup/start verify effective native policy and require a live qualification record. A private HOME or a prompt alone is not sufficient. The model cannot write task policy, state, files, Git refs, PRs or approvals. The coordinator validates exact-input structured output; public agent text is never an independent host actor. Unknown or partial output fails closed. See [review isolation, evidence and monetary limitations](first-party-review.md) and [unmet live qualification](audit/first-party-review.md). Review grants no merge or deployment authority.
316
+
317
+ Repository identity, credential transport and PR evidence are defined by the
318
+ [Git host contract](git-hosts.md). GitHub and Bitbucket Cloud can dispatch;
319
+ Bitbucket's live no-reviewer path has been qualified on a disposable public
320
+ repository. Independent Bitbucket review remains unvalidated. Existing IDs and
321
+ chain ownership are retained without a state migration.
322
+
323
+ ## Independent Bitbucket reviewer credentials
324
+
325
+ Coding sessions receive only their repository-bound coding credential. Reviewer
326
+ credentials belong on an isolated reviewer machine, OS account, or container.
327
+ The independent publisher accepts only the configured stable actor and prepared
328
+ exact head; a successful Pipeline without a posted verdict is silence.
329
+ See [reviewer isolation and publication](bitbucket-review.md#independent-local-codex-reviewer).
330
+ Setup never installs a pipeline, creates a token, or authorizes inference.
331
+
332
+ ## Keep working artifacts out of pull requests
333
+
334
+ Every local harness receives the same publication policy and generated `commit-msg` hook. The hook examines the
335
+ NUL-delimited staged file list and rejects task scratch directories, conventional work logs, audit/evidence notes,
336
+ and carried task inputs. Removing those files is allowed; preserve any carried files locally because the brief and
337
+ snapshot checks still need them. The hook is refreshed at start and on every resumed/fix run. Hosted file results
338
+ are checked before writing them, and the coordinator checks the complete remote PR diff before expensive first-party review and before readiness, even when the optional output-content scan is disabled. An unreadable or malformed diff is retried and
339
+ never treated as clean. A prohibited file schedules a normal corrective round with its exact path.
340
+
341
+ Requested audit reports, screenshots and other evidence are still valid deliverables. The operator names exact
342
+ paths in the approved brief's [`publish_files`](prd.md) list. The coordinator uses its saved snapshot, never a
343
+ session-edited whitelist. Before upgrading or restarting the daemon for existing runs, review retained deliverables in reserved directories.
344
+ The operator must name their exact paths in `publish_files` and accept the updated saved brief through the usual
345
+ `resume --resnapshot` flow at a safe resume boundary. Do not edit a running session's snapshot or grandfather all
346
+ existing files. Without those prior approved exceptions, the new guard will request cleanup instead of readiness.
347
+
348
+ Use a temporary directory outside the repository for scratch files. Runner command/session logs remain in task
349
+ storage; concise verification results belong in the PR receipt. Keep durable release/rollback instructions in the
350
+ project docs without appending a running execution diary. This policy does not inspect arbitrary prose or provide
351
+ an isolation boundary: an agent with Git credentials can bypass local hooks and push, but reserved work-artifact
352
+ paths will not pass the coordinator's readiness check. A clean check is cached only for its exact head, base and approved policy, so review polls do not repeatedly fetch
353
+ the diff. Normal rechecks also inspect legacy ready entries; no PR is automatically rewritten.
354
+
355
+ First-party reviewers receive carried text inputs from the coordinator's immutable `readSource` snapshots, with
356
+ content digests in their private evidence. They do not fetch those files from remote HEAD or the mutable session
357
+ checkout. These inputs follow the existing capture, per-job input and review-job caps; missing or oversized input
358
+ is reported explicitly, never silently omitted. Keep source context concise: it accompanies each source/visual
359
+ review piece and the final synthesis. The complete brief plus private source context and review metadata must fit the
360
+ configured per-job input cap (at most 100,000 serialized UTF-8 bytes). Larger private sources must be narrowed or
361
+ split into separately approved tasks; do not commit them as a workaround. Required image evidence remains in Git at its approved output paths.
362
+
363
+ `openai-agents` transports all approved inputs privately with their original hashes, but only explicit output overlays
364
+ are forced into a result. Verification permits private inputs to remain untracked or unstaged only while their bytes
365
+ and modes exactly match the coordinator snapshots. Editing, staging, deleting or substituting them fails publication.
366
+ Codex Cloud's Git-only input transport cannot provide this privacy for new/changed inputs and refuses before commit
367
+ or push; its dispatch is separately unavailable until repository binding is qualified. See [codex-cloud.md](codex-cloud.md).