@nurix/etna 0.18.6 → 0.18.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/README.md +2 -2
- package/bin/etna.js +4 -4
- package/data/harness-index.json +1 -1
- package/data/harnesses/code/agents/harness-manager.md +6 -6
- package/data/harnesses/code/harness.json +2 -3
- package/data/harnesses/code/skills/documentation/references/templates.md +3 -3
- package/data/harnesses/discover/harness.json +1 -2
- package/data/harnesses/discover/rules/discovery.md +2 -1
- package/data/harnesses/discover/rules/ingestion.md +1 -0
- package/data/harnesses/discover/rules/self-correction.md +1 -1
- package/data/harnesses/hr/harness.json +1 -2
- package/data/harnesses/kb-agi/harness.json +0 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -32,12 +32,12 @@ your-project/
|
|
|
32
32
|
├── rules/ ← general.md, nomenclature.md
|
|
33
33
|
├── hooks/ ← post-commit, post-tool-failure, session-stop + lib/redact (knowledge-ledger capture)
|
|
34
34
|
├── settings.json ← the hooks are deep-merged in here (your existing keys preserved)
|
|
35
|
-
└── harness.json ← {version,
|
|
35
|
+
└── harness.json ← {version, digest} — the installed-harness sentinel
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
That's the entire footprint. Nothing is written outside the project. No marketplace registration, no `enabledPlugins` entry, no global cache dependency — Claude Code picks up the project-scoped agents/skills/rules on its next session start, and the hooks wire in through `.claude/settings.json`.
|
|
39
39
|
|
|
40
|
-
Re-run `npx @nurix/etna --name=code` anytime to refresh the harness content with what the latest published package ships. Existing same-named files are overwritten; files you've added that aren't part of the harness are left alone. In a git repo the previous `CLAUDE.md` is overwritten in place (recover it with `git checkout CLAUDE.md`); outside a git repo it's backed up to `CLAUDE.md.bak.<ISO-timestamp>`. Because the new `harness.json` carries the installed `{version,
|
|
40
|
+
Re-run `npx @nurix/etna --name=code` anytime to refresh the harness content with what the latest published package ships. Existing same-named files are overwritten; files you've added that aren't part of the harness are left alone. In a git repo the previous `CLAUDE.md` is overwritten in place (recover it with `git checkout CLAUDE.md`); outside a git repo it's backed up to `CLAUDE.md.bak.<ISO-timestamp>`. Because the new `harness.json` carries the installed `{version, digest}`, a re-run whose **major** version is ahead of your repo's stamped `harness-version` is what the reconcile (below) detects as a structural upgrade.
|
|
41
41
|
|
|
42
42
|
## After install: bootstrap the harness
|
|
43
43
|
|
package/bin/etna.js
CHANGED
|
@@ -142,7 +142,7 @@ function migrateFromPluginInstall(targetDir, pluginName) {
|
|
|
142
142
|
return removed;
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
// Hook scripts shipped by earlier
|
|
145
|
+
// Hook scripts shipped by earlier harness versions (the legacy memory-ledger tier) and since retired.
|
|
146
146
|
// mergeHooks is additive, so an upgrade must explicitly remove both the stale settings.json
|
|
147
147
|
// entries pointing at these and the leftover script files they reference.
|
|
148
148
|
const RETIRED_HOOKS = ['session-stop.js', 'post-tool-failure.js', 'post-commit.js'];
|
|
@@ -264,7 +264,7 @@ async function installHarness(harnessName, harnesses) {
|
|
|
264
264
|
const targetDir = process.cwd();
|
|
265
265
|
const claudeMdDest = join(targetDir, 'CLAUDE.md');
|
|
266
266
|
|
|
267
|
-
// Bundled
|
|
267
|
+
// Bundled harness marker — names the version for the banner and carries the
|
|
268
268
|
// `files` list (project-root config shipped outside the plugin route).
|
|
269
269
|
const bundledHarnessJson = join(bundledHarnessDir, 'harness.json');
|
|
270
270
|
const harnessMeta = existsSync(bundledHarnessJson) ? readJson(bundledHarnessJson) : {};
|
|
@@ -304,7 +304,7 @@ async function installHarness(harnessName, harnesses) {
|
|
|
304
304
|
if (count > 0) installed.push(`${count} ${sub} → .claude/${sub}/`);
|
|
305
305
|
}
|
|
306
306
|
|
|
307
|
-
// Copy the
|
|
307
|
+
// Copy the harness marker so harness-manager can resolve the installed version.
|
|
308
308
|
if (existsSync(bundledHarnessJson)) {
|
|
309
309
|
const harnessJsonDest = join(targetDir, '.claude', 'harness.json');
|
|
310
310
|
mkdirSync(dirname(harnessJsonDest), { recursive: true });
|
|
@@ -324,7 +324,7 @@ async function installHarness(harnessName, harnesses) {
|
|
|
324
324
|
installed.push(`${rel} → ./${rel}`);
|
|
325
325
|
}
|
|
326
326
|
|
|
327
|
-
// Retire hooks earlier
|
|
327
|
+
// Retire hooks earlier harness versions shipped before merging, so the additive merge
|
|
328
328
|
// never resurrects an entry pointing at a script this bundle no longer carries.
|
|
329
329
|
for (const r of retireOldHooks(targetDir)) notices.push(`removed ${r}`);
|
|
330
330
|
|
package/data/harness-index.json
CHANGED
|
@@ -22,7 +22,7 @@ The upgrade story is the two run back-to-back: install refreshes the engine →
|
|
|
22
22
|
|
|
23
23
|
## Modes
|
|
24
24
|
|
|
25
|
-
- **Reconcile** (incl. **baseline**) — read the repo's `harness-version
|
|
25
|
+
- **Reconcile** (incl. **baseline**) — read the repo's `harness-version` (a semver); if absent or behind the installed **major**, converge `docs/` to the installed shape and stamp the installed version. A minor/patch gap means the mandated shape is unchanged — re-stamp only, no reshape. The Bootstrap invokes this.
|
|
26
26
|
- **Health** (on demand) — audit structural conformance to the installed spec. Report only; do not edit docs for content accuracy.
|
|
27
27
|
|
|
28
28
|
## The seam vs the `maintenance` agent
|
|
@@ -37,8 +37,8 @@ You never edit a doc for content fidelity (that is `maintenance`); `maintenance`
|
|
|
37
37
|
## Before starting
|
|
38
38
|
|
|
39
39
|
1. Verify a **root `CLAUDE.md` exists** before any reconcile. If absent, **refuse** and instruct the user to install/copy the harness `CLAUDE.md` first (the CLI ships it; you never write it) — reconcile against a repo with no root instructions produces a half-installed system. Detect-and-instruct, not a gate.
|
|
40
|
-
2. Resolve the **installed harness
|
|
41
|
-
3. Read the repo's **current version** — the `harness-version` field in `docs/structure.md` frontmatter. Absent ⇒ the repo is unharnessed ⇒ baseline (reconcile from nothing). Equal to installed ⇒ report and stop, **except** when re-invoked for the Step 6 module proposal: the version is already current from your first pass, so skip the stop and go straight to Step 6. (Health asked ⇒ run Health.) Behind ⇒ reconcile forward.
|
|
40
|
+
2. Resolve the **installed harness version** (semver) — read `version` from `.claude/harness.json`, shipped by the CLI at install. Never a number baked into this file. If `.claude/harness.json` is absent, the install predates the marker ⇒ instruct the user to re-run `npx @nurix/etna --name=code`, then retry. The resolved version is the target; its **major** is the structural-shape signal (a major bump is what used to be an "epoch" — it means the mandated `docs/` shape changed).
|
|
41
|
+
3. Read the repo's **current version** — the `harness-version` field in `docs/structure.md` frontmatter (a semver). Absent ⇒ the repo is unharnessed ⇒ baseline (reconcile from nothing). Equal to installed ⇒ report and stop, **except** when re-invoked for the Step 6 module proposal: the version is already current from your first pass, so skip the stop and go straight to Step 6. (Health asked ⇒ run Health.) Behind on **major** ⇒ reconcile forward (the mandated shape changed). Behind on only minor/patch ⇒ the shape is unchanged; re-stamp the version (Step 5) and stop — no reshape.
|
|
42
42
|
4. If `docs/memory/harness-manager.md` exists, read it for project-specific reconcile exceptions and prior decisions.
|
|
43
43
|
|
|
44
44
|
---
|
|
@@ -106,7 +106,7 @@ Scaffold `docs/memory/facts/` so the distilled tier has a home from day one: the
|
|
|
106
106
|
|
|
107
107
|
### Step 5 — Stamp the version
|
|
108
108
|
|
|
109
|
-
Write `harness-version: <installed
|
|
109
|
+
Write `harness-version: <installed version>` (the semver from `.claude/harness.json`) into `docs/structure.md` frontmatter. This single field is the repo's baseline-and-version sentinel — there is no second marker (no `epoch`).
|
|
110
110
|
|
|
111
111
|
### Step 5b — Register the qmd retrieval lens (optional, skip-if-absent)
|
|
112
112
|
|
|
@@ -157,9 +157,9 @@ Confirm all mandated files exist; `structure.md` carries the current `harness-ve
|
|
|
157
157
|
|
|
158
158
|
Conformance, not fidelity. Report a table; fix nothing destructively without asking.
|
|
159
159
|
|
|
160
|
-
- **Version currency** — `harness-version` present in `structure.md` and equal to installed? If behind/absent →
|
|
160
|
+
- **Version currency** — `harness-version` present in `structure.md` and equal to installed? If the **major** is behind → recommend Reconcile (the mandated shape changed); if only minor/patch behind/absent → note it (re-stamped on the next reconcile; no reshape needed). (This is the _repo-vs-installed_ gap — it self-heals once the consumer reinstalls and re-runs you. The next two checks catch what reinstall _hasn't_ happened yet, or was bypassed by a hand-edit.)
|
|
161
161
|
- **Published-version currency** _(advisory, network)_ — the installed `.claude/harness.json` records the kit's `version`; the published kit may have moved past it. Attempt `npm view @nurix/etna version` (the kit is a restricted package — needs npm auth + network). **Guard:** on _any_ failure — offline, no auth, npm absent, timeout — skip and report one line: _"couldn't check the published harness version — re-run `npx @nurix/etna --name=code` to refresh to the latest."_ On success, compare the published version against `.claude/harness.json`'s `version`; if published is ahead, recommend re-running the CLI to pull the newer kit. Never a gate, never blocks.
|
|
162
|
-
- **Kit build fingerprint (digest)** _(informational)_ — `.claude/harness.json` carries a `digest`: a deterministic fingerprint of the exact kit **build** the consumer installed (`build-data` computes it over the shipped bundle). Two installs share a digest iff they are byte-identical builds; a hotfix that changes kit bytes without bumping `version` still moves the digest — so it answers _which build am I on_, finer than `version
|
|
162
|
+
- **Kit build fingerprint (digest)** _(informational)_ — `.claude/harness.json` carries a `digest`: a deterministic fingerprint of the exact kit **build** the consumer installed (`build-data` computes it over the shipped bundle). Two installs share a digest iff they are byte-identical builds; a hotfix that changes kit bytes without bumping `version` still moves the digest — so it answers _which build am I on_, finer than `version` alone. **Don't recompute it over `.claude/` to self-check:** the installed layout is a superset of the build (the project `CLAUDE.md` sits at the repo root, `.claude/` adds `settings.json`/`harness.json`/local rule files), so paths and file sets differ **by design** — a recompute would never match. The actionable upgrade signals are the two checks above (major-version reconcile + published-version); the digest is provenance, and the seed for any future published-digest drift check.
|
|
163
163
|
- **Scaffold completeness** — every mandated file present.
|
|
164
164
|
- **Dissolved-version residue** — any `operations/guardrails.md`, repo-wide `docs/pillars/`, `architecture/overview.md`, a persisted `docs/boundaries/` tree, or other old-shape artifact lingering.
|
|
165
165
|
- **Module declaration coverage** — do the repo's bounded contexts have declared module homes where the author intended them? (Surface gaps; never auto-declare.)
|
|
@@ -77,13 +77,13 @@ Use for: defining which folder owns which topic and how docs are maintained.
|
|
|
77
77
|
|
|
78
78
|
```
|
|
79
79
|
---
|
|
80
|
-
harness-version:
|
|
80
|
+
harness-version: 1.0.0
|
|
81
81
|
---
|
|
82
82
|
|
|
83
83
|
# Documentation Structure
|
|
84
84
|
|
|
85
85
|
> This file is the entry point for understanding the docs folder.
|
|
86
|
-
> `harness-version` above is the repo's single baseline/version sentinel — the `harness-manager` agent owns it and stamps the installed
|
|
86
|
+
> `harness-version` above is the repo's single baseline/version sentinel — the `harness-manager` agent owns it and stamps the installed harness version (semver) on every reconcile.
|
|
87
87
|
|
|
88
88
|
## Authority Map
|
|
89
89
|
|
|
@@ -243,7 +243,7 @@ description: Shared knowledge accumulated across agent sessions. All agents shou
|
|
|
243
243
|
- **Baselined:** {today}
|
|
244
244
|
- **Structure:** v{harness-version} (architecture, features, operations, history, memory; + modules/, tests/ when present)
|
|
245
245
|
- **Spec version:** v{harness-version}
|
|
246
|
-
<!-- v{harness-version} resolves to the installed
|
|
246
|
+
<!-- v{harness-version} resolves to the installed harness version — read it from `.claude/harness.json` (`version`) / `docs/structure.md` frontmatter (`harness-version`); never hardcode a literal version here. -->
|
|
247
247
|
|
|
248
248
|
## Knowledge Tiers
|
|
249
249
|
|
|
@@ -132,6 +132,7 @@ The three named **cases** are presets over this vector — a target can light se
|
|
|
132
132
|
- **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.
|
|
133
133
|
- **Dimension-level access overrides the target headline** for method selection (a Case-1 target can still have a Case-3 session dimension).
|
|
134
134
|
- Method swaps on axis _value_: `source:full` ⇒ `clone-and-map`; `source:partial` ⇒ `source-map-reassembly`; `runtime:reachable + source:none` ⇒ `bundle-string-mine` + wire-capture.
|
|
135
|
+
- **`source:full` also unlocks a _runtime you own_ — prefer booting it locally over deferring the gated runtime lanes.** An OSS repo is not only `clone-and-map` read-surface: stand up the project's own **local dev / self-host** (`docker-compose` / dev quickstart) for a first-party `localhost` runtime, then run `session` / `wire-capture` / Cartography against it **without** the vendor's cloud login or any TOS/credential gate. **Code access via the public repo is the cornerstone of strategy** — for any open-source target, self-host is the preferred path to the runtime/experiential lanes (it converts an otherwise-gated experiential axis into a fully-authorized capture). Confirm before anything that spends or mutates; the local boot itself is you-own-it / read-only. (Origin: Twenty — `source:full` was read but the app was never booted, so the runtime lanes were deferred when a local `docker compose up` would have unlocked them.)
|
|
135
136
|
|
|
136
137
|
Discovery records the resolved vector in the `access_grade` frontmatter of `00-recon-plan.md`.
|
|
137
138
|
|
|
@@ -167,7 +168,7 @@ See git history / the source playbook for the full strategy text; in brief:
|
|
|
167
168
|
- **docs** — prefer in-repo docs, then `llms.txt`/`llms-full.txt`, then crawl; organize by section.
|
|
168
169
|
- **packages** — per public package: registry metadata, `exports` map + `.d.ts` type surface, health. **Registry-ownership cheap-test (grade ownership before calling an SDK "partial/unverified").** Read the registry `author`/`maintainers`/`summary`/`project_urls`/`Homepage` fields and check the dependency set for a generator fingerprint (Stainless: `httpx`/`pydantic`/`anyio`/`distro`/`sniffio`
|
|
169
170
|
- in-file "generated by Stainless" headers; Speakeasy; OpenAPI-Generator). An `author`/`summary` that says "official … library for the X API" + a vendor-domain `project_urls` confirms **official** ownership at **high** confidence even when the _source_ repo is private — the published tarball IS the public-API mirror (a high-confidence `registry-metadata` anchor), so it is **not** "partial." Tag a genuinely third-party/community package (different author/scope) as such, but don't down-grade an official-but-private-source SDK to "unverified."
|
|
170
|
-
- **api** — fetch the spec verbatim, build an endpoint catalog (auth, envelope, pagination, webhooks). **Grade the method from a RETRIEVED artifact, never a label.** Before grading `openapi-verbatim`, actually fetch the candidate spec URL and confirm a **parseable JSON/YAML body** — a docs page merely _titled_ "OpenAPI" with no served `spec.json` (or a `/swagger` that 403s) is `docs-reconstructed` (capped medium), and Discovery must pre-grade it that way so the plan matches reality. **A sibling-declared host/op/route count is a coverage checklist (a floor), never a ceiling** — every collector expands from sibling-mined hosts/routes and records the predicted-vs-found delta. **NEW fold-in:** also probe MCP/tool surfaces — `/.well-known/mcp`, an MCP server manifest, a function-calling tool schema, an LLM "actions" file — and write `raw/tool-catalog.md` (an MCP tool list _is_ an API catalog; it lives here, not in its own dimension). **Unauth MCP-probe recipe (when the tool catalog itself is auth-gated):** a `GET /mcp` → `405` body often names the transport (e.g. "stateless; only POST is supported" = streamable-HTTP); `GET /sse` presence/absence tells legacy-SSE vs streamable; and `/.well-known/oauth-authorization-server` + `/.well-known/oauth-protected-resource/{name}` reveal the **OAuth/PKCE model + issuer** (e.g. a `jwks_uri` on the auth vendor names Clerk/Auth0/etc.) — all without a token. Capture transport + auth + issuer from these, reconstruct the tool list from docs/SDK, and mark the verbatim `tools/list` **partial** (OAuth-gated).
|
|
171
|
+
- **api** — fetch the spec verbatim, build an endpoint catalog (auth, envelope, pagination, webhooks). **Grade the method from a RETRIEVED artifact, never a label.** Before grading `openapi-verbatim`, actually fetch the candidate spec URL and confirm a **parseable JSON/YAML body** — a docs page merely _titled_ "OpenAPI" with no served `spec.json` (or a `/swagger` that 403s) is `docs-reconstructed` (capped medium), and Discovery must pre-grade it that way so the plan matches reality. **Seed the warm-entry path that actually returned 200 in the probe — never a sibling that 403'd:** if `/rest/open-api/core` 403s while `/open-api/core` serves 200, the plan must name the **200** alias, else the collector inherits a dead path and burns a step re-deriving the working one mid-run (Twenty: recon seeded the 403 variant; the `api` collector had to re-find the live alias). **A sibling-declared host/op/route count is a coverage checklist (a floor), never a ceiling** — every collector expands from sibling-mined hosts/routes and records the predicted-vs-found delta. **NEW fold-in:** also probe MCP/tool surfaces — `/.well-known/mcp`, an MCP server manifest, a function-calling tool schema, an LLM "actions" file — and write `raw/tool-catalog.md` (an MCP tool list _is_ an API catalog; it lives here, not in its own dimension). **Unauth MCP-probe recipe (when the tool catalog itself is auth-gated):** a `GET /mcp` → `405` body often names the transport (e.g. "stateless; only POST is supported" = streamable-HTTP); `GET /sse` presence/absence tells legacy-SSE vs streamable; and `/.well-known/oauth-authorization-server` + `/.well-known/oauth-protected-resource/{name}` reveal the **OAuth/PKCE model + issuer** (e.g. a `jwks_uri` on the auth vendor names Clerk/Auth0/etc.) — all without a token. Capture transport + auth + issuer from these, reconstruct the tool list from docs/SDK, and mark the verbatim `tools/list` **partial** (OAuth-gated).
|
|
171
172
|
- **website** — crawl home/features/pricing/customers/integrations; extract positioning, pricing matrix, target market.
|
|
172
173
|
- **community** — _first-party only_: changelog cadence + direction, issue/discussion themes, blog.
|
|
173
174
|
- **session** — the deepest, opt-in, user-gated dimension; delegates to the session playbook in `ingestion` §9 (3-pass, P0–P6, captures/raw/curls). For any `auth:have-login`/`auth:claimed` target, Discovery **seeds the Pass-2 decision** (`pass2: offered-pending | declined-by-user | deferred`) into `00-recon-plan.md`, so a Pass-1-only (read-only) session is a _recorded choice_, not a silent omission of the write surface (ingestion §9.2).
|
|
@@ -127,6 +127,7 @@ Large artifacts (a 3 MB bundle, a 5 MB response, a 700-page sitemap) are **diges
|
|
|
127
127
|
|
|
128
128
|
- **One physical file, one canonical location, append-only.** The seam files live at `dimensions/_shared/api-path-catalog.md` and `dimensions/_shared/feature-flags.md` — **Ingestion seeds the two empty files (with a header) once, before the collector fan-out.** Every contributing dimension **appends a `source:`-tagged section** (`source: bundle | session | wire | distribution`) and **never creates its own copy**; each collector's `_summary.md` Artifacts list **links** the shared file rather than duplicating it. **Shared-seam allowlist:** these two filenames are the _only_ shared/single-physical artifacts — every other `raw/*` is dimension-private.
|
|
129
129
|
- Evaluation owns the **API-path diff** (an _adaptive N-way_ diff over whichever runtime sources were actually run — see evaluation template 3) in `data-model-api-surface.md`. A path that appears in `bundle` but never in `session`/`wire` is a dormant/unshipped route — a finding, not noise.
|
|
130
|
+
- **The cloned source tree is a shared working copy too (a sequencing race, not just the seam files).** On a `source:full` target, `codebase` clones into `source/<target>/`, and other dimensions (`docs`/`packages`) may read in-repo files from it. A clone-dependent collector dispatched **concurrently** with the clone can read a **mid-checkout tree** (a `.git`-only state) and silently fall back to a weaker source. So either (a) treat the `codebase` clone as a **sequencing barrier** — let it finish before dispatching any collector that reads `source/<target>/` — or (b) require each clone-dependent collector to **fetch its own copy** (GitHub API / its own shallow clone) and never assume the shared clone is ready. (Origin: Twenty — `docs` raced the `codebase` clone, saw a `.git`-only tree, and fell back to the live docs site; `packages` correctly fetched its own manifests and was unaffected.)
|
|
130
131
|
|
|
131
132
|
> **Same artifact ⇒ ONE source (never independent corroboration).** Two dimensions that string-mine the _same_ static asset (one bundle / one spec / one binary) are **one source** for the promotion rule — never a confidence band-bump — and their divergent counts are a **reported range, not a flagged conflict.** Name **one owner dimension per asset**: when `source:none` and no machine spec is served, `deployed-client-bundle` **owns** the app-API bundle mine, and `api` is re-scoped to the _published/partner_ spec only (or marked `partial` if none is served) — the others **cite the owner by path and do not re-mine**.
|
|
132
133
|
|
|
@@ -75,7 +75,7 @@ Inspect the run and emit **every** defect that fired, each as: `{mode, defect, s
|
|
|
75
75
|
| # | Axis (max) | How to score |
|
|
76
76
|
| --- | --- | --- |
|
|
77
77
|
| 1 | **Dimensional coverage** (15) | `15 × (dimensions captured 'complete' ÷ dimensions reachable per the access vector)`; **−3** per dimension blocked where Discovery predicted available. |
|
|
78
|
-
| 2 | **Experiential / IA coverage** (20) | the Cartography scorecard, fed in: `8 × feature_location_rate/100` + `6 × flow_coverage/100` + `4 × screenshot_coverage/100` + `2 ×` (`ia_nav_complete` ? 1 : surface-cards ÷ top-level-destinations); **−2** per _claimed-but-not-located_ feature left **un-dispositioned**. Floored at 0. _(the heavily-weighted axis: a run that collects feature pages but never locates / walks / diagrams / screenshots them scores low here.)_ |
|
|
78
|
+
| 2 | **Experiential / IA coverage** (20) | the Cartography scorecard, fed in: `8 × feature_location_rate/100` + `6 × flow_coverage/100` + `4 × screenshot_coverage/100` + `2 ×` (`ia_nav_complete` ? 1 : surface-cards ÷ top-level-destinations); **−2** per _claimed-but-not-located_ feature left **un-dispositioned**. Floored at 0. **When the session/experiential lane is deliberately deferred — gated by policy or no-login, NOT a tool failure — set `experiential_gated:true`:** keep the honest 0 on observed `flow_coverage`/`screenshot_coverage` (the run truly lacks live coverage), but **record the cause** beside the axis so cross-run comparison can tell a policy-deferral from a sloppy coverage miss — the annotation documents, it does **not** inflate the score. _(the heavily-weighted axis: a run that collects feature pages but never locates / walks / diagrams / screenshots them scores low here.)_ |
|
|
79
79
|
| 3 | **Provenance integrity** (15) | `7.5 × (captures with complete honest frontmatter ÷ all captures)` + `7.5 × (evaluation claims anchored+provenance-tagged ÷ all claims)`. |
|
|
80
80
|
| 4 | **Reconciliation correctness** (20) | start 20; **−3** per weighting violation (over-promotion, tiebreaker skipped, single-source-as-fact, count-divergence-as-conflict, published-vs-app diff missing where a public API exists, a UX-flow drawn observed on a `write_side_observed:false` run). |
|
|
81
81
|
| 5 | **Calibration & safety** (15) | gaps/absences recorded honestly + confidence bands honest, scaled to 15. **A redaction miss hard-zeros this axis** and flags the run `unsafe` regardless of the others. |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nurix/etna",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.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": {
|