You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit a49c793
Browse filesBrowse the repository at this point in the historyBrowse files
# `offline-suite` deliberately cannot reach the network, which is right: a reviewer or a
6
6
# fork must be able to re-run every check without being given a key. But that means the
7
7
# real network boundary is represented entirely by stubs, and the suite stays green while
8
-
# real collection fails on a changed payload, a proxy, a platform TLS quirk, a 429, or a
9
-
# partial response.
8
+
# real collection fails on a changed payload, a proxy, a platform TLS quirk, or a 429.
10
9
#
11
-
#This exists to exercise that boundary on purpose, with the cost visible and bounded.
10
+
#ONE SUCCESS PREDICATE, AND IT IS NOT "the steps ran".
12
11
#
13
-
# It is:
14
-
# manual only no push, no pull_request, no schedule - nothing runs it by
15
-
# accident, and a fork cannot trigger it
16
-
# budgeted `max_pages` is an input with a small default, and the run
17
-
# reports the credits it actually spent
18
-
# credential-scoped one secret, read from the environment, never written to disk
19
-
# corpus-isolated it collects into a scratch project under RUNNER_TEMP and
20
-
# commits nothing. The repository's own corpus is evidence for
21
-
# its own unknowns, not a place to put test captures
22
-
# redacted the key never reaches a log line; the adapter refuses a query
23
-
# containing it before transmit, and `command()` renders
24
-
# pre-redacted
12
+
# The first version of this workflow ran the right checks and then swallowed every one of
13
+
# them with `|| true`, so a green run proved only that the repository was not modified.
14
+
# That is worse than no workflow: it is a signal that looks like verification. Every
15
+
# required condition below now fails the job, and the summary states which ones were
16
+
# checked - so a green run means all of this held:
17
+
#
18
+
# 1. the vendor CLI is a major this adapter supports
19
+
# 2. the collection command exited 0
20
+
# 3. a ledger was written, and it parses
21
+
# 4. handoff exits 0 - the corpus arrived whole
22
+
# 5. preflight exits 0 - the corpus passes the same checks a synthetic one does
23
+
# 6. the repository is unchanged
24
+
#
25
+
# Diagnostics are still captured when a step fails, but they are captured in a way that
26
+
# preserves the exit status rather than discarding it.
25
27
#
26
28
# WHEN TO RUN IT
27
29
# - before trusting a Firecrawl CLI version this adapter has not seen
28
-
# - after changing anything under lib/firecrawl.mjs, lib/http-transport.mjs,
29
-
# lib/serpapi.mjs or lib/collect.mjs
30
+
# - after changing lib/firecrawl.mjs, lib/http-transport.mjs, lib/serpapi.mjs, lib/collect.mjs
30
31
# - when a real collection fails in a way the offline suite cannot reproduce
31
-
#
32
-
# WHAT A FAILURE HERE MEANS
33
-
# The offline suite passing and this failing is the interesting case, and the expected
34
-
# one: it means the stubs and the vendor have diverged. Read the version report first.
35
32
36
33
on:
37
34
workflow_dispatch:
@@ -46,6 +43,22 @@ on:
46
43
default: 'firecrawl-cli'
47
44
type: choice
48
45
options: [firecrawl-cli, http-keyless]
46
+
cli_version:
47
+
description: 'Firecrawl CLI version to install. "tested" pins the version the adapter was written against; "latest" is compatibility surveillance and may legitimately fail.'
48
+
required: true
49
+
default: 'tested'
50
+
type: choice
51
+
options: [tested, latest]
52
+
53
+
# Paid runs are SERIALISED.
54
+
#
55
+
# max_pages bounds one run. It does not bound the meter: two dispatches a second apart
56
+
# spend concurrently, and a reader who sees "max 10 pages" reasonably believes that is the
57
+
# ceiling. `cancel-in-progress: false` is deliberate - cancelling a paid collection
58
+
# mid-flight wastes the credits already spent and can leave a scratch ledger torn.
59
+
concurrency:
60
+
group: live-collection
61
+
cancel-in-progress: false
49
62
50
63
permissions:
51
64
contents: read
@@ -55,7 +68,6 @@ jobs:
55
68
name: live
56
69
runs-on: ubuntu-latest
57
70
timeout-minutes: 15
58
-
# A budget nobody can raise by editing an input: the job itself refuses a large run.
59
71
environment: live-collection
60
72
defaults:
61
73
run:
@@ -67,32 +79,61 @@ jobs:
67
79
with:
68
80
node-version: '22'
69
81
82
+
- name: announce the run, its budget and its policy
83
+
run: |
84
+
{
85
+
echo "| setting | value |"
86
+
echo "|---|---|"
87
+
echo "| run | ${{ github.run_id }} |"
88
+
echo "| transport | ${{ inputs.transport }} |"
89
+
echo "| max pages | ${{ inputs.max_pages }} |"
90
+
echo "| CLI policy | ${{ inputs.cli_version }} |"
91
+
} >> "$GITHUB_STEP_SUMMARY"
92
+
70
93
- name: refuse an unbounded run
71
94
run: |
72
95
pages='${{ inputs.max_pages }}'
73
96
case "$pages" in (''|*[!0-9]*) echo "max_pages must be a whole number"; exit 1;; esac
74
97
if [ "$pages" -lt 1 ] || [ "$pages" -gt 10 ]; then
75
98
echo "max_pages=$pages is outside 1..10."
76
-
echo "This workflow spends real credits; a large run belongs on a machine where"
99
+
echo "This workflow spends real credits; a larger run belongs on a machine where"
77
100
echo "somebody is watching the meter, not in CI."
78
101
exit 1
79
102
fi
80
-
echo "budget: $pages page(s)"
81
103
82
-
- name: install the vendor CLI, and report the version this run used
104
+
# Installation failure and INCOMPATIBILITY are different facts and are reported
105
+
# separately. The first version suppressed both with `|| true`, so "the package
106
+
# moved" and "the CLI is a major we do not support" looked identical.
Copy file name to clipboardExpand all lines: docs/ARCHITECTURE.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -146,7 +146,7 @@ variable (`CLAUDE_SETTINGS_PATH`) without ever honouring it. Owns the machine ro
146
146
| `handoff.mjs` | The **arrival question**: `verifyHandoff(root)` reports a ledger that is absent or empty, every capture an evidence row names that is not on disk, and a chain that does not verify — each named. Read-only by design: the machine that asks cannot collect the missing bytes. The report also carries `lineEndings`, the captures whose body hash fails *only* because git rewrote CRLF into them on checkout, and **`handoffRemedy(report)` picks the remedy from the cause** rather than printing one text for every way a corpus can look broken (ADR-0020): `HANDOFF_REMEDY` when something did not travel (the collector must push `research/raw/`, dotfiles included), `lineEndingRemedy` when everything travelled and this machine rewrote it (pin with `.gitattributes`, re-check out, touch no collector and spend no credits), both when a report holds both. Consumed by `bin/handoff.mjs` and doctor (blocker on `role=builder`, silent on a collector; doctor passes the snapshot it already read, so the question is composed once for both). | ADR-0011, ADR-0020 |
147
147
| `bundle.mjs` | The **archive this project arrived as**, and how far the tree has moved from it. `BUNDLE_INDEX.md` lists 80 SHA-256 digests taken at the 2026-09-17 handover; until ADR-0028 **nothing had ever read them**, which is how ADR-0022 could treat them as a constraint for three days without noticing the constraint was already violated. `verifyBundle(root)` sorts every entry into unchanged / drifted / unexpected / missing, where "drifted" means a file in `EXPECTED_TO_DRIFT` — the corpus, the map, the ADR index, the manifest itself, and (from 2026-09-20) `CONTEXT.md` and the root `README.md`, which are documentation ABOUT the code and go stale the moment it moves, each of which moves because one of this project's own rules *requires* it to. The list is deliberately narrow: exempting a planning document would leave the report unable to say anything, and a test asserts none is exempted. Hashes **bytes**, not decoded text. Reports; never fails a build — a changed file is a fact about history, and the only thing that makes it a problem is nobody knowing. | ADR-0028 |
|`runtime.mjs`| The host prerequisites a command actually needs: `checkNode` (22+), `checkGit`, `checkPython` (3.12+, reading either stream because Python 2 printed its version to stderr), and `requireRuntime({ node, git, python })` which exits **3** — distinct from a product failure — naming the missing piece and how to install it. Deliberately per-command rather than one gate that demands everything: Python is used by the cross-language conformance runners and nothing else, and a command that only reads the corpus has no business refusing to run because a language it never calls is absent. | — |
149
+
|`runtime.mjs`| The host prerequisites a command actually needs: `checkNode` (22+), `checkGit`, `checkPython` (3.12+, reading either stream because Python 2 printed its version to stderr, trying `python3`**first** and continuing past an old interpreter rather than stopping at it — `python` is an alias for 2.7 on the most common Linux and older-macOS layout, and stopping there reported "no usable Python" with a good 3.12 one name away), and `requireRuntime({ node, git, python })` which exits **3** — distinct from a product failure — naming the missing piece and how to install it. Deliberately per-command rather than one gate that demands everything: Python is used by the cross-language conformance runners and nothing else, and a command that only reads the corpus has no business refusing to run because a language it never calls is absent. | — |
150
150
|`scaffold.mjs`| Project shape: `LAYOUT` (12 entries), the **four**`GATE_MARKERS` (pinned by ADR-0001 and its test), template rendering, placeholder validation, hook executability. `.gitattributes` is a LAYOUT entry but **not** a gate marker: a project without it still gates, it just breaks on a Windows builder (ADR-0020). | ADR-0001, ADR-0020 |
151
151
|`installer.mjs`| Installs the git hook (records/restores prior `hooksPath`) and the edit-time gate (backs up, repairs known corruption, refuses unfamiliar states). The hook was renamed (A10.4): the installer recognises a registration left at a retired name, replaces it rather than adding a second, and reports the repair — `retiredRepairNote`. | ADR-0012 |
152
152
|`render.mjs`| Terminal table rendering for CLI output. | — |
0 commit comments