@nurix/etna 0.15.6 → 0.15.7
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.
- package/data/harness-index.json +1 -1
- package/data/harnesses/re/CLAUDE.md +35 -16
- package/data/harnesses/re/agents/deployed-client-bundle.md +17 -11
- package/data/harnesses/re/agents/distribution-artifacts.md +9 -8
- package/data/harnesses/re/agents/infra-backend-fingerprint.md +1 -1
- package/data/harnesses/re/agents/session.md +12 -2
- package/data/harnesses/re/agents/wire-capture.md +5 -3
- package/data/harnesses/re/harness.json +2 -2
- package/data/harnesses/re/rules/re-discovery.md +41 -9
- package/data/harnesses/re/rules/re-evaluation.md +29 -4
- package/data/harnesses/re/rules/re-ingestion.md +71 -16
- package/package.json +1 -1
package/data/harness-index.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Product Reverse-Engineering — Orchestrator
|
|
2
2
|
|
|
3
3
|
This is the **policy** half of the `re` harness. The plugin ships the capabilities (11
|
|
4
|
-
dimension-dumper agents +
|
|
4
|
+
dimension-dumper agents + 4 `re-*` rules, one per mode); this file drives them. Together they reverse-engineer a
|
|
5
5
|
product across every surface it exposes and dump a structured, provenance-tracked corpus into
|
|
6
6
|
`research/<target>/`.
|
|
7
7
|
|
|
@@ -81,8 +81,11 @@ method · confidence · completeness · gaps) + `raw/`, obeying `.claude/rules/r
|
|
|
81
81
|
is authorized, **dispatch the non-browser dumpers in the background (`run_in_background`) and drive
|
|
82
82
|
the gated browser session in the main session concurrently** — they don't contend (Chrome belongs to
|
|
83
83
|
the main session; the dumpers use WebFetch/curl), so the whole of Ingestion runs in parallel.
|
|
84
|
-
- **Shared seam** —
|
|
85
|
-
with a
|
|
84
|
+
- **Shared seam** — **seed the two shared files `dimensions/_shared/{api-path-catalog.md,
|
|
85
|
+
feature-flags.md}` (empty, with a header) once, before the dumper fan-out**; bundle/session/wire/
|
|
86
|
+
distribution then each *append* a `source:`-tagged section to the same physical file (never their own
|
|
87
|
+
copy). One owner dimension per static asset; a second mine of the same asset is one source, not
|
|
88
|
+
corroboration (`re-ingestion` §6).
|
|
86
89
|
|
|
87
90
|
Validate each return (`_summary.md` + provenance present). A `blocked`/`partial` return is recorded,
|
|
88
91
|
not blindly re-run.
|
|
@@ -101,19 +104,35 @@ high→fact, low/single-source→tentative, conflict→flagged. The four rollups
|
|
|
101
104
|
|
|
102
105
|
---
|
|
103
106
|
|
|
104
|
-
## Mode 4 — Self-correction (the harness improves
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
**
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
107
|
+
## Mode 4 — Self-correction (the run corrects itself; the harness improves only on approval)
|
|
108
|
+
|
|
109
|
+
Mode 4 is a loop, not a one-shot. Follow `.claude/rules/re-self-correction.md` — it carries the
|
|
110
|
+
**defect checklist** (A), the **measurement rubric** (B), and the **iterate-or-propose loop** (C).
|
|
111
|
+
Three stages, driven by the **main session** (not a sub-agent):
|
|
112
|
+
|
|
113
|
+
1. **Inspect** the finished run (scope verdict, plan, every dimension `_summary.md`, the rollups)
|
|
114
|
+
against the **built-in defect checklist** → a concrete list of *behavioral defects* in the prior
|
|
115
|
+
steps (mode · defect · severity · evidence anchor · within-run|harness-changing).
|
|
116
|
+
2. **Measure** the run against the **rubric** → a `/100` score + vibe band. Always — every iteration,
|
|
117
|
+
including the final one; the self-correcting step ALWAYS evaluates the current run.
|
|
118
|
+
3. **Iterate-or-propose**, splitting each defect by one test — *does the fix require editing a `re-*`
|
|
119
|
+
rule or an agent?*
|
|
120
|
+
- **No → within-run:** the main session **auto-iterates** (no approval), re-running the cheapest
|
|
121
|
+
affected Mode 1–3 steps on THIS target and re-measuring each round. The loop is **capable of ≥5
|
|
122
|
+
iterations** and **stops on regression** (a clear score drop → revert to the best prior run),
|
|
123
|
+
**convergence** (no within-run defects left), or the cap. **Read-only / no-cost only** — any fix
|
|
124
|
+
needing a Pass-2 / credit-spend / state-change / credential action goes through the
|
|
125
|
+
explicit-confirmation gate, never the auto-loop.
|
|
126
|
+
- **Yes → harness-changing:** accumulate into `research/<target>/04-self-correction-proposal.md`
|
|
127
|
+
(the shape is in `re-self-correction.md`: run measurement · iteration ledger · defect list ·
|
|
128
|
+
within-run fixes applied · the approval-gated harness-change table).
|
|
129
|
+
|
|
130
|
+
**Approval gate (unchanged):** present the harness-change table + the iteration ledger and STOP —
|
|
131
|
+
nothing in the harness is applied. The user accepts / rejects / defers per item. Then the **main
|
|
132
|
+
session** (not a sub-agent) applies accepted items, flips each row to APPLIED, and logs the change.
|
|
133
|
+
Promote only what the *next, different* target would also hit; prefer additive edits; structural edits
|
|
134
|
+
are flagged, never auto-applied. (For a batch, additionally roll up into a cross-target synthesis that
|
|
135
|
+
promotes only patterns ≥2 *independent* targets hit — a homogeneous batch's 6/6 is one vote, not six.)
|
|
117
136
|
|
|
118
137
|
---
|
|
119
138
|
|
|
@@ -41,13 +41,16 @@ the endpoints it will call, and the flags it gates behind.
|
|
|
41
41
|
manifests (`__BUILD_MANIFEST`, `/_next/static/.../_buildManifest.js`), lazy-import chunk maps.
|
|
42
42
|
`grep -oE '"/[a-z][a-z0-9/:_-]*"'` over the de-minified source, then de-dup → `raw/route-table.md`.
|
|
43
43
|
4. **API-path catalog (SHARED seam — §6).** Mine fetch/axios base URLs and path literals
|
|
44
|
-
(`/api/`, `/graphql`, `${API_BASE}` template fragments).
|
|
45
|
-
`
|
|
46
|
-
|
|
47
|
-
diff. A path here that `session`/`wire` never hit is a
|
|
44
|
+
(`/api/`, `/graphql`, `${API_BASE}` template fragments). **Append** rows to the **one physical
|
|
45
|
+
shared file** `research/<target>/dimensions/_shared/api-path-catalog.md` with a `source: bundle`
|
|
46
|
+
column — do NOT create a copy under your own `raw/`; `session`/`wire`/`distribution` append to the
|
|
47
|
+
*same* file so evaluation runs its adaptive diff. A path here that `session`/`wire` never hit is a
|
|
48
|
+
dormant/unshipped route (a finding). **You OWN the app-API bundle mine** (re-ingestion §6): when
|
|
49
|
+
`source:none` and no machine spec is served, other dimensions cite your catalog by path and do not
|
|
50
|
+
re-mine the same bundle (a second mine is one source, never corroboration).
|
|
48
51
|
5. **Feature flags (SHARED).** Find flag SDK keys and flag literals (LaunchDarkly `client-side-id`,
|
|
49
52
|
Statsig/Flagsmith/PostHog keys, `flags[` / `isEnabled('...')` / `experiment` string literals).
|
|
50
|
-
|
|
53
|
+
**Append** to the shared `research/<target>/dimensions/_shared/feature-flags.md` with `source: bundle`.
|
|
51
54
|
6. **Embedded env config.** Grep `VITE_`, `NEXT_PUBLIC_`, `REACT_APP_`, `import.meta.env`,
|
|
52
55
|
`window.__ENV__`. **Field-names only — REDACT every value** to `<REDACTED:env-value>` per §7
|
|
53
56
|
(publishable keys, analytics IDs, base URLs are field-name-worthy; treat any value as a secret
|
|
@@ -79,17 +82,20 @@ gaps: [<unmined chunks, absent source maps, obfuscated route tables, ...>]
|
|
|
79
82
|
|
|
80
83
|
Then Method / Findings (framework, build tool, route count, endpoint count — tables) / Inferences
|
|
81
84
|
(public-vs-gated routes, the backend the SPA expects, which third-party SDKs are wired) / Open
|
|
82
|
-
questions / Artifacts.
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
questions / Artifacts. Dimension-private `raw/` files: `raw/{route-table.md, env-config.md,
|
|
86
|
+
bundle-map.md}` — each prose artifact carrying the `<!-- source: ... · captured_at: ... · method: ... -->`
|
|
87
|
+
line; the API-path catalog and feature flags are **appended to the shared
|
|
88
|
+
`dimensions/_shared/{api-path-catalog.md, feature-flags.md}`**, which your `_summary.md` Artifacts list
|
|
89
|
+
*links* (not duplicates).
|
|
85
90
|
|
|
86
91
|
## Return value
|
|
87
92
|
|
|
88
93
|
Return a one-paragraph headline of what the deployed shell reveals — framework + build tool, route
|
|
89
94
|
count, the shape of the API surface it calls, whether source maps were shipped (and the confidence
|
|
90
|
-
that implies). **Cross-checks:** flag that `
|
|
91
|
-
the SHARED seam artifacts (§6
|
|
92
|
-
`
|
|
95
|
+
that implies). **Cross-checks:** flag that `dimensions/_shared/api-path-catalog.md` and
|
|
96
|
+
`dimensions/_shared/feature-flags.md` are the SHARED seam artifacts (§6, one physical file each) —
|
|
97
|
+
`session`/`wire`/`distribution` append to the same files with `source: session | wire | distribution`,
|
|
98
|
+
and evaluation owns the adaptive static-vs-observed diff. Surface any
|
|
93
99
|
endpoint or flag that looks authed/internal but is statically declared in the unauth bundle — that
|
|
94
100
|
gap is the dimension's highest-value output.
|
|
95
101
|
|
|
@@ -46,9 +46,10 @@ Then dispatch by artifact type (do all that apply):
|
|
|
46
46
|
- **CLI.** Install / fetch and harvest help text: `<cli> --help`, `<cli> help`, and per-subcommand
|
|
47
47
|
`<cli> <sub> --help`. The subcommand tree **is** an API catalog. → `raw/cli-catalog.md`.
|
|
48
48
|
|
|
49
|
-
For each, **also** harvest the API surface and feature flags
|
|
50
|
-
(contract §6): `
|
|
51
|
-
|
|
49
|
+
For each, **also** harvest the API surface and feature flags by **appending** to the **shared seam
|
|
50
|
+
artifacts** (contract §6, one physical file each): `dimensions/_shared/api-path-catalog.md` with a
|
|
51
|
+
`source: distribution` column, and `dimensions/_shared/feature-flags.md` if flags ship — never a private
|
|
52
|
+
copy. Digest large bundles (counts + shape + one redacted sample), never paste (§5).
|
|
52
53
|
|
|
53
54
|
## Output
|
|
54
55
|
|
|
@@ -78,16 +79,16 @@ inference vs. fact), **Open questions** (EULA-restricted decompilation, missing
|
|
|
78
79
|
|
|
79
80
|
Then write the per-type raw files that apply — `raw/{extension-manifest.md, electron-asar-map.md,
|
|
80
81
|
mobile-strings.md, cli-catalog.md}` (each with the `<!-- source · captured_at · method -->`
|
|
81
|
-
metadata line) — plus `
|
|
82
|
-
`
|
|
82
|
+
metadata line) — plus **appends** to the shared `dimensions/_shared/api-path-catalog.md`
|
|
83
|
+
(`source: distribution`) and, if flags ship, `dimensions/_shared/feature-flags.md`.
|
|
83
84
|
|
|
84
85
|
## Return value
|
|
85
86
|
|
|
86
87
|
Return a **one-paragraph headline** of what the shipped client reveals — its declared hosts,
|
|
87
88
|
permission surface, embedded vendor SDKs, and how much richer (or not) it is than the web app.
|
|
88
|
-
The API paths and feature flags you
|
|
89
|
-
|
|
90
|
-
(`source: bundle`), `session`, and `wire-capture`. The hosts and SDK list cross-check
|
|
89
|
+
The API paths and feature flags you appended feed the **seam rule (§6)**: your
|
|
90
|
+
`dimensions/_shared/api-path-catalog.md` rows carry `source: distribution` so evaluation can run its
|
|
91
|
+
adaptive diff against `deployed-client-bundle` (`source: bundle`), `session`, and `wire-capture`. The hosts and SDK list cross-check
|
|
91
92
|
**infra-backend-fingerprint** (a host the binary calls that DNS/CT didn't surface is a finding);
|
|
92
93
|
the runtime hosts also seed **wire-capture** targets (the binary says what it *might* call; the
|
|
93
94
|
capture says what it *does*).
|
|
@@ -86,7 +86,7 @@ per §5):
|
|
|
86
86
|
Return a **one-paragraph headline** of the reconstructed backend — origin cloud, edge CDN, email +
|
|
87
87
|
AI + payments providers, and the most interesting CT-leaked host (`staging.`/`internal.`/`admin.`).
|
|
88
88
|
Cross-check against siblings: the CSP `connect-src` and CT-found `api.<target>` host should match the
|
|
89
|
-
**`
|
|
89
|
+
**`dimensions/_shared/api-path-catalog.md`** seam (§6) produced by `deployed-client-bundle`/`session`/`wire-capture`
|
|
90
90
|
— flag a host in your fingerprint that none of them ever hit as a dormant/internal surface, and flag
|
|
91
91
|
a vendor named in `sub-processors.md` (e.g. an AI provider) that no other dimension surfaced. Note
|
|
92
92
|
any CT-leaked host worth a `wire-capture` or `deployed-client-bundle` follow-up.
|
|
@@ -41,10 +41,20 @@ Under `research/<target>/dimensions/session/`:
|
|
|
41
41
|
- `captures/p0-surface.md`, `p1-auth.md`, and per-phase narratives (P2 core action, P3
|
|
42
42
|
streaming, P4 runtime/state, P5 iteration) — decoded, opinionated, per `re-ingestion` §9.5.
|
|
43
43
|
- `raw/*.json` — verbatim endpoint captures with `_meta` + `_decoded_fields`, **all secrets
|
|
44
|
-
redacted** (`re-ingestion` §9.5). Digest bodies >50KB.
|
|
44
|
+
redacted** (`re-ingestion` §9.5). Digest bodies >50KB. App API paths + flags you observe **append
|
|
45
|
+
to the shared `dimensions/_shared/{api-path-catalog.md, feature-flags.md}` with `source: session`**
|
|
46
|
+
(re-ingestion §6) — and the folded rung-1 wire tap appends there as `source: wire`.
|
|
45
47
|
- `curls.md` — reproducible commands per endpoint, auth model documented (`re-ingestion` §9.5).
|
|
48
|
+
- **Visual / surface map** — `captures/screens/` is preferred *when screenshots are available*; when
|
|
49
|
+
they are **not** (no image tool, or the app holds a persistent connection that never reaches
|
|
50
|
+
page-idle), a textual `captures/surface-map.md` is the **accepted substitute** that satisfies the
|
|
51
|
+
§9.5 visual-map requirement — and you record the visual-coverage gap in the `_summary.md` `gaps:`
|
|
52
|
+
frontmatter (a known constraint, not a silent miss).
|
|
46
53
|
- `_summary.md` — a short bridge file in the standard dump shape pointing into the above, so
|
|
47
|
-
the synthesis step can treat session like any other dimension.
|
|
54
|
+
the synthesis step can treat session like any other dimension. Its frontmatter additionally carries
|
|
55
|
+
**`write_side_observed: <true|false>`** and **`pass2: <not-applicable | offered-pending |
|
|
56
|
+
declined-by-user | deferred | done>`** (§9.2) so Evaluation renders the write-side gap once,
|
|
57
|
+
machine-readably; a deferred Pass 2 may add an optional `captures/pass2-followup.md`.
|
|
48
58
|
|
|
49
59
|
## Return value
|
|
50
60
|
A one-paragraph headline (the auth model + transport + the single most load-bearing wire
|
|
@@ -72,9 +72,11 @@ Then the captures + raw artifacts (per `re-discovery` Part C (wire-capture)):
|
|
|
72
72
|
- `raw/flows.json` — verbatim-but-**redacted and digested** flows, each with the `_meta` header
|
|
73
73
|
(incl. `kind`, `byte_length`, `redactions[]`, and the **chosen rung + authorization**), `body`,
|
|
74
74
|
`_decoded`. Digest large captures (schema + one redacted sample + counts), never paste megabytes.
|
|
75
|
-
- `
|
|
76
|
-
`source: wire
|
|
77
|
-
`session` rows.
|
|
75
|
+
- `dimensions/_shared/api-path-catalog.md` — the **shared-surface artifact** (§6, one physical file):
|
|
76
|
+
**append** rows carrying `source: wire` to it (never a private copy), so evaluation can run its
|
|
77
|
+
adaptive diff against `bundle`/`session`/`distribution` rows. When `wire-capture` is folded into
|
|
78
|
+
`session` (the common path — §7.1), `session` owns this append; a standalone `wire-capture` appends
|
|
79
|
+
directly.
|
|
78
80
|
- `curls.md` — reproducer `curl` skeletons with all credentials replaced by placeholders.
|
|
79
81
|
|
|
80
82
|
## Return value
|
|
@@ -146,6 +146,7 @@ The three named **cases** are presets over this vector — a target can light se
|
|
|
146
146
|
(Liveblocks = source:full + runtime:reachable + auth:obtainable + presence:rich → nearly all
|
|
147
147
|
dimensions). Rules:
|
|
148
148
|
- **`auth:obtainable` is a hint, not actionable** — the harness never self-signs-up; it only counts as `have-login` if the *user* hands over a session.
|
|
149
|
+
- **A *claimed* login is `auth:claimed` (confidence medium), not `auth:have-login` (high), until a cheap live probe confirms it.** A user saying "I'm logged in" — or a session being merely *expected* — is not proof: profiles expire, a fresh tab may not restore an in-memory token, and a deep-link can bounce to a login wall while the root looks authed. Grade `auth:claimed` until Discovery (or the `session` agent's first step) navigates the app and confirms an **authenticated surface** (a dashboard, a populated `viewer`/`/me`, a token in the store) — only then promote to `have-login`. Grading a claimed login `high` lets a session collapse to `blocked` after dispatch, with the wasted dispatch hidden behind a confident grade.
|
|
149
150
|
- **Dimension-level access overrides the target headline** for method selection (a Case-1 target can still have a Case-3 session dimension).
|
|
150
151
|
- Method swaps on axis *value*: `source:full` ⇒ `clone-and-map`; `source:partial` ⇒ `source-map-reassembly`; `runtime:reachable + source:none` ⇒ `bundle-string-mine` + wire-capture.
|
|
151
152
|
|
|
@@ -172,6 +173,11 @@ Discovery records the resolved vector in the `access_grade` frontmatter of `00-r
|
|
|
172
173
|
> **Deferred (available on request, not built):** `external-reputation` (G2/Reddit/HN — the only
|
|
173
174
|
> "what others say" surface) and `hiring-intel` (job posts leak the backend stack). Strong
|
|
174
175
|
> candidates, declined for this iteration. Re-add via self-correction if a run needs them.
|
|
176
|
+
> **Conditional trigger:** when `community` returns **no first-party feedback loop** (no public
|
|
177
|
+
> issues/roadmap/changelog/forum — feedback funnelled to a gated channel), flag `external-reputation`
|
|
178
|
+
> as **recommended-for-this-run** in `00-recon-plan.md`, so the user-sentiment blind spot is a surfaced
|
|
179
|
+
> choice rather than a silent gap (the `community` user-pain claims are then capped at tentative —
|
|
180
|
+
> re-evaluation closed-feedback cap).
|
|
175
181
|
|
|
176
182
|
An **absent** dimension is a finding — record it with its evidence; never silently drop it.
|
|
177
183
|
|
|
@@ -183,6 +189,12 @@ See git history / the source playbook for the full strategy text; in brief:
|
|
|
183
189
|
- **docs** — prefer in-repo docs, then `llms.txt`/`llms-full.txt`, then crawl; organize by section.
|
|
184
190
|
- **packages** — per public package: registry metadata, `exports` map + `.d.ts` type surface, health.
|
|
185
191
|
- **api** — fetch the spec verbatim, build an endpoint catalog (auth, envelope, pagination, webhooks).
|
|
192
|
+
**Grade the method from a RETRIEVED artifact, never a label.** Before grading `openapi-verbatim`,
|
|
193
|
+
actually fetch the candidate spec URL and confirm a **parseable JSON/YAML body** — a docs page merely
|
|
194
|
+
*titled* "OpenAPI" with no served `spec.json` (or a `/swagger` that 403s) is `docs-reconstructed`
|
|
195
|
+
(capped medium), and Discovery must pre-grade it that way so the plan matches reality. **A
|
|
196
|
+
sibling-declared host/op/route count is a coverage checklist (a floor), never a ceiling** — every
|
|
197
|
+
dumper expands from sibling-mined hosts/routes and records the predicted-vs-found delta.
|
|
186
198
|
**NEW fold-in:** also probe MCP/tool surfaces — `/.well-known/mcp`, an MCP server manifest, a
|
|
187
199
|
function-calling tool schema, an LLM "actions" file — and write `raw/tool-catalog.md` (an MCP tool
|
|
188
200
|
list *is* an API catalog; it lives here, not in its own dimension).
|
|
@@ -190,7 +202,10 @@ See git history / the source playbook for the full strategy text; in brief:
|
|
|
190
202
|
matrix, target market.
|
|
191
203
|
- **community** — *first-party only*: changelog cadence + direction, issue/discussion themes, blog.
|
|
192
204
|
- **session** — the deepest, opt-in, user-gated dimension; delegates to the session playbook in
|
|
193
|
-
`re-ingestion` §9 (3-pass, P0–P6, captures/raw/curls).
|
|
205
|
+
`re-ingestion` §9 (3-pass, P0–P6, captures/raw/curls). For any `auth:have-login`/`auth:claimed`
|
|
206
|
+
target, Discovery **seeds the Pass-2 decision** (`pass2: offered-pending | declined-by-user |
|
|
207
|
+
deferred`) into `00-recon-plan.md`, so a Pass-1-only (read-only) session is a *recorded choice*, not a
|
|
208
|
+
silent omission of the write surface (re-ingestion §9.2).
|
|
194
209
|
|
|
195
210
|
## 8 — deployed-client-bundle — `deployed-client-bundle`
|
|
196
211
|
|
|
@@ -198,15 +213,22 @@ See git history / the source playbook for the full strategy text; in brief:
|
|
|
198
213
|
(marketing) and `session` (authenticated). Works on closed SaaS with no repo and no login.
|
|
199
214
|
|
|
200
215
|
**Detection:** an app subdomain (`app.<target>.*`) or SPA route serves a JS bundle;
|
|
201
|
-
`sourceMappingURL` present; a `/assets/*.js` graph.
|
|
216
|
+
`sourceMappingURL` present; a `/assets/*.js` graph. **Two cheap Discovery probes pre-grade the method
|
|
217
|
+
and surface a leak early:** (a) does an entry chunk's `sourceMappingURL` resolve to a `.map`-200? →
|
|
218
|
+
pre-grade `source-map-reassembly` (confidence high — original `src/` recovers). (b) probe a few
|
|
219
|
+
bootstrap-config paths (`/config`, `/backend/config/*`, `/env.json`, a runtime-config endpoint) — a
|
|
220
|
+
200 here is both a method pre-grade and a possible unauth config/secret leak (a finding).
|
|
202
221
|
|
|
203
222
|
**Strategy:** fetch the main bundle(s); string-mine the **route table**, the **API-path catalog**
|
|
204
|
-
(→ shared `
|
|
205
|
-
`
|
|
206
|
-
field-names only, redact values), and reassemble **source maps** if
|
|
207
|
-
source-map-reassembly`, confidence high). Digest huge bundles, don't paste.
|
|
223
|
+
(→ append to the shared `dimensions/_shared/api-path-catalog.md`, `source: bundle` — re-ingestion §6),
|
|
224
|
+
**feature flags** (→ shared `dimensions/_shared/feature-flags.md`), embedded **env config** (`VITE_*`,
|
|
225
|
+
`NEXT_PUBLIC_*`, public keys — field-names only, redact values), and reassemble **source maps** if
|
|
226
|
+
shipped (`method: source-map-reassembly`, confidence high). Digest huge bundles, don't paste. This
|
|
227
|
+
dimension **owns** the app-API bundle mine — other dimensions cite its catalog by path, never re-mine
|
|
228
|
+
the same bundle (re-ingestion §6).
|
|
208
229
|
|
|
209
|
-
**Artifacts:** `_summary.md` + `raw/{route-table.md,
|
|
230
|
+
**Artifacts:** `_summary.md` + `raw/{route-table.md, env-config.md, bundle-map.md}` + appends to the
|
|
231
|
+
shared `dimensions/_shared/{api-path-catalog.md, feature-flags.md}`.
|
|
210
232
|
|
|
211
233
|
## 9 — infra-backend-fingerprint — `infra-backend-fingerprint`
|
|
212
234
|
|
|
@@ -236,7 +258,17 @@ structured XHRs worth a tap, AND the appropriate ethics rung is authorized.
|
|
|
236
258
|
2. HAR export → `wire-har`;
|
|
237
259
|
3. mitmproxy (**gated, opt-in, user-run, first-party traffic only**) → `wire-mitmproxy`.
|
|
238
260
|
|
|
239
|
-
**
|
|
261
|
+
**Fold note (common path):** when there is no separate non-browser client, wire-capture **folds into
|
|
262
|
+
`session`** (which owns the browser singleton), **never into a curl/WebFetch dumper** (a non-browser
|
|
263
|
+
dumper cannot run rung-1's in-page tap, and routing it there yields zero `source: wire` rows —
|
|
264
|
+
re-ingestion §7.1). The folded rung-1 *is* the interceptor `session` installs; its observed paths
|
|
265
|
+
append to the shared `dimensions/_shared/api-path-catalog.md` as `source: wire`. A folded wire-capture
|
|
266
|
+
still leaves a one-paragraph `_summary.md` (`status: folded`, naming the fold target) — never a silent
|
|
267
|
+
drop.
|
|
268
|
+
|
|
269
|
+
**Artifacts:** `_summary.md` + `captures/wire-narrative.md` + `raw/flows.json (redacted/digested)` +
|
|
270
|
+
appends to shared `dimensions/_shared/api-path-catalog.md (source: wire)` + `curls.md`. Record the
|
|
271
|
+
chosen rung + authorization in `_meta`.
|
|
240
272
|
|
|
241
273
|
## 11 — distribution-artifacts — `distribution-artifacts`
|
|
242
274
|
|
|
@@ -253,7 +285,7 @@ route/API/flag catalog from the desktop client (often richer than web). **mobile
|
|
|
253
285
|
keys**). **CLI** — help text/subcommands = an API catalog. Read the artifact's EULA first (see
|
|
254
286
|
`re-ingestion` §7.2); never silently decompile a restrictively-licensed binary.
|
|
255
287
|
|
|
256
|
-
**Artifacts:** `_summary.md` + `raw/{extension-manifest.md, electron-asar-map.md, mobile-strings.md, cli-catalog.md}` (whichever apply) + `
|
|
288
|
+
**Artifacts:** `_summary.md` + `raw/{extension-manifest.md, electron-asar-map.md, mobile-strings.md, cli-catalog.md}` (whichever apply) + appends to shared `dimensions/_shared/api-path-catalog.md` (source: distribution).
|
|
257
289
|
|
|
258
290
|
---
|
|
259
291
|
|
|
@@ -23,6 +23,23 @@ coherent picture, **weighted by how each claim was obtained**, with disagreement
|
|
|
23
23
|
`distribution-artifacts` are mutually independent and independent of marketing. **`website` and
|
|
24
24
|
`docs` are NOT independent** for *feature claims* (docs often restate marketing) — two of them
|
|
25
25
|
agreeing is still one source. A bundle-declared route + a session-observed route ARE independent.
|
|
26
|
+
**Same artifact ⇒ one source.** Two dimensions that string-mine the *same* static asset (one bundle /
|
|
27
|
+
one spec / one binary) are **one source** — never a band-bump — even when they report different
|
|
28
|
+
counts; the divergent counts are a **reported range, not a flagged conflict** (`deployed-client-bundle`
|
|
29
|
+
278 vs `website` 361 over one bundle is one finding with a range, not corroboration and not a conflict).
|
|
30
|
+
|
|
31
|
+
**Closed-feedback confidence cap.** When the `community` dimension finds **no first-party feedback
|
|
32
|
+
loop** (no public issues / roadmap / changelog / forum — feedback funnelled to a gated channel), its
|
|
33
|
+
user-pain / most-requested-feature claims are **inference-from-changelog only → capped at
|
|
34
|
+
`low`/tentative**, never promoted on changelog frequency alone. The surface that *would* corroborate
|
|
35
|
+
user sentiment is `external-reputation` (a deferred dimension) — flag it as recommended-for-this-run
|
|
36
|
+
when this cap fires (see re-discovery Part C deferred-dimension trigger).
|
|
37
|
+
|
|
38
|
+
**Write-side-unobserved cap.** A `session` dimension carrying `write_side_observed: false` (a
|
|
39
|
+
Pass-1-only run) has observed feature *existence/gating* but **not** feature *execution behavior*. Any
|
|
40
|
+
marketed generate/submit/launch *behavior* claim therefore stays **tentative and is never promoted to
|
|
41
|
+
fact** from marketing/docs alone — render the write-side gap **once** from the frontmatter flag, not
|
|
42
|
+
re-hedged per rollup.
|
|
26
43
|
|
|
27
44
|
**Presentation mapping:** high → stated as fact; low/single-source → hedged as tentative;
|
|
28
45
|
conflicted → flagged. (This is the "lighter" form of the provenance-weighting — done inline in the
|
|
@@ -58,11 +75,19 @@ prose, not via a separate `claims.yaml`.)
|
|
|
58
75
|
# <Target> — Data Model & API / SDK Surface
|
|
59
76
|
## Core entities (domain objects + relations; ER-style — when the runtime exposes an RBAC verb
|
|
60
77
|
taxonomy, derive the entity set from it: `X_CREATE/VIEW/EDIT/DELETE` ⇒ entity X)
|
|
61
|
-
## Integration surface (SDK/packages public API · REST/HTTP catalog · realtime/wire protocol
|
|
62
|
-
|
|
78
|
+
## Integration surface (SDK/packages public API · REST/HTTP catalog · realtime/wire protocol)
|
|
79
|
+
## Published-vs-app-own API diff (emit WHENEVER the target publishes a developer/partner/MCP API —
|
|
80
|
+
common for mature SaaS, but not universal. The app the SPA runs on is frequently
|
|
81
|
+
a different, broader, differently-authed API than the published one: list ops the
|
|
82
|
+
app uses that the public API omits, AND public ops the app never calls — both are
|
|
83
|
+
findings. If there is NO published API, say so explicitly: "no published API — the
|
|
84
|
+
app surface is the only surface" is itself the finding, not an empty section.)
|
|
63
85
|
## Auth & tenancy model (token type, where it lives, scope expression)
|
|
64
|
-
##
|
|
65
|
-
|
|
86
|
+
## API-path diff (adaptive, N-way over the runtime sources present) (the seam rule: bundle-declared vs
|
|
87
|
+
session-observed vs wire-observed. Title it for the sources ACTUALLY run —
|
|
88
|
+
enumerate only those lanes; an absent lane [session blocked / wire folded] is a
|
|
89
|
+
recorded gap, NOT a structural hole to apologize for. Dormant/unshipped routes
|
|
90
|
+
are findings.)
|
|
66
91
|
## Cross-dimension reconciliation (published surface [api/packages/docs] vs observed wire [session/
|
|
67
92
|
wire-capture]; document drift — published=fact, observed-drift=tentative)
|
|
68
93
|
## Open questions
|
|
@@ -19,15 +19,28 @@ This contract generalizes the source playbook's three-format contract (`captures
|
|
|
19
19
|
## 1. Folder layout
|
|
20
20
|
|
|
21
21
|
```
|
|
22
|
-
research/<target>/dimensions
|
|
23
|
-
├──
|
|
24
|
-
|
|
22
|
+
research/<target>/dimensions/
|
|
23
|
+
├── _shared/ ← cross-dimension seam artifacts, ONE physical copy (see §6)
|
|
24
|
+
│ ├── api-path-catalog.md
|
|
25
|
+
│ └── feature-flags.md
|
|
26
|
+
└── <dimension>/
|
|
27
|
+
├── _summary.md ← decoded narrative + provenance frontmatter (human + machine read this)
|
|
28
|
+
└── raw/ ← verbatim artifacts, DIMENSION-PRIVATE (the reproducer reads these)
|
|
25
29
|
```
|
|
26
30
|
|
|
27
31
|
Richer dimensions inherit the playbook contract (extra files, same `_summary.md` provenance):
|
|
28
32
|
- **session**: `dimensions/session/{_summary.md, captures/p*.md, raw/*.json, curls.md}`
|
|
29
33
|
- **wire-capture**: `dimensions/wire-capture/{_summary.md, captures/wire-narrative.md, raw/flows.json, curls.md}`
|
|
30
34
|
|
|
35
|
+
Two layout rules the seam and the "absence is a finding" principle depend on:
|
|
36
|
+
- **Shared-seam files live in `dimensions/_shared/`, one physical copy each — never under a single
|
|
37
|
+
dimension's `raw/`** (§6). Everything else under a dimension's `raw/` is **dimension-private by
|
|
38
|
+
default**; only the §6 allowlist (`api-path-catalog.md`, `feature-flags.md`) is shared.
|
|
39
|
+
- **A folded or absent dimension still leaves a record.** When a dimension is folded into another or
|
|
40
|
+
is absent, write a one-paragraph `_summary.md` with `status: folded` (naming the fold target) or
|
|
41
|
+
`status: absent` (+ the cheap evidence). "An absent dimension is a finding" must be **materialized
|
|
42
|
+
as a file**, never a silent drop.
|
|
43
|
+
|
|
31
44
|
---
|
|
32
45
|
|
|
33
46
|
## 2. `_summary.md` — required shape (with provenance frontmatter)
|
|
@@ -115,19 +128,34 @@ readable, not a memory dump. Set `digested: true` context in the artifact's `_me
|
|
|
115
128
|
|
|
116
129
|
`deployed-client-bundle` (static unauth SPA), `session` (authenticated browser runtime), and
|
|
117
130
|
`wire-capture` (non-browser client) can all surface the same **API path catalog** and **feature
|
|
118
|
-
flags**. To keep them consumable instead of triplicated
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
-
|
|
123
|
-
|
|
124
|
-
|
|
131
|
+
flags**. To keep them consumable instead of triplicated **N times** (a real run forked
|
|
132
|
+
`api-path-catalog.md` up to 7×, and "two copies agree" then mis-reads as corroboration):
|
|
133
|
+
|
|
134
|
+
- **One physical file, one canonical location, append-only.** The seam files live at
|
|
135
|
+
`dimensions/_shared/api-path-catalog.md` and `dimensions/_shared/feature-flags.md` — **Ingestion
|
|
136
|
+
seeds the two empty files (with a header) once, before the dumper fan-out.** Every contributing
|
|
137
|
+
dimension **appends a `source:`-tagged section** (`source: bundle | session | wire | distribution`)
|
|
138
|
+
and **never creates its own copy**; each dumper's `_summary.md` Artifacts list **links** the shared
|
|
139
|
+
file rather than duplicating it. **Shared-seam allowlist:** these two filenames are the *only*
|
|
140
|
+
shared/single-physical artifacts — every other `raw/*` is dimension-private.
|
|
141
|
+
- Evaluation owns the **API-path diff** (an *adaptive N-way* diff over whichever runtime sources were
|
|
142
|
+
actually run — see re-evaluation template 3) in `data-model-api-surface.md`. A path that appears in
|
|
143
|
+
`bundle` but never in `session`/`wire` is a dormant/unshipped route — a finding, not noise.
|
|
144
|
+
|
|
145
|
+
> **Same artifact ⇒ ONE source (never independent corroboration).** Two dimensions that string-mine
|
|
146
|
+
> the *same* static asset (one bundle / one spec / one binary) are **one source** for the promotion
|
|
147
|
+
> rule — never a confidence band-bump — and their divergent counts are a **reported range, not a
|
|
148
|
+
> flagged conflict.** Name **one owner dimension per asset**: when `source:none` and no machine spec
|
|
149
|
+
> is served, `deployed-client-bundle` **owns** the app-API bundle mine, and `api` is re-scoped to the
|
|
150
|
+
> *published/partner* spec only (or marked `partial` if none is served) — the others **cite the owner
|
|
151
|
+
> by path and do not re-mine**.
|
|
125
152
|
|
|
126
153
|
> **Published API ≠ the app's own API.** A product's developer/REST/MCP surface (`api`/`docs`/`packages`
|
|
127
154
|
> dims) is frequently *not* the API its own app runs on (`session`/`bundle` dims) — different protocol,
|
|
128
155
|
> host, and operation set. Always diff the two: operations the app uses but the public API omits, **and**
|
|
129
156
|
> public operations the app never calls, are both findings. The published surface is the integration
|
|
130
|
-
> story; the runtime surface is the real architecture.
|
|
157
|
+
> story; the runtime surface is the real architecture. When a published API exists, Evaluation emits
|
|
158
|
+
> this split as a *named* output, not inline prose (re-evaluation template 3).
|
|
131
159
|
|
|
132
160
|
---
|
|
133
161
|
|
|
@@ -163,6 +191,14 @@ chosen rung in `_meta`:
|
|
|
163
191
|
*user* installs the CA and routes their client — the agent only ingests exported flows. →
|
|
164
192
|
`method: wire-mitmproxy`. Same explicit-authorization loop as session Pass-2.
|
|
165
193
|
|
|
194
|
+
> **Never fold a browser-rung into a non-browser (curl/WebFetch) dumper.** Rung 1 *is* a browser tap,
|
|
195
|
+
> and the browser is a singleton owned by `session`/`wire-capture` — routing it to a curl dumper
|
|
196
|
+
> produces zero `source: wire` rows (a real run did exactly this). When `wire-capture` is **folded**,
|
|
197
|
+
> the rung-1 tap is the **in-page interceptor that `session` already installs**: `session` appends its
|
|
198
|
+
> observed paths to `dimensions/_shared/api-path-catalog.md` as `source: wire`. A folded `wire-capture`
|
|
199
|
+
> still leaves a one-paragraph `_summary.md` (`status: folded`, naming the fold target) per §1 —
|
|
200
|
+
> "folded" is recorded, never silently dropped.
|
|
201
|
+
|
|
166
202
|
> Wireshark / packet capture is explicitly **not** used: for HTTPS it yields only TLS ciphertext,
|
|
167
203
|
> and a packet sweep of a third party is the bright line this harness will not cross.
|
|
168
204
|
|
|
@@ -234,6 +270,17 @@ completion event, server-side resolution of shorthand, ID/slug-generation, the r
|
|
|
234
270
|
endpoint, and the full realtime event catalog. **Legitimate to skip** if the user opts out — leave
|
|
235
271
|
write-side shapes as open questions; never fabricate them.
|
|
236
272
|
|
|
273
|
+
> **Record the write-side decision as a machine flag, not re-derived prose.** A Pass-1-only run leaves
|
|
274
|
+
> the *entire* write/generate/launch surface unobserved — feature *existence/gating* is solid, but
|
|
275
|
+
> feature *execution behavior* rests on marketing/docs and must never be promoted to fact (this caveat
|
|
276
|
+
> otherwise gets re-hedged across 3–4 rollups every cost-gated run). So the session `_summary.md`
|
|
277
|
+
> frontmatter carries `write_side_observed: <true|false>` and `pass2: <not-applicable | offered-pending
|
|
278
|
+
> | declined-by-user | deferred | done>` (this flag is the load-bearing part — it lets Evaluation render
|
|
279
|
+
> the write-side gap *once*). When it would help a later run resume, optionally add
|
|
280
|
+
> `captures/pass2-followup.md` listing the **exact cheapest-mode write actions + est. cost** that would
|
|
281
|
+
> close the gap. Discovery seeds the `pass2:` decision in `00-recon-plan.md` for any `auth:have-login`
|
|
282
|
+
> target.
|
|
283
|
+
|
|
237
284
|
**Pass 3 — synthesis.** Walk the captures, pull each finding into the dimension's `_summary.md`,
|
|
238
285
|
note the cleverest design choices, defaults imposed, performance characteristics, and open
|
|
239
286
|
questions.
|
|
@@ -311,13 +358,21 @@ Under `research/<target>/dimensions/session/`:
|
|
|
311
358
|
redacted) + `_decoded_fields`. Digest bodies > 50 KB into a structured summary.
|
|
312
359
|
- **`curls.md`** — reproducible curl per endpoint, the auth model documented, a variables block,
|
|
313
360
|
and an endpoint-catalog table.
|
|
314
|
-
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
361
|
+
- **Visual / surface map** — `captures/screens/` (**preferred when available**): one annotated
|
|
362
|
+
screenshot per primary surface (each major nav section), redact visible PII before saving. **When
|
|
363
|
+
screenshot capture is unavailable** (e.g. the runtime lacks an image tool, or the app holds a
|
|
364
|
+
persistent connection that never reaches page-idle), a **textual `captures/surface-map.md` is the
|
|
365
|
+
accepted substitute** and satisfies this visual-map requirement — and the **visual-coverage gap is
|
|
366
|
+
recorded in the `gaps:` frontmatter** so Evaluation reads a *known constraint*, not a silent miss.
|
|
367
|
+
- **`captures/pass2-followup.md`** (optional, when Pass 2 is deferred/declined and it would help a
|
|
368
|
+
later run resume) — the exact cheapest-mode write/generate actions + estimated cost that would close
|
|
369
|
+
the write-side gap (§9.2). The `write_side_observed`/`pass2` frontmatter flags are mandatory; this
|
|
370
|
+
file is the convenience.
|
|
318
371
|
- **`_summary.md`** — the standard dimension bridge file (provenance frontmatter per §2) pointing
|
|
319
372
|
into the above, so Evaluation treats session like any other dimension. `method: session-playbook`,
|
|
320
|
-
`confidence: low` for Pass-1-only/inferred.
|
|
373
|
+
`confidence: low` for Pass-1-only/inferred. **Session frontmatter additionally carries
|
|
374
|
+
`write_side_observed: <true|false>` and `pass2: <not-applicable | offered-pending | declined-by-user
|
|
375
|
+
| deferred | done>`** (§9.2) so Evaluation renders the write-side gap once, machine-readably.
|
|
321
376
|
|
|
322
377
|
### 9.6 Session ethics (binds hardest here — see §7 above)
|
|
323
378
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nurix/etna",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.7",
|
|
4
4
|
"description": "Bootstrap a project with a Nurix harness — copies the harness's CLAUDE.md, skills, agents, rules, and hooks directly into the project from a bundled payload (no marketplace fetch, no network).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|