{
  "profile": "alltio-text-2",
  "note": "Conformance suite. An implementation is conformant when every vector's canonical text and digest match exactly, and every error vector throws. Digests are SHA-256, lowercase hex, over the canonical text encoded UTF-8 without BOM.",
  "vectors": [
    {
      "name": "minimal",
      "why": "Baseline: one paragraph, nothing to strip.",
      "html": "<article data-alltio-body><p>Hello.</p></article>",
      "canonical": "Hello.",
      "sha256": "2d8bd7d9bb5f85ba643f0110d50cb506a1fe439e769a22503193ea6046bb87f7"
    },
    {
      "name": "scope-is-the-body-only",
      "why": "Head, nav and footer are outside the marked subtree, so they are excluded by scope rather than by any per-element rule. This is why the JSON-LD mark, analytics and the build stamp never touch the digest.",
      "html": "<html><head><title>T</title><script>var a=1</script></head><body><nav>Home Blog</nav><article data-alltio-body><p>Body.</p></article><footer>Contact</footer></body></html>",
      "canonical": "Body.",
      "sha256": "521b25cc458684eb504a7c885adccd748cf2f97429ff80a14886d0804d62c862"
    },
    {
      "name": "comments-dropped",
      "why": "A comment is not an element, so the element list in step 3 does not reach it. Dropping it is required: a commented-out block that is later uncommented must not move the digest.",
      "html": "<article data-alltio-body><p>Kept.</p><!-- <p>Not the work.</p> RECORD_ID --></article>",
      "canonical": "Kept.",
      "sha256": "38bbfc82be4e4d46e051c1d1b1c8d451616afaa56b78f110bea167be559e1c77"
    },
    {
      "name": "uncommenting-the-mark-is-a-no-op",
      "why": "The circularity case. The same work, once with the mark commented out and once with it live, must produce one digest — otherwise stamping a page invalidates the record just filed for it.",
      "html": "<article data-alltio-body><p>Work.</p><p class=\"alltio-mark\" data-alltio-mark>Registered with Alltio · ALT-XXXX-0000 · <a href=\"https://alltio.com/r/ALT-XXXX-0000\">Verify</a></p></article>",
      "canonical": "Work.",
      "sha256": "bc92a1db5e32de1f2d019ac13ccf77af7b3eda6b7508988dc489dec7f8a37a39"
    },
    {
      "name": "nested-exclusion",
      "why": "An excluded subtree is removed whole, including kept-looking descendants.",
      "html": "<article data-alltio-body><p>A</p><div data-alltio-mark><p>B</p><div data-alltio-mark><p>C</p></div><p>D</p></div><p>E</p></article>",
      "canonical": "A\nE",
      "sha256": "53ef2ed874462cb51ae803023c8ea49ca6141fc5a5c914af19bc311d6ed7f413"
    },
    {
      "name": "inline-exclusion-leaves-no-boundary",
      "why": "Removing an inline subtree joins the surrounding text with nothing between. Pinned because it is surprising and a reasonable implementer might insert a space.",
      "html": "<article data-alltio-body><p>foo<span data-alltio-mark>bar</span>baz</p></article>",
      "canonical": "foobaz",
      "sha256": "798f012674b5b8dcab4b00114bdf6738a69a4cdcf7ca0db1149260c9f81b73f7"
    },
    {
      "name": "script-style-template-noscript",
      "why": "Removed with their contents even though their text would otherwise be extracted.",
      "html": "<article data-alltio-body><p>Real.</p><script>var x='fake'</script><style>p{color:red}</style><template><p>tpl</p></template><noscript>ns</noscript></article>",
      "canonical": "Real.",
      "sha256": "80156831ad113514e96c14cd91933e16aebefa4d4892af07edfacbfaf662efd2"
    },
    {
      "name": "br-inside-paragraph",
      "why": "<br> emits a line break; the paragraph still emits its own on close.",
      "html": "<article data-alltio-body><p>One<br>Two</p><p>Three</p></article>",
      "canonical": "One\nTwo\nThree",
      "sha256": "0e103bf76de9c9b9dc7f796a282c6f7453620e2d5480aad93051de60c3b01b6e"
    },
    {
      "name": "inline-elements-contribute-nothing",
      "why": "Emphasis and links carry text but add no structure, so a rewrap into different inline markup must not change the digest.",
      "html": "<article data-alltio-body><p>A <strong>bold</strong> and <a href=\"/x\">linked</a> line.</p></article>",
      "canonical": "A bold and linked line.",
      "sha256": "623cc24ce91b92f14d32ffad29e21e9d15c03115e02d2101932ce1eb2cae5384"
    },
    {
      "name": "entity-heavy",
      "why": "Character references are decoded by the parser before extraction, then folded, so the source encoding of a character is invisible to the digest.",
      "html": "<article data-alltio-body><p>Sweden&rsquo;s BankID &mdash; &ldquo;quoted&rdquo; &amp; &lt;escaped&gt; &#8212; &#x2014;</p></article>",
      "canonical": "Sweden's BankID - \"quoted\" & <escaped> - -",
      "sha256": "72246fc898fb35129bc4956b37d382cab77e129defd0984a03b34f21101289bd"
    },
    {
      "name": "typographic-folding",
      "why": "Step 7. Platforms rewrite straight quotation marks into curly ones at publish, so the curly and straight renderings of one work must hash identically. Both paragraphs here fold to the same characters and land on one line each.",
      "html": "<article data-alltio-body><p>‘a’ “b” — c</p><p>'a' \"b\" - c</p></article>",
      "canonical": "'a' \"b\" - c\n'a' \"b\" - c",
      "sha256": "d929b9b5f9facaf64c8e7aa3ecabb7238e55f6bdd3bbd80488b1ea98343ce47b"
    },
    {
      "name": "folding-primes-ellipsis-dashes",
      "why": "Step 7's full inventory: primes fold to typewriter quotes, en and em dashes and the minus sign fold to a hyphen, and an ellipsis character becomes three periods.",
      "html": "<article data-alltio-body><p>5′10″ tall… range −3 – 4 — done</p></article>",
      "canonical": "5'10\" tall... range -3 - 4 - done",
      "sha256": "60522137db7c04c871aa8bb27ae8bf47fe65317cd8f398aa5f2a2aa96a764f46"
    },
    {
      "name": "folding-removes-invisibles",
      "why": "Step 7. Soft hyphens and zero-width characters are typographic dress a platform inserts; none of them are the work.",
      "html": "<article data-alltio-body><p>hy­phen zero​width join‍er word⁠joiner</p></article>",
      "canonical": "hyphen zerowidth joiner wordjoiner",
      "sha256": "7e47c539b0c3c08f1d0e53a4879d2b7a8d94ca0195c5efd32bbf854a392c69f9"
    },
    {
      "name": "nfc-not-nfkc",
      "why": "Decomposed and composed forms of the same character must agree (NFC), but ligatures and superscripts must survive (not NFKC).",
      "html": "<article data-alltio-body><p>café ﬁn 2²</p></article>",
      "canonical": "café ﬁn 2²",
      "sha256": "3f49d3e0650c62a290a5e9f5a3cf4228b4d0db48b96dac9c17e65fefd821970f"
    },
    {
      "name": "mixed-whitespace",
      "why": "Runs of Unicode whitespace collapse to one space within a line, lines are trimmed, blank lines vanish, and there is no trailing newline.",
      "html": "<article data-alltio-body>\n  <p>  spaced\t\tout   here  </p>\n\n  <p>\n     second\n  </p>\n</article>",
      "canonical": "spaced out here\nsecond",
      "sha256": "2406d3e3a37a3f2ee1fc33af7d7667ff146eee4107b7d3d5ef7af83bf136c44f"
    },
    {
      "name": "list-and-nesting",
      "why": "Every list item is its own line; nesting does not add blank lines because empty lines are dropped.",
      "html": "<article data-alltio-body><p>Q:</p><ul><li>One</li><li>Two<ul><li>Inner</li></ul></li></ul></article>",
      "canonical": "Q:\nOne\nTwo\nInner",
      "sha256": "d93952baa249c8e0a6f533ae7b7b6841978f4d7d167c2b88c306694b9ae1a660"
    },
    {
      "name": "figcaption-is-in-scope",
      "why": "A caption is authored argument, not chrome. Image bytes are not covered by a text hash at all; the image is a separate asset under the same work.",
      "html": "<article data-alltio-body><figure><img src=\"/a.png\" alt=\"Alt text not hashed\"><figcaption>The caption is.</figcaption></figure></article>",
      "canonical": "The caption is.",
      "sha256": "9d2984764c5918e68af4cccdb81728da57fc36af25e1df4b5c669b2578fd9392"
    },
    {
      "name": "whitespace-only-body",
      "why": "A body with no text is empty, not an error. Registering it is a caller decision.",
      "html": "<article data-alltio-body>   \n  <script>x</script>  </article>",
      "canonical": "",
      "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
    },
    {
      "name": "error-no-body",
      "why": "Fail closed rather than falling back to <article>.",
      "html": "<article><p>No marker.</p></article>",
      "throws": "expected exactly one [data-alltio-body], found 0"
    },
    {
      "name": "error-two-bodies",
      "why": "Fail closed rather than concatenating or picking the first.",
      "html": "<article data-alltio-body><p>A</p></article><article data-alltio-body><p>B</p></article>",
      "throws": "expected exactly one [data-alltio-body], found 2"
    }
  ],
  "textVectors": [
    {
      "name": "text-prose-blank-line-paragraphs",
      "why": "A prose file separates paragraphs with blank lines; the HTML pipeline emits one line per block element. Both must land on the same canonical form or a file registration never matches its published page.",
      "text": "First paragraph.\n\nSecond paragraph.\n",
      "canonical": "First paragraph.\nSecond paragraph.",
      "sha256": "31cf545a878cf251517e18064d04daa77a847d9f40e2af899deeb419168d9c30"
    },
    {
      "name": "text-matches-html-pipeline",
      "why": "The standing acceptance test at unit level: this text digest must equal the 'minimal' HTML vector's digest for the same prose.",
      "text": "Hello.",
      "canonical": "Hello.",
      "sha256": "2d8bd7d9bb5f85ba643f0110d50cb506a1fe439e769a22503193ea6046bb87f7"
    },
    {
      "name": "text-messy-editor-whitespace",
      "why": "Editor buffers carry trailing spaces, tabs, NBSP, and CRLF. All of it is incidental; none of it is the work.",
      "text": "Line one. \t\r\nLine two.\r\n\r\n   Line three.   ",
      "canonical": "Line one.\nLine two.\nLine three.",
      "sha256": "cced344019bb360eb0b7a5471e7174f1aa94de6a074748b674c7956a92a08955"
    },
    {
      "name": "text-nfc",
      "why": "Step 6 applies in text mode too: decomposed e + combining acute normalizes to the precomposed form.",
      "text": "café",
      "canonical": "café",
      "sha256": "850f7dc43910ff890f8879c0ed26fe697c93a067ad93a7d50f466a7028a9bf4e"
    },
    {
      "name": "text-curly-equals-straight",
      "why": "The acceptance test's folding case at unit level: the file holds straight quotes, the platform published curly ones, and both must produce one digest.",
      "text": "She said “don’t” — twice…",
      "canonical": "She said \"don't\" - twice...",
      "sha256": "39e86e32379eb382d23a287890dcaf32dac2e14aa255d7bcd4dee2368f580fe0"
    },
    {
      "name": "text-empty",
      "why": "Empty text is empty, not an error, mirroring whitespace-only-body.",
      "text": "   \n\t\n",
      "canonical": "",
      "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
    }
  ]
}
