Skip to content

Commit 606e86e

Browse files
Merge pull request #36 from StepenkoAnatoli/docs/corroborate-the-delivery-corpus
Corroborate the three delivery-architecture claims that carry decisions
2 parents dfff763 + 63e6335 commit 606e86e

12 files changed

Lines changed: 569 additions & 15 deletions

‎docs/adr/0031-actions-first-delivery-and-pin-the-api-version.md‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,27 @@ decision 6 and the credential store it depends on.
100100
**Research whose subject is sensitive needs a paid plan, not just a visibility change.**
101101
That should be settled before anything depends on it.
102102

103+
### Corroborated, 2026-09-21 — and the pin turns out to have a deadline
104+
105+
Decision 2 above ("any client pins `X-GitHub-Api-Version`") rested on a single page. A
106+
second, independent one (E-10) confirms the cause and supplies what the first did not.
107+
108+
"Requests without the `X-GitHub-Api-Version` header will default to use the `2022-11-28`
109+
version" — so the 204 was never a broken endpoint, it was a three-year-old version
110+
answering exactly as specified. "Removing or renaming a response field" is listed among
111+
breaking changes, which is why both shapes are correct at once.
112+
113+
The new part: an API version is supported "at least 24 more months" after its successor,
114+
announced by `Deprecation` and then `Sunset` — the two headers this repository already
115+
observed on its own 204 response, dated `Tue, 10 Mar 2026` and `Fri, 10 Mar 2028`. After
116+
retirement, "requests that do not specify an API version default to the **next oldest
117+
supported version**, not the closing down version. If you rely on unversioned requests, you
118+
may observe behavioral changes as older versions are removed from support."
119+
120+
**So an unpinned integration does not keep working — it moves.** Pinning was argued here as
121+
the way to get a run id; it is also the only way to stop the contract changing underneath a
122+
caller on a date nobody chose.
123+
103124
## Alternatives considered
104125

105126
**Local Windows `.exe` first.** Deferred, not rejected. Node's single-executable feature is

‎docs/adr/0035-a-privacy-claim-is-measured-not-asserted.md‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,26 @@ group), and the API refuses them to a stranger with `403 Must have admin rights
9999
Repository`. Whether the UI is equally strict for a signed-in reader is **unknown**, and
100100
"unknown" is what the documentation now says rather than "safe".
101101

102+
### Corroborated, 2026-09-21 — and going private fails earlier than this ADR said
103+
104+
Decision 1 rested on E-06 alone. E-11, an independent reference page, states the same rule
105+
as availability rather than as consequence: "If you are using GitHub Free, environment
106+
secrets are only available in public repositories", with the identical note for required
107+
reviewers, wait timers, administrator bypass and custom protection rules.
108+
109+
It also carries the part E-06 did not, and it changes the predicted failure. Environment
110+
**variables** are governed the same way — available for all public repositories, and for
111+
private ones only on Pro or Team. So a Free repository converted to private loses
112+
`RESEARCH_KIT_COLLECTION_ENV` as well as `FIRECRAWL_API_KEY`.
113+
114+
This ADR predicted the collector would stop at the **credential** check. It would in fact
115+
stop one step earlier, at "the protected environment is the one that approved this run",
116+
reporting that the environment did not supply its marker — which reads as a missing or
117+
auto-created environment rather than as a plan limitation. Still a refusal rather than a
118+
silent spend, and a worse diagnostic than expected. The step's message already names the
119+
right fix for the wrong reason; anybody hitting it on a Free private repository should read
120+
this paragraph first.
121+
102122
## Alternatives considered
103123

104124
**Go private anyway, to be safe.** Breaks the collector on this plan, for an exposure the

‎docs/decisions/2026-09-21-delivery-architecture/research/BRIEF.md‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,38 @@ private, so the approval gate and the credential store both disappear silently.
163163
research needs a paid plan, not just a visibility toggle. That should be decided before
164164
anything depends on it.
165165

166+
## Corroboration pass, 2026-09-21
167+
168+
Every unknown in this brief originally rested on **one** capture, and the corpus passed
169+
preflight and `--strict` anyway - no check in this kit notices single-sourcing. Three
170+
unknowns carry decisions, and each now cites a second independent page. All three agreed,
171+
and each added a fact the original did not carry:
172+
173+
**U-1 / E-10 - the pin has a deadline.** "Requests without the `X-GitHub-Api-Version`
174+
header will default to use the `2022-11-28` version", which is why the unpinned dispatch
175+
returned 204: a three-year-old version answering correctly. But support runs "at least 24
176+
more months", signalled by `Deprecation` then `Sunset` - the same headers this repository
177+
saw on its own 204 - and afterwards "requests that do not specify an API version default to
178+
the next oldest supported version". **An unpinned client does not keep working; it changes
179+
behaviour on a date.** Pinning stops being a preference.
180+
181+
**U-5 / E-11 - going private breaks more than the secret.** E-06 said a Free repository
182+
converted to private has its rules and secrets "ignored". E-11 states it as availability -
183+
"If you are using GitHub Free, environment secrets are only available in public
184+
repositories" - and adds the part nobody had: environment **variables** are governed the
185+
same way. A Free repository gone private would lose `RESEARCH_KIT_COLLECTION_ENV` as well
186+
as `FIRECRAWL_API_KEY`, so `collect.yml` would refuse at the *environment* check rather
187+
than the credential one. A better failure than spending, and a more confusing one than
188+
either ADR predicted.
189+
190+
**U-3 / E-12 - free is also unlimited.** "Use of the standard GitHub-hosted runners is free
191+
and **unlimited** on public repositories." There is no minute quota to exhaust here, so the
192+
only meter on this repository is the Firecrawl credit.
193+
194+
The other five unknowns remain single-sourced, and that is stated rather than left: they
195+
are GitHub documenting its own product on pages that cross-link, and nothing rests on them
196+
that a second reading of the same vendor would test.
197+
166198
## Next steps
167199

168200
1. Record this as an ADR in `../../adr/`, citing this brief as its evidence basis.

‎docs/decisions/2026-09-21-delivery-architecture/research/DISCOVERY.md‎

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,31 @@ Anything else (`OPEN`, blank, "in progress") fails the gate.
4242

4343
| ID | Unknown | Why it blocks the build | Status | Evidence |
4444
|---|---|---|---|---|
45-
| U-1 | Does `POST /actions/workflows/{id}/dispatches` return anything identifying the run it created? | Decides whether a caller can follow its own run, and therefore whether the hybrid and REST options need a caller-chosen correlation token designed in from the first release | CLOSED | E-01: **yes, under API version `2026-03-10`** - `200` with `{workflow_run_id, run_url, html_url}`. Under `2022-11-28` the same call returns `204 No Content` and the caller learns nothing. Both verified on this machine against this repository; run `35548135379` came back from the 200 and resolves. The correlation race a caller faces on the old version disappears entirely by pinning the header |
45+
| U-1 | Does `POST /actions/workflows/{id}/dispatches` return anything identifying the run it created? | Decides whether a caller can follow its own run, and therefore whether the hybrid and REST options need a caller-chosen correlation token designed in from the first release | CLOSED | E-01: **yes, under API version `2026-03-10`** - `200` with `{workflow_run_id, run_url, html_url}`. Under `2022-11-28` the same call returns `204 No Content` and the caller learns nothing. Both verified on this machine against this repository; run `35548135379` came back from the 200 and resolves. The correlation race a caller faces on the old version disappears entirely by pinning the header. **Corroborated by E-10**, independently: "Requests without the `X-GitHub-Api-Version` header will default to use the `2022-11-28` version" - so the 204 was a three-year-old API version answering correctly, not a broken endpoint. E-10 also dates the exposure: unpinned requests fall to "the next oldest supported version" as older ones retire, so an unpinned client changes behaviour on a schedule rather than staying still |
4646
| U-2 | How long does a workflow artifact survive, and is that period configurable? | Decides whether a ZIP may be treated as delivery only, or also as storage. If artifacts expire, evidence that must persist has to be committed or kept elsewhere | CLOSED | E-03: 90 days by default, configurable 1-90 on a public repository and 1-400 on a private one, non-retroactively; a single artifact may set its own shorter period. E-02: deleting a run deletes its artifacts. So a ZIP is delivery, never storage - evidence that must persist is committed, as this project's own corpus is |
47-
| U-3 | What does a run of this collector cost on GitHub-hosted runners, for a public repository and for a private one? | The privacy analysis argues this repository should go private for sensitive topics; if that flips the cost from zero to metered, the recommendation changes with it | CLOSED | E-04: free on standard GitHub-hosted runners for public repositories; private repositories draw on a monthly quota (Free 2,000 minutes / 500 MB, Pro 3,000 / 1 GB, Team 3,000 / 2 GB) billed to the repository owner rather than the triggering user. Going private costs runner minutes - but E-06 shows it costs more than that on a free plan |
47+
| U-3 | What does a run of this collector cost on GitHub-hosted runners, for a public repository and for a private one? | The privacy analysis argues this repository should go private for sensitive topics; if that flips the cost from zero to metered, the recommendation changes with it | CLOSED | E-04: free on standard GitHub-hosted runners for public repositories; private repositories draw on a monthly quota (Free 2,000 minutes / 500 MB, Pro 3,000 / 1 GB, Team 3,000 / 2 GB) billed to the repository owner rather than the triggering user. Going private costs runner minutes - but E-06 shows it costs more than that on a free plan. **Corroborated by E-12**, and strengthened: "Use of the standard GitHub-hosted runners is free and **unlimited** on public repositories" - there is no minute quota to exhaust here, so the only meter on this repository is the Firecrawl credit |
4848
| U-4 | What is the stability and platform support of Node's single-executable applications feature? | Decides whether the local `.exe` option is buildable today on the operator's Windows machine, and how much the packaging story is likely to move underneath a shipped product | CLOSED | E-05: "Stability: 1.1 - Active development"; Windows is supported and macOS **x64** is the exclusion ("not currently supported and is skipped in the tests"). Buildable for this operator today. The caveat the page supplies against itself: the bundled-asset virtual filesystem this kit would need to read its own files is newer (v26.9.0) and weaker - "Stability: 1.0 - Early development" |
49-
| U-5 | Can a workflow run be gated behind a human approval or a wait period before it spends anything? | This collector spends real credits. Without a mechanism to require approval, an Actions-first delivery hands the meter to anyone with write access | CLOSED | E-06: yes - environment protection rules give required reviewers (up to 6, one approval suffices, optional prevent-self-review) and a wait timer, and environment secrets stay unreadable until those rules pass. **Conditioned on plan and visibility:** on GitHub Free, Pro or Team those rules exist only for public repositories, and a Free repository converted to private has its protection rules and environment secrets *ignored* rather than refused |
49+
| U-5 | Can a workflow run be gated behind a human approval or a wait period before it spends anything? | This collector spends real credits. Without a mechanism to require approval, an Actions-first delivery hands the meter to anyone with write access | CLOSED | E-06: yes - environment protection rules give required reviewers (up to 6, one approval suffices, optional prevent-self-review) and a wait timer, and environment secrets stay unreadable until those rules pass. **Conditioned on plan and visibility:** on GitHub Free, Pro or Team those rules exist only for public repositories, and a Free repository converted to private has its protection rules and environment secrets *ignored* rather than refused. **Corroborated by E-11**, which states the rule as availability rather than as consequence: "If you are using GitHub Free, environment secrets are only available in public repositories", with the same note for required reviewers, wait timers, administrator bypass and custom rules. E-11 adds what E-06 lacked - environment **variables** are restricted the same way, so a Free repository gone private would also lose `RESEARCH_KIT_COLLECTION_ENV` and fail at the environment check rather than the credential one |
5050
| U-6 | What of a workflow run is exposed by a public repository - secrets, logs, artifacts - and to whom? | Collected URLs, topics and evidence text are the research subject. If they become public on reaching a log or an artifact listing, Actions-first delivery is unsafe for sensitive topics regardless of cost | CLOSED | E-07 for the credential: secrets are sealed-box encrypted and log-redacted, with the redaction stated as not guaranteed and job-scoped. E-08 for the subject, measured unauthenticated against this public repository rather than read: run metadata, the job listing with step names, and the artifact listing all return `200` to an anonymous caller; `/actions/secrets` returns `401` and raw job logs `403`. So the credential is protected and the *shape* of the run is not - and artifact and step names alone disclose a topic |
5151
| U-7 | Who may trigger a `workflow_dispatch`, and what inputs may it declare? | Decides whether "the operator clicks a button" is a real workflow for a non-technical user, and what the dispatch contract can carry | CLOSED | E-08 and E-01: the Run workflow button appears only once the workflow file is on the default branch; API dispatch needs "Actions" repository permissions (**write**). Inputs are declared in the workflow file with `description`, `required`, `default`, and `type` including `choice`/`options`, capped at 25 top-level properties and 65,535 characters of payload |
5252
| U-8 | Can a run name or an artifact name be built from a dispatch input? | This is the mechanism a correlation token would use. If run names cannot interpolate inputs, U-1's remedy has to live somewhere else - in the artifact name, or in the artifact itself | CLOSED | E-09: yes - `run-name` "can include expressions and can reference the `github` and `inputs` contexts", documented with `run-name: Deploy to ${{ inputs.deploy_target }} by @${{ github.actor }}`. Given U-1 this is now a fallback for callers pinned to `2022-11-28` rather than a requirement of the design |
5353

54+
### A note on corroboration, added 2026-09-21
55+
56+
Every unknown above originally rested on **exactly one capture**, and the corpus passed
57+
preflight and `--strict` anyway: no check in this kit notices single-sourcing. The gate was
58+
structurally blind to it.
59+
60+
The three unknowns that carry decisions - U-1 behind ADR-0031, U-3 behind the cost
61+
argument, U-5 behind ADR-0035 - now cite a second, independent page each. All three
62+
**agreed** with the original, and each added a fact the original did not carry, which is
63+
the outcome worth recording: corroboration that confirms is not a wasted collection, it is
64+
the only way to tell a single correct source from a single lucky one.
65+
66+
The other five remain single-sourced. They are GitHub documenting its own product on pages
67+
that link to each other, and nothing rests on them that a second reading of the same
68+
vendor would test. Named here rather than quietly left.
69+
5470
## Questions for the human (maximum 3)
5571

5672
Intent questions only - things no document can answer. Facts never go here; they go in the

0 commit comments

Comments
 (0)