Skip to content

Commit 656b0d1

Browse files
Use the kit on ADR-0031's own deferral, and find the premise was false
ADR-0031 deferred the Windows .exe with a dated trigger: revisit when `useVfs` reaches Stability 1.1. Collecting against that trigger found the stability reading correct and the sentence under it wrong. The kit never needed `useVfs`. The `assets` config key and the `sea.getAsset()` family bundle and read files at build time, predate the VFS by years, and carry no separate stability marker - so they sit at the feature's own 1.1. On the current page `1.0 - Early development` appears exactly once, under the VFS heading. `useVfs` is a convenience that keeps `node:fs` calls working unchanged, not the only route to the assets. So the trigger waited on a condition the decision never depended on. It is withdrawn. What replaces it is a scope question, not a stability one. How the error got in is the part worth keeping: the original sentence was written from the delivery-architecture corpus, where the SEA page closed an unknown about platform limits. It read a marker correctly off that page and then inferred which API the kit would use - an inference no row supported, sitting in a sentence shaped like a citation. `corroboration` could not have caught it: the claim was not under-sourced, it was unsourced and adjacent to a sourced one. Three things the gate did to its own authors: - U-3 was CLOSED citing no E-## row, because I had "closed" it by grepping this repository. `unknown-closure/no-evidence` refused it. It is not a research question and is now recorded as a checked premise instead of dressed up as a fetched row. - Two `corroboration/single-source` warnings stand, accepted on the record. The only available second source was a stale mirror; citing it would have cleared both warnings and made the corpus weaker. - The corpus PASSes at its declared policy and FAILs `--strict`. Said plainly in BRIEF.md and START_HERE.md, because the delivery-architecture corpus passes `--strict` and a reader would assume parity. ADR-0036 gains the mirror finding, which is sharper than the general hedge it already carried. `lira.epac.to` serves the same Node document six majors stale, so citing it beside nodejs.org scores `independent` - the check's best grade - for one witness plus a staleness `freshness` cannot see, since that check grades when a page was fetched and this one was fetched today. The host heuristic does not merely miss a mirror, it inverts on one. No code change: detecting mirrors means diffing documents or parsing vendor version strings, and a check that guessed at either is the reasoning-grader ADR-0013 refused. What changes is the reviewer's instruction - `independent` is a prompt to check the sources are different documents, not a certificate that they are. One in three captures returned nothing usable (a GitHub discussion whose body is script-rendered). All three rows are kept and one is cited. A corpus that drops its failures reports a better hit rate than it earned. Collected by run 35623502540 via bin/collect-remote.mjs. 57/57 tests pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 6a281e8 commit 656b0d1

19 files changed

Lines changed: 2770 additions & 0 deletions

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,33 @@ part the kit would actually need: reading its own bundled files through `useVfs`
130130
v26.9.0 and carrying a weaker "Stability: 1.0 — Early development". Revisit when that
131131
reaches 1.1, or if artifact download proves too awkward in practice.
132132

133+
> **Amendment, 2026-09-21 — the paragraph above rests on a false premise.**
134+
> Evidence: `docs/decisions/2026-09-21-sea-assets/research/BRIEF.md`.
135+
>
136+
> The stability reading is right. The word **"need"** is wrong, and it is the load-bearing
137+
> word. The kit does not require `useVfs` to read its own bundled files: the `assets`
138+
> configuration key bundles them at build time and `sea.getAsset()`, `getAssetAsBlob()`,
139+
> `getRawAsset()` and `getAssetKeys()` read them back. That API predates the VFS — a v20.19.2
140+
> copy of the same page documents it in full with no VFS section at all — and carries **no
141+
> separate stability marker**, so it sits at the feature's own 1.1. On the current page,
142+
> `1.0 - Early development` appears exactly once, under `Virtual file system (VFS) for
143+
> assets`. `useVfs` is a convenience that lets existing `node:fs` calls keep working
144+
> unchanged; it is not the only route to the assets.
145+
>
146+
> **So the trigger was waiting on a condition this decision never depended on.** It is
147+
> withdrawn. What remains is not a stability objection but a scope one, and a cheaper one to
148+
> state honestly: taking the 1.1 route means adding an asset-aware branch to the three
149+
> modules that read non-JavaScript files at runtime (`lib/scaffold.mjs`, `lib/decompose.mjs`,
150+
> `lib/artifact-validator.mjs`), and nobody has yet said the `.exe` is still wanted now that
151+
> `bin/collect-remote.mjs` and the MCP server reach the collector without one.
152+
>
153+
> **How the error happened is the part worth keeping.** The original text was written from
154+
> the delivery-architecture corpus, in which the SEA page was one capture closing one unknown
155+
> about platform limits. It read a stability marker correctly off that page and then inferred
156+
> which API the kit would use — an inference no row in that corpus supported, sitting in a
157+
> sentence that looks like a citation. `corroboration` could not have caught it; the claim
158+
> was not under-sourced, it was unsourced and adjacent to a sourced one.
159+
133160
**Hybrid first.** The strongest long-term shape and the most work, and it needs the
134161
collector anyway. It is what the collector grows into, not an alternative to building it.
135162

‎docs/adr/0036-the-gate-can-see-single-sourcing.md‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,39 @@ corpus existed, and the corpus was used to make two architecture decisions in th
9797
verdict passing, and now isolates the claim. That proxy only ever worked while nothing
9898
else in the policy set fired.
9999

100+
## Amendment, 2026-09-21 — a mirror is the case where `independent` is actively worse
101+
102+
The closing section below says `independent` means only "this check found no reason to flag
103+
the support". Hours later a collection found a concrete failure mode sharper than that hedge,
104+
and it deserves naming rather than being covered by a general disclaimer.
105+
106+
Collecting on Node's single-executable API returned `nodejs.org` **and**
107+
`lira.epac.to/DOCS/nodejs/api/single-executable-applications.html`. Two hosts. Cite both for
108+
one unknown and this check reports `independent` — its best grade.
109+
110+
They are **the same document**, and the mirror is six major versions stale: v20.19.2 against
111+
the v26.9.0 nodejs.org serves. It predates the entire section that the current page's only
112+
`Stability: 1.0` marker sits under. A reader corroborating against it would have their
113+
reading of an *older* edition confirmed by an *older* edition, and the gate would call it
114+
independent support.
115+
116+
**So the host heuristic does not merely fail to notice a mirror — it inverts on one.** A
117+
mirror scores better than the honest `one-voice` that two genuine pages from one vendor get,
118+
while carrying strictly less information than either. The failure is not that two hosts can
119+
be one witness; ADR-0036 already said that. It is that two hosts can be one witness *plus a
120+
staleness the freshness check cannot see*, because `freshness` grades when the page was
121+
**fetched** and this one was fetched today.
122+
123+
**No code changes.** Detecting mirrors means comparing document content or parsing version
124+
strings out of vendor pages, and a check that guessed at either would be the reasoning-grader
125+
ADR-0013 refused. What changes is what a reviewer is told to do: **`independent` is a prompt
126+
to check that the sources are different documents, not a certificate that they are.**
127+
128+
Recorded live rather than reasoned about: the corpus that found it
129+
(`docs/decisions/2026-09-21-sea-assets/`) keeps the mirror as an uncited row and accepts two
130+
`single-source` warnings instead — the correct trade, and the one the check's grades
131+
currently push against.
132+
100133
## What this ADR does not claim
101134

102135
That two hosts make a claim true. Two vendors can repeat one another, and a specification
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# The corpus's line endings are integrity, not style.
2+
#
3+
# A capture's body hash is taken over the LF bytes the collector fetched. git's smudge
4+
# filter rewrites every text file on a default Windows checkout (core.autocrlf=true), so
5+
# without this file the whole corpus fails `body-unmodified` on arrival with nothing
6+
# actually wrong with it. This file outranks a reader's core.autocrlf. See ADR-0020.
7+
8+
research/raw/* text eol=lf
9+
*.jsonl text eol=lf
10+
research/*.md text eol=lf
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
node_modules/
2+
.DS_Store
3+
4+
# Credentials never belong in a research project (AGENTS.md Rule 6). Note that
5+
# `firecrawl env` writes the key into .env, which is why the rule says never to run it
6+
# inside a repository.
7+
.env
8+
.env.*
9+
*.pem
10+
*.key
11+
12+
# The Firecrawl CLI saves scrape output into .firecrawl/ in whatever directory it runs
13+
# from. That is a vendor cache, not evidence - the kit's own captures live in
14+
# research/raw/ with a ledger entry behind each one.
15+
.firecrawl/
16+
17+
# The kit's local review logs are not evidence.
18+
research/raw/.usage.jsonl
19+
research/raw/.failures.jsonl
20+
research/raw/.diagnostics.jsonl
21+
research/raw/.fetches.lock
22+
23+
# The chain IS evidence and must travel. The explicit negation is here so a broader
24+
# dotfile rule added later cannot silently exclude it - this repository lost its ledger
25+
# exactly that way once.
26+
!research/raw/.fetches.jsonl
27+
!research/overrides.log
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
# Research-first project bootstrap
2+
3+
Agent instructions for this project. Read this before planning, designing, or building
4+
anything here.
5+
6+
## How this project works: two phases, two roles
7+
8+
**Phase 1 - research (this kit).** Close every blocking unknown with fetched primary
9+
sources, then pass the gate. The output is a briefing, not code: `research/DISCOVERY.md`
10+
(the contract), `research/EVIDENCE.md` (claims with cached pages behind them), and
11+
`research/BRIEF.md` (the handoff). Phase 1 never writes product code.
12+
13+
**Phase 2 - build (someone else's job).** A builder - another agent, a different model, or
14+
a human - takes `research/BRIEF.md` plus `research/` and implements. They should not need
15+
to re-research anything: if they do, phase 1 was incomplete, and the fix is to collect the
16+
missing fact rather than to let the builder guess it.
17+
18+
The gate is the handoff point. Before it passes, phase 2 does not start.
19+
20+
## Two machines, two roles
21+
22+
The role is machine config - `role: "collector" | "builder"` in
23+
`~/.agents/research-kit.config.json`, default `collector`; declare it with
24+
`node ~/.agents/research-kit/bin/install-hooks.mjs --role builder`.
25+
26+
| | **collector** (the operator's PC) | **builder** (a sandbox, a CI box, a laptop) |
27+
|---|---|---|
28+
| holds | the Firecrawl key | no key, no Firecrawl egress |
29+
| runs | `decompose.mjs`, `research.mjs` | `handoff.mjs`, `preflight.mjs`, the build |
30+
| a missing key is | a **FAIL** | **informational** |
31+
| must | push `research/raw/` including its dotfiles | **not collect** - the collection CLIs refuse (exit 2) |
32+
33+
**If you are on a builder machine and there is no brief: you do not collect.** A page
34+
fetched by hand is not evidence in this kit, and a builder that "re-collects" a missing
35+
page forges a corpus instead of reporting a gap. Name the missing fact instead.
36+
37+
A builder's first command is:
38+
39+
```
40+
node ~/.agents/research-kit/bin/handoff.mjs
41+
```
42+
43+
The remedy depends on the cause, and the command says which: something that did not
44+
travel is the collector's to push (`git add -f research/raw/`, dotfiles included);
45+
a corpus that travelled whole and was rewritten on checkout here is fixed **here**, with
46+
`.gitattributes`, and costs no credits.
47+
48+
## Starting in the wrong place: ask which project, do not hunt for it
49+
50+
The project is the **current working directory**. The kit takes no project argument and
51+
never will. If the cwd is not the project the operator means - the kit's own repo, a
52+
parent folder, an unrelated checkout - **ask which project**, and wait. Do not search the
53+
filesystem, do not infer it from a name, do not look it up on a remote. Searching a
54+
person's disk to guess his intent reads directories nobody authorised, and the question
55+
it replaces takes one line.
56+
57+
Signals: no `AGENTS.md`, no `research/` directory, or a `research/` corpus plainly about
58+
something else. An existing corpus about another topic is the signal doing its job.
59+
60+
## Resuming after an interruption: resume, do not restart
61+
62+
The gate is a pure function of repository state, so orient from disk before touching
63+
anything. `doctor.mjs` and preflight answer *where this project is*; the last commit
64+
report and `docs/ARCHITECTURE.md` say *what was happening and why*; `git status` answers
65+
what is unfinished, and its uncommitted changes are the interrupted task - partial and
66+
unverified, work in progress, never state to trust. The corpus is already collected and
67+
spent credits are not spent again.
68+
69+
## Rule 1 - research first, then build
70+
71+
The sequence is decompose -> contract -> collect -> gate -> brief.
72+
73+
0. **Decompose** (collector machine): `node ~/.agents/research-kit/bin/decompose.mjs --topic "<topic>"`
74+
drafts `research/MAP.md` seeded with the universal checklist. The tool contains no
75+
judgment. Mark every row COVERED (citing U-## rows), DISMISSED (reason required), or
76+
GAP.
77+
1. **Write the intent** in `research/DISCOVERY.md` under `## Build intent`, and enumerate
78+
the blocking unknowns FROM the map.
79+
2. **Collect**: `node ~/.agents/research-kit/bin/research.mjs --plan research/plan.json`. Prefer the page
80+
that *owns* the fact over any write-up about it.
81+
3. **Rewrite** each auto-extracted `Finding` cell into a real claim, keeping the `Raw`
82+
cell pointing at the cached page.
83+
4. **Gate**: `node ~/.agents/research-kit/bin/preflight.mjs`. **Do not start building until it prints
84+
PASS.** Evidence must be *fetched*, not typed, and by a named transport.
85+
5. **Hand off**: write `research/BRIEF.md`.
86+
87+
There are exactly three overrides - `git commit --no-verify`, a deliberate
88+
`research/GATE_OFF`, and a repository-local `core.hooksPath` - and all three are recorded
89+
in `research/overrides.log`. If you take one, say so in your reply.
90+
91+
## Rule 2 - questions are for intent, never for facts
92+
93+
At most **3** questions, once, up front, and only about things no document can answer. If
94+
a question's answer is in public documentation, it is a research task. **Never answer
95+
"insufficient info" and stop.**
96+
97+
## Rule 3 - known unknowns are allowed, silence is not
98+
99+
Mark a genuinely unreachable fact `KNOWN-UNKNOWN` and write the day-one verification step
100+
in the `Evidence` cell. An unlabeled gap is the failure mode this project exists to
101+
prevent.
102+
103+
## Rule 4 - source quality
104+
105+
`P` primary/official carries the design. `S` secondary is context. `L` lead-only is a
106+
hint, never proof. Never invent a citation. Flag contradictions instead of averaging them.
107+
108+
## Rule 5 - cost discipline
109+
110+
Every scrape spends credits. Plan the queries in `research/plan.json` first, reuse the
111+
cache (`--refresh-days`), and check the budget with `node ~/.agents/research-kit/bin/research.mjs --status`.
112+
113+
## Rule 6 - secrets
114+
115+
The key lives in the CLI config or the environment. Never write it into this repository.
116+
117+
## The standing protocol
118+
119+
Five rules for how work here is committed and recorded. Documentation, not enforcement:
120+
no check judges prose, because a gate that judges prose is a gate that will be wrong.
121+
122+
1. **Architecture map current in the same commit.** A commit touching a declared code
123+
path (`research/kit.json`) stages `docs/ARCHITECTURE.md` with it. Enforced - and a
124+
prompt, not a proof: the gate checks the map was *staged*, not that it is *current*.
125+
2. **Commit report: five named parts** - what changed / why / what it touched / what you
126+
verified / what you got wrong and fixed. The got-wrong line is not optional; if
127+
nothing was gotten wrong it is written as "nothing to report".
128+
3. **An ADR for any choice with a rejected alternative**, dated, with the reason a future
129+
explorer would need to avoid re-suggesting it.
130+
4. **One commit per task - the revert test.** `git revert <sha>` undoes it alone.
131+
5. **A red suite stops work**, reported immediately and alone, **with the cwd recorded**.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Start here
2+
3+
A **decision project** (ADR-0030). Read `research/BRIEF.md`; everything else is what it
4+
rests on.
5+
6+
**The question:** ADR-0031 deferred the local Windows `.exe` with a dated trigger - revisit
7+
when `useVfs` reaches Stability 1.1. Is that trigger the right one?
8+
9+
## Why it exists
10+
11+
It is not. The trigger was checked and the **premise under it turned out to be false**: the
12+
kit does not need `useVfs` to read its own bundled files. The `assets` configuration key and
13+
the `sea.getAsset()` family do that, they predate the VFS by years, and they sit at the
14+
feature's own Stability 1.1. The `1.0 - Early development` marker ADR-0031 cited is real and
15+
attaches only to the VFS section - a convenience the kit can decline.
16+
17+
So the `.exe` was waiting on a condition it never depended on. ADR-0031 carries an amendment
18+
saying so.
19+
20+
## How it was collected
21+
22+
Dispatched through `bin/collect-remote.mjs` - the agent path - as run
23+
[35623502540](https://github.com/StepenkoAnatoli/Research-Kit/actions/runs/35623502540),
24+
depth `quick`. Three pages, all graded `full`. One is authoritative and current, one is a
25+
stale mirror of it, and one rendered no content at all.
26+
27+
**That one-in-three hit rate is the second finding, and it is deliberately not hidden.**
28+
`EVIDENCE.md` keeps all three rows and cites one. The mirror also found a real limitation in
29+
this repository's own `corroboration` check, recorded in ADR-0036.
30+
31+
## Verifying it
32+
33+
From **this** directory:
34+
35+
```
36+
cd docs/decisions/2026-09-21-sea-assets
37+
node ..\..\..\research-kit\bin\preflight.mjs
38+
node ..\..\..\research-kit\bin\handoff.mjs
39+
```
40+
41+
As of 2026-09-21: `PASS 0 blocking, 2 warning(s), 12 passing` and `handoff OK - 3 ledger
42+
entries, chain verifies`.
43+
44+
**Under `--strict` this corpus fails**, 2 blocking, and that is expected. Both warnings are
45+
`corroboration/single-source` on U-1 and U-2, both accepted on the record rather than
46+
cleared - the only available second source was the stale mirror, and citing it would have
47+
made the corpus read stronger while making it weaker. `research/BRIEF.md` argues it.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# ARCHITECTURE - the map of the code
2+
3+
What each module owns, the seams between them, and which decision governs each. This is
4+
a map of the **code**, not of the research: `research/MAP.md` is the topic map - a
5+
different artifact with a different job, judged by a different check.
6+
7+
The rule this map lives by: a commit touching a **declared code path** (declared in
8+
`research/kit.json`, defaulting to `src` / `lib` / `bin` / `scripts` / `app`) carries
9+
this file's update in the **same commit**. The commit gate refuses such commits without
10+
it.
11+
12+
What the rule proves is deliberately modest: the gate checks this file was **staged**
13+
with the code, not that it is current - a whitespace edit satisfies it. That makes a
14+
stale map a deliberate act rather than mere forgetting. A prompt, not a proof.
15+
16+
## The one picture
17+
18+
```
19+
_Replace this with the shape of the thing you build: the entry points, the modules
20+
they reach, and the seams between them._
21+
```
22+
23+
## Modules - what each one owns
24+
25+
| Module | Owns | Governed by |
26+
|---|---|---|
27+
| _module_ | _the one concept it is responsible for_ | _ADR or decision_ |
28+
29+
## The seams
30+
31+
_Where modules touch, what is injectable, and why testing can stay offline._
32+
33+
## Current shape, for the record
34+
35+
_Counts and invariants a reader can check against the code: how many checks, how many
36+
adapters, which defaults._

0 commit comments

Comments
 (0)