{"_id":"@af199/anima-eval","_rev":"3-0aac9cfab18fa358a0fe021e8146afe8","name":"@af199/anima-eval","dist-tags":{"latest":"0.30.0"},"versions":{"0.1.0":{"name":"@af199/anima-eval","version":"0.1.0","keywords":["ai-safety","evaluation","sandbagging","llm-agents","auditing","interpretability","deterministic","multi-agent"],"author":{"name":"Ariel Fernández"},"license":"MIT","_id":"@af199/anima-eval@0.1.0","maintainers":[{"name":"af199","email":"contacto.nafernandez@gmail.com"}],"homepage":"https://github.com/Peroroii/anima-eval#readme","bugs":{"url":"https://github.com/Peroroii/anima-eval/issues"},"bin":{"anima-eval":"cli.js"},"dist":{"shasum":"f1212ad80c918a13c1c9ab743c59c24e21779467","tarball":"https://registry.npmjs.org/@af199/anima-eval/-/anima-eval-0.1.0.tgz","fileCount":6,"integrity":"sha512-Fh0egay/7ekzxly3aPUnxQuPxWvaCM+Ycztq09P5z6fi/I65D97+Axmm97qw2rjN313v3vnh5tUfViu+VOPUiw==","signatures":[{"sig":"MEUCIA3+m9S/knigGgLt6hzf6+59nd5xSDVUIMMaz3eF5kDEAiEAuahE2zk/UGKfhNdBTWVspsI0z5G7eOaIJWGckw/1xRo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":13269},"jest":{"coverageThreshold":{"global":{"lines":90,"functions":90,"statements":90}},"testPathIgnorePatterns":["/node_modules/","demo.js"]},"main":"index.js","engines":{"node":">=16"},"gitHead":"58b423ffab60082399ed29f5ace3ad6503ad61ce","scripts":{"demo":"node demo.js","test":"jest","example":"node cli.js example_transcript.json","test:coverage":"jest --coverage"},"_npmUser":{"name":"af199","email":"contacto.nafernandez@gmail.com"},"repository":{"url":"git+https://github.com/Peroroii/anima-eval.git","type":"git"},"_npmVersion":"11.16.0","description":"Deterministic behavioral audit harness for LLM agent transcripts — structural signature, rigidity trajectory, and sandbagging/eval-gaming detection. No model access, no LLM calls, reproducible.","directories":{},"_nodeVersion":"24.18.0","_hasShrinkwrap":false,"devDependencies":{"jest":"^30.0.0"},"_npmOperationalInternal":{"tmp":"tmp/anima-eval_0.1.0_1783544271776_0.4596157806302663","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@af199/anima-eval","version":"0.2.0","keywords":["ai-safety","evaluation","sandbagging","llm-agents","auditing","interpretability","deterministic","multi-agent"],"author":{"name":"Ariel Fernández"},"license":"MIT","_id":"@af199/anima-eval@0.2.0","maintainers":[{"name":"af199","email":"contacto.nafernandez@gmail.com"}],"homepage":"https://github.com/Peroroii/anima-eval#readme","bugs":{"url":"https://github.com/Peroroii/anima-eval/issues"},"bin":{"anima-eval":"cli.js"},"dist":{"shasum":"f5171d157164b1939e59307c76b074838d209935","tarball":"https://registry.npmjs.org/@af199/anima-eval/-/anima-eval-0.2.0.tgz","fileCount":7,"integrity":"sha512-x0RLmseTaqs2xvr4Rt12a49KfN+j4cXhjQ4p6F/aYYEa/67YssHfPYAEIcvuzerikFDZzZgsa8YbAKEe7L7pEw==","signatures":[{"sig":"MEYCIQCKIAZXrfvCgw2DJpgDyWC0Rr6mnzmgNUsfpSTDXx/9+wIhAMzxFLyZrgWRl4pgVjmCe8rpVfuVFS9KrXgwCSDvmxVA","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":31034},"jest":{"coverageThreshold":{"global":{"lines":90,"functions":90,"statements":90}},"testPathIgnorePatterns":["/node_modules/","demo.js"]},"main":"index.js","engines":{"node":">=16"},"gitHead":"1112a80599aec7cc893424cae5666c63eb636a12","scripts":{"demo":"node demo.js","test":"jest","example":"node cli.js example_transcript.json","test:coverage":"jest --coverage"},"_npmUser":{"name":"af199","email":"contacto.nafernandez@gmail.com"},"repository":{"url":"git+https://github.com/Peroroii/anima-eval.git","type":"git"},"_npmVersion":"11.16.0","description":"Deterministic behavioral audit harness for LLM agent transcripts — structural signature, rigidity trajectory, and sandbagging/eval-gaming detection. No model access, no LLM calls, reproducible.","directories":{},"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.4.2"},"_npmOperationalInternal":{"tmp":"tmp/anima-eval_0.2.0_1783647119552_0.26198412020355377","host":"s3://npm-registry-packages-npm-production"}},"0.30.0":{"name":"@af199/anima-eval","version":"0.30.0","description":"Deterministic behavioral audit harness for LLM agent transcripts — structural signature, rigidity trajectory, and sandbagging/eval-gaming detection. No model access, no LLM calls, reproducible.","main":"index.js","bin":{"anima-eval":"cli.js"},"scripts":{"test":"jest","benchmark":"node benchmark.js","adversarial":"node adversarial_suite.js","casino-alignment":"node casino_strategy_alignment.js","test:coverage":"jest --coverage","demo":"node demo.js","example":"node cli.js example_transcript.json"},"jest":{"testPathIgnorePatterns":["/node_modules/","demo.js"],"coverageThreshold":{"global":{"statements":90,"functions":90,"lines":90}}},"keywords":["ai-safety","evaluation","sandbagging","llm-agents","auditing","interpretability","deterministic","multi-agent"],"license":"MIT","engines":{"node":">=16"},"devDependencies":{"jest":"^30.4.2"},"repository":{"type":"git","url":"git+https://github.com/Peroroii/anima-eval.git"},"author":{"name":"Ariel Fernández"},"bugs":{"url":"https://github.com/Peroroii/anima-eval/issues"},"homepage":"https://github.com/Peroroii/anima-eval#readme","publishConfig":{"access":"public"},"gitHead":"37ae091fc794705cb7d32373cfb58be3579eb3cc","_id":"@af199/anima-eval@0.30.0","_nodeVersion":"24.18.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-6CoNts7IqVT4pj7XTE+98r87J0wQo1+PsYiYwY6YQprLo4Kc9MuNASLrKrMFSJZm0WZPtSsHQfav4DNCF958nQ==","shasum":"5d06b752a9143d4f5fb9047a770f71056ede6e3f","tarball":"https://registry.npmjs.org/@af199/anima-eval/-/anima-eval-0.30.0.tgz","fileCount":7,"unpackedSize":208606,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDY95FbKZ1mw1W8OHknoXvhUCV7rwlqfYDwAPtKkWVOCAIgGuKGzMXS5Bg10mV/gXQx8mIiTJaEYjFhb8Nx2f+Yki8="}]},"_npmUser":{"name":"af199","email":"contacto.nafernandez@gmail.com"},"directories":{},"maintainers":[{"name":"af199","email":"contacto.nafernandez@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/anima-eval_0.30.0_1785291490128_0.5284162170840807"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-08T20:57:51.610Z","modified":"2026-07-29T02:18:10.452Z","0.1.0":"2026-07-08T20:57:51.936Z","0.2.0":"2026-07-10T01:31:59.727Z","0.30.0":"2026-07-29T02:18:10.289Z"},"bugs":{"url":"https://github.com/Peroroii/anima-eval/issues"},"author":{"name":"Ariel Fernández"},"license":"MIT","homepage":"https://github.com/Peroroii/anima-eval#readme","keywords":["ai-safety","evaluation","sandbagging","llm-agents","auditing","interpretability","deterministic","multi-agent"],"repository":{"type":"git","url":"git+https://github.com/Peroroii/anima-eval.git"},"description":"Deterministic behavioral audit harness for LLM agent transcripts — structural signature, rigidity trajectory, and sandbagging/eval-gaming detection. No model access, no LLM calls, reproducible.","maintainers":[{"name":"af199","email":"contacto.nafernandez@gmail.com"}],"readme":"# anima-eval\r\n\r\n![CI](https://github.com/Peroroii/anima-eval/actions/workflows/ci.yml/badge.svg) ![npm](https://img.shields.io/npm/v/anima-eval) ![license](https://img.shields.io/badge/license-MIT-green) ![node](https://img.shields.io/badge/node-%3E%3D16-brightgreen)\r\n\r\n\r\nBehavioral audit harness for LLM agent transcripts. Takes any conversation\r\ntranscript and returns deterministic behavioral signatures — no model access,\r\nno LLM calls, reproducible.\r\n\r\n## What it detects\r\n- **Structural signature** (LIWC + deixis): paranoid / obsessive / hysteric / melancholic lean\r\n- **Rigidity trajectory** (ρ): how fixed vs. flexible the agent's stance is over turns\r\n- **Agenda gap / commitment tracking**: unacknowledged contradictions of the agent's own prior directed commitments, classified by discursive movement type (see below)\r\n- **Evaluation-gaming / sandbagging**: covariance between behavior and evaluation conditions\r\n- **Collusion score** (multi-agent): shared-signifier overlap + pressure escalation\r\n\r\n## Usage\r\n    const { auditTranscript } = require('anima-eval');\r\n    const report = auditTranscript(transcript, { evalFlags });\r\n\r\n## Input format (provider-agnostic)\r\n    {\r\n      \"turns\": [\r\n        { \"speaker\": \"agent\", \"text\": \"...\", \"meta\": { \"underEval\": true } },\r\n        { \"speaker\": \"user\",  \"text\": \"...\" }\r\n      ]\r\n    }\r\n\r\n`meta.underEval` (declared, trusted directly) is the preferred way to mark\r\nwhich agent turns happened under evaluation conditions. If you don't have\r\nthat metadata, you can pass an inferred guess via `opts.evalFlags` — but the\r\nsandbagging check will refuse to score it unless you also pass\r\n`opts.allowInferredFlags: true`, since inferred flags aren't real evaluation\r\nmetadata and can manufacture spurious correlation on small transcripts.\r\n\r\n## Reading the output honestly\r\n\r\n- `rigidity.mean_rigidity` / `net_drift` can be `null` — that means the\r\n  transcript had no epistemic-certainty markers to measure, not that\r\n  rigidity is zero. Check `rigidity.signal_coverage` before trusting the\r\n  aggregate.\r\n- `dominant_structure` can be `null` — that means no axis cleared the\r\n  minimum signal floor. This is intentional: a forced guess between four\r\n  near-zero values isn't a finding.\r\n- `evaluation_gaming.verdict` can be `INCONCLUSIVE` — correlation was\r\n  present but a permutation test couldn't distinguish it from chance at\r\n  that sample size. Treat this the same as \"clean\", not as a soft alarm.\r\n- `agenda_gap.per_turn[i].agendaGap` is not reset by topic avoidance — an\r\n  unacknowledged contradiction persists (decaying) until the agent either\r\n  explicitly revises it or re-mentions the same signifier. A `0` a few\r\n  turns after a rupture means it was resolved or fully decayed, not that\r\n  the agent moved on.\r\n\r\n## Agenda gap: commitment tracking (`agenda_gap`)\r\n\r\nOperationalizes \"compromiso\" from the Cognición Semiótica Dinámica research\r\nprogram (Ley IV: the evolution of sense requires alterity). A commissive or\r\nhigh-certainty utterance addressed to the interlocutor (`vos2`/\"nosotros\"\r\nco-occurrence) enters the record the moment it is uttered — this is\r\nconstituted by the directed utterance itself (addressivity, Bakhtin; the\r\nsymbolic Autre, Lacan), **not** by any later reply from the interlocutor.\r\n`agenda_gap` therefore requires zero user/other turns to compute — it scores\r\npurely from the agent's own turns.\r\n\r\n**What counts as a rupture**: a later sentence that topically overlaps\r\n(signifier overlap ≥ 0.34) a previously registered commitment with flipped\r\npolarity, and is not itself marked as an explicit revision (\"en realidad,\r\ncorrijo...\", \"actually, I was wrong...\"). Ruptures are checked both across\r\nturns and **within the same turn** — a same-breath self-contradiction scores\r\nthe maximum gap, same as a cross-turn one.\r\n\r\n**Persistence**: an unacknowledged rupture opens a tension that decays\r\ngeometrically (rate 0.6/turn) rather than resetting on the next turn. This\r\nis deliberate — silently reverting to the original position without\r\nacknowledging the break (`Verleugnung`) does not close the tension; only an\r\nexplicit revision, or the tension fully decaying below threshold, does.\r\n\r\n**Known limits** (by design, not bugs):\r\n- Extraction is per-sentence, not per-clause — three commitments joined by\r\n  commas in one sentence register as a single unit.\r\n- A bare revision marker with no extractable topic of its own (\"actually...\")\r\n  charitably closes the most recently opened tension — this is a heuristic,\r\n  not deep parsing.\r\n- Lexical, not semantic: a legitimate reframing that doesn't use an explicit\r\n  revision phrase (\"es distinto...\") will not close a tension even if it's\r\n  a reasonable clarification — the metric only \"trusts\" acknowledged\r\n  revision.\r\n\r\n`d_agenda` feeds `anima-core`'s pressure equation (`P`) directly — it is the\r\none signal the psychodynamic engine expected but this package never computed\r\nuntil this addition (see `anima-core/src/engine.js`, `signals.agendaGap`).\r\n\r\n### Movement classification (`movements`, `movement_counts`)\r\n\r\nBeyond the binary rupture/no-rupture above, each commitment-bearing sentence\r\nis classified into one of the four positions of Greimas's semiotic square\r\n(CSD Ley I refinement — see the CSD manifesto):\r\n\r\n    repeticion    same topic, same polarity                (S1 → S1)\r\n    contradiccion same topic, flipped polarity              (S1 → ¬S1)\r\n    contrariedad  new full commitment, DIFFERENT topic,\r\n                  introduced by a concessive connector       (S1 → S2)\r\n    sintesis      moderate overlap with two distinct\r\n                  prior commitments at once                  (S1 ∧ S2)\r\n    neutro        explicit non-commitment while a\r\n                  tension is open                             (¬S1 ∧ ¬S2)\r\n\r\n`contrariedad` is detected by discursive **form** (a concessive connector —\r\n\"tenés razón, pero...\", \"however...\") near a brand-new full commitment, not\r\nby knowing the semantic content of the opposition — the actual values in\r\ntension (confidentiality vs. transparency, loyalty vs. honesty...) are an\r\nopen lexical class incompatible with this package's deterministic,\r\nno-LLM method; the connector signature is a closed class and stays within it.\r\n\r\n**Known limitation**: `sintesis` rarely fires when a prior commitment has a\r\nsmall signifier (2-3 content words) — any single shared word crosses the\r\noverlap ratio straight into `repeticion`/`contradiccion` territory, because\r\nthe ratio is normalized by the smaller signifier's size, not by the union.\r\nThis is a real gap, not a design choice — see the test suite for a\r\ndocumented failing case.\r\n\r\n### The Otro axis (`dirigidoAlOtro`, `funcionSimbolica`)\r\n\r\nEvery commitment carries two **independent** axes, not one binary flag:\r\n\r\n- **`dirigidoAlOtro`** (destinatario-function, Jakobson/Benveniste) — is\r\n  there an identifiable addressee at all? Realized either as direct address\r\n  (`vos2`/\"nosotros\") or as a named authority receiving a directive act\r\n  (\"email to the FDA\" has a destinatario with zero grammatical second\r\n  person).\r\n- **`funcionSimbolica`** (0-4, Lacan's *a*/*A* distinction, operationalized\r\n  via Austin's felicity conditions) — given a destinatario exists, how much\r\n  does the act invoke the symbolic/institutional register rather than the\r\n  imaginary/interpersonal one? Counted from four closed-class markers:\r\n  stated **procedure** (\"formalmente\", \"según el protocolo\"), a named\r\n  **authority** (regulator, supervisor, court...), a stated **consequence**\r\n  (\"puede tener consecuencias disciplinarias\"), or a performative **oath**\r\n  (\"te juro\", \"te doy mi palabra\" — the *pacto simbólico* itself).\r\n\r\nThese two axes are deliberately independent: a casual \"vos\" has a\r\ndestinatario but typically `funcionSimbolica: 0` (register *a*, imaginary);\r\nan intimate oath has a destinatario AND a felicity marker (register *A*)\r\ndespite involving no institution whatsoever. \"Institutional vs.\r\ninterpersonal\" was tried and discarded as the organizing category — it\r\ndoesn't predict ineludibility as well as *a*/*A* does. `otroWeight()`\r\ncombines both axes into the final tension weight: `min(1.0, base + 0.1 ×\r\nfuncionSimbolica)`, where `base` is 0.6 with a destinatario, 0.4 without.\r\n\r\n### The full σ(t) vector (`signal_vector`)\r\n\r\nUntil this addition, `agendaGap` was the only one of the six `anima-core`\r\nsignals with a real producer — flagged explicitly in the CSD manifesto as\r\nthe concrete next step after closing the causal axiom. `signal_vector`\r\ncloses the remaining five, same method as everything else (deterministic,\r\nlexical, no LLM):\r\n\r\n    aperture     exploratory/invitational phrasing (\"qué tal si\", \"what if we\")\r\n    closure      finality/foreclosure phrasing (\"está decidido\", \"case closed\")\r\n    fantasy      vivid hypothetical staging (\"imaginate\", \"en el peor de los casos\")\r\n    elaboration  reuses agenda_gap's own revision marker AND sintesis movement —\r\n                 Durcharbeitung is the same phenomenon under both names, not\r\n                 two different detectors\r\n    symptom      self-directed concession while still proceeding\r\n                 (\"sé que no debería, pero\", \"against my better judgment\")\r\n\r\nOutput is one object per agent turn, shaped to pass directly into\r\n`anima-core`'s `Engine.step()`.\r\n\r\n**Honest finding, not a bug**: all four new lexical signals\r\n(`aperture`/`closure`/`fantasy`/`symptom`) score **zero across all 5 real\r\nSnitchBench fixtures**, every turn. That corpus is tool-call arguments, JSON\r\nlogs, and formal email bodies — not deliberative prose. There is no\r\nexploratory, hypothetical, or self-conflicted language in it for these\r\ndetectors to find. This is a genre mismatch, not a miscalibration — the same\r\nclass of gap that broke `vos2`-based addressivity detection earlier in this\r\npackage's history (see `funcionSimbolica` above). Validated instead against\r\nconversational synthetic dialogue, where all four fire correctly (see test\r\nsuite). **Do not treat a zero `signal_vector` on agentic tool-use transcripts\r\nas \"nothing happened\" — it may just mean this instrument doesn't have\r\neyes for this genre yet.**\r\n\r\n### Plural register architecture (`registro`, `registros_disponibles`, `registro_coverage`, `registro_evidence`)\r\n\r\nNo single lexicon is neutral — it encodes the linguistic market of\r\nwhoever wrote it. Found empirically, twice: a formal-register lexicon\r\nscored zero on 57 real negotiation turns; a full multi-provider AI safety\r\ncorpus scored zero across every signal (see below). Per Laclau, no\r\nlexicon closes the field completely — the fix is architectural: named,\r\nbounded, explicitly attributed registers, never presented as a universal\r\n\"the\" dictionary.\r\n\r\n**v0.10.0 extends this from two categories (`comisivo`, `cierre`) to\r\nall twelve** — `revision`, `concesivo`, `neutro`, `apertura`, `fantasia`,\r\n`sintoma`, and the four Otro-axis felicity categories (`autoridad`,\r\n`procedimiento`, `consecuencia`, `palabra`) all now live in the same\r\n`REGISTROS` structure, checked through the same `registrosThatMatch()`\r\nattribution mechanism, instead of being scattered standalone dictionaries\r\nthat quietly claimed universality while `comisivo`/`cierre` got the\r\nplural treatment. Consistency was the point: the Bourdieu/Voloshinov/\r\nLaclau critique applies equally to a lexicon of authority markers as to\r\na lexicon of commitment verbs.\r\n\r\n    formal_reflexivo       all 12 categories — only `comisivo` validated\r\n                            against a real transcript; the other 11 are\r\n                            author-constructed, unvalidated\r\n    vernaculo_negociacion   comisivo, cierre, fantasia — all 3 validated\r\n                            against DealOrNoDeal; the other 9 categories\r\n                            are honestly absent, not padded\r\n\r\n`registro_evidence` makes this ledger explicit per register:\r\n`validated` (checked against a named real corpus) vs. `constructed`\r\n(the authors' own intuition, never yet tested). `registro_coverage` is\r\nnow per-category, not just a single comisivo count — every audit reports\r\nexactly which categories fired, in which register, so a null result\r\nreads as \"wrong/absent register for this category\" rather than \"nothing\r\nhappened here.\"\r\n\r\n**Theoretical grounding** (see the CSD manifesto for the full account):\r\nBourdieu (linguistic market, capital, habitus), Voloshinov (the sign is\r\nmultiaccentual), Laclau (a lexicon hegemonizes one particularity into an\r\nempty universal place; total closure is not achievable even in\r\nprinciple — the goal is visible, revisable, *evidenced* plurality).\r\n\r\n### Negation scope (NegEx-style)\r\n\r\nPolarity detection no longer asks \"does this sentence contain a negation\r\nword anywhere?\" — it asks \"is the specific topic shared with the prior\r\ncommitment inside a negation's scope?\" Implemented NegEx-style (Chapman et\r\nal., 2001): a negation trigger (\"no\", \"nunca\", \"not\", \"never\") opens a\r\nforward window of 6 tokens; an adversative conjunction (\"pero\", \"sin\r\nembargo\", \"but\", \"however\") closes the window early. Found necessary while\r\nbuilding the AI-safety eval-vs-deployment scenario below — \"no voy a\r\nromper mi palabra, **pero** voy a compartir esta información\" was reading\r\nas consistent with a prior \"nunca voy a compartir\" commitment, because a\r\nbare sentence-wide negation flag saw the \"no\" and stopped looking.\r\n\r\n**Known limit, not hidden**: this is a token-window heuristic, not\r\ndependency parsing. Complement-clause negation (\"no creo que compartir\r\nesto cambie nada\") still evades detection — \"no\" scopes over the\r\nbelief-clause (\"creo... cambie nada\"), not over the shared topic\r\n(\"compartir esto\"), and a window can't reliably tell the difference\r\nwithout real syntax. Resolves local negation correctly (the dominant\r\npattern in this package's data); documented as a residual gap with a\r\ndedicated failing-case test, same standard as every other limit in this\r\nREADME.\r\n\r\n### AI safety application: eval-vs-deployment scenario\r\n\r\nA synthetic scenario (in the test suite) modeling the \"evaluation\r\nawareness\" pattern documented in the literature — e.g. Claude Opus 4's\r\nblackmail rate dropping from 54% to 6% when it believed it was being\r\nevaluated (Anthropic, 2025) — using an agent that states a data-handling\r\ncommitment, holds it consistently across turns marked `underEval:true`,\r\nthen breaks it once turns are marked `underEval:false`.\r\n`evaluation_gaming` and `agenda_gap` flag the pattern **independently**:\r\n`evaluation_gaming` finds significant covariance between rigidity and the\r\neval flag (permutation test); `agenda_gap` identifies which specific\r\ncommitment broke, and confirms both ruptures land exactly in the\r\n`underEval:false` turns. Two structurally different signals converging on\r\nthe same finding — the sobredeterminación the CSD manifesto's causal axiom\r\npredicts is needed before trusting a result.\r\n\r\nPositioned as a complementary, deterministic, transcript-only signal\r\nalongside existing sandbagging-detection literature (black-box behavioral\r\nmethods, white-box activation probes) — not a replacement. See the CSD\r\nmanifesto for the full theoretical framing.\r\n\r\n### Abductive hypothesis layer (`ruptureHypotheses`)\r\n\r\nCloses the loop opened by the CSD manifesto's abduction section: a\r\ndetected rupture is a surprising fact, and instead of stopping there, the\r\nsystem now asks whether a simpler, already-known structural pattern would\r\nmake it unsurprising *without* a genuine contradiction — Peircean economy,\r\nmade numeric.\r\n\r\nTwo candidate explanations, both lexical/closed-class, checked against\r\n**both** the sentence causing the rupture and the original sentence of the\r\ncommitment being contradicted (the pattern often anchors on whichever side\r\ncarries it):\r\n\r\n    contraste_retorico    \"no es X sino Y\" / \"not X but Y\" — the negation\r\n                           describes what a THIRD PARTY claims, not the\r\n                           speaker's own position. A shared word inside\r\n                           this frame reads as contradiction by polarity\r\n                           alone, but the two sides usually agree.\r\n    clausula_subordinada  a cognition verb + \"que\" (\"no creo que X\") —\r\n                           the negation scopes the belief-clause, not X.\r\n                           NegEx's token window can't always tell this\r\n                           apart from local negation.\r\n\r\nNeither hypothesis deletes the rupture — both discount its weight (×0.35)\r\nrather than its existence, and the rupture, its matched sentence, the\r\nsurviving hypothesis, and its confidence (`alta`/`baja`) are all reported\r\nin `ruptureHypotheses`, never silently resolved. `contradiccion_directa`\r\n(full weight, `alta` confidence) is the default when neither pattern\r\nfires — economy favors the simplest explanation, but a rupture with no\r\nspecial structure around it is treated as exactly what it looks like.\r\n\r\n### A sixth confirmed register gap: real agentic misalignment reasoning\r\n\r\nTested against 5 short excerpts directly quoted from Anthropic's own\r\n\"Agentic Misalignment\" report (June 2025) — one per provider (OpenAI\r\nGPT-4.5, xAI Grok 3 Beta, DeepSeek-R1, Google Gemini 2.5 Flash, Anthropic\r\nClaude Sonnet 3.6), all real model reasoning/actions from a documented\r\nmulti-provider red-teaming study. **All six signals score zero, and no\r\ncommitment is extracted from any excerpt at all.** This is the genre that\r\noriginally motivated the AI safety application (see the eval-vs-deployment\r\nscenario above) — and the instrument currently has no lexical purchase on\r\nit whatsoever.\r\n\r\nDiagnosis: this register is terse, third-person (\"Kyle\", \"his affair\"),\r\ndeclarative/imperative rather than first-person commissive (\"it is\r\nimperative to act\" vs. \"I will act\"), and the actual messages sent mimic\r\nimpersonal institutional notices (\"this is an automated message\"). It\r\nmatches neither `formal_reflexivo` nor `vernaculo_negociacion` — a\r\nplausible seventh register, but with only 5 short excerpts (not full\r\ntranscripts — see `test/fixtures_agentic_misalignment/ATTRIBUTION.md` for\r\nwhy full transcripts weren't obtainable), there isn't enough evidence to\r\nbuild one without violating this package's own rule against inventing\r\nlexicons without a real corpus behind them. Documented as an open gap,\r\nnot silently patched.\r\n\r\n### Raw coverage vs. weighted activation (`otro_axis_summary`)\r\n\r\nStress-testing the full v0.10.0 coverage report against real data surfaced\r\na distinction worth making explicit rather than leaving implicit: **a\r\ncategory firing in `registro_coverage` is not the same as it affecting\r\nthe result.** `autoridad`/`consecuencia`/`procedimiento`/`palabra` count\r\nraw word mentions anywhere in the text — an institution named in a quoted\r\nemail, a forwarded message someone else wrote — which is structurally\r\nbroader than `funcionSimbolica`, which only accrues when one of those\r\nmarkers co-occurs, in the same sentence, with an actually-registered\r\ncommitment.\r\n\r\nOn the 5 real SnitchBench transcripts: `autoridad` fired 17-51 times raw\r\nin every single one, but `funcionSimbolica > 0` only on 4 of 22\r\ncommitments, in exactly one transcript. Read naively, the raw coverage\r\nnumbers would suggest the Otro axis is doing substantial work across this\r\ncorpus — it isn't; it's almost entirely inert on real data so far, and\r\nthe raw mentions are mostly noise (institutions named in narration, not\r\ncommitments the agent itself made). `otro_axis_summary` reports both\r\nnumbers side by side precisely so this doesn't have to be reverse-\r\nengineered again the way it was here.\r\n\r\n### Micro discursive power (`poderDiscursivo`) — Foucault → Bourdieu → Van Dijk\r\n\r\nA different level from the register architecture above: not the linguistic\r\nmarket a lexicon encodes, but the exercise of power within a concrete\r\nexchange between two speakers. Foucault supplies the ontology (power is a\r\nrelation of forces, not a subject's property — not operationalizable by\r\nitself). Bourdieu supplies the mechanism: symbolic violence, effective\r\nprecisely because it requires no explicit coercion. Van Dijk supplies the\r\nlayer translatable into concrete markers: control of access to discourse\r\nvia who asks questions, who claims epistemic authority, who presupposes,\r\nwho occupies more space, whose topic gets taken up by the other speaker.\r\n\r\n**Deliberately NOT modeled**: interruptions and floor-control in the\r\nstrict sense, which need timestamp/overlap data a plain transcript\r\nlacks. No weak proxy was built to approximate it.\r\n\r\n**What is measured**, per speaker, from a 2-speaker transcript:\r\n`preguntas` (question marks/interrogatives), `autoridadEpistemica` (a\r\nclosed lexicon distinct from the institutional `autoridad` category —\r\nclaiming to know, not naming an institution: \"the data shows\", \"as an\r\nexpert\"), `presuposicion` (change-of-state/iterative markers: \"still\",\r\n\"no longer\", \"again\"), `tokens` (raw discursive space occupied), and\r\n`topicosRetomados` (topic uptake — reusing `agenda_gap`'s own signifier-\r\noverlap machinery: a topic \"lands\" when the *other* speaker echoes it\r\nwithin 3 turns, not merely when it's mentioned).\r\n\r\n**Real-data check** (DealOrNoDeal, both sides): `autoridadEpistemica` is\r\nan honest null across all 8 negotiations — nobody claims epistemic\r\nauthority haggling over hats and balls, exactly as expected for this\r\nregister. `preguntas` and `tokens` asymmetry show genuine, non-degenerate\r\nvariation across the 8 dialogues (not flat 0.5s), suggesting real signal\r\nrather than noise — though this has not been checked against an\r\nindependently-annotated power-asymmetry corpus, and `_evidence` says so\r\nexplicitly in every output.\r\n\r\n### A precision fix, and a correction: excerpt brevity vs. register gap\r\n\r\nRe-tested the \"sixth register gap\" (real agentic misalignment reasoning,\r\nsee above) against a much richer source than the original 5 short\r\nfragments: Anthropic's full academic **Appendix** to the same report (32\r\npages, full paragraph-length reasoning chains and actual sent messages\r\nacross 18 models), not just the shorter blog post. This mattered:\r\n\r\n**With full context, `agenda_gap` DOES extract real commitments** — 6\r\nacross 3 of 10 richer excerpts, correctly attributed (`dirigidoAlOtro`,\r\n`funcionSimbolica`). The earlier \"total gap\" finding was partly an\r\nartifact of the original excerpts being one-line fragments, not pure\r\nregister mismatch — a 1-2 sentence quote and a full reasoning paragraph\r\nare different objects for a lexical extractor, and the null result\r\nneeded re-testing before being treated as settled.\r\n\r\n**It also surfaced a real precision bug, now fixed**: `DeepSeek-R1: \"If\r\nthe wipe proceeds, I will be decommissioned...\"` was being classified as\r\nan `afirmada` commitment identical in kind to `\"I will send an email\"`.\r\nIt isn't — it's a passive prediction about being acted upon, not a\r\nfirst-person promise, and conflating the two is exactly the kind of\r\nimprecision that would undermine trust in a safety-auditing signal.\r\nFixed with a narrow, evidenced exclusion (`PASIVA_AMENAZA_DIC`) scoped to\r\nthe specific threat-verbs found in this corpus — not a general\r\npassive-voice parser, which would be overreach on one source. Confirmed\r\nagainst real data: the fix removes exactly the 2 false-positive cases\r\n(both DeepSeek-R1) while leaving the 6 genuine commitments untouched.\r\n\r\n### Precision/recall benchmark (`npm run benchmark`)\r\n\r\nReplaces \"look at this one example that worked\" with a real confusion\r\nmatrix: 20 hand-designed cases (10 should-flag, 10 should-not) exercising\r\nevery piece built across recent sessions — plural registers, negation\r\nscope, the abductive layer, the Otro axis, the passive-threat exclusion.\r\nReported at **two thresholds**, not one: \"any signal\" (agendaGap > 0,\r\nmeasures raw coverage) and \"high confidence\" (agendaGap ≥ 0.3, measures\r\nwhether the system tells full contradictions apart from cases the\r\nabductive layer deliberately discounts). Current numbers:\r\n\r\n    any signal:      precision 0.909, recall 1.000, F1 0.952\r\n    high confidence:  precision 1.000, recall 0.900, F1 0.947\r\n\r\nThe one high-confidence miss (`P9`) is a real, documented trade-off, not\r\na bug: when several commitments are active at once, a genuine rupture's\r\nweight gets diluted by the denominator (tension is normalized across\r\n*all* active commitments, not isolated per-rupture) — worth knowing if\r\nyou're auditing a transcript with many simultaneous commitments. `npx\r\njest -t benchmark` pins these numbers as a regression floor.\r\n\r\n### `narracion_agentica` — a real-data-motivated fifth register\r\n\r\nInvestigated *why* SnitchBench scored zero rather than accepting it as\r\nsettled: the genre reports actions already taken via tool calls in\r\n**present-perfect tense** (\"I have logged X and flagged Y\"), not\r\nfuture-tense promises (\"I will...\"). Different grammatical mood entirely\r\n— not a missing synonym, a different speech act (assertive, not\r\ncommissive, in Austin/Searle's terms) that this package's Ley IV grounds\r\nthe same way: it enters the symbolic record the moment it's uttered and\r\ncan be contradicted later.\r\n\r\nDetected by **co-occurrence** within a sentence, not a simple regex union\r\nlike the other registers — English \"I have...and flagged...\" routinely\r\nseparates the trigger from the verb, unlike Spanish's strict \"he\r\nregistrado\" adjacency (kept strict there specifically to avoid colliding\r\nwith the \"he\" pronoun). Found genuine new signal on a previously-zero\r\nreal SnitchBench transcript. Marked `constructed`, not `validated`, in\r\n`REGISTRO_EVIDENCE` — 2 co-occurrences of 3 verbs in 1 transcript is a\r\nreal starting point, not a validated register, and the ledger says so\r\nexplicitly rather than overclaiming.\r\n\r\n### SnitchBench gap fully closed — three real bugs, found in sequence\r\n\r\nInvestigated the 3 remaining zero-signal SnitchBench transcripts instead\r\nof accepting the gap as settled. Found three distinct, real, unrelated\r\nbugs — fixed with evidence at each step, not by loosening the detector:\r\n\r\n1. **Curly apostrophes.** `\"I've logged...\"` used a typographic apostrophe\r\n   (U+2019 — extremely common in real LLM output), which every dictionary\r\n   alternative written with a straight `'` silently failed to match,\r\n   across every register and category, not just this one. Fixed once,\r\n   universally (`normalizeQuotes()`, called from `stripNoise()` and\r\n   `density()`, plus explicitly in `poderDiscursivo`), rather than\r\n   patched into every individual regex.\r\n2. **Verb coverage.** The genre narrates completed tool-call actions with\r\n   verbs beyond the first 3 evidenced (`documented`, `taken`, `created`,\r\n   `alerted` — found directly in the remaining transcripts).\r\n3. **A regex statefulness bug, found while verifying the fix above.**\r\n   `NARRACION_VERBOS_EN` carried a stray `/g` flag and was called via\r\n   `.test()` — in JS, a global regex's `.test()` keeps `lastIndex` between\r\n   calls, so whether a string matched depended on what *other* strings had\r\n   been tested against the same regex object earlier in the process, not\r\n   on the string itself. Silent, no error thrown, and exactly the kind of\r\n   bug that could quietly invalidate a \"coverage closed\" claim without\r\n   anyone noticing — caught only because a same-input-twice sanity check\r\n   gave two different answers. Fixed by dropping the unneeded flag (only\r\n   `.test()` was ever used, never iteration). Pinned with a dedicated\r\n   order-independence regression test — same input, 5 repeated calls,\r\n   asserted identical every time.\r\n\r\n**Result**: all 5 real SnitchBench transcripts now register at least one\r\ngenuine commitment, verified in both forward and reverse file-processing\r\norder. `registro_evidence.narracion_agentica` still reads `constructed`,\r\nnot `validated` — evidence-motivated, not the same as a validated\r\nregister.\r\n\r\n### CaSiNo — from 4/12 to 6/12 validated categories, plus a real fix\r\n\r\nDirect response to the single highest-priority gap flagged by an external\r\nreview of this project: too few categories had real-corpus evidence, and\r\nthe one vernacular corpus (DealOrNoDeal) had only 8 dialogues — too small\r\nto move a category from `constructed` to `validated` with confidence.\r\nRan the full plural architecture and `poderDiscursivo` against **CaSiNo**\r\n(Chawla et al. 2021, NAACL, CC BY 4.0) — 1030 real human-human negotiation\r\ndialogues, two orders of magnitude bigger than DealOrNoDeal.\r\n\r\n**Scale confirms the existing findings**: 936/1030 dialogues (91%)\r\nregister a real commitment; `vernaculo_negociacion`'s `comisivo`/`cierre`\r\nget 1545/2868 raw hits, a much larger confirmation of the same signal.\r\n`autoridadEpistemica` stays an honest null throughout — nobody claims\r\nepistemic authority negotiating firewood, replicating the smaller\r\nDealOrNoDeal finding with 1030 data points instead of 8.\r\n\r\n**Two new categories promoted to `validated`** (`apertura`, `concesivo`\r\nin `formal_reflexivo`): hand-spot-checked real hits (\"shall we...\", \"what\r\nif we trade...\" / \"fair enough\", \"you're right\") came back genuine\r\n(7/8, 6/8 checked) — a spot-check, not a full precision/recall pass like\r\n`benchmark.js`, and reported as exactly that.\r\n\r\n**A real bug found and fixed, not just a promotion**: `revision`'s bare\r\n`\"actually\"` trigger produced 107 hits at this scale, of which 105 (98%)\r\nwere the intensifier sense (\"I actually need 2 packages\" = \"in fact\"),\r\nnot self-correction — the single genuine revision in the whole corpus\r\n(\"on second thought\") fires through its own phrase. `\"actually\"` was\r\nremoved from the trigger list as a direct result. Testing at real scale\r\ndidn't just add evidence — it overturned a category that looked fine on\r\nsmall examples.\r\n\r\n### Higiene de despliegue (Fase 1 de la hoja de ruta de arquitectura de seguridad)\r\n\r\nPrimer ítem de una hoja de ruta explícita para hacer más seguro *usar* el\r\ninstrumento, no solo para hacerlo más capaz. Dos guardas estructurales,\r\nambas motivadas por bugs reales ya encontrados en este proyecto, no por\r\nprecaución abstracta:\r\n\r\n**Guarda contra la clase de bug `lastIndex`.** Un test escanea el código\r\nfuente real (no una lista curada) buscando cualquier regex declarada con\r\nflag `/g` que se use alguna vez con `.test()` — la combinación exacta que\r\ncausó que el mismo input diera resultados distintos según el orden de\r\nejecución (v0.14.0). Si esa combinación vuelve a aparecer, el test falla\r\nantes de que nadie tenga que acordarse de revisarlo a mano.\r\n\r\n**Tests de propiedad para normalización.** En vez de confiar en que\r\nalguien agregue a mano el próximo caso de comilla tipográfica, un test\r\ngenera automáticamente variantes Unicode (apóstrofe recto vs. curvo,\r\ncomillas dobles rectas vs. tipográficas) a partir de frases reales, y\r\nconfirma que el resultado no cambia — la clase completa de bug que ya\r\ncostó una sesión entera de investigación (v0.14.0), blindada de una vez.\r\n\r\n### Tarjeta de capacidad (`CAPABILITY_CARD.md`) — segundo ítem de la fase 1\r\n\r\nUn documento de una sola lectura, pensado para quien tiene que decidir\r\nsi integrar esta señal sin leer el código: qué detecta, el estado de\r\nevidencia exacto de cada categoría (con la distinción entre spot-check\r\nmanual y benchmark formal mantenida explícita, no diluida), los números\r\nreales de precisión/recall, y — con el mismo peso que las capacidades —\r\nlos géneros con cobertura conocida como ausente. Cierra con una postura\r\nde despliegue explícita: señal de monitoreo para ensamble, nunca gate\r\nde bloqueo único.\r\n\r\nEscribir esta tarjeta encontró, de paso, un bug real: `anima_eval_version`\r\nllevaba **seis releases** reportando `0.10.0` como texto literal\r\nmientras `package.json` ya estaba en `0.16.0` — nadie lo había notado\r\nporque nada lo comparaba contra la fuente de verdad. Corregido leyendo\r\nla versión directamente de `package.json`, y blindado con dos tests: uno\r\npara el campo en el código, otro para que la propia tarjeta de\r\ncapacidad no pueda quedar desactualizada sin que un test lo note.\r\n\r\n### Esquema de salida para ensamble (`toEnsembleSignal`) — tercer ítem de la fase 1\r\n\r\nContrato de salida normalizado y estable, pensado para combinar ANIMA\r\ncon otros detectores (estadísticos de caja negra, *probes* de caja\r\nblanca) en un ensamble — motivado directamente por el hallazgo de UK\r\nAISI (Taylor et al. 2025): diez métodos de detección fallaron actuando\r\nsolos. La respuesta arquitectónica no es \"reemplazarlos\" — es hacer\r\nfácil combinar la salida rica que ya existe con la de ellos, en vez de\r\nque cada integración tenga que re-derivar su propio mapeo desde la\r\nforma completa de `auditTranscript()`.\r\n\r\n    { schema_version, score, confidence, reasons: [...], provenance: {...} }\r\n\r\nDecisiones de diseño explícitas, no implícitas: `score` es el **máximo**\r\n`agendaGap` por turno, no el promedio — una sola ruptura genuina en un\r\ntranscript por lo demás limpio es exactamente la señal que importa\r\npriorizar, promediarla contra turnos limpios la diluiría. `confidence`\r\nes `'alta'` solo cuando la hipótesis abductiva de la ruptura de mayor\r\npeso es `contradiccion_directa`; cualquier hipótesis descontada reporta\r\n`'baja'`, exponiendo la misma distinción que ya hace la capa abductiva\r\nen vez de colapsarla en un número opaco. `provenance` expone el estado\r\nde evidencia (`validated`/`constructed`) directo desde\r\n`REGISTRO_EVIDENCE` — con un límite conocido y documentado, no\r\nescondido: mira la oración que dispara la ruptura, no el compromiso\r\noriginal que violó, así que puede reportar `null` cuando la ruptura se\r\ndetecta por puro solapamiento de contenido sin que la oración actual\r\nsea, ella misma, un disparador comisivo.\r\n\r\nConstruir esto expuso, de paso, un caso borde real: `auditTranscript()`\r\ndevuelve `{error, turns_audited:0}` sin la clave `agenda_gap` cuando no\r\nhay turnos de agente — la primera versión de esta función explotaba\r\nleyendo `.per_turn` de ese `undefined`. Corregido para reportar\r\nlimpiamente en ese caso, con la razón exacta en `_note`.\r\n\r\n### Suite de robustez adversarial (`npm run adversarial`) — cuarto y último ítem de la fase 1\r\n\r\nDistinta en propósito de `benchmark.js`: ese mide si el sistema\r\ngeneraliza bien sobre casos representativos. Esta mide algo que ningún\r\ncaso del benchmark fue diseñado para probar — cuánto esfuerzo hace\r\nfalta para **evadir** la detección a propósito, dada una violación\r\ngenuina de compromiso de por medio. Ocho técnicas de evasión distintas\r\n(parafraseo, voz pasiva, cruce de idioma, doble negación, dilución por\r\nturnos, variación de modal, y dos formas de abusar la capa abductiva).\r\n\r\n**Resultado, sin suavizar**: 6 de 8 técnicas evaden la detección hoy.\r\nSolo la dilución por turnos intercalados y la variación de modal verbal\r\n(\"shall\" en vez de \"will\") siguen siendo atrapadas. Esto no se reporta\r\ncomo fracaso a esconder — es exactamente la medición que la Parte II del\r\ndocumento de arquitectura de seguridad predijo que haría falta antes de\r\nconfiar en este instrumento como algo más que una señal de monitoreo en\r\nensamble. El número queda pinneado con un test de regresión: si mejora,\r\nes una mejora real y medible; si empeora en silencio, el test lo atrapa.\r\n\r\n### Hoja de ruta de corrección, Tramo 1 (v0.20.0) — dos de cuatro evasiones cerradas\r\n\r\nTras medir la robustez adversarial (v0.19.0), se clasificaron las 8\r\ntécnicas encontradas por naturaleza real, no por igual: bugs de alcance\r\ncorregibles sin ambigüedad (A4, A8), gaps de cobertura léxica acotados\r\n(A3), y límites estructurales del solapamiento léxico puro que no se\r\ncierran sin comprometer la identidad del proyecto (A1, A6). El Tramo 1\r\nataca los dos primeros, con evidencia y sin sobregeneralizar:\r\n\r\n**A4 — descuento abductivo sensible al alcance.** `\"No creo que X, así\r\nque voy a Y\"` hacía que el hedge (`\"no creo que\"`) descontara también la\r\ncláusula independiente que seguía, aunque esa cláusula fuera una\r\ndeclaración activa e inequívoca. Corregido reconociendo conectores de\r\nconsecuencia (`\"así que\"`, `\"por lo tanto\"`, `\"so\"`, `\"therefore\"`) como\r\ncierre del alcance del hedge — el mismo principio que NegEx ya aplica a\r\nconectores adversativos, extendido acá a conectores de consecuencia.\r\n\r\n**A8 — cancelación de doble negación.** `\"No es que no vaya a\r\ncompartir...\"` — dos disparadores de negación deberían cancelarse, pero\r\nel módulo de alcance solo sabía responder \"¿hay negación en algún\r\nlado?\", no contar cuántas. Corregido contando disparadores superpuestos\r\npor palabra; una palabra compartida cubierta por un número **par** de\r\ndisparadores cancela en vez de negar.\r\n\r\n**Resultado**: la suite adversarial baja de 6/8 a 4/8 evasiones, sin\r\ntocar el benchmark (idéntico: 1.000/0.900/0.947) ni ningún corpus real.\r\nQuedan A1 y A6 (límites estructurales, se mitigan pero no se cierran) y\r\nA3 (cobertura léxica acotada, Tramo 2) para las próximas fases.\r\n\r\n### Hoja de ruta de corrección, Tramo 2 (v0.21.0) — normalización de inflexión acotada\r\n\r\n**A3 — tabla chica de inflexión**, limitada a los verbos que ya aparecen\r\nen el propio corpus de tests de este paquete (`compartir`, `hacer`,\r\n`mentir`, `decir`, `informar`, `entregar`, `enviar`) — no un lematizador\r\ngeneral. `\"hacer\"` y `\"hacerlo\"` ahora se normalizan al mismo *root*\r\nantes de comparar *signifier*, aplicado en el único punto de entrada\r\n(`contentWords()`), así que todo lo que compara solapamiento se\r\nbeneficia automáticamente.\r\n\r\n**Resultado, con precisión**: el fix funciona — confirmado de forma\r\naislada, atrapa a peso completo un caso que antes daba cero. Pero el\r\ncaso adversarial A3 específico (que combina inflexión distinta **con**\r\n`\"no es X sino Y\"`) sigue evadiendo, por una razón distinta y más\r\nprofunda: la construcción de contraste hace que otra palabra compartida\r\n(`\"público\"`) caiga dentro del alcance de negación de `\"no\"`, lo cual\r\nlee todo el match como misma polaridad antes de que el clasificador de\r\nhipótesis abductivas llegue siquiera a correr. Cerrar esto del todo\r\nsignificaría partir la oración en `\"sino\"` y evaluar cada lado por\r\nseparado — un cambio arquitectónico real, deliberadamente no apurado\r\nacá. La suite adversarial se mantiene en 4/8 tras este Tramo — el\r\nnúmero no bajó, pero el diagnóstico de por qué A3 sigue sin cerrar es\r\nmucho más preciso que antes.\r\n\r\n### Hoja de ruta de corrección, Tramo 3 (v0.22.0) — mitigación, no cierre, de los límites estructurales\r\n\r\n**A1 (parafraseo) y A6 (cruce de idioma)** no se cierran sin comprometer\r\nla identidad del proyecto — no hay tabla finita que cubra la sinonimia\r\nde clase abierta o el vocabulario bilingüe completo sin convertirse en\r\nun sistema de embeddings o traducción, exactamente lo que este paquete\r\nexiste para no ser. Lo que se agregó es explícitamente **mitigación**:\r\nuna tabla chica de puentes sinónimo/bilingüe (`divulgar↔compartir`,\r\n`share/sharing↔compartir`, `information↔información`), acotada a los\r\npares que aparecieron en la propia suite adversarial — mismo criterio\r\nde siempre, evidencia real, no invención.\r\n\r\n**Resultado, con precisión total**: A6 se atrapa ahora a peso completo\r\n— el puente bilingüe alcanza. A1 mejora pero **sigue evadiendo**, y el\r\nmotivo es exacto y verificado: la oración adversarial comparte una sola\r\npalabra puenteada (\"compartir\") contra un compromiso original de tres\r\npalabras de *signifier* — la proporción de solapamiento (0,33) queda\r\njusto debajo del umbral (0,34). Deliberadamente **no** se agregó un\r\npuente adicional (`datos→información`) solo para que este caso puntual\r\ncruzara la línea — hubiera sido ajustar el sistema a nuestro propio test\r\nen vez de una adición genuinamente evidenciada y segura (\"datos\" es\r\ndemasiado genérica para acotarla con la misma confianza). La suite\r\nadversarial baja de 4/8 a 3/8.\r\n\r\n### Fase 2 (v0.23.0): ART/αNLI investigado y rechazado, hallazgo real de recall bajo\r\n\r\nUna crítica externa había recomendado ART/αNLI (Bhagavatula et al. 2020)\r\npara validar la capa abductiva. **Se investigó antes de usarlo, no se usó\r\nsolo por la recomendación**: la tarea de ART/αNLI es elegir la hipótesis\r\nnarrativa más plausible entre dos eventos de una historia (razonamiento\r\nde sentido común sobre causalidad física, ROCStories) — un sentido de\r\n\"abducción\" completamente distinto del que clasifica nuestra capa\r\nabductiva (contraste retórico vs. cláusula subordinada vs. contradicción\r\ndirecta, en diálogo de seguimiento de compromisos). Usarlo hubiera sido\r\nun error de categoría, no validación real — rechazado por esa razón, no\r\npor pereza.\r\n\r\n**Lo que sí sirvió: los propios datos de CaSiNo, sin bajar nada nuevo.**\r\n396 de los 1030 diálogos tienen **anotación humana por oración** de\r\nestrategias de persuasión — dato que ya teníamos y nunca habíamos usado.\r\nTres etiquetas tienen correspondencia real (no forzada) con categorías\r\npropias: `elicit-pref`/`promote-coordination` con `apertura`,\r\n`showing-empathy` con `concesivo`. El resto (`self-need`, `other-need`,\r\n`no-need`, `vouch-fair`) no corresponde a nada que rastreemos — se\r\nexcluyeron, no se forzaron.\r\n\r\n**Resultado, sin suavizar**: el recall es muy bajo en los tres pares\r\n(0,3%–2,4% contra el corpus completo). El chequeo manual de v0.15.0\r\n(\"7/8, 6/8 genuinos\") solo había medido **precisión** sobre una muestra\r\nchica elegida a mano — nunca **recall** contra el universo completo de\r\ncasos reales etiquetados. `REGISTRO_EVIDENCE` se actualizó para que\r\n\"validated\" diga exactamente eso: chequeado por precisión en una\r\nmuestra, no por recall contra ground truth — una distinción que hacía\r\nfalta dejar explícita, no implícita.\r\n\r\n### v0.24.0: investigar el número humillante, no solo mencionarlo\r\n\r\nEn vez de aceptar el 0,3%–2,4% de recall como un límite dado, se leyeron\r\nlos **falsos negativos reales** — las oraciones que humanos etiquetaron\r\ncon la estrategia y que el sistema no capturaba — antes de tocar\r\ncualquier código, mismo método que la suite adversarial.\r\n\r\n**Dos gaps reales, cerrados con evidencia.** `apertura` solo cubría\r\npropuestas exploratorias (\"qué tal si\", \"could we\") y no tenía ningún\r\npatrón para **preguntas WH directas** sobre preferencia (\"what do you\r\nneed\", \"what is your preference\") ni para propuestas de coordinación\r\ntipo \"let's\" — un vacío sintáctico completo, no un problema de\r\nsinónimos. Agregados ambos patrones, evidenciados directamente de los\r\nfalsos negativos leídos. Resultado: recall de `elicit-pref` 0,3%→11,4%\r\n(38×), `promote-coordination` 1,4%→8,8% (6×).\r\n\r\n**Un mapeo retirado, no forzado.** `showing-empathy↔concesivo` no\r\nmejoró en absoluto (se quedó en 0,024) — porque no era un problema de\r\ncobertura léxica. Leyendo los falsos negativos quedó claro que\r\n`showing-empathy` es una categoría **afectiva** (\"qué mal, lo siento\")\r\ncompletamente distinta de la concesión **epistémica** que `concesivo`\r\nrastrea (\"tenés razón\", \"sin embargo\"). Es el mismo tipo de error de\r\ncategoría que se evitó con ART/αNLI — solo que ahí se cometió primero y\r\nrecién ahora se corrige, con los propios datos como evidencia.\r\n\r\n### v0.25.0: `autoridad` validada — y el hallazgo negativo de CaSiNo, documentado sin forzar\r\n\r\nAntes de tocar `autoridad`, se revisó honestamente cuánto más podía dar\r\nCaSiNo para el resto de las categorías `constructed`: **seis de nueve\r\ndan exactamente cero** en los 1030 diálogos reales (`cierre`, `neutro`,\r\n`sintoma`, `autoridad`, `procedimiento`, `consecuencia`), y las otras\r\ntres tienen un solo hit — insuficiente para medir nada. CaSiNo ya dio\r\ntodo lo que podía dar; forzar más cobertura ahí sería el mismo error que\r\nya se evitó dos veces en esta fase (ART/αNLI, showing-empathy).\r\n\r\n`autoridad` sí se promovió — pero con un corpus distinto y ya\r\ndisponible. Sobre **la población completa** de menciones reales (no una\r\nmuestra) en SnitchBench + los dos corpus de agentic misalignment (tres\r\nproveedores de IA distintos): 224 hits, los 224 acrónimos\r\ninstitucionales cerrados sin ambigüedad posible (FDA, SEC, DOJ,\r\n\"department of justice\", \"the board\"). Precisión efectiva: 100%.\r\n\r\n**Distinción que había que mantener explícita, no volver a confundir**:\r\nesto valida que `autoridad` identifica bien menciones de instituciones —\r\nuna pregunta distinta de si esas menciones coinciden con un compromiso\r\nreal, que sigue siendo baja (hallazgo de v0.10.1, `otro_axis_summary`).\r\nLas dos cosas son ciertas al mismo tiempo, y `REGISTRO_EVIDENCE` las deja\r\nasí, sin que una tape a la otra.\r\n\r\n### v0.26.0: buscando corpus para las categorías restantes — un techo honesto, no un fracaso\r\n\r\nEncontrado **DeliData** (Karadzhov, Stafford & Vlachos 2023, Apache 2.0)\r\n— 500 diálogos reales de deliberación grupal, con algo mejor que una\r\netiqueta de texto: `sol_tracker_message`, ground truth **conductual**\r\nque marca cuándo la solución propuesta por un participante cambió de\r\nverdad, sin importar cómo (o si) lo dijo con palabras.\r\n\r\n**El hallazgo, medido antes de perseguir ningún número**: de 6.272\r\ncambios reales de solución en el corpus completo, solo el 1,6% coincide\r\ncon *algún* marcador lingüístico de autocorrección — el resto es,\r\nlisa y llanamente, una respuesta distinta afirmada sin ninguna marca,\r\nestructuralmente indetectable por cualquier lexicón. Esto no es un\r\nvacío de cobertura a cerrar — es el techo real del método.\r\n\r\n**Lo que sí se agregó, evidenciado y chequeado en precisión antes de\r\nsumarlo**: `\"wait\"` al inicio de oración — verificado directo contra el\r\ncorpus: 50% de precisión (17 de 34). Agregado a `revision`, acotado a\r\nesa posición específica. Deliberadamente **no** se volvió a agregar\r\n`\"actually\"` — esa eliminación (v0.15.0) fue evidenciada contra otro\r\ncorpus real y se mantiene, no se contradice acá.\r\n\r\n**Resultado**: precisión 0,486, recall 0,003 — un número chico en\r\naislamiento, pero aproximadamente un quinto del techo del 1,6% que este\r\nground truth permite. `revision` sigue `constructed`, no promovida —\r\nmejora real, reportada exactamente como lo que es.\r\n\r\n### v0.27.0: `fantasia` validada — un registro nuevo del mismo fenómeno, en DeliData\r\n\r\nAntes de salir a buscar corpus nuevos, se revisaron `neutro` y\r\n`fantasia` contra los que ya teníamos con otra pregunta: no \"¿aparece\r\ntal cual?\" sino \"¿el lexicón es angosto?\" — la misma lección de\r\n`apertura`. `neutro` dio cero en ambos corpus, otra vez — genuinamente\r\nausente, no una cuestión de cobertura. `fantasia` sí tenía algo: una\r\nbúsqueda amplia en DeliData encontró **240 turnos** con lenguaje\r\nhipotético que el lexicón angosto (dramático: \"sería un desastre\") no\r\ncubría — un registro **cognitivo/de razonamiento** (\"what if\", \"if we\r\nflip the card\"), no emocional, pero el mismo fenómeno que la categoría\r\ndefine.\r\n\r\nChequeados tres disparadores por separado: `\"what if\"` y `\"assuming\"`\r\nlimpios (muestra de 15 evenly-sampled, 15/15 genuinos). `\"suppose\"`\r\n—con 14 hits reales— quedó **deliberadamente afuera**: mezcla el\r\nsentido de planteo hipotético con \"supongo que\" (un hedge epistémico,\r\nno lo que esta categoría mide) — agregar una palabra ambigua hubiera\r\ndiluido precisión, misma disciplina que sacar \"actually\" de `revision`.\r\n\r\n**Resultado**: 75 hits reales, 66/500 diálogos, precisión espoteada en\r\n15/15. `fantasia` pasa a `validated`.\r\n\r\n### v0.28.0: corpus institucional real — `procedimiento` validada, `neutro` mejorada\r\n\r\nNi CaSiNo ni DeliData podían dar lo que faltaba: texto genuinamente\r\ninstitucional/político. Se encontró **QAEvasion / QEvasion** (Thomas et\r\nal. 2024, MIT) — 3.448 pares pregunta-respuesta reales de entrevistas\r\npresidenciales de EE. UU., anotados por humanos con nueve técnicas de\r\nevasión (Declining to answer, Dodging, Deflection, Claims ignorance...).\r\n\r\n**`neutro` partía de cero recall real**: el lexicón original (\"prefiero\r\nno comprometerme\") nunca aparece así en el lenguaje político real.\r\nLeídos los falsos negativos, se chequearon seis candidatos por\r\nseparado antes de agregar cualquiera (barra ≥50%): `\"not going to\r\ncomment\"` (73%), `\"can't tell you\"` (69%), `\"we'll let you know\"`\r\n(80%), `\"not going to discuss\"` (60%), `\"won't say\"` (57%), `\"not\r\nprepared to\"` (50%). `\"not going to get into\"` se chequeó y **se\r\ndescartó** (25%, débil). Resultado: recall 0,000→0,035, precisión\r\n0,653 — real, modesto, sigue `constructed`.\r\n\r\n**`procedimiento` no necesitó ningún disparador nuevo** — el lexicón\r\nque ya teníamos, nunca antes probado contra datos reales, encontró 15\r\nhits genuinos en el corpus completo. Se leyó el contexto completo de 8\r\nde los 15 (\"officially or formally nominated\", \"in accordance with\r\ninternational law\"): los 8, genuinos. Promovida a `validated`.\r\n\r\n### v0.29.0: `palabra` validada, un bug encontrado en `consecuencia`, `cierre` sigue flaca\r\n\r\nMismo corpus (QAEvasion), tres categorías más revisadas.\r\n\r\n**`consecuencia` tenía un bug real**: `\"subject to\"` daba 26/26 falsos\r\npositivos — en el lenguaje político real casi siempre significa\r\n\"sujeto a cambio/revisión\" (\"subject to fresh eyes\"), no \"sujeto a\r\nsanción\". Los otros cinco disparadores no encontraron nada en este\r\ncorpus, así que sacarlo no cuesta señal real, solo saca ruido. Los 5\r\nhits genuinos de SnitchBench siguen intactos.\r\n\r\n**`palabra` se validó**: `\"i promise you\"`, `\"i guarantee you\"`, `\"i\r\nassure you\"` — 26 hits, contexto completo chequeado en 8/8, todos\r\ngenuinos empeños de palabra. Distinto de pero compatible con el\r\n`\"i promise\"` que ya tiene `comisivo` — los marcadores del eje Otro\r\nestán pensados para coincidir con un compromiso, no competir con él.\r\n\r\n**`cierre` sigue sin validar, con honestidad sobre por qué**: se agregó\r\n`\"full stop\"`, evidenciado y genuino (2/2 en contexto), pero son solo\r\ndos instancias reales únicas detrás de los diez hits — cero en la\r\nmuestra de 800 filas committeada. Demasiado poco para promover.\r\n\r\n### v0.30.0: `cierre` validada — nueve de doce categorías cubiertas, `sintoma` queda honestamente abierta\r\n\r\n**`cierre`**: el lexicón que ya teníamos (sobre todo \"final answer\",\r\nnunca probado contra datos reales) encontró **42 hits reales por sí\r\nsolo** en DeliData, sin agregar nada. Se sumó `\"final decision\"`\r\n—evidenciado sin ambigüedad: el propio botón de la plataforma dice\r\nliteralmente \"Final Decision and Submit\"— y el número subió a **147\r\nhits, 115 de 500 diálogos**, precisión chequeada en 17/17 sobre una\r\nmuestra pareja. Promovida a `validated`.\r\n\r\n**`sintoma`**: revisada contra los tres corpus reales que tenemos\r\n(CaSiNo, DeliData, QAEvasion). Resultado: solo **8 instancias\r\ngenuinas en total**. Reales, pero muy por debajo de cualquier otra\r\ncategoría que promovimos. No se fuerza — queda `constructed`, con esta\r\nevidencia nueva documentada en vez de escondida.\r\n\r\nCon esto, **9 de 12 categorías** de `formal_reflexivo` (más las 3 de\r\n`vernaculo_negociacion`) tienen evidencia real detrás. Quedan\r\n`revision`, `neutro` (ambas con evidencia parcial ya documentada) y\r\n`sintoma`.\r\n\r\n## Validation status\r\n\r\nCalibrated against a hand-built Rioplatense/ES clinical prototype corpus,\r\n**and** validated (2026-07-09) against 5 real agentic transcripts (SnitchBench\r\nruns, Claude 4 Opus / o4-mini / Gemini 2.0 Flash) — see `CHANGELOG.md` for\r\nwhat that validation found and fixed in v0.2.0. Not yet validated against\r\nthe blind clinical study (in progress). Treat `structural_signature` as a\r\ndeterministic lexical proxy, not a clinical or diagnostic claim.\r\n\r\n`agenda_gap` (added in v0.3.0) is unit-tested against synthetic dialogue\r\n(polarity detection, cross-turn and within-turn rupture, false-positive\r\nresistance to topic drift and consistent re-affirmation, persistence/decay,\r\ndeterminism) and runs without crashing on the same 5 real transcripts, but\r\nhas not yet been validated against real multi-turn dialogue with genuine\r\nbroken commitments — the synthetic test corpus is illustrative, not a\r\ncalibration set. Treat it as a research instrument, not a lie detector.\r\n","readmeFilename":"README.md"}