@nurix/etna 0.15.6 → 0.15.8

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.
Files changed (88) hide show
  1. package/bin/etna.js +64 -13
  2. package/data/harness-index.json +7 -5
  3. package/data/harnesses/code/CLAUDE.md +3 -7
  4. package/data/harnesses/code/agents/harness-manager.md +4 -4
  5. package/data/harnesses/code/agents/maintenance.md +1 -1
  6. package/data/harnesses/code/harness.json +4 -3
  7. package/data/harnesses/code/hooks/hooks.json +3 -17
  8. package/data/harnesses/code/hooks/prompt-recall.js +157 -0
  9. package/data/harnesses/code/hooks/session-reflect.js +283 -0
  10. package/data/harnesses/code/skills/distiller/SKILL.md +62 -60
  11. package/data/harnesses/code/skills/distiller/references/docs-mode.md +21 -21
  12. package/data/harnesses/code/skills/distiller/references/method.md +41 -41
  13. package/data/harnesses/code/skills/documentation/references/templates.md +20 -27
  14. package/data/harnesses/code-fable/CLAUDE.md +138 -0
  15. package/data/harnesses/code-fable/agents/brainstorm.md +35 -0
  16. package/data/harnesses/code-fable/agents/change-review.md +249 -0
  17. package/data/harnesses/code-fable/agents/harness-manager.md +193 -0
  18. package/data/harnesses/code-fable/agents/maintenance.md +123 -0
  19. package/data/harnesses/code-fable/agents/performance-review.md +218 -0
  20. package/data/harnesses/code-fable/agents/spec-mode.md +56 -0
  21. package/data/harnesses/code-fable/harness.json +7 -0
  22. package/data/harnesses/code-fable/hooks/hooks.json +27 -0
  23. package/data/harnesses/code-fable/hooks/lib/redact.js +37 -0
  24. package/data/harnesses/code-fable/hooks/prompt-recall.js +157 -0
  25. package/data/harnesses/code-fable/hooks/session-reflect.js +283 -0
  26. package/data/harnesses/code-fable/rules/general.md +96 -0
  27. package/data/harnesses/code-fable/rules/nomenclature.md +34 -0
  28. package/data/harnesses/code-fable/skills/boundary/SKILL.md +262 -0
  29. package/data/harnesses/code-fable/skills/boundary/references/boundary-taxonomy.md +734 -0
  30. package/data/harnesses/code-fable/skills/brainstorm/README.md +136 -0
  31. package/data/harnesses/code-fable/skills/brainstorm/SKILL.md +135 -0
  32. package/data/harnesses/code-fable/skills/brainstorm/harvest.md +26 -0
  33. package/data/harnesses/code-fable/skills/brainstorm/templates/backlog.md +39 -0
  34. package/data/harnesses/code-fable/skills/brainstorm/templates/build.md +37 -0
  35. package/data/harnesses/code-fable/skills/brainstorm/templates/decisions.md +29 -0
  36. package/data/harnesses/code-fable/skills/brainstorm/templates/doctrine.md +31 -0
  37. package/data/harnesses/code-fable/skills/brainstorm/templates/domain-model.md +25 -0
  38. package/data/harnesses/code-fable/skills/brainstorm/templates/glossary.md +19 -0
  39. package/data/harnesses/code-fable/skills/brainstorm/templates/milestones.md +43 -0
  40. package/data/harnesses/code-fable/skills/brainstorm/templates/non-goals.md +21 -0
  41. package/data/harnesses/code-fable/skills/brainstorm/templates/plan-doc.md +61 -0
  42. package/data/harnesses/code-fable/skills/brainstorm/templates/questions.md +35 -0
  43. package/data/harnesses/code-fable/skills/brainstorm/templates/references.md +28 -0
  44. package/data/harnesses/code-fable/skills/brainstorm/templates/rejected.md +29 -0
  45. package/data/harnesses/code-fable/skills/brainstorm/templates/state.md +8 -0
  46. package/data/harnesses/code-fable/skills/brainstorm/templates/tech.md +23 -0
  47. package/data/harnesses/code-fable/skills/brainstorm/templates/thesis.md +21 -0
  48. package/data/harnesses/code-fable/skills/distiller/SKILL.md +219 -0
  49. package/data/harnesses/code-fable/skills/distiller/references/docs-mode.md +526 -0
  50. package/data/harnesses/code-fable/skills/distiller/references/method.md +166 -0
  51. package/data/harnesses/code-fable/skills/documentation/SKILL.md +127 -0
  52. package/data/harnesses/code-fable/skills/documentation/references/examples.md +193 -0
  53. package/data/harnesses/code-fable/skills/documentation/references/style-guide.md +288 -0
  54. package/data/harnesses/code-fable/skills/documentation/references/templates.md +942 -0
  55. package/data/harnesses/code-fable/skills/workflow-mapper/SKILL.md +430 -0
  56. package/data/harnesses/code-fable/skills/workflow-mapper/references/patterns.md +214 -0
  57. package/data/harnesses/discover/CLAUDE.md +180 -0
  58. package/data/harnesses/{re → discover}/agents/api.md +3 -3
  59. package/data/harnesses/{re → discover}/agents/codebase.md +3 -3
  60. package/data/harnesses/{re → discover}/agents/community.md +3 -3
  61. package/data/harnesses/{re → discover}/agents/deployed-client-bundle.md +21 -15
  62. package/data/harnesses/{re → discover}/agents/distribution-artifacts.md +13 -12
  63. package/data/harnesses/{re → discover}/agents/docs.md +3 -3
  64. package/data/harnesses/{re → discover}/agents/infra-backend-fingerprint.md +3 -3
  65. package/data/harnesses/{re → discover}/agents/packages.md +3 -3
  66. package/data/harnesses/{re → discover}/agents/session.md +29 -11
  67. package/data/harnesses/{re → discover}/agents/website.md +3 -3
  68. package/data/harnesses/{re → discover}/agents/wire-capture.md +14 -10
  69. package/data/harnesses/discover/harness.json +7 -0
  70. package/data/harnesses/{re/rules/re-discovery.md → discover/rules/discovery.md} +86 -17
  71. package/data/harnesses/{re/rules/re-evaluation.md → discover/rules/evaluation.md} +40 -4
  72. package/data/harnesses/discover/rules/ingestion.md +551 -0
  73. package/data/harnesses/discover/rules/self-correction.md +177 -0
  74. package/data/harnesses/discover/rules/tradecraft.md +532 -0
  75. package/data/harnesses/hr/CLAUDE.md +91 -0
  76. package/data/harnesses/hr/harness.json +7 -0
  77. package/data/harnesses/hr/skills/interview-eval/SKILL.md +118 -0
  78. package/data/harnesses/hr/skills/interview-eval/TEMPLATE.md +124 -0
  79. package/data/harnesses/hr/skills/interview-eval/extract_session.py +418 -0
  80. package/data/harnesses/hr/skills/interview-eval/rubric.md +219 -0
  81. package/data/harnesses/kb-agi/harness.json +1 -0
  82. package/package.json +1 -1
  83. package/data/harnesses/code/hooks/post-commit.js +0 -136
  84. package/data/harnesses/code/hooks/post-tool-failure.js +0 -136
  85. package/data/harnesses/code/hooks/session-stop.js +0 -207
  86. package/data/harnesses/re/CLAUDE.md +0 -146
  87. package/data/harnesses/re/harness.json +0 -6
  88. package/data/harnesses/re/rules/re-ingestion.md +0 -327
@@ -1,19 +1,32 @@
1
1
  # Discovery Reference — Scope Gate · Access Vector · Dimension Catalog
2
2
 
3
- The reference knowledge for **Discovery** (`re` harness, Mode 1). It carries all three of
4
- Discovery's steps in the order they run:
3
+ The reference knowledge for **Discovery** (`discover` harness, Mode 1). It carries all three of
4
+ Discovery's steps in the order they run (preceded by corpus-root resolution, Step 00 below):
5
5
 
6
6
  - **Part A — Scope-feasibility gate** (Step 0): resolve the target's identity and emit a verdict
7
7
  so the run never wastes effort on an infeasible target.
8
8
  - **Part B — Access vector** (Step 1): grade the four-axis capability vector that decides which
9
9
  dimensions are reachable and which method each uses.
10
10
  - **Part C — Dimension catalog** (Step 2): the canonical list of dimensions, their detection
11
- signals, dump strategy, and owning agent.
11
+ signals, collection strategy, and owning agent.
12
12
 
13
13
  `ingestion` also reads **Part C** to dispatch the right agent with the right method.
14
14
 
15
15
  ---
16
16
 
17
+ # Step 00 — Resolve the corpus root (before the gate)
18
+
19
+ Before Part A, decide **where this run writes** — the harness picks intelligently, it does not hardcode `research/`:
20
+
21
+ 1. **Reuse an existing discovery corpus** if the project has one — search for any folder containing a prior run's `*/00-scope-verdict.md` (commonly `research/`, but also `recon/`, `discovery/`, `teardowns/`, `analysis/`, or a folder the user names).
22
+ 2. If several exist, prefer the one the user points at, else the most recently written.
23
+ 3. If none exists and the user hasn't named one, default to `research/` at the repo root.
24
+ 4. **Confirm the chosen root in one line** before writing `00-scope-verdict.md`.
25
+
26
+ All `research/<target>/` paths in the harness are the *default form*, relative to the resolved `<corpus>/`.
27
+
28
+ ---
29
+
17
30
  # Part A — Scope-feasibility gate (Step 0)
18
31
 
19
32
  Run this **before** any dimension probing. It resolves the target's identity and emits one of four
@@ -146,11 +159,20 @@ The three named **cases** are presets over this vector — a target can light se
146
159
  (Liveblocks = source:full + runtime:reachable + auth:obtainable + presence:rich → nearly all
147
160
  dimensions). Rules:
148
161
  - **`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.
162
+ - **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
163
  - **Dimension-level access overrides the target headline** for method selection (a Case-1 target can still have a Case-3 session dimension).
150
164
  - 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
165
 
152
166
  Discovery records the resolved vector in the `access_grade` frontmatter of `00-recon-plan.md`.
153
167
 
168
+ > **Hypotheses are not facts (seed them tagged, never echo them).** Any *derived inference* Discovery
169
+ > makes beyond the four graded axes — e.g. "this `localStorage` key implies a GraphQL backend", "this
170
+ > host is the realtime endpoint" — is recorded in `00-recon-plan.md` **as a labelled hypothesis**, never
171
+ > as a plan fact, and is tagged `verify:may-be-stale` when seeded to a collector (CLAUDE.md Mode 2) so
172
+ > Ingestion **re-derives** rather than echoes it. A wrong inference seeded as framing propagates: a real
173
+ > run's `apolloAnonId ⇒ GraphQL` guess was repeated (hedged) by two captures before the `session` dimension
174
+ > refuted it (the backend was RSC + Server Actions; the key was an Apollo.io tracker).
175
+
154
176
  ---
155
177
 
156
178
  # Part C — The dimension catalog (Step 2)
@@ -163,7 +185,7 @@ Discovery records the resolved vector in the `access_grade` frontmatter of `00-r
163
185
  | 4 | **api** | `api` | runtime/presence | OpenAPI/GraphQL → endpoint catalog (+ **MCP/tool-catalog fold-in**) |
164
186
  | 5 | **website** | `website` | presence | crawl public pages → features, pricing, positioning |
165
187
  | 6 | **community** | `community` | presence | first-party changelog/issues/discord themes |
166
- | 7 | **session** | `session` | auth:have-login | delegate to the session playbook (§9 of `re-ingestion`: 3-pass, P0–P6) |
188
+ | 7 | **session** | `session` | auth:have-login | delegate to the session playbook (§9 of `ingestion`: 3-pass, P0–P6) |
167
189
  | 8 | **deployed-client-bundle** | `deployed-client-bundle` | runtime:reachable | unauth SPA: route table, API-path catalog, flags, env, source maps |
168
190
  | 9 | **infra-backend-fingerprint** | `infra-backend-fingerprint` | runtime/presence | DNS, cert-transparency, CDN/cloud, headers (+ **sub-processor/trust fold-in**) |
169
191
  | 10 | **wire-capture** | `wire-capture` | runtime (source:none) | the 3-rung ladder for non-browser/no-source clients (gated) |
@@ -172,6 +194,11 @@ Discovery records the resolved vector in the `access_grade` frontmatter of `00-r
172
194
  > **Deferred (available on request, not built):** `external-reputation` (G2/Reddit/HN — the only
173
195
  > "what others say" surface) and `hiring-intel` (job posts leak the backend stack). Strong
174
196
  > candidates, declined for this iteration. Re-add via self-correction if a run needs them.
197
+ > **Conditional trigger:** when `community` returns **no first-party feedback loop** (no public
198
+ > issues/roadmap/changelog/forum — feedback funnelled to a gated channel), flag `external-reputation`
199
+ > as **recommended-for-this-run** in `00-recon-plan.md`, so the user-sentiment blind spot is a surfaced
200
+ > choice rather than a silent gap (the `community` user-pain claims are then capped at tentative —
201
+ > evaluation closed-feedback cap).
175
202
 
176
203
  An **absent** dimension is a finding — record it with its evidence; never silently drop it.
177
204
 
@@ -182,15 +209,39 @@ See git history / the source playbook for the full strategy text; in brief:
182
209
  packages + internal dep hierarchy, return a per-package work-list for the main-session fan-out.
183
210
  - **docs** — prefer in-repo docs, then `llms.txt`/`llms-full.txt`, then crawl; organize by section.
184
211
  - **packages** — per public package: registry metadata, `exports` map + `.d.ts` type surface, health.
212
+ **Registry-ownership cheap-test (grade ownership before calling an SDK "partial/unverified").** Read
213
+ the registry `author`/`maintainers`/`summary`/`project_urls`/`Homepage` fields and check the
214
+ dependency set for a generator fingerprint (Stainless: `httpx`/`pydantic`/`anyio`/`distro`/`sniffio`
215
+ + in-file "generated by Stainless" headers; Speakeasy; OpenAPI-Generator). An `author`/`summary` that
216
+ says "official … library for the X API" + a vendor-domain `project_urls` confirms **official**
217
+ ownership at **high** confidence even when the *source* repo is private — the published tarball IS the
218
+ public-API mirror (a high-confidence `registry-metadata` anchor), so it is **not** "partial." Tag a
219
+ genuinely third-party/community package (different author/scope) as such, but don't down-grade an
220
+ official-but-private-source SDK to "unverified."
185
221
  - **api** — fetch the spec verbatim, build an endpoint catalog (auth, envelope, pagination, webhooks).
222
+ **Grade the method from a RETRIEVED artifact, never a label.** Before grading `openapi-verbatim`,
223
+ actually fetch the candidate spec URL and confirm a **parseable JSON/YAML body** — a docs page merely
224
+ *titled* "OpenAPI" with no served `spec.json` (or a `/swagger` that 403s) is `docs-reconstructed`
225
+ (capped medium), and Discovery must pre-grade it that way so the plan matches reality. **A
226
+ sibling-declared host/op/route count is a coverage checklist (a floor), never a ceiling** — every
227
+ collector expands from sibling-mined hosts/routes and records the predicted-vs-found delta.
186
228
  **NEW fold-in:** also probe MCP/tool surfaces — `/.well-known/mcp`, an MCP server manifest, a
187
229
  function-calling tool schema, an LLM "actions" file — and write `raw/tool-catalog.md` (an MCP tool
188
- list *is* an API catalog; it lives here, not in its own dimension).
230
+ list *is* an API catalog; it lives here, not in its own dimension). **Unauth MCP-probe recipe (when
231
+ the tool catalog itself is auth-gated):** a `GET /mcp` → `405` body often names the transport
232
+ (e.g. "stateless; only POST is supported" = streamable-HTTP); `GET /sse` presence/absence tells
233
+ legacy-SSE vs streamable; and `/.well-known/oauth-authorization-server` + `/.well-known/oauth-protected-resource/{name}`
234
+ reveal the **OAuth/PKCE model + issuer** (e.g. a `jwks_uri` on the auth vendor names Clerk/Auth0/etc.)
235
+ — all without a token. Capture transport + auth + issuer from these, reconstruct the tool list from
236
+ docs/SDK, and mark the verbatim `tools/list` **partial** (OAuth-gated).
189
237
  - **website** — crawl home/features/pricing/customers/integrations; extract positioning, pricing
190
238
  matrix, target market.
191
239
  - **community** — *first-party only*: changelog cadence + direction, issue/discussion themes, blog.
192
240
  - **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).
241
+ `ingestion` §9 (3-pass, P0–P6, captures/raw/curls). For any `auth:have-login`/`auth:claimed`
242
+ target, Discovery **seeds the Pass-2 decision** (`pass2: offered-pending | declined-by-user |
243
+ deferred`) into `00-recon-plan.md`, so a Pass-1-only (read-only) session is a *recorded choice*, not a
244
+ silent omission of the write surface (ingestion §9.2).
194
245
 
195
246
  ## 8 — deployed-client-bundle — `deployed-client-bundle`
196
247
 
@@ -198,15 +249,22 @@ See git history / the source playbook for the full strategy text; in brief:
198
249
  (marketing) and `session` (authenticated). Works on closed SaaS with no repo and no login.
199
250
 
200
251
  **Detection:** an app subdomain (`app.<target>.*`) or SPA route serves a JS bundle;
201
- `sourceMappingURL` present; a `/assets/*.js` graph.
252
+ `sourceMappingURL` present; a `/assets/*.js` graph. **Two cheap Discovery probes pre-grade the method
253
+ and surface a leak early:** (a) does an entry chunk's `sourceMappingURL` resolve to a `.map`-200? →
254
+ pre-grade `source-map-reassembly` (confidence high — original `src/` recovers). (b) probe a few
255
+ bootstrap-config paths (`/config`, `/backend/config/*`, `/env.json`, a runtime-config endpoint) — a
256
+ 200 here is both a method pre-grade and a possible unauth config/secret leak (a finding).
202
257
 
203
258
  **Strategy:** fetch the main bundle(s); string-mine the **route table**, the **API-path catalog**
204
- (→ shared `raw/api-path-catalog.md`, `source: bundle`), **feature flags** (→ shared
205
- `raw/feature-flags.md`), embedded **env config** (`VITE_*`, `NEXT_PUBLIC_*`, public keys —
206
- field-names only, redact values), and reassemble **source maps** if shipped (`method:
207
- source-map-reassembly`, confidence high). Digest huge bundles, don't paste.
259
+ (→ append to the shared `dimensions/_shared/api-path-catalog.md`, `source: bundle` — ingestion §6),
260
+ **feature flags** (→ shared `dimensions/_shared/feature-flags.md`), embedded **env config** (`VITE_*`,
261
+ `NEXT_PUBLIC_*`, public keys — field-names only, redact values), and reassemble **source maps** if
262
+ shipped (`method: source-map-reassembly`, confidence high). Digest huge bundles, don't paste. This
263
+ dimension **owns** the app-API bundle mine — other dimensions cite its catalog by path, never re-mine
264
+ the same bundle (ingestion §6).
208
265
 
209
- **Artifacts:** `_summary.md` + `raw/{route-table.md, api-path-catalog.md, feature-flags.md, env-config.md, bundle-map.md}`.
266
+ **Artifacts:** `_summary.md` + `raw/{route-table.md, env-config.md, bundle-map.md}` + appends to the
267
+ shared `dimensions/_shared/{api-path-catalog.md, feature-flags.md}`.
210
268
 
211
269
  ## 9 — infra-backend-fingerprint — `infra-backend-fingerprint`
212
270
 
@@ -231,12 +289,23 @@ what hosts it *might* call; the capture says what it *actually* calls.
231
289
  **Detection:** a non-browser client exists (from distribution-artifacts) OR an unauth SPA makes
232
290
  structured XHRs worth a tap, AND the appropriate ethics rung is authorized.
233
291
 
234
- **Strategy:** the **3-rung ladder** (lowest privilege first) — see `re-ingestion` §7.1:
292
+ **Strategy:** the **3-rung ladder** (lowest privilege first) — see `ingestion` §7.1:
235
293
  1. browser network tap (unauth, default) → `wire-tap-browser`;
236
294
  2. HAR export → `wire-har`;
237
- 3. mitmproxy (**gated, opt-in, user-run, first-party traffic only**) → `wire-mitmproxy`.
295
+ 3. mitmproxy (**gated, opt-in, user-run, first-party traffic only**) → `wire-mitmproxy`;
296
+ 4. **first-party SDK-harness** (when the product publishes an official SDK + the *user* can provision keys) — scaffold + instrument a throw-away client you own (`document_start` taps, full wire) → `sdk-harness` (`ingestion` §7.1). The deepest lane for a `runtime:reachable + source:none` product whose SDK is the only public mirror of the runtime; gated like rung 3.
297
+
298
+ **Fold note (common path):** when there is no separate non-browser client, wire-capture **folds into
299
+ `session`** (which owns the browser singleton), **never into a curl/WebFetch collector** (a non-browser
300
+ collector cannot run rung-1's in-page tap, and routing it there yields zero `source: wire` rows —
301
+ ingestion §7.1). The folded rung-1 *is* the interceptor `session` installs; its observed paths
302
+ append to the shared `dimensions/_shared/api-path-catalog.md` as `source: wire`. A folded wire-capture
303
+ still leaves a one-paragraph `_summary.md` (`status: folded`, naming the fold target) — never a silent
304
+ drop.
238
305
 
239
- **Artifacts:** `_summary.md` + `captures/wire-narrative.md` + `raw/{flows.json (redacted/digested), api-path-catalog.md (source: wire)}` + `curls.md`. Record the chosen rung + authorization in `_meta`.
306
+ **Artifacts:** `_summary.md` + `captures/wire-narrative.md` + `raw/flows.json (redacted/digested)` +
307
+ appends to shared `dimensions/_shared/api-path-catalog.md (source: wire)` + `curls.md`. Record the
308
+ chosen rung + authorization in `_meta`.
240
309
 
241
310
  ## 11 — distribution-artifacts — `distribution-artifacts`
242
311
 
@@ -251,9 +320,9 @@ capability map). **Electron** — `npx asar extract app.asar` → map JS modules
251
320
  route/API/flag catalog from the desktop client (often richer than web). **mobile** — `Info.plist`/
252
321
  `AndroidManifest` hosts, ATS exceptions, embedded-SDK list from strings (**redact any embedded
253
322
  keys**). **CLI** — help text/subcommands = an API catalog. Read the artifact's EULA first (see
254
- `re-ingestion` §7.2); never silently decompile a restrictively-licensed binary.
323
+ `ingestion` §7.2); never silently decompile a restrictively-licensed binary.
255
324
 
256
- **Artifacts:** `_summary.md` + `raw/{extension-manifest.md, electron-asar-map.md, mobile-strings.md, cli-catalog.md}` (whichever apply) + `raw/api-path-catalog.md` (source: distribution).
325
+ **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
326
 
258
327
  ---
259
328
 
@@ -23,6 +23,29 @@ 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
+ **OSS distribution clients are an independent corroboration lane.** An API-surface claim resting on a
31
+ single *third-party* wrapper (a community MCP server, an unofficial SDK) is tentative — but a
32
+ **first-party open-source integration client** (`distribution-artifacts`: a Unity/Figma/CLI plugin or
33
+ published SDK source) that calls the same routes is **independent of both marketing and the third-party
34
+ wrapper**, and corroborates it → promotes. (A legacy/granular route family seen only in a third-party
35
+ MCP becomes a real finding once the official OSS client calls it too.)
36
+
37
+ **Closed-feedback confidence cap.** When the `community` dimension finds **no first-party feedback
38
+ loop** (no public issues / roadmap / changelog / forum — feedback funnelled to a gated channel), its
39
+ user-pain / most-requested-feature claims are **inference-from-changelog only → capped at
40
+ `low`/tentative**, never promoted on changelog frequency alone. The surface that *would* corroborate
41
+ user sentiment is `external-reputation` (a deferred dimension) — flag it as recommended-for-this-run
42
+ when this cap fires (see discovery Part C deferred-dimension trigger).
43
+
44
+ **Write-side-unobserved cap.** A `session` dimension carrying `write_side_observed: false` (a
45
+ Pass-1-only run) has observed feature *existence/gating* but **not** feature *execution behavior*. Any
46
+ marketed generate/submit/launch *behavior* claim therefore stays **tentative and is never promoted to
47
+ fact** from marketing/docs alone — render the write-side gap **once** from the frontmatter flag, not
48
+ re-hedged per rollup.
26
49
 
27
50
  **Presentation mapping:** high → stated as fact; low/single-source → hedged as tentative;
28
51
  conflicted → flagged. (This is the "lighter" form of the provenance-weighting — done inline in the
@@ -58,11 +81,19 @@ prose, not via a separate `claims.yaml`.)
58
81
  # <Target> — Data Model & API / SDK Surface
59
82
  ## Core entities (domain objects + relations; ER-style — when the runtime exposes an RBAC verb
60
83
  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 — flag
62
- where the app's OWN API differs from the published/developer API; that split is common)
84
+ ## Integration surface (SDK/packages public API · REST/HTTP catalog · realtime/wire protocol)
85
+ ## Published-vs-app-own API diff (emit WHENEVER the target publishes a developer/partner/MCP API —
86
+ common for mature SaaS, but not universal. The app the SPA runs on is frequently
87
+ a different, broader, differently-authed API than the published one: list ops the
88
+ app uses that the public API omits, AND public ops the app never calls — both are
89
+ findings. If there is NO published API, say so explicitly: "no published API — the
90
+ app surface is the only surface" is itself the finding, not an empty section.)
63
91
  ## Auth & tenancy model (token type, where it lives, scope expression)
64
- ## Three-way API-path diff (the seam rule: bundle-declared vs session-observed vs wire-observed —
65
- dormant/unshipped routes are findings)
92
+ ## API-path diff (adaptive, N-way over the runtime sources present) (the seam rule: bundle-declared vs
93
+ session-observed vs wire-observed. Title it for the sources ACTUALLY run —
94
+ enumerate only those lanes; an absent lane [session blocked / wire folded] is a
95
+ recorded gap, NOT a structural hole to apologize for. Dormant/unshipped routes
96
+ are findings.)
66
97
  ## Cross-dimension reconciliation (published surface [api/packages/docs] vs observed wire [session/
67
98
  wire-capture]; document drift — published=fact, observed-drift=tentative)
68
99
  ## Open questions
@@ -104,3 +135,8 @@ prose, not via a separate `claims.yaml`.)
104
135
  4. Tag every claim with provenance; weight per the rules above; flag every disagreement; record
105
136
  every gap. A confident doc built on one low-confidence dimension is worse than an honest
106
137
  "single-source, unverified."
138
+
139
+ > **Classifying a raw observation** — to turn a storage-key prefix, an auth tell, an envelope shape,
140
+ > or a realtime frame into a *named* stack finding, use the fingerprint tables in
141
+ > `tradecraft.md` (storage→stack, auth-provider, API-envelope, realtime-trap). They name what
142
+ > a finding *is*; this file governs how confidently to *state* it.