{"_id":"@ariada-org/ai-authorship","name":"@ariada-org/ai-authorship","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@ariada-org/ai-authorship","version":"0.1.0","description":"AI authorship attribution — per-finding classifier for source code hunks. Multi-signal ensemble (lexical entropy + AST shape + naming cadence + edit-history rhythm) with calibrated posteriors. EU AI Act Article 50 transparency commodity surface. Open sour","license":"EUPL-1.2","type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"dependencies":{"@ariada-org/haes":"0.1.0"},"devDependencies":{"@types/node":"^22.10.0","rimraf":"^6.0.1","typescript":"^5.7.2","vitest":"^4.1.0","eslint":"^9.17.0","@vitest/coverage-v8":"^2.1.8"},"engines":{"node":">=22"},"keywords":["ai-authorship","ai-attribution","code-classification","eu-ai-act","article-50","transparency","calibrated-probability","ensemble-classifier","regulatory-tech","eupl"],"homepage":"https://ariada.org/packages/ai-authorship","repository":{"type":"git","url":"git+https://github.com/ariada-org/ariada.git","directory":"packages/ariada-ai-authorship"},"bugs":{"url":"https://github.com/ariada-org/ariada/issues"},"author":{"name":"Alekszandr Bricskin","email":"git@ariada.org","url":"Agonist Development AB"},"publishConfig":{"access":"public","provenance":true},"scripts":{"build":"tsc -p tsconfig.json","typecheck":"tsc -p tsconfig.json --noEmit","test":"vitest run","test:watch":"vitest","test:coverage":"vitest run --coverage","clean":"rimraf dist coverage","lint":"eslint src tests"},"_id":"@ariada-org/ai-authorship@0.1.0","_integrity":"sha512-z/OdTrvllcn80AsNAFGHk0sjW7Axb7lT1zJRUoFi74liZb4bT0gA7A0AtkJ02434lukAeWEUnFlVspxPufe0og==","_resolved":"/tmp/ed0ff813367508096828191422555164/ariada-org-ai-authorship-0.1.0.tgz","_from":"file:ariada-org-ai-authorship-0.1.0.tgz","_nodeVersion":"22.22.3","_npmVersion":"10.9.8","dist":{"integrity":"sha512-z/OdTrvllcn80AsNAFGHk0sjW7Axb7lT1zJRUoFi74liZb4bT0gA7A0AtkJ02434lukAeWEUnFlVspxPufe0og==","shasum":"b26d25b93caebbd98f0522876b2f778372c8a2d2","tarball":"https://registry.npmjs.org/@ariada-org/ai-authorship/-/ai-authorship-0.1.0.tgz","fileCount":81,"unpackedSize":135039,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@ariada-org%2fai-authorship@0.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIAGwYPExx8juGvfQS+yYz4JkJyPhXsVfMZyuh2DNDunFAiB96ziR9C+tZWCrbxmCIVn76nDy5m32WASPYcknpNx9Qg=="}]},"_npmUser":{"name":"agonist","email":"ab@agonist.ai"},"directories":{},"maintainers":[{"name":"agonist","email":"ab@agonist.ai"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ai-authorship_0.1.0_1781536547928_0.42768651400632485"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-15T15:15:47.784Z","0.1.0":"2026-06-15T15:15:48.081Z","modified":"2026-06-15T15:15:48.444Z"},"maintainers":[{"name":"agonist","email":"ab@agonist.ai"}],"description":"AI authorship attribution — per-finding classifier for source code hunks. Multi-signal ensemble (lexical entropy + AST shape + naming cadence + edit-history rhythm) with calibrated posteriors. EU AI Act Article 50 transparency commodity surface. Open sour","homepage":"https://ariada.org/packages/ai-authorship","keywords":["ai-authorship","ai-attribution","code-classification","eu-ai-act","article-50","transparency","calibrated-probability","ensemble-classifier","regulatory-tech","eupl"],"repository":{"type":"git","url":"git+https://github.com/ariada-org/ariada.git","directory":"packages/ariada-ai-authorship"},"author":{"name":"Alekszandr Bricskin","email":"git@ariada.org","url":"Agonist Development AB"},"bugs":{"url":"https://github.com/ariada-org/ariada/issues"},"license":"EUPL-1.2","readme":"<!-- SPDX-FileCopyrightText: 2025-2026 Agonist Development AB -->\n<!-- SPDX-License-Identifier: CC-BY-SA-4.0 -->\n\n# @ariada-org/ai-authorship\n\nPer-code-hunk AI-authorship attribution. Multi-signal ensemble (lexical\nentropy, AST shape, naming cadence, edit-history rhythm) with calibrated\nposteriors over a closed set of known AI coding assistants plus the\nexplicit categories `human` and `other`.\n\nComposes with [`@ariada-org/haes`](https://www.npmjs.com/package/@ariada-org/haes)\nso that a posterior attribution can be canonicalised (RFC 8785 JCS),\nsigned (Ed25519), and appended to a tamper-evident append-only ledger.\nThat composition supports transparency obligations on AI-generated content\nunder EU Regulation 2024/1689 (the EU AI Act) Article 50, enforceable\nfrom 2026-08-02.\n\n## Install\n\n```sh\nnpm install @ariada-org/ai-authorship\n```\n\n## Usage — offline mode (no network)\n\n```ts\nimport {\n  attributeOffline,\n  type AttributionInput,\n} from \"@ariada-org/ai-authorship\";\nimport { createHash } from \"node:crypto\";\n\nconst hashedEmail = createHash(\"sha256\")\n  .update(\"dev@example.com\")\n  .digest(\"hex\");\n\nconst input: AttributionInput = {\n  code: \"function add(a, b) {\\n  return a + b;\\n}\\n\",\n  diff_unified: \"+function add(a, b) {\\n+  return a + b;\\n+}\",\n  language: \"ts\",\n  commit_metadata: {\n    timestamp_utc: new Date().toISOString(),\n    git_author_email: hashedEmail,\n    commit_message: \"add: scalar add helper\",\n    prior_commit_timestamps: [],\n  },\n  file_path: \"src/add.ts\",\n};\n\nconst result = attributeOffline(input);\nif (result.ok) {\n  const top = result.value.posterior[0];\n  console.log(`top: ${top.agent} @ p=${top.probability.toFixed(3)}`);\n}\n```\n\n## Usage — hosted mode + transparency anchor\n\n```ts\nimport { attribute, anchorPosterior } from \"@ariada-org/ai-authorship\";\nimport {\n  HaesClient,\n  generateEd25519Keypair,\n  sha256Hex,\n} from \"@ariada-org/haes\";\n\nconst keypair = generateEd25519Keypair();\nconst client = new HaesClient({ signingKey: keypair });\n\nconst result = await attribute(input, {\n  api_key: process.env.ARIADA_API_KEY ?? \"\",\n});\nif (result.ok) {\n  const anchored = await anchorPosterior(result.value, {\n    client,\n    signing_key_id: keypair.keyId,\n  });\n  console.log(`entry_id=${anchored.entry.entry_id} top=${anchored.top_agent}`);\n}\n```\n\n## Public API\n\n| Export                                     | Type     | Description                                                                  |\n| ------------------------------------------ | -------- | ---------------------------------------------------------------------------- |\n| `attribute(input, override?)`              | function | Single-input inference; hosted by default, offline fallback when no API key  |\n| `attributeBatch(inputs, override?)`        | function | Batched inference — preferred for CI (single roundtrip per batch)            |\n| `attributeOffline(input)`                  | function | Synchronous offline-only inference; confidence capped at 0.6                 |\n| `extractSignals(input)`                    | function | Signal-extraction inspection without running the ensemble combiner           |\n| `anchorPosterior(posterior, opts)`         | function | Canonicalise + sign + append a posterior to a HAES chain                     |\n| `canonicalisePosterior(posterior)`         | function | Produce the canonical bytes + SHA-256 checksum                               |\n| `buildAnchorInclusionProof(entries, hash)` | function | Build a Merkle inclusion proof for an anchored posterior                     |\n| `AttributionPosterior`                     | type     | Output contract — sum-to-one posterior + signal contributions + version pins |\n| `AttributionInput`                         | type     | Per-hunk input contract                                                      |\n| `AIAgentId`                                | type     | Closed enum of supported agents (8 named + `human` + `other`)                |\n\n## Output invariants\n\nEvery `AttributionPosterior` satisfies:\n\n1. Probabilities sum to 1.0 ± 1e-6.\n2. Array length equals the canonical agent count (every agent present, including zero-probability ones).\n3. Sorted descending by probability; ties broken by canonical declaration order.\n4. `confidence ∈ [0, 1]`.\n5. Offline-mode `confidence ≤ 0.6`.\n6. `signal_contributions.length` equals the canonical signal count (4).\n7. Per-signal contributions sum approximately to zero across agents (signals are evidence, not bias).\n8. `classifier_version` and `calibration_version` are non-empty semver strings.\n\n## Inference modes\n\n- **Hosted** (default): the OSS client batches up to 256 inputs per request and posts to a hosted endpoint that runs the calibrated classifier. Confidence is uncapped. Authentication via bearer token (`ARIADA_API_KEY`).\n- **Offline**: pure-local execution using the bundled minimal classifier. Confidence is capped at 0.6 to mark the lower-fidelity surface. Suitable for air-gapped CI, on-premise compliance, and reproducibility audits.\n\nSet `ARIADA_ATTRIBUTION_OFFLINE=1` to force offline mode even when an API key is present.\n\n## Honest framing\n\nMethodology validation on a multi-language, multi-model corpus is not the\nsame as end-to-end production accuracy on real customer code. The\npublished research signal is not deployment telemetry. We do not claim\n\"validated on N customer sites\" today.\n\n## Calibration\n\nCalibration target is a Brier score ≤ 0.15 on per-class binary decomposition\nof the held-out validation split. The OSS reference implementation ships a\nno-op calibration suitable for the offline-mode classifier; the hosted\nclassifier ships the calibrated Platt-scaling + isotonic-regression overlay\nthat reaches the headline target.\n\nThe exposed `CalibrationParams` shape lets a researcher swap in a custom\ncalibration when reproducing the validation harness.\n\n## License\n\nEUPL-1.2. See `LICENSE`.\n","readmeFilename":"README.md","_rev":"1-93df35b11678601cf689672ab6049da0"}