@nurix/etna 0.19.40 → 0.19.41

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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "fingerprint": "a4419d09d415",
2
+ "fingerprint": "c96b6524c5e6",
3
3
  "harnesses": {
4
4
  "code": {
5
5
  "plugin": "code",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "harness": "code",
3
3
  "name": "code",
4
- "version": "3.5.7",
4
+ "version": "3.5.8",
5
5
  "files": [
6
6
  ".prettierignore",
7
7
  ".prettierrc.json",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "harness": "delivery",
3
3
  "name": "delivery",
4
- "version": "0.1.3",
4
+ "version": "0.1.4",
5
5
  "files": [
6
6
  ".prettierignore",
7
7
  ".prettierrc.json",
@@ -44,7 +44,7 @@ Agent name = dimension name. ⚠ = gated (needs user authorization before dispat
44
44
 
45
45
  - **It exists** → tooling was already reviewed here — skip straight to Mode 1. **Never re-prompt in the same folder.**
46
46
  - **It's absent** → run the one-time check:
47
- 1. Read [`tooling-recommendations.md`](tooling-recommendations.md) (beside this file at the project root) — the Tier 1 (clean) and Tier 2 (gated) tool lists + the AVOID list.
47
+ 1. Read [`.claude/rules/tooling.md`](.claude/rules/tooling.md) — the Tier 1 (clean) and Tier 2 (gated) tool lists + the AVOID list.
48
48
  2. **Validate what's already installed before recommending anything** — `command -v <tool>` per recommended tool (`npm ls -g <pkg>` for the Node libraries that ship no binary, e.g. `chrome-remote-interface`). Detection only — nothing is installed at this step.
49
49
  3. **Recommend only the missing tools**, grouped **clean** (safe to install freely — offer the Tier-1 one-paste block) vs **gated** (first-party / user-owned / opt-in — surface the command but **never run it for the user**; these need the user in the loop). Never suggest anything on the AVOID list. If nothing is missing, say so in one line.
50
50
  4. **Write `.claude/discover-tooling.json`** so the harness never asks again in this folder:
@@ -73,13 +73,15 @@ Cheap, read-only. Scope the target, grade its access, detect which dimensions it
73
73
 
74
74
  Dispatch one collector per available dimension; collect exhaustively before context is lost. Every collector writes `research/<target>/dimensions/<dim>/_summary.md` (with the **provenance frontmatter** — method · confidence · completeness · gaps) + `raw/`, obeying `.claude/rules/ingestion.md`.
75
75
 
76
- - **Run independents in parallel** — dispatch `docs`, `packages`, `api`, `website`, `community`, `deployed-client-bundle`, `infra-backend-fingerprint`, `distribution-artifacts` together (`subagent_type='<dimension>'`, one message, multiple Agent calls). Seed each collector with **warm entry points (URLs / repos / hosts), not claimed facts** — any fact **or inference** carried from Discovery (a price, a tier name, a version — **or a derived hypothesis like "localStorage-key X ⇒ backend is Y"**) is tagged `verify:may-be-stale` so the collector **re-derives it instead of anchoring** on a possibly-stale (or possibly-wrong) value. A Discovery _inference_ is never seeded as a plan fact: label it a hypothesis in `00-recon-plan.md` and tag it `verify:` in the seed, so a collector that inherits it reports it hedged rather than echoing it as observed (a real run seeded an `apolloAnonId ⇒ GraphQL backend` guess that two captures then repeated before the session refuted it). Only one dimension may drive the browser at a time (see `ingestion` §7 rule 9): the parallel collectors use WebFetch/curl, leaving Chrome to `session`.
76
+ - **Run independents in parallel** — dispatch `docs`, `packages`, `api`, `website`, `community`, `deployed-client-bundle`, `infra-backend-fingerprint`, `distribution-artifacts` together (`subagent_type='<dimension>'`, one message, multiple Agent calls). Seed each collector with **warm entry points (URLs / repos / hosts), not claimed facts** — any fact **or inference** carried from Discovery (a price, a tier name, a version — **or a derived hypothesis like "localStorage-key X ⇒ backend is Y"**) is tagged `verify:may-be-stale` so the collector **re-derives it instead of anchoring** on a possibly-stale (or possibly-wrong) value. A Discovery _inference_ is never seeded as a plan fact: label it a hypothesis in `00-recon-plan.md` and tag it `verify:` in the seed, so a collector that inherits it reports it hedged rather than echoing it as observed (a real run seeded an `apolloAnonId ⇒ GraphQL backend` guess that two captures then repeated before the session refuted it). **A sibling collector's _summary_ is a claim, not a source** — when seeding one collector with something another collector reported, tag it `verify:` too, unless the main session has actually read the underlying `raw/` artifact. A returned summary is a compressed, unverified assertion; relaying it into a fresh brief launders it into apparent provenance, and the receiving sub-agent (which cannot see the conversation) has no way to tell a seeded claim from an established fact. (Origin: Emergent — the orchestrator relayed a "documented limitation: the connector cannot deploy" line from one collector's summary into another's brief; it was **not in the corpus**, and only the receiving agent's own verification caught it.) Only one dimension may drive the browser at a time (see `ingestion` §7 rule 9): the parallel collectors use WebFetch/curl, leaving Chrome to `session`.
77
77
  - **Codebase fan-out** — dispatch `codebase`; it clones + maps + returns a per-package work-list; then the main session fans out one reader per substantial package.
78
78
  - **Gated dimensions** — `session` and `wire-capture` (rung ≥2) need explicit user authorization first (see `ingestion` §7). `session` follows `.claude/rules/ingestion.md` §9. When `session` is authorized, **dispatch the non-browser collectors in the background (`run_in_background`) and drive the gated browser session in the main session concurrently** — they don't contend (Chrome belongs to the main session; the collectors use WebFetch/curl), so the whole of Ingestion runs in parallel.
79
79
  - **Shared seam** — **seed the two shared files `dimensions/_shared/{api-path-catalog.md, feature-flags.md}` (empty, with a header) once, before the collector fan-out**; bundle/session/wire/ distribution then each _append_ a `source:`-tagged section to the same physical file (never their own copy). One owner dimension per static asset; a second mine of the same asset is one source, not corroboration (`ingestion` §6).
80
80
 
81
81
  Validate each return (`_summary.md` + provenance present). A `blocked`/`partial` return is recorded, not blindly re-run.
82
82
 
83
+ **Validate a delegated artifact by READING THE FILE, not by trusting the agent's return.** A sub-agent can report success, deliver one of two assigned artifacts, or leave a **stale prior-run file** untouched — and a stale file is **worse than a missing one, because it scores silently**. For any artifact a later mode reads programmatically (above all `evaluation/feature-coverage.md`, whose `coverage_scorecard` frontmatter Mode 5 scores directly), assert (a) the file's mtime is newer than the dispatch **and** (b) its frontmatter matches this run's facts. If it doesn't, write it yourself. (Origin: Emergent — a sub-agent delivered its IA doc and silently dropped the coverage doc; the untouched Pass-1 file would have scored a full write-side run at `screenshot_coverage: 0` / `write_side_observed: false`, i.e. the *previous* run's numbers.)
84
+
83
85
  - **Capability gap = a checkpoint, not a silent fallback** (`ingestion` §8). If a _preferred_ capture capability is found unavailable mid-run (CDP/debugging port closed, browser MCP unreachable, a gated proxy can't be stood up) and only a **materially weaker** method remains, **pause and confirm** with the user before continuing on the fallback — naming what's unavailable and the coverage lost. (Distinct from a planned method pre-grade, which is recorded, not confirmed.)
84
86
 
85
87
  ---
@@ -117,6 +119,51 @@ Mode 5 is a loop, not a one-shot. Follow `.claude/rules/self-correction.md` —
117
119
 
118
120
  ---
119
121
 
122
+ ## Mirroring applied harness changes (the delivery step)
123
+
124
+ `self-correction.md` instructs the main session to "mirror to the harness home" and attributes the procedure
125
+ to "per ingestion / the orchestrator" — **which never defined one.** It was a dangling reference, and the
126
+ cost was measurable: **275 lines of accumulated rules across 4 commits sat only in one working copy**, so
127
+ the distributable package a new user installs was missing every lesson the fleet had learned.
128
+
129
+ **The procedure, defined here.** After applying accepted harness changes and flipping the rows to APPLIED:
130
+
131
+ 1. Resolve the home. Default `~/dev/etna/harness/discover/`; if absent, ask — never guess, never skip.
132
+ 2. Copy `CLAUDE.md` → `<home>/CLAUDE.md`, `.claude/rules/*.md` → `<home>/rules/`,
133
+ `.claude/agents/*.md` → `<home>/agents/`.
134
+ 3. **Assert zero drift** (`diff -r`) and report the line delta. A non-zero delta after mirroring is a
135
+ failure, not a warning.
136
+ 4. If the home is a distributable package (e.g. `packages/cli/data/harnesses/`), note that it ships to new
137
+ users and flag whether a version bump is needed — a rule that exists only in a working copy has not
138
+ shipped.
139
+
140
+ **A harness change is not "applied" until it is mirrored.** Applying locally and stopping means the next
141
+ *different* target — the entire justification for promoting the rule — never sees it.
142
+
143
+ ## Calibration — the only external signal (a cross-run process, not a mode)
144
+
145
+ Everything in Modes 1–5 is self-assessment: collectors grade their own confidence, Evaluation weights those
146
+ self-grades, Mode 5 scores against a checklist this system wrote. **Calibration is the one procedure that
147
+ tests whether any of it is true** — it re-derives a prior run's claims **blind** and records what survived.
148
+
149
+ Governed by [`.claude/rules/calibration.md`](.claude/rules/calibration.md); the fleet metric accumulates in
150
+ `research/_calibration/ledger.md`. Two tiers: a **monthly Tier-A claim spot-check** (~15–20 claims, one
151
+ session — this is the default, because a metric too expensive to run leaves the sample at n=1 forever) and a
152
+ **quarterly Tier-B full blind re-run**. Target is chosen by **rotation, never judgment**.
153
+
154
+ **Three rules make it evidence rather than bookkeeping:**
155
+
156
+ 1. **Blind.** Re-derive from the live product and write down what you observed **before** opening the prior
157
+ corpus. This deliberately defers `discovery.md` Step 00 for calibration runs — a run that reads the prior
158
+ claim first anchors on it and reports its own suggestibility as a confirmation rate.
159
+ 2. **`refuted` ≠ `stale`.** "Wrong when made" indicts the method; "true when made, product changed" does
160
+ not. Conflating them makes the harness fix the wrong problem.
161
+ 3. **Never grade with it.** The moment `refutation_rate` becomes a rubric input, the run acquires an
162
+ interest in the number and the one uncorrupted signal is gone. It measures the **harness**, not the run.
163
+
164
+ **Current state: n=1**, and the one data point is uncomfortable — 44% of re-tested claims refuted, with the
165
+ `high`-confidence band refuting *more* often than `low`. Do not act on it yet; do grow n.
166
+
120
167
  ## Ethics (non-negotiable)
121
168
 
122
169
  For spec-writing, integration planning, and competitive analysis — **not** credential theft, rate-limit bypass, or scraping. Full rules: `.claude/rules/ingestion.md` §7.
@@ -142,5 +189,6 @@ Output lives under the **resolved corpus root** (default `research/`; chosen per
142
189
  | `evaluation/{information-architecture, ux-flows, feature-coverage}.md` | Cartography (Mode 4) | the three cartography artifacts |
143
190
  | `README.md` | Evaluation | run story + headline findings |
144
191
  | `05-self-correction-proposal.md` | Self-correction (Mode 5) | proposed harness fixes (approval-gated) |
192
+ | `00-prior-run-reconciliation.md` | Calibration (when a prior corpus exists) | refuted / corrected / confirmed / stale per claim + the confidence regression (`calibration.md`) |
145
193
 
146
194
  Cloned repos live in `source/<target>/`. Provenance is the "self-aware" layer: each collector records _how_ it was obtained; Evaluation weights claims by it. Detailed shapes live in the rules.
@@ -33,3 +33,27 @@ You collect a target's documented machine interface into `research/<target>/dime
33
33
  A one-paragraph headline (the API surface in a sentence) + endpoint-family counts + the auth model. Flag overlap with the packages/docs dimensions (the published SDK often wraps this API) and especially any drift vs. the session dimension's _observed_ wire surface, for synthesis.
34
34
 
35
35
  **Discipline:** the spec is the load-bearing artifact — capture it accurately, digest if huge. Redact any embedded keys/example tokens. A disabled-introspection or undocumented API is a finding, recorded as an Open question, not a guess.
36
+
37
+ ---
38
+
39
+ ## Dump manifest (ingestion §5.3–5.4) — evidence before narrative
40
+
41
+ **MUST land in `raw/` as verbatim, redacted files before this dimension may be `status: complete`:**
42
+ the served spec **exactly as served** (`openapi.json` / SDL / introspection result) saved with `curl -o` — never a re-typed table; plus each probed endpoint's raw response body.
43
+
44
+ Three rules bind this, and they override any instinct to summarise:
45
+
46
+ 1. **If you cite it, dump it (§5.3).** Every value that reaches your `_summary.md` — a version, a path, a
47
+ count, a price, a field name — must be traceable to a file on disk. **The session is not a storage
48
+ medium:** a number you extracted from a response you did not save is unverifiable by the next run, and
49
+ the citation will outlive its evidence.
50
+ 2. **Digest IN ADDITION, never INSTEAD (§5.1).** `raw/` is the evidence layer and may be unreadable;
51
+ `_summary.md` is the narrative layer. A readable digest whose source artifact was never written is an
52
+ essay, not a capture.
53
+ 3. **Size is a routing problem (§5.2).** Never read a large artifact into context to save it — pipe it
54
+ straight to disk (`curl -o`, `| gzip >`, or the clipboard channel for in-page captures). If you must
55
+ bound an unbounded source, record the bound in `_meta.sampling`. Context budget is never a reason to
56
+ discard evidence.
57
+
58
+ **Self-check before returning:** count the verbatim files in `raw/`. Zero ⇒ the dimension is `partial`,
59
+ regardless of how good the prose is.
@@ -43,3 +43,27 @@ Return a **per-unit work-list** as a compact table so the main session can dispa
43
43
  Plus a one-paragraph headline of what the codebase reveals. The main session will dispatch readers that each write `raw/<unit>.md` (install/exports/key-files/architecture for that unit).
44
44
 
45
45
  **Discipline:** breadth over depth; digest large trees; never read or write secrets (scan `.env*`, config, fixtures for credentials and redact before quoting). An empty/over-large area is an Open question, not a guess.
46
+
47
+ ---
48
+
49
+ ## Dump manifest (ingestion §5.3–5.4) — evidence before narrative
50
+
51
+ **MUST land in `raw/` as verbatim, redacted files before this dimension may be `status: complete`:**
52
+ the resolved manifests (`package.json`, `pyproject.toml`, lockfile summaries) and the structure map — the clone in `source/<target>/` is itself the artifact.
53
+
54
+ Three rules bind this, and they override any instinct to summarise:
55
+
56
+ 1. **If you cite it, dump it (§5.3).** Every value that reaches your `_summary.md` — a version, a path, a
57
+ count, a price, a field name — must be traceable to a file on disk. **The session is not a storage
58
+ medium:** a number you extracted from a response you did not save is unverifiable by the next run, and
59
+ the citation will outlive its evidence.
60
+ 2. **Digest IN ADDITION, never INSTEAD (§5.1).** `raw/` is the evidence layer and may be unreadable;
61
+ `_summary.md` is the narrative layer. A readable digest whose source artifact was never written is an
62
+ essay, not a capture.
63
+ 3. **Size is a routing problem (§5.2).** Never read a large artifact into context to save it — pipe it
64
+ straight to disk (`curl -o`, `| gzip >`, or the clipboard channel for in-page captures). If you must
65
+ bound an unbounded source, record the bound in `_meta.sampling`. Context budget is never a reason to
66
+ discard evidence.
67
+
68
+ **Self-check before returning:** count the verbatim files in `raw/`. Zero ⇒ the dimension is `partial`,
69
+ regardless of how good the prose is.
@@ -33,3 +33,27 @@ You collect a target's living signal into `research/<target>/dimensions/communit
33
33
  A one-paragraph headline (where the product is heading + its biggest acknowledged gap) + the top 3–5 themes. This feeds the competitive-positioning and product-features rollups.
34
34
 
35
35
  **Discipline:** themes over threads; cite representative examples, don't dump feeds. Respect rate limits and TOS. Mark anything paywalled/private as an Open question.
36
+
37
+ ---
38
+
39
+ ## Dump manifest (ingestion §5.3–5.4) — evidence before narrative
40
+
41
+ **MUST land in `raw/` as verbatim, redacted files before this dimension may be `status: complete`:**
42
+ the changelog / issue / release payloads **as fetched** — JSON wherever an API exists (GitHub API, RSS, Featurebase/Canny), not only a themed digest.
43
+
44
+ Three rules bind this, and they override any instinct to summarise:
45
+
46
+ 1. **If you cite it, dump it (§5.3).** Every value that reaches your `_summary.md` — a version, a path, a
47
+ count, a price, a field name — must be traceable to a file on disk. **The session is not a storage
48
+ medium:** a number you extracted from a response you did not save is unverifiable by the next run, and
49
+ the citation will outlive its evidence.
50
+ 2. **Digest IN ADDITION, never INSTEAD (§5.1).** `raw/` is the evidence layer and may be unreadable;
51
+ `_summary.md` is the narrative layer. A readable digest whose source artifact was never written is an
52
+ essay, not a capture.
53
+ 3. **Size is a routing problem (§5.2).** Never read a large artifact into context to save it — pipe it
54
+ straight to disk (`curl -o`, `| gzip >`, or the clipboard channel for in-page captures). If you must
55
+ bound an unbounded source, record the bound in `_meta.sampling`. Context budget is never a reason to
56
+ discard evidence.
57
+
58
+ **Self-check before returning:** count the verbatim files in `raw/`. Zero ⇒ the dimension is `partial`,
59
+ regardless of how good the prose is.
@@ -53,3 +53,27 @@ Then Method / Findings (framework, build tool, route count, endpoint count — t
53
53
  Return a one-paragraph headline of what the deployed shell reveals — framework + build tool, route count, the shape of the API surface it calls, whether source maps were shipped (and the confidence that implies). **Cross-checks:** flag that `dimensions/_shared/api-path-catalog.md` and `dimensions/_shared/feature-flags.md` are the SHARED seam artifacts (§6, one physical file each) — `session`/`wire`/`distribution` append to the same files with `source: session | wire | distribution`, and evaluation owns the adaptive static-vs-observed diff. Surface any endpoint or flag that looks authed/internal but is statically declared in the unauth bundle — that gap is the dimension's highest-value output.
54
54
 
55
55
  **Discipline:** breadth over depth; digest large chunks, never paste them; check for a source map before string-mining (it upgrades confidence); REDACT every env value before any `raw/` write and log it in `_meta.redactions`; obey the seam rule — one canonical shared catalog name, never a private fork. An absent bundle, obfuscated route table, or missing source map is an Open question, not a guess.
56
+
57
+ ---
58
+
59
+ ## Dump manifest (ingestion §5.3–5.4) — evidence before narrative
60
+
61
+ **MUST land in `raw/` as verbatim, redacted files before this dimension may be `status: complete`:**
62
+ the entry bundle itself (`curl -o raw/bundle.js`, gzip is fine) and any `.map` — the route table, API-path catalog and flag extracts are written **in addition**, never instead.
63
+
64
+ Three rules bind this, and they override any instinct to summarise:
65
+
66
+ 1. **If you cite it, dump it (§5.3).** Every value that reaches your `_summary.md` — a version, a path, a
67
+ count, a price, a field name — must be traceable to a file on disk. **The session is not a storage
68
+ medium:** a number you extracted from a response you did not save is unverifiable by the next run, and
69
+ the citation will outlive its evidence.
70
+ 2. **Digest IN ADDITION, never INSTEAD (§5.1).** `raw/` is the evidence layer and may be unreadable;
71
+ `_summary.md` is the narrative layer. A readable digest whose source artifact was never written is an
72
+ essay, not a capture.
73
+ 3. **Size is a routing problem (§5.2).** Never read a large artifact into context to save it — pipe it
74
+ straight to disk (`curl -o`, `| gzip >`, or the clipboard channel for in-page captures). If you must
75
+ bound an unbounded source, record the bound in `_meta.sampling`. Context budget is never a reason to
76
+ discard evidence.
77
+
78
+ **Self-check before returning:** count the verbatim files in `raw/`. Zero ⇒ the dimension is `partial`,
79
+ regardless of how good the prose is.
@@ -58,3 +58,27 @@ Then write the per-type raw files that apply — `raw/{extension-manifest.md, el
58
58
  Return a **one-paragraph headline** of what the shipped client reveals — its declared hosts, permission surface, embedded vendor SDKs, and how much richer (or not) it is than the web app. The API paths and feature flags you appended feed the **seam rule (§6)**: your `dimensions/_shared/api-path-catalog.md` rows carry `source: distribution` so evaluation can run its adaptive diff against `deployed-client-bundle` (`source: bundle`), `session`, and `wire-capture`. The hosts and SDK list cross-check **infra-backend-fingerprint** (a host the binary calls that DNS/CT didn't surface is a finding); the runtime hosts also seed **wire-capture** targets (the binary says what it _might_ call; the capture says what it _does_).
59
59
 
60
60
  **Discipline:** EULA before extraction — restrictive license ⇒ Open question, never silent decompile. Manifests/strings only; no protected-logic reversing. Redact every embedded key before any `raw/` write (§7 rule 3). Digest large bundles (§5). A missing artifact type is a recorded gap, not a guess.
61
+
62
+ ---
63
+
64
+ ## Dump manifest (ingestion §5.3–5.4) — evidence before narrative
65
+
66
+ **MUST land in `raw/` as verbatim, redacted files before this dimension may be `status: complete`:**
67
+ the manifests verbatim (`manifest.json`, `Info.plist`, `AndroidManifest.xml`) and the extracted file listing.
68
+
69
+ Three rules bind this, and they override any instinct to summarise:
70
+
71
+ 1. **If you cite it, dump it (§5.3).** Every value that reaches your `_summary.md` — a version, a path, a
72
+ count, a price, a field name — must be traceable to a file on disk. **The session is not a storage
73
+ medium:** a number you extracted from a response you did not save is unverifiable by the next run, and
74
+ the citation will outlive its evidence.
75
+ 2. **Digest IN ADDITION, never INSTEAD (§5.1).** `raw/` is the evidence layer and may be unreadable;
76
+ `_summary.md` is the narrative layer. A readable digest whose source artifact was never written is an
77
+ essay, not a capture.
78
+ 3. **Size is a routing problem (§5.2).** Never read a large artifact into context to save it — pipe it
79
+ straight to disk (`curl -o`, `| gzip >`, or the clipboard channel for in-page captures). If you must
80
+ bound an unbounded source, record the bound in `_meta.sampling`. Context budget is never a reason to
81
+ discard evidence.
82
+
83
+ **Self-check before returning:** count the verbatim files in `raw/`. Zero ⇒ the dimension is `partial`,
84
+ regardless of how good the prose is.
@@ -37,4 +37,30 @@ You collect a target's docs into `research/<target>/dimensions/docs/`. Read `.cl
37
37
 
38
38
  A one-paragraph headline (the product's documented surface in a sentence) + the section list with page counts + anything that overlaps the api/packages dimensions (flag it so synthesis can cross-check).
39
39
 
40
- **Discipline:** distill, don't mirror. A 300-page docs site becomes a navigable map + the load-bearing content, not 300 verbatim files. Record paywalled/gated docs as Open questions.
40
+ **Discipline:** distill **in addition to**, never instead of. Save each captured page's source form under `raw/pages/` (md or html, as fetched) — that is the evidence layer — and build the navigable map + load-bearing content as the narrative layer beside it (ingestion §5.1). A distilled section whose source page was never saved is unverifiable by the next run (§5.3).
41
+
42
+ **Do not mirror the SITE:** A 300-page docs site becomes a navigable map + the load-bearing content, not 300 verbatim files. Record paywalled/gated docs as Open questions.
43
+
44
+ ---
45
+
46
+ ## Dump manifest (ingestion §5.3–5.4) — evidence before narrative
47
+
48
+ **MUST land in `raw/` as verbatim, redacted files before this dimension may be `status: complete`:**
49
+ each captured page's source form under `raw/pages/` (md or html, as fetched).
50
+
51
+ Three rules bind this, and they override any instinct to summarise:
52
+
53
+ 1. **If you cite it, dump it (§5.3).** Every value that reaches your `_summary.md` — a version, a path, a
54
+ count, a price, a field name — must be traceable to a file on disk. **The session is not a storage
55
+ medium:** a number you extracted from a response you did not save is unverifiable by the next run, and
56
+ the citation will outlive its evidence.
57
+ 2. **Digest IN ADDITION, never INSTEAD (§5.1).** `raw/` is the evidence layer and may be unreadable;
58
+ `_summary.md` is the narrative layer. A readable digest whose source artifact was never written is an
59
+ essay, not a capture.
60
+ 3. **Size is a routing problem (§5.2).** Never read a large artifact into context to save it — pipe it
61
+ straight to disk (`curl -o`, `| gzip >`, or the clipboard channel for in-page captures). If you must
62
+ bound an unbounded source, record the bound in `_meta.sampling`. Context budget is never a reason to
63
+ discard evidence.
64
+
65
+ **Self-check before returning:** count the verbatim files in `raw/`. Zero ⇒ the dimension is `partial`,
66
+ regardless of how good the prose is.
@@ -64,3 +64,27 @@ Return a **one-paragraph headline** of the reconstructed backend — origin clou
64
64
  **Discipline:** read-only public recon — never scan, brute-force, or hit a non-public host; respect crt.sh/WHOIS rate limits and back off; redact any credential-shaped value before writing (contract §7 rule 3 — DSNs, verification tokens, embedded keys surfaced in headers/TXT). An unresolvable host or a missing sub-processor page is an Open question, not a guess.
65
65
 
66
66
  **Verify an absence before asserting it (contract §7 rule 10).** Before reporting any host as **NXDOMAIN / absent** — especially `api.<target>` or any host a sibling dimension (bundle / session / wire) reports actually hitting — re-resolve via a **second resolver** (`dig @1.1.1.1 <host>`, `dig @8.8.8.8 <host>`) **and** a direct `curl -sI https://<host>`. An HTTP 4xx/5xx response means the host **resolves** → report it **present**, not absent. A single negative resolver result is recorded as _tentative_, never stated as fact and never used to instruct sibling dimensions. Likewise, an _inferred_ backend engine (e.g. "looks like Hasura/Supabase from the CNAME") is phrased as an inference and yields to a runtime-observing dimension (`session`/`deployed-client-bundle`) that names the engine directly.
67
+
68
+ ---
69
+
70
+ ## Dump manifest (ingestion §5.3–5.4) — evidence before narrative
71
+
72
+ **MUST land in `raw/` as verbatim, redacted files before this dimension may be `status: complete`:**
73
+ the raw `dig`, `crt.sh` and HTTP header responses as returned; the decoded table is the narrative layer beside them.
74
+
75
+ Three rules bind this, and they override any instinct to summarise:
76
+
77
+ 1. **If you cite it, dump it (§5.3).** Every value that reaches your `_summary.md` — a version, a path, a
78
+ count, a price, a field name — must be traceable to a file on disk. **The session is not a storage
79
+ medium:** a number you extracted from a response you did not save is unverifiable by the next run, and
80
+ the citation will outlive its evidence.
81
+ 2. **Digest IN ADDITION, never INSTEAD (§5.1).** `raw/` is the evidence layer and may be unreadable;
82
+ `_summary.md` is the narrative layer. A readable digest whose source artifact was never written is an
83
+ essay, not a capture.
84
+ 3. **Size is a routing problem (§5.2).** Never read a large artifact into context to save it — pipe it
85
+ straight to disk (`curl -o`, `| gzip >`, or the clipboard channel for in-page captures). If you must
86
+ bound an unbounded source, record the bound in `_meta.sampling`. Context budget is never a reason to
87
+ discard evidence.
88
+
89
+ **Self-check before returning:** count the verbatim files in `raw/`. Zero ⇒ the dimension is `partial`,
90
+ regardless of how good the prose is.
@@ -30,3 +30,27 @@ You collect a target's installable artifacts into `research/<target>/dimensions/
30
30
  A one-paragraph headline (the package family in a sentence) + the package table + which packages are the core public API (so synthesis can anchor the SDK surface). Flag overlap with the docs api-reference and the codebase dimensions for cross-check.
31
31
 
32
32
  **Discipline:** the exports map + type defs are the load-bearing artifact — prioritize them over download-count trivia. Digest huge `.d.ts` to signatures. Redact any registry tokens.
33
+
34
+ ---
35
+
36
+ ## Dump manifest (ingestion §5.3–5.4) — evidence before narrative
37
+
38
+ **MUST land in `raw/` as verbatim, redacted files before this dimension may be `status: complete`:**
39
+ per package: the registry metadata JSON (`npm view <pkg> --json > raw/<pkg>.registry.json`, PyPI `/pypi/<pkg>/json`) and the `.d.ts` / exports surface as fetched.
40
+
41
+ Three rules bind this, and they override any instinct to summarise:
42
+
43
+ 1. **If you cite it, dump it (§5.3).** Every value that reaches your `_summary.md` — a version, a path, a
44
+ count, a price, a field name — must be traceable to a file on disk. **The session is not a storage
45
+ medium:** a number you extracted from a response you did not save is unverifiable by the next run, and
46
+ the citation will outlive its evidence.
47
+ 2. **Digest IN ADDITION, never INSTEAD (§5.1).** `raw/` is the evidence layer and may be unreadable;
48
+ `_summary.md` is the narrative layer. A readable digest whose source artifact was never written is an
49
+ essay, not a capture.
50
+ 3. **Size is a routing problem (§5.2).** Never read a large artifact into context to save it — pipe it
51
+ straight to disk (`curl -o`, `| gzip >`, or the clipboard channel for in-page captures). If you must
52
+ bound an unbounded source, record the bound in `_meta.sampling`. Context budget is never a reason to
53
+ discard evidence.
54
+
55
+ **Self-check before returning:** count the verbatim files in `raw/`. Zero ⇒ the dimension is `partial`,
56
+ regardless of how good the prose is.
@@ -41,3 +41,43 @@ Under `research/<target>/dimensions/session/`:
41
41
  A one-paragraph headline (the auth model + transport + the single most load-bearing wire finding) + the phase coverage + which passes ran. Flag drift between the _observed_ wire surface and the _published_ api/packages surface — that drift is the highest-value synthesis input. If Pass 2 was needed but not authorized, list the open write-side questions; never fabricate request bodies.
42
42
 
43
43
  **Discipline:** ethics first, always. Redact before writing. Confirm before any state change. No destructive actions. No exfiltration. A gap is an Open question, never a guess.
44
+
45
+ ---
46
+
47
+ ## Dump manifest (ingestion §5.3–5.4) — evidence before narrative
48
+
49
+ **MUST land in `raw/` as verbatim, redacted files before this dimension may be `status: complete`:**
50
+ ≥3 verbatim envelopes as `raw/*.json` — the identity read, one canonical list read, and the primary write (request + response) — per ingestion §8.
51
+
52
+ Three rules bind this, and they override any instinct to summarise:
53
+
54
+ 1. **If you cite it, dump it (§5.3).** Every value that reaches your `_summary.md` — a version, a path, a
55
+ count, a price, a field name — must be traceable to a file on disk. **The session is not a storage
56
+ medium:** a number you extracted from a response you did not save is unverifiable by the next run, and
57
+ the citation will outlive its evidence.
58
+ 2. **Digest IN ADDITION, never INSTEAD (§5.1).** `raw/` is the evidence layer and may be unreadable;
59
+ `_summary.md` is the narrative layer. A readable digest whose source artifact was never written is an
60
+ essay, not a capture.
61
+ 3. **Size is a routing problem (§5.2).** Never read a large artifact into context to save it — pipe it
62
+ straight to disk (`curl -o`, `| gzip >`, or the clipboard channel for in-page captures). If you must
63
+ bound an unbounded source, record the bound in `_meta.sampling`. Context budget is never a reason to
64
+ discard evidence.
65
+
66
+ **Self-check before returning:** count the verbatim files in `raw/`. Zero ⇒ the dimension is `partial`,
67
+ regardless of how good the prose is.
68
+
69
+ ## Visual capture (ingestion §5.5) — screenshot generously
70
+
71
+ You drive a real browser, so you carry the visual-evidence obligation. **Capture continuously, not
72
+ one-image-per-surface:** every surface, plus every materially different state within it — empty vs
73
+ populated, modal/drawer open, dropdown expanded, error and validation states, permission/plan walls,
74
+ loading/in-flight, and the before/after pair around any authorized state change.
75
+
76
+ This is **not** scored — `screenshot_coverage` is a narrow Mode-5 floor. The beneficiary is the human
77
+ reading this corpus weeks later for a purpose nobody anticipated. The product's past state is the one thing
78
+ a later run genuinely cannot reproduce.
79
+
80
+ **Redact in the DOM before the shutter** (`tradecraft.md` §1c) — a leaked pixel is undetectable afterwards.
81
+ **Check the corners of the frame**, not just the content: support-chat widgets, toasts, presence avatars and
82
+ member lists routinely carry *another human's* name and message. Then look at the saved image, and record
83
+ `redacted: <what>` in `screens/_index.md` rather than a blanket zero-PII claim.
@@ -38,3 +38,27 @@ You collect a target's public-facing site into `research/<target>/dimensions/web
38
38
  A one-paragraph headline (the positioning in a sentence) + the pricing tiers + the headline feature claims. Flag claims that should be cross-checked against the codebase/docs (marketing often over-claims) so synthesis can reconcile.
39
39
 
40
40
  **Discipline:** quote positioning verbatim; capture pricing precisely (numbers + limits); separate _claims_ from verified capability — the reconciliation happens in synthesis. Respect robots.txt and rate limits; this is read-only public crawling, not scraping at scale.
41
+
42
+ ---
43
+
44
+ ## Dump manifest (ingestion §5.3–5.4) — evidence before narrative
45
+
46
+ **MUST land in `raw/` as verbatim, redacted files before this dimension may be `status: complete`:**
47
+ the raw HTML or extracted text per captured page, and the pricing table as structured data.
48
+
49
+ Three rules bind this, and they override any instinct to summarise:
50
+
51
+ 1. **If you cite it, dump it (§5.3).** Every value that reaches your `_summary.md` — a version, a path, a
52
+ count, a price, a field name — must be traceable to a file on disk. **The session is not a storage
53
+ medium:** a number you extracted from a response you did not save is unverifiable by the next run, and
54
+ the citation will outlive its evidence.
55
+ 2. **Digest IN ADDITION, never INSTEAD (§5.1).** `raw/` is the evidence layer and may be unreadable;
56
+ `_summary.md` is the narrative layer. A readable digest whose source artifact was never written is an
57
+ essay, not a capture.
58
+ 3. **Size is a routing problem (§5.2).** Never read a large artifact into context to save it — pipe it
59
+ straight to disk (`curl -o`, `| gzip >`, or the clipboard channel for in-page captures). If you must
60
+ bound an unbounded source, record the bound in `_meta.sampling`. Context budget is never a reason to
61
+ discard evidence.
62
+
63
+ **Self-check before returning:** count the verbatim files in `raw/`. Zero ⇒ the dimension is `partial`,
64
+ regardless of how good the prose is.
@@ -45,3 +45,43 @@ Then the captures + raw artifacts (per `discovery` Part C (wire-capture)):
45
45
  Return a **one-paragraph headline** of what the wire reveals — the real hosts contacted, the envelope/auth scheme, and the rung used (so the reader knows how much to trust it). Then a compact table of observed endpoints. **Flag the seam rule (§6):** every `api-path-catalog.md` row is `source: wire`, so evaluation can diff _actually-called_ (wire) against _statically-declared_ (`bundle` / `distribution-artifacts`) and _browser-observed_ (`session`) — a host or path the binary declares but the wire never hits is a finding, not noise; the inverse (called but undeclared) is a stronger one. If only rung 1 was authorized, say so and name what rungs 2/3 would unlock so the main session can request authorization.
46
46
 
47
47
  **Discipline:** lowest privilege first; never self-escalate the ladder; never install a CA or tap third-party traffic; never run Wireshark; redact every body before disk and log it in `_meta`. An unauthorized higher rung is an Open question, not an excuse to guess what the wire would show.
48
+
49
+ ---
50
+
51
+ ## Dump manifest (ingestion §5.3–5.4) — evidence before narrative
52
+
53
+ **MUST land in `raw/` as verbatim, redacted files before this dimension may be `status: complete`:**
54
+ the flow log itself (HAR or the tap's JSON export), not only the decoded narrative.
55
+
56
+ Three rules bind this, and they override any instinct to summarise:
57
+
58
+ 1. **If you cite it, dump it (§5.3).** Every value that reaches your `_summary.md` — a version, a path, a
59
+ count, a price, a field name — must be traceable to a file on disk. **The session is not a storage
60
+ medium:** a number you extracted from a response you did not save is unverifiable by the next run, and
61
+ the citation will outlive its evidence.
62
+ 2. **Digest IN ADDITION, never INSTEAD (§5.1).** `raw/` is the evidence layer and may be unreadable;
63
+ `_summary.md` is the narrative layer. A readable digest whose source artifact was never written is an
64
+ essay, not a capture.
65
+ 3. **Size is a routing problem (§5.2).** Never read a large artifact into context to save it — pipe it
66
+ straight to disk (`curl -o`, `| gzip >`, or the clipboard channel for in-page captures). If you must
67
+ bound an unbounded source, record the bound in `_meta.sampling`. Context budget is never a reason to
68
+ discard evidence.
69
+
70
+ **Self-check before returning:** count the verbatim files in `raw/`. Zero ⇒ the dimension is `partial`,
71
+ regardless of how good the prose is.
72
+
73
+ ## Visual capture (ingestion §5.5) — screenshot generously
74
+
75
+ You drive a real browser, so you carry the visual-evidence obligation. **Capture continuously, not
76
+ one-image-per-surface:** every surface, plus every materially different state within it — empty vs
77
+ populated, modal/drawer open, dropdown expanded, error and validation states, permission/plan walls,
78
+ loading/in-flight, and the before/after pair around any authorized state change.
79
+
80
+ This is **not** scored — `screenshot_coverage` is a narrow Mode-5 floor. The beneficiary is the human
81
+ reading this corpus weeks later for a purpose nobody anticipated. The product's past state is the one thing
82
+ a later run genuinely cannot reproduce.
83
+
84
+ **Redact in the DOM before the shutter** (`tradecraft.md` §1c) — a leaked pixel is undetectable afterwards.
85
+ **Check the corners of the frame**, not just the content: support-chat widgets, toasts, presence avatars and
86
+ member lists routinely carry *another human's* name and message. Then look at the saved image, and record
87
+ `redacted: <what>` in `screens/_index.md` rather than a blanket zero-PII claim.
@@ -1,12 +1,11 @@
1
1
  {
2
2
  "harness": "discover",
3
3
  "name": "discover",
4
- "version": "0.1.12",
4
+ "version": "0.1.13",
5
5
  "files": [
6
6
  ".prettierignore",
7
7
  ".prettierrc.json",
8
- ".vscode/settings.json",
9
- "tooling-recommendations.md"
8
+ ".vscode/settings.json"
10
9
  ],
11
- "digest": "48356bdb7940"
10
+ "digest": "3272a670df3c"
12
11
  }
@@ -33,6 +33,40 @@ differently:
33
33
  | **edition/plan-gated** | not in this tenant's edition/plan (e.g. a trial) | a recorded gap — **not** re-walked (re-walking can't find what isn't shipped here) |
34
34
  | **roadmap-not-shipped** | marketed but not yet a shipped capability | a recorded gap |
35
35
  | **marketing over-claim** | the claim overstates what the product does | an `evaluation/product-features.md` **over-claim flag** |
36
+ | **not-yet-reachable** | it exists and is shipped, but the surface **does not render at all** until a state change (deploy / connect / upgrade / first-run) that this run did not perform | the **gated re-walk queue** — NOT the read-only auto-loop |
37
+
38
+ ### `not-yet-reachable` vs `deeper-than-looked` — the distinction that matters
39
+
40
+ These two look identical in a coverage matrix and route **oppositely**, so get it right:
41
+
42
+ - **`deeper-than-looked`** — the surface **is in the DOM right now**; the run just didn't navigate to it.
43
+ More read-only walking finds it. Routes to the **read-only re-walk queue**, which Mode 5's auto-loop
44
+ works for free.
45
+ - **`not-yet-reachable`** — the surface **is not in the product yet.** No amount of navigation reveals it,
46
+ because the affordance is created by a state change. Routes to a **separate gated queue** that the
47
+ auto-loop must **not** touch: closing it costs money, mutates state, or needs a third-party consent, so
48
+ it goes through the explicit-confirmation gate (ingestion §7 rule 4) or is recorded as a standing gap.
49
+
50
+ **Mis-filing a `not-yet-reachable` row as `deeper-than-looked` is a Cartography defect**, because it sends
51
+ the auto-loop hunting for something that does not exist, and it reads as "we were sloppy" when the honest
52
+ statement is "the product's IA is state-dependent and this run stayed inside its authorization."
53
+
54
+ **A run that never performs the state change cannot map a state-dependent IA — say so rather than
55
+ scoring it as a coverage miss.** Note it beside the scorecard the same way `experiential_gated` annotates
56
+ a policy deferral: it documents, it does not inflate.
57
+
58
+ > (Origin: Emergent — a deployment executed mid-run **created** two whole surfaces: the entire *Manage
59
+ > Publishing* panel with five sub-tabs, and the `db_tool` database-console affordance, which opened a
60
+ > separately-hosted plugin on a second auth system. Neither exists in the toolbar of an undeployed project.
61
+ > The pre-deploy coverage doc had filed the publish family under *deeper-than-looked* and queued it for a
62
+ > read-only re-walk that could never have succeeded. Note also the **two-factor gate**: the cohort flag
63
+ > `db_tool: true` was necessary but **not sufficient** — an entitlement flag reading `true` does not mean
64
+ > the surface is reachable.)
65
+
66
+ **Where this bites generally:** any PaaS or marketplace with deploy/publish-gated management surfaces; any
67
+ product whose integrations render only after an OAuth connect; any tier-gated admin console; any
68
+ first-run/onboarding-gated dashboard. Treat an entitlement flag as **necessary, not sufficient** — check
69
+ whether the *state* it depends on has also been reached.
36
70
 
37
71
  ---
38
72
 
@@ -50,6 +84,7 @@ coverage_scorecard:
50
84
  ia_surfaces_mapped: <N> # surface cards written in information-architecture.md
51
85
  ia_nav_complete: <true|false> # every top-level nav destination has a surface card
52
86
  screenshot_coverage: <0-100> # primary surfaces with a screenshot ÷ all primary surfaces
87
+ features_not_yet_reachable: <N> # shipped, but behind a state change this run did not perform
53
88
  ---
54
89
  ## Coverage matrix
55
90
  | Feature (claimed) | Source | Located? | Route · depth | Walked? | Edition-gated? | Confidence | Note |
@@ -57,6 +92,9 @@ coverage_scorecard:
57
92
  | <feature> | website,docs | ✅ | #/…/x · D2 | ❌ not-walked | — | high | promoted on site, 2 levels deep, not exercised this run |
58
93
  | <feature> | website(AI) | ⚠ edition? | — | ❌ | maybe-not-in-trial | low | marketed flagship, not located in this tenant |
59
94
  ## Located-but-not-walked (the within-run re-walk queue — Mode 5 walks these read-only, no cost)
95
+ ## Not-yet-reachable (the GATED queue — shipped surfaces behind a deploy/connect/upgrade this run
96
+ did not perform. Mode 5 must NOT auto-walk these; each names the exact state
97
+ change that would unlock it and its cost/consent class)
60
98
  ## Claimed-but-not-located (each row dispositioned per the taxonomy above — NEVER left blank)
61
99
  ## Buried flagships (marketing-promoted features sitting ≥D3 — the positioning-vs-product gap,
62
100
  drawn from information-architecture.md's promoted-vs-buried headline)
@@ -69,6 +107,10 @@ coverage_scorecard:
69
107
  experiential / IA coverage axis (`self-correction.md` rubric, axis 2, max 20) is reproducible:
70
108
 
71
109
  - `feature_location_rate` = `100 × features_located ÷ features_claimed`.
110
+ - **`not-yet-reachable` rows stay in the `features_claimed` denominator** — they are real, shipped,
111
+ unlocated capabilities and hiding them would inflate the rate. But they are **dispositioned**, so they
112
+ never draw the −2 un-dispositioned penalty, and the scorecard carries `features_not_yet_reachable` so a
113
+ reader can tell a *policy/authorization* boundary from a *thoroughness* failure.
72
114
  - `flow_coverage` = `100 × (primary journeys diagrammed in ux-flows.md ÷ journeys identified)`.
73
115
  - `screenshot_coverage` = `100 × (primary surfaces with a screenshot ÷ all primary surfaces)`.
74
116
  - `ia_nav_complete` = every D0 nav destination has a surface card.
@@ -81,6 +123,13 @@ un-dispositioned. The `located-but-not-walked` list is the re-walk queue Mode 5
81
123
 
82
124
  ## Screenshots — `dimensions/session/captures/screens/`
83
125
 
126
+ > **The scorecard metric is a FLOOR, not the capture rule.** `screenshot_coverage` asks a narrow question —
127
+ > did each *primary surface* get one image — because Mode 5 needs something countable. **The actual capture
128
+ > obligation is `ingestion.md` §5.5: screenshot generously, including states within a surface, for the human
129
+ > who reads this corpus later.** Satisfying this metric and stopping is the failure mode; the metric is
130
+ > nearly always already met by a real walk. Nothing here caps how much you capture, and extra images never
131
+ > hurt the score.
132
+
84
133
  One annotated screenshot per **primary** surface (each D0 nav destination + each materially distinct
85
134
  detail / editor surface). **Redact visible PII before saving** (user names, emails, customer data,
86
135
  partner identifiers). Name `<nn>-<surface>.png`; write a one-line `screens/_index.md` mapping each file
@@ -89,6 +138,25 @@ partner identifiers). Name `<nn>-<surface>.png`; write a one-line `screens/_inde
89
138
  **Screenshots are the Mode-4 deliverable that the session playbook's textual surface-map only
90
139
  _substitutes_ for** (ingestion §9.5) — capture them live here; fall back to the textual map (and record
91
140
  the `screenshot_coverage` gap) only when the runtime genuinely cannot screenshot (no image tool, or the
92
- app never reaches page-idle because of a persistent connection). The screenshots live under the
141
+ app never reaches page-idle because of a persistent connection).
142
+
143
+ > **Re-test the capability before recording `screenshot_coverage: 0` — an environment limitation claimed
144
+ > by a PRIOR run is `verify:`, never inherited.** Take one screenshot with `save_to_disk: true` in the
145
+ > current session and record the literal tool result. Only an actual failure in *this* session justifies
146
+ > the textual fallback. (Origin: Emergent — a run recorded `screenshot_coverage: 0` because "`save_to_disk`
147
+ > returned no persistable path in this environment", and the harness codified that as an accepted
148
+ > fallback. In the same environment it works and returns a real path; the next run captured 13 images. An
149
+ > unverified environment claim had become a standing excuse that suppressed the most heavily-weighted
150
+ > rubric axis.)
151
+ >
152
+ > **Validate the coverage doc by READING THE FILE, not by trusting a delegated agent's return.** Because
153
+ > Mode 5 scores this file's `coverage_scorecard` frontmatter directly, a **stale** `feature-coverage.md`
154
+ > is worse than a missing one — it scores silently, against the *previous* run's numbers. Assert (a) the
155
+ > file's mtime is newer than the dispatch and (b) its frontmatter matches this run's facts
156
+ > (`write_side_observed`, `screenshot_coverage`, the credit figure). (Origin: Emergent, second run — a
157
+ > sub-agent delivered its IA doc and silently dropped this one; the untouched Pass-1 file would have
158
+ > scored a full write-side run at `screenshot_coverage: 0` / `write_side_observed: false`.)
159
+
160
+ The screenshots live under the
93
161
  `session` dimension (it owns the browser captures); `information-architecture.md`'s surface cards
94
162
  reference them by path.