{"_id":"@aikdna/kdna-eval","_rev":"6-e60f95d2f9442c87641872730721859e","name":"@aikdna/kdna-eval","dist-tags":{"latest":"0.3.2"},"versions":{"0.1.0":{"name":"@aikdna/kdna-eval","version":"0.1.0","keywords":["kdna","scoring","evaluation","dimension","judgment"],"license":"Apache-2.0","_id":"@aikdna/kdna-eval@0.1.0","maintainers":[{"name":"code2mp4","email":"hi@code2mp4.com"}],"homepage":"https://aikdna.com","bugs":{"url":"https://github.com/aikdna/kdna/issues"},"dist":{"shasum":"571359cf9ef27663ab6cd2328c7b557468628a2c","tarball":"https://registry.npmjs.org/@aikdna/kdna-eval/-/kdna-eval-0.1.0.tgz","fileCount":10,"integrity":"sha512-0YAQNMPLkceNlzgJwYMXhTRRBVj09+nY5Bp+Yb7tpzvE1/FUybjIRSfm3qIygNsqwVsQmdlZse7DaJAO3gC3KA==","signatures":[{"sig":"MEYCIQCOswTLRZO1Il6JFGRNJut2xr+1k9Z7vX5NbIJ/I0fEEQIhAK9SHpHc85AEpoTY2YpkvzD2GSaO9mbzdME8+jM4bFts","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":23046},"main":"src/index.js","type":"commonjs","types":"src/types.d.ts","module":"src/index.mjs","exports":{".":{"types":"./src/types.d.ts","import":"./src/index.mjs","require":"./src/index.js"},"./route":{"types":"./src/types.d.ts","import":"./src/route.mjs","require":"./src/route.js"},"./loader":{"types":"./src/types.d.ts","import":"./src/loader.mjs","require":"./src/loader.js"},"./package.json":"./package.json"},"gitHead":"c8e44c7f7ce0e78517bbcc68a6bcbda8125bba67","scripts":{"test":"node test/test-wrapper.js"},"_npmUser":{"name":"code2mp4","email":"hi@code2mp4.com"},"repository":{"url":"git+https://github.com/aikdna/kdna.git","type":"git","directory":"packages/kdna-eval"},"_npmVersion":"10.9.4","description":"KDNA runtime scoring primitives — configurable condition matching, dimension scoring, and multi-domain weighted evaluation.","directories":{},"_nodeVersion":"22.21.1","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/kdna-eval_0.1.0_1781177977509_0.9945400353618257","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@aikdna/kdna-eval","version":"0.2.0","keywords":["kdna","scoring","evaluation","dimension","judgment"],"license":"Apache-2.0","_id":"@aikdna/kdna-eval@0.2.0","maintainers":[{"name":"code2mp4","email":"hi@code2mp4.com"}],"homepage":"https://aikdna.com","bugs":{"url":"https://github.com/aikdna/kdna/issues"},"dist":{"shasum":"0b898ee5bff92772f149af990891fdde06dbce9a","tarball":"https://registry.npmjs.org/@aikdna/kdna-eval/-/kdna-eval-0.2.0.tgz","fileCount":22,"integrity":"sha512-DQzXrAHsBEiLBws9mzvtZX9EBna7tKMGwsdMYsV26jxMv0uZ+aIvt/NF+1rllAbHlJexH/pcXdLJstsUZl0Qeg==","signatures":[{"sig":"MEUCIHMsEDPXSkiGuO5G4poPXK/34RYX+RDVjEyESQ578jj/AiEA/CL+bdNHllh5zctAcwxh0Bpbu2B6kfQtya2fhd65wHg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":57881},"main":"src/index.js","type":"commonjs","types":"src/types.d.ts","module":"src/index.mjs","exports":{".":{"types":"./src/types.d.ts","import":"./src/index.mjs","require":"./src/index.js"},"./cost":{"types":"./src/types.d.ts","import":"./src/cost.mjs","require":"./src/cost.js"},"./gates":{"types":"./src/types.d.ts","import":"./src/gates.mjs","require":"./src/gates.js"},"./route":{"types":"./src/types.d.ts","import":"./src/route.mjs","require":"./src/route.js"},"./loader":{"types":"./src/types.d.ts","import":"./src/loader.mjs","require":"./src/loader.js"},"./replay":{"types":"./src/types.d.ts","import":"./src/replay.mjs","require":"./src/replay.js"},"./consume":{"types":"./src/types.d.ts","import":"./src/consume.mjs","require":"./src/consume.js"},"./route-card":{"types":"./src/types.d.ts","import":"./src/route-card.mjs","require":"./src/route-card.js"},"./package.json":"./package.json","./consumer-index":{"types":"./src/types.d.ts","import":"./src/consumer-index.mjs","require":"./src/consumer-index.js"}},"gitHead":"7ffa5c2f7139f8ddd02a4996d5217f2c7f897b48","scripts":{"test":"node test/test-wrapper.js"},"_npmUser":{"name":"code2mp4","email":"hi@code2mp4.com"},"repository":{"url":"git+https://github.com/aikdna/kdna.git","type":"git","directory":"packages/kdna-eval"},"_npmVersion":"10.9.8","description":"KDNA consumption evaluation framework — configurable scoring, multi-gate gating, replay regression, and cost tracking.","directories":{},"_nodeVersion":"22.22.3","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/kdna-eval_0.2.0_1783690585165_0.04085448837945238","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"@aikdna/kdna-eval","version":"0.3.1","keywords":["kdna","scoring","evaluation","dimension","judgment"],"license":"Apache-2.0","_id":"@aikdna/kdna-eval@0.3.1","maintainers":[{"name":"code2mp4","email":"hi@code2mp4.com"}],"homepage":"https://aikdna.com","bugs":{"url":"https://github.com/aikdna/kdna/issues"},"dist":{"shasum":"63e4ec8e3ffa7b2cf424fba8c1ed3ee0b76a64a6","tarball":"https://registry.npmjs.org/@aikdna/kdna-eval/-/kdna-eval-0.3.1.tgz","fileCount":27,"integrity":"sha512-3mxN1kjjNr0Cnjhc5JE2LLktclZcUCuil/RNFYEI6/LaLYmr01s+pA4iVS4jqz+z4palFulV3xTa85Gb4LKlKg==","signatures":[{"sig":"MEQCIFyGatFp26A2IaS5aRJC8Mj0H/MTbezyur5bk0EC334ZAiBX4pVP8L2+reNBNo2M7AG5/AiHLh3K52LeccO0I58YEg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aikdna%2fkdna-eval@0.3.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":115448},"main":"src/index.js","type":"commonjs","types":"src/types.d.ts","module":"src/index.mjs","exports":{".":{"types":"./src/types.d.ts","import":"./src/index.mjs","require":"./src/index.js"},"./cost":{"types":"./src/types.d.ts","import":"./src/cost.mjs","require":"./src/cost.js"},"./assay":{"types":"./src/types.d.ts","import":"./src/assay.mjs","require":"./src/assay.js"},"./gates":{"types":"./src/types.d.ts","import":"./src/gates.mjs","require":"./src/gates.js"},"./route":{"types":"./src/types.d.ts","import":"./src/route.mjs","require":"./src/route.js"},"./loader":{"types":"./src/types.d.ts","import":"./src/loader.mjs","require":"./src/loader.js"},"./replay":{"types":"./src/types.d.ts","import":"./src/replay.mjs","require":"./src/replay.js"},"./consume":{"types":"./src/types.d.ts","import":"./src/consume.mjs","require":"./src/consume.js"},"./route-card":{"types":"./src/types.d.ts","import":"./src/route-card.mjs","require":"./src/route-card.js"},"./package.json":"./package.json","./cluster-assay":{"types":"./src/types.d.ts","import":"./src/cluster-assay.mjs","require":"./src/cluster-assay.js"},"./consumer-index":{"types":"./src/types.d.ts","import":"./src/consumer-index.mjs","require":"./src/consumer-index.js"}},"gitHead":"92839b43ece35d3087bbc4955d09d8c1e8623335","scripts":{"test":"node test/test-wrapper.js","typecheck":"tsc --noEmit --strict --skipLibCheck false --lib es2022 src/types.d.ts","prepublishOnly":"npm test && npm run typecheck"},"_npmUser":{"name":"code2mp4","email":"hi@code2mp4.com"},"repository":{"url":"git+https://github.com/aikdna/kdna.git","type":"git","directory":"packages/kdna-eval"},"_npmVersion":"10.9.8","description":"KDNA consumption evaluation framework — configurable scoring, multi-gate gating, replay regression, and cost tracking.","directories":{},"_nodeVersion":"22.23.1","_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.9.3"},"_npmOperationalInternal":{"tmp":"tmp/kdna-eval_0.3.1_1783899976022_0.8012269718409726","host":"s3://npm-registry-packages-npm-production"}},"0.3.2":{"name":"@aikdna/kdna-eval","version":"0.3.2","keywords":["kdna","scoring","evaluation","dimension","judgment"],"license":"Apache-2.0","_id":"@aikdna/kdna-eval@0.3.2","maintainers":[{"name":"code2mp4","email":"hi@code2mp4.com"}],"homepage":"https://aikdna.com","bugs":{"url":"https://github.com/aikdna/kdna/issues"},"dist":{"shasum":"bdc633d6479e7b89d3212af2701454037e4f6a40","tarball":"https://registry.npmjs.org/@aikdna/kdna-eval/-/kdna-eval-0.3.2.tgz","fileCount":38,"integrity":"sha512-mdrerWERputbr7J7lPWO/387dWlnCrUjGUVkNxgMdJwDCyLyaF+W5XRT3TpUePbYNxQFpnIpjytohz6PT94MCA==","signatures":[{"sig":"MEYCIQCtxWyg75Lae97ZcBQBwgrCsjzpupuTX1etzsDBTz/l/wIhAPfYUt6FiJACK/2JtoKeQ5FI6xigQsOz+FeSKQN1zwdl","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aikdna%2fkdna-eval@0.3.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":214308},"main":"src/index.js","type":"commonjs","_from":"file:release-evidence/aikdna-kdna-eval-0.3.2.tgz","types":"src/types.d.ts","module":"src/index.mjs","exports":{".":{"types":"./src/types.d.ts","import":"./src/index.mjs","require":"./src/index.js"},"./cost":{"types":"./src/cost.d.ts","import":"./src/cost.mjs","require":"./src/cost.js"},"./assay":{"types":"./src/assay.d.ts","import":"./src/assay.mjs","require":"./src/assay.js"},"./gates":{"types":"./src/gates.d.ts","import":"./src/gates.mjs","require":"./src/gates.js"},"./route":{"types":"./src/route.d.ts","import":"./src/route.mjs","require":"./src/route.js"},"./loader":{"types":"./src/loader.d.ts","import":"./src/loader.mjs","require":"./src/loader.js"},"./replay":{"types":"./src/replay.d.ts","import":"./src/replay.mjs","require":"./src/replay.js"},"./consume":{"types":"./src/consume.d.ts","import":"./src/consume.mjs","require":"./src/consume.js"},"./route-card":{"types":"./src/route-card.d.ts","import":"./src/route-card.mjs","require":"./src/route-card.js"},"./package.json":"./package.json","./cluster-assay":{"types":"./src/cluster-assay.d.ts","import":"./src/cluster-assay.mjs","require":"./src/cluster-assay.js"},"./consumer-index":{"types":"./src/consumer-index.d.ts","import":"./src/consumer-index.mjs","require":"./src/consumer-index.js"}},"scripts":{"test":"node test/test-wrapper.js","typecheck":"tsc --noEmit --strict --skipLibCheck false --lib es2022 src/types.d.ts","release:check":"node ../../scripts/check-post-cutover-naming.mjs && node ../../scripts/check-scoped-release-readiness.mjs --package=packages/kdna-eval --scope=eval --label=eval","prepublishOnly":"npm run release:check && npm run release:evidence:check && npm test && npm run typecheck","release:evidence:check":"node ../../scripts/check-scoped-release-readiness.mjs --package=packages/kdna-eval --scope=eval --label=eval --evidence=release-evidence/artifact-manifest.json"},"_npmUser":{"name":"code2mp4","email":"hi@code2mp4.com"},"_resolved":"/home/runner/work/kdna/kdna/release-evidence/aikdna-kdna-eval-0.3.2.tgz","_integrity":"sha512-mdrerWERputbr7J7lPWO/387dWlnCrUjGUVkNxgMdJwDCyLyaF+W5XRT3TpUePbYNxQFpnIpjytohz6PT94MCA==","repository":{"url":"git+https://github.com/aikdna/kdna.git","type":"git","directory":"packages/kdna-eval"},"_npmVersion":"10.9.8","description":"KDNA consumption evaluation framework — configurable scoring, multi-gate gating, replay regression, and cost tracking.","directories":{},"_nodeVersion":"22.23.1","_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.9.3"},"_npmOperationalInternal":{"tmp":"tmp/kdna-eval_0.3.2_1784410196149_0.7518768330621908","host":"s3://npm-registry-packages-npm-production"}}},"time":{"created":"2026-06-11T11:39:37.334Z","modified":"2026-07-20T04:19:16.200Z","0.1.0":"2026-06-11T11:39:37.647Z","0.2.0":"2026-07-10T13:36:25.315Z","0.3.1":"2026-07-12T23:46:16.152Z","0.3.2":"2026-07-18T21:29:56.272Z"},"bugs":{"url":"https://github.com/aikdna/kdna/issues"},"license":"Apache-2.0","homepage":"https://aikdna.com","keywords":["kdna","scoring","evaluation","dimension","judgment"],"repository":{"url":"git+https://github.com/aikdna/kdna.git","type":"git","directory":"packages/kdna-eval"},"description":"KDNA consumption evaluation framework — configurable scoring, multi-gate gating, replay regression, and cost tracking.","maintainers":[{"name":"code2mp4","email":"hi@code2mp4.com"}],"readme":"# @aikdna/kdna-eval\n\nKDNA consumption evaluation framework — configurable scoring, multi-gate\ngating, replay regression detection, and cost/budget tracking.\n\nComplements `@aikdna/kdna-core` (loads and renders domains as prompt text)\nby executing evaluation pipelines at runtime.\n\nThis package is **generic infrastructure** — it contains no built-in domains,\npersonas, or product-specific defaults. Those belong in the consuming\napplication.\n\n## Consumption evaluation\n\n`@aikdna/kdna-eval` also provides primitives for evaluating how an application\nuses KDNA assets. These APIs help a runtime keep task selection, composition,\nprojection, cost, quality, and promotion decisions visible and testable.\n\n| Module | Purpose |\n| --- | --- |\n| `./replay` | Run and compare named replay modes. |\n| `./gates` | Combine independent runtime gates into one report. |\n| `./cost` | Track context budgets and asset counts. |\n| `./consume` | Reference route, compose, projection, quality, and promotion gates. |\n| `./route-card` | Load and apply route-card sidecars. |\n| `./consumer-index` | Load consumer-index sidecars with explicit enablement checks. |\n\nThese modules do not rank assets or certify their content. They provide\nbuilding blocks for a consuming application to apply its own policy and to\nrecord the evidence behind that policy.\n\n### Example\n\n```js\nconst { createConsumptionRunner } = require(\"@aikdna/kdna-eval/consume\");\n\nconst runtime = createConsumptionRunner({\n  policies: myPolicies,\n  budgetProfile: \"interactive\",\n});\n\nconst route = runtime.route(asset, { task: \"review\" });\nconst cost = runtime.cost(asset, { advisors: [] });\n```\n\nFor the command-line workflow, see the\n[KDNA CLI Consumption Runtime guide](https://github.com/aikdna/kdna-cli/blob/main/docs/consumption-runtime.md).\n\n## Quick Start\n\n```js\nconst { createEvaluator } = require(\"@aikdna/kdna-eval\");\n\nconst evaluator = createEvaluator({\n  dimensions: [\"clarity\", \"impact\"],\n  defaults: { clarity: 50, impact: 50 }\n});\n\nconst rules = [\n  { id: \"length-bonus\", dimensions: [\"clarity\"], condition: { path: \"text.length\", op: \"gt\", value: 20 }, effect: { value: 10 } }\n];\nconst domain = { id: \"my-domain\", schemaVersion: 1, x_eval: { rules } };\n\nconst results = evaluator.score(\n  [{ text: \"A substantive segment about technology\" }, { text: \"short\" }],\n  [{ id: \"my-domain\", data: domain }]\n);\n```\n\n## API\n\n### Main entry (`@aikdna/kdna-eval`)\n\n| Export | Description |\n|---|---|\n| `createEvaluator(options)` | Factory returning a configured evaluator with `score()` method |\n| `evaluateCandidates(candidates, domains, options?)` | Score multiple candidates across multiple domains |\n| `evaluateAxioms(candidate, rules, context?)` | Score a single candidate against one set of rules |\n| `evaluateCondition(candidate, condition, context?)` | Match a single condition |\n| `computeComposite(dimensions, weights?, dimNames?)` | Weighted dimension composite |\n| `getPath(obj, pathStr)` | Dot-separated path navigation |\n| `extractRules(domainData)` | Read `x_eval.rules` from domain (fallback to `axioms`) |\n| **0.2.0:** `createReplayEngine(options)` | Replay engine with 5 modes (repair, holdout, fresh, candidate-sealed, new-sealed) |\n| **0.2.0:** `createMultiGateRunner(gates)` | Multi-gate evaluation runner (route, compose, projection, cost, quality, promotion) |\n| **0.2.0:** `createCostTracker(profile)` | Context budget tracking (tokens, chars, assets) |\n\n### Loader (`@aikdna/kdna-eval/loader`)\n\nFlat JSON file loading from `~/.kdna/` directories. For standard `.kdna`\nZIP container loading, use `@aikdna/kdna-core`'s `loadKDNA()`.\n\n| Export | Description |\n|---|---|\n| `loadFlatDomainFromFile(fileName, kdnaDir?, defaults?)` | Load a flat JSON domain file |\n| `loadFlatDomainFromData(data, fileName?)` | Parse domain from object or JSON string |\n| `loadFlatDomains(names, options?)` | Batch load, preserves input order |\n| `listDomains(kdnaDir?)` | List `.kdna` / `.json` files |\n| `loadPersona(personaId, options?)` | Load a director persona |\n| `listPersonas(kdnaDir?, defaults?)` | List available personas |\n| `validateDomain(data, fileName?)` | Validate one flat domain object |\n| `validatePersona(data)` | Validate one persona object |\n\n`loadDomainFromFile`, `loadDomainFromData`, and `loadDomains` are aliases for\ntheir `loadFlat*` counterparts. `KDNA_DIR` exposes the default flat-file\ndirectory.\n\n### Route (`@aikdna/kdna-eval/route`)\n\n| Export | Description |\n|---|---|\n| `resolveDomains(operation, options?)` | Resolve domains for an operation with overrides |\n| `getRoutePolicy(operation, policies?)` | Get policy for a named operation |\n\n### Replay (`@aikdna/kdna-eval/replay`) — 0.2.0\n\nReplay engine for regression detection across five modes:\n\n| Export | Description |\n|---|---|\n| `createReplayEngine(options?)` | Create a replay engine with optional `store` and `logger` |\n| `REPLAY_MODES` | Array: `[\"repair\", \"holdout\", \"fresh\", \"candidate-sealed\", \"new-sealed\"]` |\n\nEngine API:\n- `replayRun(mode, { policy, fixtures, previousRun?, evaluate? })` → `{ mode, timestamp, inputHash, results, regressionFlags, summary }`\n- `compareRuns(runA, runB)` → `{ diff, scoreDelta }`\n- `isRegression(current, baseline, tolerance)` → `boolean`\n\n```js\nconst { createReplayEngine } = require(\"@aikdna/kdna-eval/replay\");\n\nconst engine = createReplayEngine();\nconst run = engine.replayRun(\"fresh\", {\n  fixtures: [{ id: \"f1\", text: \"hello\", score: 75, pass: true }],\n  policy: { id: \"p1\" }\n});\n// Check for regressions against previous run\nengine.compareRuns(run, previousRun);\n```\n\n### Gates (`@aikdna/kdna-eval/gates`) — 0.2.0\n\nMulti-gate evaluation with pluggable gate functions:\n\n| Export | Description |\n|---|---|\n| `createMultiGateRunner(gates?)` | Create runner; defaults to all 6 gates if omitted |\n| `aggregateGates(results)` | Aggregate gate results into `{ overall, passed_gates, failed_gates, blocked_gates }` |\n| `gateFromArray(results)` | Returns `true` only if all gates pass |\n| `GATE_NAMES` | Array: `[\"route\", \"compose\", \"projection\", \"cost\", \"quality\", \"promotion\"]` |\n\n```js\nconst { createMultiGateRunner } = require(\"@aikdna/kdna-eval/gates\");\n\nconst runner = createMultiGateRunner([\n  (ctx) => ({ gate: \"route\", pass: true, score: 0.95, details: {}, errors: [] }),\n  (ctx) => ({ gate: \"cost\", pass: true, score: 1.0, details: {}, errors: [] }),\n]);\nconst report = runner.runAll({ policy: myPolicy, fixtures: myFixtures });\n```\n\n### Cost (`@aikdna/kdna-eval/cost`) — 0.2.0\n\nContext budget tracking with built-in profiles:\n\n| Export | Description |\n|---|---|\n| `createCostTracker(profile)` | Create a tracker; `profile` can be `\"interactive\"`, `\"code-review\"`, `\"offline-audit\"`, or a `{ maxTokens, maxChars, maxAssets }` object |\n| `BUDGET_PROFILES` | Object mapping profile names to `{ maxTokens, maxChars, maxAssets }` limits |\n\nTracker API:\n- `trackAsset(asset)` — track one asset\n- `trackAdvisor(advisor)` — track one advisor\n- `isOverBudget()` → `boolean`\n- `getCostReport()` → structured report with consumption breakdown\n\n```js\nconst { createCostTracker } = require(\"@aikdna/kdna-eval/cost\");\n\nconst tracker = createCostTracker(\"code-review\");\ntracker.trackAsset({ id: \"domain-1\", tokens: 700, chars: 1000 });\ntracker.trackAdvisor({ id: \"system\", tokens: 200, content: \"...\" });\n\nconst report = tracker.getCostReport();\n// { profile: \"code-review\", consumed: { tokens: 900, chars: 1003, assets: 2 }, over_budget: false, ... }\n```\n\n## Scoring Rule Format\n\nRules live under `x_eval.rules` in domain data. `axioms` array at root is\naccepted as a backward-compatible fallback.\n\n```json\n{\n  \"id\": \"my-domain\",\n  \"schemaVersion\": 1,\n  \"x_eval\": {\n    \"rules\": [{\n      \"id\": \"my-rule\",\n      \"dimensions\": [\"clarity\"],\n      \"condition\": { \"path\": \"text.length\", \"op\": \"gt\", \"value\": 20 },\n      \"effect\": { \"value\": 10 }\n    }]\n  }\n}\n```\n\n**Condition operators:** `eq`, `gt`, `gte`, `lt`, `lte`, `between`\n\n**Effect fields:** `value`, `multiplyBy`, `clamp.min`, `clamp.max`\n\n## Integration with @aikdna/kdna-core\n\nkdna-core loads/validates `.kdna` containers; kdna-eval scores:\n\n```js\nconst { loadKDNA } = require(\"@aikdna/kdna-core\");\nconst { createEvaluator } = require(\"@aikdna/kdna-eval\");\n\nconst profile = await loadKDNA(\"my_domain.kdna\", { profile: \"full\" });\nconst evaluator = createEvaluator({ dimensions: [\"story\", \"rhythm\"] });\nconst results = evaluator.score(candidates, [\n  { id: profile.manifest.name, data: profile.domain }\n]);\n```\n\n## Version 0.3.2 TypeScript and ESM parity\n\nVersion 0.3.2 keeps the CommonJS, ESM, and TypeScript value exports in lockstep\nat the package root and at every documented subpath. TypeScript consumers can\nimport the replay, gate, cost, consumption, route-card, and consumer-index APIs\nfrom the package root or their matching subpaths, and ESM consumers receive the\nsame score constants and loader validators as CommonJS consumers.\n\nVersion 0.3.2 also closes implicit-evidence paths in Assay and Replay APIs:\n\n- Asset fixtures require a non-empty task and non-empty expected result;\n  malformed, duplicate, empty, or below-threshold fixture sets fail before the\n  runner is called.\n- Cluster fixtures require a non-empty expected primary asset. Empty,\n  malformed, or duplicate Cluster fixture sets cannot produce a passing Assay\n  verdict and are rejected before Replay invokes its engine.\n- Replay counts a result as passed only when it contains the explicit boolean\n  value `pass: true`. Missing or non-boolean pass evidence is counted as failed\n  and reported in `summary.incomplete`.\n- Cluster and advisor-ledger identifiers are non-empty strings at runtime and\n  in the strict TypeScript declarations.\n- Domain, Persona, RouteCard, and ConsumerIndex validators enforce their full\n  declared nested shapes, including fallback-loaded defaults. Consumer-index\n  resolution and trust checks return safe disabled results for malformed\n  indexes rather than trusting partial data.\n- Asset Assay requires exactly the four documented baseline arms, once each,\n  before invoking a runner. Empty, partial, duplicate, unknown, or malformed\n  arm sets fail closed regardless of relaxed thresholds.\n- Asset and Cluster dataset fingerprints hash canonical evaluation content,\n  including fixture IDs, tasks, categories, and expected evidence. Object key\n  order does not change the hash, while task or expectation changes do.\n  `created_at` and the derived `task_hash` are excluded from the fingerprint.\n- `generateEvidenceClaim(report, options)` requires `options.traceId` from a\n  real JudgmentTrace. It omits absent optional plan IDs and asset digests,\n  rejects malformed digests and fingerprints, and does not claim axiom coverage\n  because an Asset Assay does not observe per-trace axiom activation. Every\n  planned baseline execution must produce a result; runner errors fail the\n  `execution_evidence` threshold and cannot become behavior-evaluated evidence.\n- Route policy lookup accepts only an operation's own validated data property.\n  Prototype members, accessors, inherited policy fields, and malformed domain\n  records are rejected; inherited, accessor-based, or non-finite domain\n  overrides are rejected without executing their getters.\n- Fixture evidence must be deterministic JSON data: cycles, `BigInt`,\n  `undefined`, functions, symbols, sparse arrays, accessors, and non-plain\n  nested objects are rejected before an Assay runner or Replay engine executes.\n- Cluster manifest identifiers, descriptions, domain load conditions, and\n  composition strategies are validated before a strongly typed report is\n  created. Missing optional identifiers retain the documented `unknown` and\n  `0.1.0` defaults.\n- A passing Cluster Assay requires a valid plan with exactly one selected\n  primary, unique selected/rejected IDs, explicit advisor contribution\n  hypotheses and rejection reasons, and fixture expectations that exactly\n  match the selected primary, advisor set, rejected set, and conflict count.\n- Loaded evidence requires exactly one verified and authorized primary matching\n  the plan, every selected advisor loaded as `advisor`, no rejected asset\n  loaded, unique IDs, and only `primary`, `advisor`, or `control` roles.\n- All seven `CLUSTER_COMPARISON_ARMS` are required exactly once. Each record\n  binds the exact fixture ID set, a finite 1–5 mean score, a result count equal\n  to the fixture count, and a valid critical-error count.\n- Passing economics evidence requires explicit positive plan limits, an asset\n  count matching the selected primary and advisors, plus observed nonnegative\n  token and model-call counts. An observed `tokens_used: 0` is preserved rather\n  than replaced by an estimate.\n- Cluster plan types distinguish executable `applies` plans from canonical\n  non-executable `blocked` plans. A blocked plan may record a zero-consumption\n  budget without `max_tokens`; the Assay reports `plan_status: \"blocked\"`, does\n  not call it malformed, and never allows any gate or verdict to pass.\n- The standalone `economicsGate(plan, executionCost)` requires both evidence\n  objects and fails closed on missing or malformed values. `runClusterAssay()`\n  and `runClusterAssay({})` remain supported diagnostic calls and always fail\n  without promotion evidence.\n- Replay generates deterministic non-empty string fallback IDs for fixtures\n  whose own or input IDs are absent, empty, or non-string. Malformed custom\n  evaluator results are incomplete failures, and arbitrary values thrown by a\n  multi-gate function are normalized to string errors. Custom gate returns must\n  provide the complete `GateResult` shape through own enumerable data\n  properties before they can pass aggregation. Accessors and inherited fields\n  are never read, and accepted results are detached into safe copies;\n  standalone behavioral and product gates likewise reject malformed evidence\n  without throwing or coercing it into a pass.\n\n## Version 0.3.1 Assay Contracts\n\nVersion 0.3.1 adds fail-closed Asset and Cluster Assay behavior exported from both the package\nroot and `@aikdna/kdna-eval/cluster-assay`:\n\n- structural gate — qualified primary and bounded advisor selection;\n- behavioral gate — at least `+0.30` over primary-only;\n- economics gate — asset count and execution budget;\n- trust gate — observed authorization and digest verification only;\n- product gate — operable, non-placeholder Cluster definition.\n\nAll five gates are fail-closed. A gate with missing evidence is `not_run` and\ncannot produce a passing promotion verdict. Plan selection is not accepted as\nproof that an asset was loaded.\n\n## Version 0.2.0 Capabilities\n\n- **Replay Engine** (`replay.js`): Five-mode replay for regression detection\n- **Multi-Gate Runner** (`gates.js`): Pluggable gate composition with pass/fail aggregation\n- **Cost Tracker** (`cost.js`): Budget profiles for interactive, code-review, and offline-audit contexts\n\nAll new modules use synthetic/constructed data only — no private fixtures.\n\n## License\n\nApache-2.0\n","readmeFilename":"README.md"}