@uchibeke/gallivant 0.0.0-stage → 0.2.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 (168) hide show
  1. package/CONTRIBUTING.md +26 -0
  2. package/LICENSE +204 -0
  3. package/README.md +201 -2
  4. package/SECURITY.md +19 -0
  5. package/bin/gallivant.mjs +257 -0
  6. package/bin/package-plugin.mjs +16 -0
  7. package/bin/release-live.mjs +29 -0
  8. package/bin/release-package.mjs +23 -0
  9. package/bin/session-runtime.mjs +13 -0
  10. package/bin/task-delivery-state.mjs +12 -0
  11. package/docs/README.md +70 -0
  12. package/docs/agent-setup.md +214 -0
  13. package/docs/app.md +111 -0
  14. package/docs/architecture.md +265 -0
  15. package/docs/chains.md +102 -0
  16. package/docs/codex-cloud.md +284 -0
  17. package/docs/commands.md +620 -0
  18. package/docs/config.md +430 -0
  19. package/docs/execution.md +796 -0
  20. package/docs/guardrails.md +311 -0
  21. package/docs/install.md +338 -0
  22. package/docs/launch.md +42 -0
  23. package/docs/learning.md +369 -0
  24. package/docs/network-recovery.md +101 -0
  25. package/docs/openai-agents.md +457 -0
  26. package/docs/prd.md +246 -0
  27. package/docs/preparation.md +110 -0
  28. package/docs/release-qualification.md +196 -0
  29. package/docs/releasing.md +140 -0
  30. package/docs/runtime-environment.md +113 -0
  31. package/docs/task-delivery.md +476 -0
  32. package/docs/tasks.md +739 -0
  33. package/lib/aport.mjs +95 -0
  34. package/lib/attribution.mjs +95 -0
  35. package/lib/block.mjs +89 -0
  36. package/lib/capabilities.mjs +3 -0
  37. package/lib/chains.mjs +222 -0
  38. package/lib/codex_cloud.mjs +160 -0
  39. package/lib/codex_cloud_config.mjs +20 -0
  40. package/lib/codex_cloud_input.mjs +49 -0
  41. package/lib/codex_cloud_result.mjs +74 -0
  42. package/lib/commands/doctor.mjs +457 -0
  43. package/lib/commands/init.mjs +34 -0
  44. package/lib/commands/learn.mjs +54 -0
  45. package/lib/commands/new.mjs +47 -0
  46. package/lib/commands/ready.mjs +45 -0
  47. package/lib/commands/register.mjs +195 -0
  48. package/lib/commands/resume.mjs +224 -0
  49. package/lib/commands/serve.mjs +349 -0
  50. package/lib/commands/start.mjs +247 -0
  51. package/lib/commands/start_services.mjs +22 -0
  52. package/lib/commands/status.mjs +150 -0
  53. package/lib/commands/task.mjs +73 -0
  54. package/lib/commands/up.mjs +228 -0
  55. package/lib/commands/why.mjs +143 -0
  56. package/lib/config.mjs +461 -0
  57. package/lib/context.mjs +100 -0
  58. package/lib/control.mjs +202 -0
  59. package/lib/control_contract.mjs +16 -0
  60. package/lib/coordinator.mjs +19 -0
  61. package/lib/credential.mjs +161 -0
  62. package/lib/daemon.mjs +156 -0
  63. package/lib/deliverable.mjs +357 -0
  64. package/lib/events.mjs +261 -0
  65. package/lib/executable.mjs +31 -0
  66. package/lib/execution.mjs +631 -0
  67. package/lib/execution_contract.mjs +15 -0
  68. package/lib/execution_input.mjs +4 -0
  69. package/lib/execution_io.mjs +94 -0
  70. package/lib/execution_journal.mjs +69 -0
  71. package/lib/execution_preparation.mjs +29 -0
  72. package/lib/execution_result.mjs +266 -0
  73. package/lib/fs.mjs +133 -0
  74. package/lib/gh.mjs +289 -0
  75. package/lib/git.mjs +434 -0
  76. package/lib/harness.mjs +521 -0
  77. package/lib/harness_log.mjs +432 -0
  78. package/lib/hash.mjs +16 -0
  79. package/lib/identity.mjs +98 -0
  80. package/lib/learning.mjs +654 -0
  81. package/lib/learning_contract.mjs +2 -0
  82. package/lib/learning_data.mjs +135 -0
  83. package/lib/learning_input.mjs +111 -0
  84. package/lib/learning_qualification.mjs +67 -0
  85. package/lib/learning_signer.mjs +151 -0
  86. package/lib/learning_store.mjs +88 -0
  87. package/lib/log.mjs +53 -0
  88. package/lib/network_diagnostics.mjs +64 -0
  89. package/lib/network_recovery.mjs +42 -0
  90. package/lib/notify.mjs +58 -0
  91. package/lib/openai_agents.mjs +373 -0
  92. package/lib/openai_agents_config.mjs +14 -0
  93. package/lib/openai_agents_http.mjs +87 -0
  94. package/lib/openai_agents_input.mjs +15 -0
  95. package/lib/openai_agents_sources.mjs +112 -0
  96. package/lib/owner_delivery.mjs +443 -0
  97. package/lib/plugin_package.mjs +340 -0
  98. package/lib/prd.mjs +635 -0
  99. package/lib/preparation_agents.mjs +33 -0
  100. package/lib/preparation_codex.mjs +212 -0
  101. package/lib/probe.mjs +126 -0
  102. package/lib/prompt.mjs +238 -0
  103. package/lib/provider_health.mjs +55 -0
  104. package/lib/public-format.mjs +31 -0
  105. package/lib/public_output.mjs +49 -0
  106. package/lib/release_package.mjs +154 -0
  107. package/lib/repository_files.mjs +86 -0
  108. package/lib/run.mjs +385 -0
  109. package/lib/run_log.mjs +94 -0
  110. package/lib/runtime-environment.mjs +87 -0
  111. package/lib/runtime_dependencies.mjs +15 -0
  112. package/lib/runtime_node.mjs +107 -0
  113. package/lib/runtime_state.mjs +174 -0
  114. package/lib/sources/index.mjs +27 -0
  115. package/lib/sources/prd.mjs +50 -0
  116. package/lib/start_contract.mjs +37 -0
  117. package/lib/state.mjs +246 -0
  118. package/lib/task_allowance.mjs +31 -0
  119. package/lib/task_completion.mjs +61 -0
  120. package/lib/task_contract.mjs +450 -0
  121. package/lib/task_delivery.mjs +219 -0
  122. package/lib/task_delivery_cancel.mjs +34 -0
  123. package/lib/task_delivery_contract.mjs +61 -0
  124. package/lib/task_delivery_mcp.mjs +40 -0
  125. package/lib/task_delivery_store.mjs +43 -0
  126. package/lib/task_delivery_view.mjs +88 -0
  127. package/lib/task_environment.mjs +281 -0
  128. package/lib/task_prepare.mjs +224 -0
  129. package/lib/task_store.mjs +38 -0
  130. package/lib/tasks.mjs +513 -0
  131. package/lib/tick.mjs +1635 -0
  132. package/lib/time.mjs +36 -0
  133. package/lib/tracker/assets.mjs +43 -0
  134. package/lib/tracker/pages.mjs +320 -0
  135. package/lib/tracker/runs.mjs +102 -0
  136. package/lib/tracker/stream.mjs +74 -0
  137. package/lib/tracker_process.mjs +107 -0
  138. package/lib/verification_sandbox.mjs +181 -0
  139. package/node_modules/smol-toml/LICENSE +24 -0
  140. package/node_modules/smol-toml/README.md +605 -0
  141. package/node_modules/smol-toml/dist/date.d.ts +41 -0
  142. package/node_modules/smol-toml/dist/date.js +156 -0
  143. package/node_modules/smol-toml/dist/error.d.ts +37 -0
  144. package/node_modules/smol-toml/dist/error.js +67 -0
  145. package/node_modules/smol-toml/dist/extract.js +289 -0
  146. package/node_modules/smol-toml/dist/index.cjs +770 -0
  147. package/node_modules/smol-toml/dist/index.d.ts +44 -0
  148. package/node_modules/smol-toml/dist/index.js +34 -0
  149. package/node_modules/smol-toml/dist/parse.d.ts +73 -0
  150. package/node_modules/smol-toml/dist/parse.js +164 -0
  151. package/node_modules/smol-toml/dist/primitive.js +151 -0
  152. package/node_modules/smol-toml/dist/stringify.d.ts +32 -0
  153. package/node_modules/smol-toml/dist/stringify.js +219 -0
  154. package/node_modules/smol-toml/dist/struct.js +156 -0
  155. package/node_modules/smol-toml/dist/util.d.ts +43 -0
  156. package/node_modules/smol-toml/dist/util.js +57 -0
  157. package/node_modules/smol-toml/package.json +68 -0
  158. package/npm-shrinkwrap.json +1823 -0
  159. package/package.json +105 -4
  160. package/templates/claude-settings.json +18 -0
  161. package/templates/passport.gallivant.json +83 -0
  162. package/templates/plugin/bundled-runtime.json +26 -0
  163. package/templates/plugin/schemas/mcp.schema.json +120 -0
  164. package/templates/plugin/schemas/plugin.schema.json +65 -0
  165. package/templates/plugin/task-delivery.SKILL.md +60 -0
  166. package/templates/prd.md +32 -0
  167. package/templates/tracker/tracker.css +301 -0
  168. package/templates/tracker/tracker.js +721 -0
@@ -0,0 +1,369 @@
1
+ # Learning from reviewed feedback
2
+
3
+ The repository-scoped learning service collects eligible feedback and keeps exact
4
+ candidate revisions for human review. A digest identifies content. Only an enrolled
5
+ Ed25519 OpenSSH signature can authorize an activation transition. Advice remains
6
+ advisory: it cannot change task scope, Verify commands, acceptance criteria, tools,
7
+ permissions, budgets, merge policy, reviewer eligibility or APort gates.
8
+
9
+ **Deployment status: UNQUALIFIED, collection only.** This implementation includes
10
+ the collector, review service, OpenSSH verifier, transition journal and shared input
11
+ seam. Installed coding adapters do not yet enforce an outer boundary protecting
12
+ learning authority from arbitrary worker code and privileged/control routes. No
13
+ configuration boolean, hash, file mode, approval flag or TTY enables application.
14
+ Setup, extraction and apply refuse that missing prerequisite. Fixture qualification
15
+ in tests is dependency injection, never a production enrollment mechanism.
16
+
17
+ The normative [architecture](https://github.com/uchibeke/gallivant/blob/main/docs/plans/review-feedback-learning.md) describes the full
18
+ delivery contract. Several implementation requirements remain outstanding; the
19
+ [qualification record](https://github.com/uchibeke/gallivant/blob/main/docs/audit/learning-qualification.md) distinguishes tested behavior
20
+ from those gaps. This release makes no effectiveness claim.
21
+
22
+ ## Collection and review on Linux and macOS
23
+
24
+ Use Node 22+, the configured `gh` credential and the existing operator configuration
25
+ with `trusted_authors` and `reviewer`. Eligible prose is still untrusted data.
26
+ Repository identity is GitHub host plus immutable numeric repository ID; a fork or
27
+ replacement repository cannot inherit lessons by reusing an owner/name. This first
28
+ transport supports github.com; enterprise hosts are refused.
29
+
30
+ ```sh
31
+ gallivant learn configure --repo owner/project --mode collect
32
+ gallivant learn --repo owner/project --since 2026-09-01 --until 2026-10-07 --dry-run
33
+ gallivant learn --repo owner/project --since 2026-09-01 --until 2026-10-07
34
+ gallivant learn list --repo owner/project --status pending
35
+ gallivant learn show lesson-validation --repo owner/project --revision SHA256
36
+ gallivant learn reject lesson-validation --repo owner/project --revision SHA256 --reason 'Contested correction'
37
+ gallivant learn report --repo owner/project
38
+ gallivant learn prune --repo owner/project
39
+ ```
40
+
41
+ Replace owner/project, IDs and digests with actual results. Dates are half-open UTC
42
+ dates. The default window is 30 days, with 100 PRs, 1,000 eligible findings, 60 API
43
+ pages and a 60-second collection deadline per invocation. PRs are scanned by update
44
+ time, including old PRs. Separate learning cursors never acknowledge coding events,
45
+ consume review rounds or change task identity. Automatic observation runs after
46
+ coding/review dispatch and does no extraction. A full source enumeration is needed
47
+ to flag deletion; filtered automatic reads cannot establish absence.
48
+ The automatic lane rotates a window of at most 100 due watched entries, independently
49
+ of request completion order. Idle progress ticks retain the next window.
50
+
51
+ Coverage, caps, continuation and rate-limit retry time are reported. Interrupted
52
+ scans resume the unfinished source kind and page within a PR. PR listing passes
53
+ retain their page cursor across invocations and skip persisted completed PR identities.
54
+ A pass that discovers new identities triggers another pass from page one to catch
55
+ PRs moved ahead of its cursor; completion requires a pass with no new identities.
56
+ Both passes respect the 60-page invocation budget and retain progress beyond page
57
+ 60. The completed identity set remains capped at 10,000. Immutable evidence
58
+ revisions deduplicate overlap. Each page saves minimized findings and continuation
59
+ together, including pages containing only ineligible comments. Deletion is deferred
60
+ until the complete source has been enumerated. Required review context is minimized,
61
+ retained only through inline enumeration, and subject to the 30-day excerpt limit
62
+ from its stored observation timestamp, independently of a future scan endpoint.
63
+ Legacy buffers without a trustworthy observation timestamp are redacted on read or prune.
64
+ When `--until` is omitted, retries reuse the incomplete scan's original date window,
65
+ including after restart; completion allows the next invocation to open a fresh window.
66
+ Dry-run uses the same transport and eligibility rules but writes no learning state
67
+ and runs no inference. A source page reserves up to 200 eligible events (100 comments
68
+ and their review summaries), so an invocation can stop below the 1,000-finding cap.
69
+ Transport and parsing share a 64 MiB ceiling for each 100-item page before body
70
+ minimization. The 10,000-observation/context-identity storage bounds and continuously
71
+ moving upstream pagination can still leave coverage incomplete; inspect the report
72
+ before assuming full history was collected. No evidence link is opened or fetched.
73
+ Pruning uses the remembered immutable identity and removes expired local excerpts
74
+ even when GitHub is unavailable. Reconfiguration refuses a different resolved ID;
75
+ identity persistence also refuses replacement, preserving offline disable ownership.
76
+ Recovery uses the remembered immutable repository identity and signed local state,
77
+ so retrying revocation controls does not depend on GitHub availability. Verified
78
+ committed removals retry their controls even after qualification is lost; prepared
79
+ transitions still require qualification before activation. Batch
80
+ approval rejects multiple revisions of one candidate before preview or signing.
81
+
82
+ `reject` requires a nonempty `--reason` and applies only to pending or already
83
+ rejected revisions. `retire` also requires a reason and, when qualification is
84
+ available, targets an exact active revision through the signing workflow.
85
+ `approve` accepts an optional reason. These are distinct from changing a
86
+ repository's collection mode.
87
+
88
+ `revise` validates closed-schema JSON and creates an unapproved revision:
89
+
90
+ ```sh
91
+ gallivant learn revise lesson-validation --repo owner/project --from reviewed-rule.json
92
+ gallivant learn show lesson-validation --repo owner/project --revision SHA256
93
+ ```
94
+
95
+ The review view contains exact text, applicability, literal project scopes, rationale,
96
+ example, evidence, fix disposition, overlap/repetition suggestions and digest. It is
97
+ escaped JSON, without a pager, executable Markdown or automatic URL opening. Editing
98
+ or combining evidence never inherits approval. Exact rejected revisions remain
99
+ suppressed. Contradictions require human judgment; repetition is a suggestion, not
100
+ validation. Copying guidance to AGENTS.md is optional ordinary reviewed navigation,
101
+ never enrollment or an automatic per-run rewrite.
102
+
103
+ Resolved source visibility is retained in evidence separately from immutable
104
+ repository identity; unavailable classification is reported as unknown. Dismissal
105
+ and deletion flags retain their first observed timestamp without changing evidence
106
+ hashes. Retracted evidence remains inspectable and is excluded from extraction.
107
+ Configuration persists the last-resolved visibility. Before storing automatic
108
+ observations, the post-dispatch collection step revalidates the immutable repository
109
+ ID and refreshes classification; a name replacement or lookup outage skips learning
110
+ without altering coding feedback. Identity checks share a five-second batch budget
111
+ and one lookup per repository per batch. Skips are logged and later ticks rotate
112
+ the bounded observation window. Legacy identity-only records remain readable.
113
+ Use historical collection to cover feedback missed while identity lookup was
114
+ unavailable; advancing coding cursors do not promise an automatic learning retry.
115
+
116
+ `learn configure --repo owner/project --mode off` uses the stored identity and invokes
117
+ local revocation controls even when GitHub, credentials or the remote repository are
118
+ unavailable. Enabling collection or application still resolves the remote identity.
119
+ Every configuration write advances a durable mode generation, including repeated
120
+ disables. An apply request awaiting qualification refuses to commit if that
121
+ generation changed; a new explicit apply request is required. Older state files
122
+ acquire this field on their next write without changing their current mode.
123
+
124
+ If revocation controls fail after the mode is saved, repeat the disabled-mode
125
+ command: both `off` and `collect` retry controls even when the mode is unchanged.
126
+
127
+ Extraction consumes stored evidence using the remembered immutable identity and
128
+ does not authenticate to GitHub or resolve the remote repository. With an
129
+ unqualified installed profile it reports unavailable even during a GitHub outage.
130
+ The service seam bounds a separate
131
+ allowance (maximum $1 per extraction), 30 seconds and 20 candidate revisions. It
132
+ persists an intent/reservation before invoking an injected data-only execution
133
+ dependency. Each intent reserves its exact observation revision digests; later
134
+ invocations select the next unreserved batch, including after restart. Unresolved
135
+ batches remain reserved and are not automatically repurchased. Legacy exact-batch
136
+ digests acquire revision keys when the same bounded input is encountered. No installed
137
+ production extractor currently implements that boundary; `dataOnly` metadata is not
138
+ an operator configuration option. List/show/report/explain cannot launch paid work.
139
+
140
+ Restricted task preparation now supplies shared native tool/context controls that
141
+ a future extraction adapter can reuse. It does not connect the learning extractor
142
+ or qualify ordinary coding workers, signing authority or control routes. The
143
+ [merged-boundary assessment](https://github.com/uchibeke/gallivant/blob/main/docs/audit/learning-qualification.md#merged-preparation-boundary-assessment)
144
+ records the reusable pieces, remaining integration work and external qualification
145
+ requirements. Preparation fixture results do not enable production learning.
146
+
147
+ ## Approval workflow contract and prerequisites
148
+
149
+ These commands describe the intended workflow; **the deployment stages below refuse
150
+ today's unqualified profiles**. Do not run setup as a coding worker, install this
151
+ development branch as the coordinator or create production keys to test it.
152
+
153
+ OpenSSH must support both `ssh-keygen -Y sign` and `-Y verify`. `learn doctor` probes
154
+ these operations with a disposable key rather than relying on a version string.
155
+ Choose an absolute protected executable (default `/usr/bin/ssh-keygen`). The file
156
+ and every ancestor must be owned by root or the operator, with no group/other
157
+ write permission. Only the fixed system temporary root (`/tmp`, resolved through its system alias)
158
+ may be a root-owned sticky ancestor, and only above
159
+ a private trusted directory; the executable's immediate parent must never be
160
+ group/other-writable. These checks run on each pin, including after enrollment.
161
+ They do not isolate a worker running as the operator: that still requires the
162
+ qualified outer boundary. Linux
163
+ operators can install their distribution's `openssh-client`; macOS operators use
164
+ their system OpenSSH or an operator-installed portable build. Changes to the pinned
165
+ binary require requalification. The offline suite additionally uses Python 3 for
166
+ disposable PTY entry; it never asks for a human passphrase.
167
+
168
+ ```sh
169
+ gallivant learn doctor --repo owner/project
170
+ gallivant learn setup --key-path /absolute/operator-approval/learning-ed25519 --ssh-keygen /usr/bin/ssh-keygen
171
+ gallivant learn approve lesson-validation --repo owner/project --revision SHA256
172
+ gallivant learn configure --repo owner/project --mode apply
173
+ gallivant learn explain --repo owner/project --run RUN_ID
174
+ gallivant learn retire lesson-validation --repo owner/project --revision SHA256 --reason 'Replaced by a regression test'
175
+ gallivant learn recover --repo owner/project
176
+ gallivant learn configure --repo owner/project --mode off
177
+ ```
178
+
179
+ `GALLIVANT_HOME` can locate nonsecret state in another operator-owned home. The
180
+ private key has a separate explicit absolute path, supporting a separate account.
181
+ Both directories must be outside worker writes, without symlinks; approval directory
182
+ 0700 and key 0600 are hygiene only. An enforced OS/container/account boundary must
183
+ also protect CLI/coordinator code, public trust, signer, active store and monotonic
184
+ checkpoint; deny private-key/credential/terminal access; and exclude privileged and
185
+ control routes that could escape it. Same-UID modes and APort hooks alone do not
186
+ qualify arbitrary shell execution. Current native escalation and hosted profiles
187
+ remain unsupported for production learning application.
188
+
189
+ When qualified, explicit interactive setup would ask OpenSSH to create a dedicated
190
+ Ed25519 key using bcrypt with at least 100 rounds, refuse existing files and
191
+ unencrypted keys, validate the public envelope and sign an enrollment manifest.
192
+ Choose a strong unique nonempty passphrase. Do not reuse GitHub signing/login keys
193
+ or load the key into an agent. Node never requests or stores the secret.
194
+
195
+ Approval freezes a complete preview, including every selected/removed revision and
196
+ evidence, then takes a separate explicit confirmation before fresh OpenSSH signing.
197
+ There is no `--yes`, wildcard, approve-all, alternate activation command or unsigned
198
+ flag. Signing uses a pinned executable and minimal environment: agent, askpass,
199
+ provider and dynamic-loader variables are absent; `SSH_ASKPASS_REQUIRE=never`.
200
+ An optional `--reason` on `learn approve` appears in the immutable preview and signed
201
+ transition as an audit explanation.
202
+ Cancellation or failed signing changes no active content. Signed prepared intent
203
+ may be recovered only against its exact current parent. The CLI currently selects
204
+ one revision per invocation; explicit batches are available only to the shared
205
+ service and enumerate every ID/digest in the preview.
206
+ `learn recover` also retries controls for committed retirements and replacements
207
+ from verified signed history, without signing or activating another transition.
208
+ Recovery verifies obsolete signed preparations whose sequence was already consumed
209
+ and moves them to a protected audit archive, then continues eligible preparations.
210
+ It never rebases an old signature. Invalid signatures still fail closed. The archive
211
+ retains exact signed bytes and disposition, is capped at 1,000 records, and its count
212
+ appears in `learn report`; older stores migrate the empty archive without read-time
213
+ writes. Include it in the same protected-store backup as approval history.
214
+
215
+ Activation checks canonical RFC 8785 bytes, SSHSIG namespace, enrolled signer,
216
+ repository identity, sequence/parent, evidence and complete active-set digests.
217
+ History, pointer and checkpoint commit through one fsynced atomic rename under the
218
+ existing process-identity lock. A stale signature requires another preview; rollback
219
+ is another signed transition. Hashes and timestamps alone authorize nothing.
220
+
221
+ Shared dispatch selects at most 20 lessons and 8 KiB, in stable ID order. Literal
222
+ project scopes match validated repository-relative paths from inline review events,
223
+ carried task files and the approved brief path. Up to 200 unique paths are selected
224
+ in stable order; invalid/absolute/traversing paths are excluded. The pinned paths
225
+ carry forward into resume, and unknown paths still omit project-scoped guidance.
226
+ It records bundle/rule,
227
+ original input, managed input and context digests plus omissions; actual delivery is
228
+ recorded after an accepted attempt ID exists. Pending and foreign material never
229
+ enters managed context. Retirement fences later delivery and uses existing
230
+ cancellation capabilities with honest confirmation limits. If old native memory
231
+ contains retired advice, ordinary resume refuses and preserves task, PR and code.
232
+ After the existing run settles, explicitly run `gallivant resume <handle> --fresh-session`. This saves a retryable transition and starts a new provider session
233
+ with the approved brief, current task/PR context and current approved advice. It
234
+ preserves checkout, branch, cursors, iteration, operation history and cumulative
235
+ allowance. Unconfirmed cancellation and unrelated stop fences remain blocking;
236
+ a provider returning the retired session is refused. Old memory is not erased.
237
+ When learning is `off` or `collect`, this fresh-session transition clears advice
238
+ locally without a learning-related GitHub lookup. Any independently required
239
+ provider or coding-workflow credentials still apply.
240
+
241
+ Prepared advice records the owning task before launch. Admission rechecks mode,
242
+ revocation and signed active revisions under the learning lock and holds that lock
243
+ through provider acceptance. Retirement or disable racing that launch reports a
244
+ busy operation and must be retried; it has not committed a stop. Once committed,
245
+ revocation also reaches accepted execution intents before registry publication.
246
+ Retired prepared inputs stay fenced across restart and re-enabling application.
247
+ The accepted-delivery outbox retries unconfirmed cancellation without redispatch.
248
+
249
+ Accepted run ownership, feedback cursors and pending delivery audit records are
250
+ saved together before writing to the learning store. If that store is locked or
251
+ unavailable, coding continues with its pinned context and the registry retains
252
+ the exact repository/input/run tuple. Coordinator ticks retry up to ten pending
253
+ records per entry, including after restart or completion. Lost replies are safe
254
+ to retry; an older audit cannot replace a later attempt's pinned context. A pending
255
+ audit warning means reports may temporarily omit that delivery, not that its worker
256
+ failed to start. Preserve the registry as well as the learning store during recovery.
257
+
258
+ A failed enrollment signature retains the newly created encrypted key and a protected
259
+ `enrollment-intent.json` containing only its identity, path and pinned signer metadata.
260
+ Setup prompts, key creation and signing run outside the global store lock. Each
261
+ write reacquires it and checks that the pending intent and authority are unchanged.
262
+ Retry `learn setup` with the same key path: it verifies the exact encrypted key and
263
+ signer, previews the pending enrollment and requests fresh signing. Cancellation
264
+ preserves the pending intent; substituted keys, paths or signers are refused. The
265
+ intent remains audit metadata after success and cannot replace an enrolled authority.
266
+ Include it in the protected-state backup; keep encrypted private keys separately.
267
+
268
+ ## Privacy, backup and recovery
269
+
270
+ Raw excerpts are bounded to 2 KiB, redacted and escaped before persistence. Source
271
+ SHA-256 digests identify the full source without retaining it. Never copy complete
272
+ logs or secrets into candidates. Invalid controls, bidirectional text, paths,
273
+ schemas, duplicate JSON keys and encodings are refused. A configured application
274
+ cannot fall back to an unsigned or foreign bundle when trust/checkpoints fail.
275
+
276
+ Raw excerpt retention is 30 days; collection/observation mutations and `prune`
277
+ remove expired observation excerpts, and read-only inspection hides them immediately.
278
+ Minimized signed evidence, hashes, disposition and approval history are retained.
279
+ Deletion cannot remove copies in backups, GitHub or already delivered provider
280
+ memory. Review views disclose expired, superseded, deleted and incomplete evidence.
281
+ Back up encrypted keys separately from nonsecret state. A generic repository backup
282
+ must never bootstrap trust or move an approval checkpoint backward.
283
+
284
+ Rotation and lost/compromised-key recovery are not yet implemented as commands.
285
+ Disable application, preserve the journal and use explicit operator-reviewed
286
+ re-enrollment/continuity once supported. Do not replace authority.json or restore an
287
+ older checkpoint to simulate rotation. Local signatures cannot prove freshness after
288
+ arbitrary rollback of the entire protected installation; V1 has no remote witness.
289
+
290
+ Reports separate confirmed recurrence from evidence-count suggestions. Known cost
291
+ is traceable; unresolved usage is unknown, not zero. The delivered-run denominator
292
+ does not yet cover every eligible coding attempt, and review-round/latency outcome
293
+ correlation remains outstanding. Different task mixes cannot establish causal
294
+ effectiveness. Held-out deterministic cases and real disposable OpenSSH bypass tests
295
+ check regressions; separately authorized paired live trials would be required for
296
+ quantitative effectiveness claims.
297
+
298
+ ## Qualification and troubleshooting
299
+
300
+ ```sh
301
+ npm run test:learning
302
+ npm run test:learning:live -- --qualify
303
+ ```
304
+
305
+ The first command makes no paid calls and enrolls no production authority. The
306
+ second is opt-in and probes disposable key/trust/verifier/checkpoint canaries plus
307
+ terminal and local-control access using OS isolation. When those probes pass, it
308
+ requires interactive creation/enrollment of a temporary encrypted key, exact approval,
309
+ context consumption by a process enclosed in that same profile, and signed retirement.
310
+ All keys/state are deleted afterward and no paid inference runs. Production stays
311
+ UNQUALIFIED even after that disposable ceremony: installed worker launch/control
312
+ integration is still outstanding. The recorded qualification audit does not supply
313
+ a successful production enrollment or live approval/delivery ceremony.
314
+
315
+ On macOS, `sandbox_apply: Operation not permitted` means the host cannot create the
316
+ required nested sandbox from that execution surface. Run the probe from an operator
317
+ terminal where sandbox-exec is permitted. On Linux, `/usr/bin/bwrap`, functioning
318
+ user/PID/network namespaces and a dedicated Node installation are prerequisites.
319
+ Neither fix alone enables production apply; the actual installed execution profile
320
+ still needs integration and qualification. Never weaken the boundary to turn a
321
+ test green. Normal unenrolled coding runs keep their existing behavior.
322
+
323
+
324
+ Delivery audit storage is limited to 1,000 exact operation records per repository
325
+ and 16 KiB per newly prepared record, including context, paths and omissions.
326
+ Reports disclose usage and limits. At capacity, new advice-bearing operations fail
327
+ before launch; existing retries, delivery acknowledgements, pruning, retirement,
328
+ and disabling remain available. Records are not silently evicted: prepared
329
+ revocation targets, exact retry identities, digests and accepted-run denominators
330
+ remain intact. Automatic archival is not implemented; do not delete audit records
331
+ or reset the store to bypass capacity. Disable application to continue without
332
+ advice while preserving the protected audit backup.
333
+
334
+ Approval confirmation and passphrase entry run without the shared store lock.
335
+ The service rechecks the complete frozen preview, mode, parent, sequence and trust
336
+ root after each interaction; concurrent changes require a new reviewed approval.
337
+ Extraction candidates may cite only evidence included in that reserved batch.
338
+
339
+
340
+ Extraction reserves exact observation revisions durably before releasing the store
341
+ lock for external execution. Other repositories and emergency disable can mutate
342
+ state during that wait. Results merge into newly loaded state only if the original
343
+ reservation is unchanged; disabled collection or stale evidence refuses candidate
344
+ insertion. A failed merge leaves the reservation intact and does not authorize
345
+ repeat inference. Known returned cost and token counts remain recorded even when
346
+ a concurrent change prevents accepting the proposals.
347
+
348
+
349
+ Delivery path audit details retain an encoded JSON sample of at most 2 KiB,
350
+ plus `pathAudit.digest`, `count` and `omitted` for the full accepted path list.
351
+ Rule selection still considers every accepted path, including those omitted from
352
+ the stored sample. Managed inputs retain the full list; the audit digest allows
353
+ that exact list to be checked without duplicating it in every delivery record.
354
+
355
+ The executable selected with setup's `--ssh-keygen` is pinned in protected
356
+ enrollment metadata and reused by later CLI and daemon services without another
357
+ flag. Pending enrollment retries also reuse that pin. Each cryptographic use,
358
+ including doctor probes, checks the exact executable path and digest before
359
+ execution; a changed or missing binary requires restoring the pinned installation
360
+ or separately reviewed requalification. Local collection and emergency disable
361
+ do not require resolving or executing the signer.
362
+
363
+
364
+ Omitted-rule audits retain at most 1 KiB of encoded detail, further reduced to
365
+ fit the delivery record's remaining byte budget. `omissionAudit` records the full
366
+ ordered list digest, total count, unsampled count and counts by omission reason.
367
+ Rule selection still traverses the entire verified active bundle; the sample does
368
+ not change relevance or context limits. Exact selected rule references and the
369
+ bundle digest remain available alongside this summary for audit reconstruction.
@@ -0,0 +1,101 @@
1
+ # Network failures and recovery
2
+
3
+ `ENOTFOUND` means a hostname lookup failed. `EAI_AGAIN` indicates a temporary
4
+ resolver failure. Neither proves that a provider is down, credentials expired,
5
+ or APort denied a tool call. DNS can affect one hostname while other sites work.
6
+
7
+ ## Automatic local recovery
8
+
9
+ For a recognized terminal connection error, Gallivant waits 1, 5, then 15 minutes
10
+ before up to three automatic resumes, on the next daemon tick after each deadline.
11
+ It preserves the session, checkout, pending work, review cursors and approved brief.
12
+ The normal resume preflight, permissions, dirty-work preservation and completion
13
+ gates still apply. A connection failure with no published progress does not count
14
+ as a completed review round. A run that pushed before failing is accounted for
15
+ normally and returns to review/CI monitoring; it cannot evade the round budget.
16
+ Retries may incur provider charges, subject to existing per-run and task allowances;
17
+ the retry budget is separate from `max_iterations`.
18
+
19
+ Counts and deadlines survive daemon restarts. The window begins when the terminal
20
+ failure is observed, before GitHub reconciliation; a simultaneous GitHub outage
21
+ cannot extend it. Published progress must still be reconciled before retrying.
22
+ No retry starts after the one-hour recovery window expires; an already-started
23
+ run retains its normal runtime limit.
24
+ The shared completion projection keeps pending retries monitored, so embedded
25
+ hosts continue waking the coordinator instead of treating the task as paused.
26
+ Exhaustion stops with `provider-network-exhausted` and notifies the operator.
27
+ Success or reconciled published progress resets the consecutive failure streak.
28
+ A manually authorized Resume starts a new streak after normal preflight.
29
+
30
+ Only short terminal errors containing `ENOTFOUND`, `EAI_AGAIN`, `ECONNRESET`,
31
+ `ECONNREFUSED` or `ETIMEDOUT` qualify. Missing results, unknown errors, authentication
32
+ failures, quota errors, policy denials, cancelled tasks and unknown process ownership
33
+ do not trigger automatic replay. A crash during launch stops for inspection rather
34
+ than guessing whether input was sent. Unrecognized error formats require manual
35
+ inspection. Hosted execution retains its transport reconciliation: this mechanism
36
+ never resubmits an ambiguously accepted remote operation.
37
+
38
+ Status, the dashboard and `gallivant why <handle>` show the error, retry count and
39
+ deadline. “Signed-in (API unchecked)” means the local version/login checks passed;
40
+ it does not prove inference access. OpenCode reports credential presence; Gemini
41
+ and Goose report only that the binary runs, with authentication unchecked.
42
+ **Recheck PR** refreshes review and CI; it cannot
43
+ clear a failed agent or pending network recovery. **Resume agent** continues the
44
+ session after you repair its prerequisites. Upgrades do not silently restart old
45
+ stopped jobs; resume those explicitly once.
46
+
47
+ Readiness checks use a bounded 20-second coordinator deadline by default; an
48
+ explicit `execution.deadlineMs` overrides it. A timeout or cancelled check leaves
49
+ dispatch blocked until a successful refresh, but does not prove credentials are
50
+ invalid. The remedy is to inspect host load/connectivity and retry the check,
51
+ rather than automatically logging in or reinstalling the CLI. Pending refreshes
52
+ are reported as pending checks.
53
+
54
+ ## Portable diagnosis
55
+
56
+ Use the actual provider origin configured for your harness. For default Claude:
57
+
58
+ ```sh
59
+ gallivant doctor --network https://api.anthropic.com
60
+ gallivant doctor --network https://api.anthropic.com --json
61
+ ```
62
+
63
+ No config, login or daemon is required. This takes three bounded samples using
64
+ Node's OS DNS resolver and credential-free HTTPS, without `dig`, `curl`, `sudo`,
65
+ systemd, launchd or a desktop. It sends HEAD requests only to your supplied HTTPS
66
+ origin, follows no redirects, and rejects credentials, paths, queries and fragments.
67
+ HTTP 401/403/404 proves an HTTPS response was received, not model access. Exit 0
68
+ requires every sample to pass; exit 1 indicates a failure or invalid input.
69
+ Passing samples cannot rule out an intermittent failure.
70
+
71
+ HTTPS testing is direct, without proxy forwarding. Proxy environment presence is
72
+ reported without its values. If a proxy is mandatory, use your administrator's
73
+ approved proxy diagnostic too. This test does not qualify the harness's proxy route.
74
+
75
+ Capture results during a failure and compare on another approved network. If only
76
+ router DNS fails while direct queries to an approved resolver succeed, repair the
77
+ router or configure that resolver through your network administrator. If OS lookup
78
+ fails while direct DNS works, inspect the resolver, VPN and endpoint-filter logs.
79
+ Linux users can use `resolvectl status` where systemd-resolved is installed;
80
+ otherwise use the distribution's network manager. Do not blindly overwrite a
81
+ managed `/etc/resolv.conf`. On macOS use Network settings and filter logs.
82
+ Do not disable TLS validation, firewalls or sandboxing to hide the failure.
83
+
84
+ After repair:
85
+
86
+ ```sh
87
+ gallivant why <handle>
88
+ gallivant resume <handle>
89
+ ```
90
+
91
+ ## Platform and release qualification
92
+
93
+ Recovery uses Node 22+ and the existing runner, with no macOS-specific commands.
94
+ CI exercises Node 22/24 on Ubuntu Linux and macOS, including tarball installation.
95
+ That is not a guarantee for every Linux distribution, container or provider CLI.
96
+ Process inspection and the selected harness's runtime/sandbox remain prerequisites;
97
+ hosted-result verification needs the isolation tools in [installation](install.md).
98
+ Missing isolation fails closed. The coordinator must remain awake and running.
99
+
100
+ Require the full CI matrix and package smoke test before release, then qualify a
101
+ small live task in the intended environment. See [release readiness](releasing.md).