@nurix/etna 0.20.4 → 0.20.5

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": "dfcdee7d275f",
2
+ "fingerprint": "e8ec199f3a00",
3
3
  "harnesses": {
4
4
  "code": {
5
5
  "plugin": "code",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "harness": "discover",
3
3
  "name": "discover",
4
- "version": "0.1.16",
4
+ "version": "0.1.17",
5
5
  "files": [
6
6
  ".prettierignore",
7
7
  ".prettierrc.json",
@@ -10,5 +10,5 @@
10
10
  "seeds": [],
11
11
  "tools": [],
12
12
  "docsRoot": "docs",
13
- "digest": "0bf7a6a6f479"
13
+ "digest": "15abe8b51cd9"
14
14
  }
@@ -292,6 +292,50 @@ the elements needing redaction change as you navigate.
292
292
  > redaction was real; the *frame* was never examined. **Never write a zero-PII assertion you did not verify
293
293
  > by looking at the image** — and prefer "redacted: <what>" over a blanket claim.)
294
294
 
295
+ ### 5.6 Reconstructing an ALGORITHM — differential testing, in separated layers
296
+
297
+ §5.4 says what a *catalog* capture must dump. This is the extra bar for the harder case: a dimension
298
+ that reconstructs **behaviour** — a scoring formula, a ranking function, a pricing calculation, a
299
+ matcher, a state machine. A word list can be checked by reading it. An algorithm cannot: it is only
300
+ `complete` once it has been **run against the live product on inputs chosen to break it**.
301
+
302
+ **The rule.** A reconstructed algorithm is `partial` until:
303
+
304
+ 1. It is **executable** and committed to the corpus, not merely described in prose.
305
+ 2. It has been **differentially tested against the live product** on a real corpus plus deliberately
306
+ adversarial inputs — not only on the examples it was derived from.
307
+ 3. The test **separates the estimator from the feature extraction**, and the per-layer pass rates are
308
+ recorded separately. One aggregate number is not enough.
309
+ 4. The inputs and the product's own observed outputs are frozen in `raw/` (or beside the
310
+ implementation) as **re-runnable fixtures**, so a later run can repeat the comparison.
311
+
312
+ **Why the layer split is the load-bearing part.** Almost every reconstruction has two independent
313
+ places to be wrong — the *computation* and the *inputs fed to it*. Tested together they are
314
+ indistinguishable, and the aggregate score points at whichever one you already suspect:
315
+
316
+ - **Layer A — the estimator.** Feed the algorithm **the product's own reported feature values** and
317
+ check it reproduces the product's own output. This tests the mathematics alone.
318
+ - **Layer B — the feature extraction.** Compare **your** computed features against the product's
319
+ reported features. This tests tokenisation / parsing / counting alone.
320
+ - **Layer C — end-to-end.** Both together. C failing while A passes localises the fault to B in one
321
+ step, with no re-derivation of a formula that was already right.
322
+
323
+ **A residual that survives a correct layer B is a finding about the TARGET, not an error in the
324
+ reconstruction** — and it is often the most valuable thing the dimension produces. Chase it; do not
325
+ tune it away. And when the target's behaviour is a defect, **do not silently replicate it** to make
326
+ the numbers match: implement the correct behaviour by default and put bug-parity behind an explicit,
327
+ documented flag. A reconstruction that quietly reproduces a bug teaches the next reader the bug.
328
+
329
+ > (Origin: hemingway — the run shipped a "validated" reference implementation of the app's readability
330
+ > scorer whose **formula was exactly right** and whose **tokenizer agreed with the target on only 41 of
331
+ > 62 real inputs**. A single end-to-end comparison read as *"the model is wrong"* and would have sent
332
+ > the run back to re-derive a correct formula. Splitting the test localised it immediately: layer A was
333
+ > **62/62** from the first run, and `Δletters = 0` in 20 of the 21 layer-B divergences pinned the fault
334
+ > to word/sentence segmentation, which was then reverse-engineered to **61/62**. The one residual that
335
+ > survived a correct tokenizer was **a defect in the product** — a literal `...` silently deletes the
336
+ > preceding text from every statistic — which no static lane could have found and which only appeared
337
+ > because adversarial inputs were included.)
338
+
295
339
  ---
296
340
 
297
341
  ## 6. The shared-surface seam rule (bundle ↔ session ↔ wire-capture)
@@ -509,6 +553,11 @@ Downloading a public binary (CRX/`.asar`/`.ipa`/`.apk`) and reading its manifest
509
553
 
510
554
  A capture is complete when: `_summary.md` exists with full provenance frontmatter + honest `status`; **every Finding is backed by a `raw/` artifact — an inline value is NOT sufficient (§5.3)**; the dimension's **§5.4 dump manifest is satisfied verbatim**; `raw/` artifacts carry `_meta` (with `verbatim:` and, if bounded, `sampling:`); redaction pass run; `gaps` recorded (never fabricated).
511
555
 
556
+ > **Algorithm reconstructions have an extra bar (§5.6):** if the dimension reconstructed *behaviour*
557
+ > rather than a catalog, it is `partial` until the implementation is executable, differentially tested
558
+ > against the live product with the **estimator and feature extraction scored as separate layers**, and
559
+ > the inputs + observed outputs are frozen as re-runnable fixtures. Record the per-layer pass rates.
560
+
512
561
  > **Self-check before writing `status: complete`:** count the verbatim artifacts in `raw/`. If that count is **zero**, the dimension is `partial` no matter how good the prose is — you have written an essay, not a capture. If a Finding names a number, a path, a version, or a field, open the file that contains it; if no such file exists, write it now (§5.3).
513
562
 
514
563
  **Summary-first + bounded, visible fan-out (never go silent long enough to look dead).** Write a `status: partial` `_summary.md` with whatever is mined so far **before** any long-tail fetch loop (downloading many chunks, crawling many pages, deep pagination), then enrich it in place and flip to `complete`. **Bound** every fan-out — cap it by count / total bytes / wall-time (e.g. ≤40 items or ≤90 s) and record the remainder as a `gap` rather than fetching exhaustively; emit a progress note per batch. A collector that fetches everything before writing anything can run many times longer than its siblings and read as hung to the orchestrator, forcing a needless salvage. Partial-but-finalized beats complete-but-silent.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nurix/etna",
3
- "version": "0.20.4",
3
+ "version": "0.20.5",
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": {
@@ -42,5 +42,5 @@
42
42
  "agent",
43
43
  "plugin"
44
44
  ],
45
- "etnaFingerprint": "dfcdee7d275f"
45
+ "etnaFingerprint": "e8ec199f3a00"
46
46
  }