{"schema_version":"1","site":"https://decosa.ai","id":"editorial-ledger","num":"31","name":"Editorial-control ledger","tool_name":"Log human edits and editor sign-off","short":"Editorial ledger","blurb":"Keeps the AI first draft, every human edit as a diff with edit metrics, and a named editor's sign-off in one signed record, with a public page per published piece. It is the evidence behind the EU AI Act's exception for AI-assisted text that had human review and editorial responsibility (Art. 50(4)).","status":"live","labels":{"industry":["creative-media","compliance-trust"],"job":["attest","review"],"input":["text"],"deploy":["hosted","selfhost"],"status":"live","output":["record","text"],"data":["confidential"],"hardware":"gpu-96","licence":"permissive"},"industries":["creative-media","compliance-trust"],"runs_in":["hosted","selfhost","crp-source-protection"],"part_of":[],"built_from":["grounding","signed-record","content-credentials"],"models":"Qwen3.8-27B (draft and claim check)","where":"Hosted for published pieces; self-host for embargoed copy","hardware":"1× RTX PRO 6000 (96 GB) or 1× RTX 5090 (32 GB) for the model; metrics, ledger and verification run on CPU","final_artifact":"A signed editorial ledger with a public verify page, and a DOCX of the published text with a C2PA credential.","self_host_first":false,"verification":{"receipt_coverage":"full","summary":"Receipted draft; signed, hash-chained ledger; optional C2PA credential","manual_qa":{"hosted":{"date":"2026-09-25","result":"pass (pre-release server)","p50_ms":58653,"p95_ms":null,"runs":null,"receipts_per_run":2,"cost_per_run_usd":0.002},"selfhost":{"date":"2026-09-25","result":"pass","method":"Fresh clone of the branch into a clean directory on our server, image built from docker/api/Dockerfile, api started with compose (named volume, python healthcheck), then the assemble prompt's smoke steps 1-8 and the CMS webhook with a minted dk_ key; torn down afterwards.","notes":"Verified 25 Sep 2026: image builds, the service starts healthy, and the sample passes end to end against local model servers equivalent to the documented ones (the already-running Qwen3.8-27B vLLM on 127.0.0.1:8114 instead of the compose llm service); model-server startup itself not re-verified. Receipts were attested (signed by the box's key). The C2PA credential answered 503 as documented: the default image has no c2pa-python and no certificate. Host networking and port 8437 were used because other services held the default ports."},"known_limits":["Hosted check ran on the pre-release server (decosa-api the pre-release branch on our server, gateway route, signed receipts): console flow, public ledger page, text check, tamper buttons, Watch replay, 390 px layout, and the Build tab's Python example as written. The production API runs it once the branch is merged and deployed.","The claim check is a model's reading: on IteraTeR it caught 31 of 35 meaning-changed edits and also fired on many 'clarity' edits (most of which did change a fact).","The named editor's identity is what the caller sends; only an optional Ed25519 editor signature binds it to a key.","The C2PA credential uses a development certificate (untrusted issuer) and needs the provenance extra in the image.","Hosted retention is fixed at 7 days for open pieces and 30 days for published ledgers.","Under heavy shared load a whole piece took up to a minute."],"nightly_covers":null},"nightly":"https://api.decosa.ai/verify/status"},"eval_summary":{"metrics":[{"name":"Edit metrics exact against scripted diffs","value":"80 / 80","unit":null,"n":80,"split":"synthetic","note":"First run 59 / 80; a harness bug and a line-wrap bug were fixed before the second run."},{"name":"Rubber-stamped vs heavily edited separated (AUC, words changed)","value":"1.00","unit":null,"n":43,"split":"synthetic","note":"32 rubber-stamped vs 11 heavy edits; the heavy edits are the builder's (3) and the model's (8), not newsroom editors'."},{"name":"Wording-only paraphrases with no claim change flagged (held out)","value":"24 / 24","unit":null,"n":24,"split":"heldout","note":"Generated after the last prompt change and never used to tune it."},{"name":"Claim-change flag on planted edits: recall / specificity","value":"24/24, 40/40","unit":null,"n":64,"split":"synthetic","note":"The style-only row was seen during prompt tuning, so it is optimistic."},{"name":"IteraTeR test, meaning-changed edits flagged (recall)","value":"31 of 35 (0.89)","unit":null,"n":35,"split":"test","note":"Precision against the intent label 0.49 (32 of 65 other edits flagged); the label is a proxy, not 'a claim changed'."},{"name":"Tampered ledgers caught","value":"120 / 120","unit":null,"n":120,"split":"synthetic","note":"15 kinds of change on 8 ledgers; all 8 genuine ledgers verify."}],"dataset":"8 fictional newsroom source packs with a Qwen3.8-27B draft each, scripted and planted edits on them, plus the IteraTeR human revisions (Apache-2.0; dev split for prompt work, test split for the numbers).","held_out":true,"caveats":["No real newsroom editors on real copy: the heavy edits are the builder's and the model's.","The style-only claim-diff cases were seen while tuning the prompt; only the 24 paraphrases are a fair wording-only number.","Claim-diff precision was not measured on a set labelled for claim changes; IteraTeR intent labels are a proxy.","A careful editor who changes nothing looks the same as a rubber stamp; the ledger does not judge review quality.","Someone holding the server's signing key who also forges a fresh gateway receipt is not caught by the record alone.","Pieces longer than about 24,000 characters and quiet-GPU latency are not measured."],"date":"2026-09-25","doc_url":"https://decosa.ai/metrics/evals/editorial-ledger"},"stack":{"summary":"An open model writes the first draft from your sources through our gateway, so the draft is bound to a signed receipt. Every save after that is a revision on a hash chain: who edited, a diff against the draft, and edit metrics anyone can recompute (share of words changed, sentence edit distance, numbers, names and quotes gone or new). A second receipted call lists the factual claims the edit added or removed. A named editor signs off on one exact version, or the piece goes out with an AI label, and the ledger records which and why. Publishing seals the record; each piece gets a public page that checks it in the reader's browser, and an optional C2PA credential on a DOCX copy of the text. A CMS drives it through one webhook. It is for EU newsrooms, agencies and comms teams that draft with AI and need to show that a person reviewed each piece.","tagline":"The AI draft, every human edit and a named sign-off in one signed record, with a public check for each published piece.","deployment":"hosted-or-self-host","regulatory_note":"Checked 25 Sep 2026. EU AI Act (Regulation (EU) 2024/1689) Art. 50(4), second subparagraph: deployers of an AI system that generates or manipulates text published to inform the public on matters of public interest must disclose that it was artificially generated or manipulated, unless the content has undergone a process of human review or editorial control and a natural or legal person holds editorial responsibility for the publication. It applies from 2 August 2026 (Art. 113); transparency breaches can be fined up to EUR 15 million or 3% of worldwide turnover (Art. 99(4)). The Digital Omnibus (Regulation (EU) 2026/1744, in force 27 July 2026) gave generative systems already on the market until 2 December 2026 for the provider marking duty; published summaries report no change to this deployer duty. The Commission's voluntary Code of Practice on marking and labelling AI-generated content (about 190 signatories by July 2026) and its Art. 50 guidelines restate the exception. This ledger is evidence that a review happened and who holds responsibility; whether a given review meets the exception is for the publisher, and ultimately regulators and courts, to judge, and the metrics cannot tell a careful read from a careless one. US: the Copyright Office's registration guidance (16 March 2023, 88 FR 16190) and its Part 2 report on copyrightability (29 January 2025) protect only human authorship and ask applicants to disclose AI-generated material and describe the human contribution; the ledger documents what a person changed, it does not make text protectable. Model licence: Apache-2.0 (Qwen3.8-27B). Not legal advice.","components":[{"id":"ledger","role":"Ledger: edit metrics, sentence alignment, hash chain, sign-off rules, sealing and verification (no model; CPU)","name":"decosa-api editorial module (decosa_api/verticals/editorial)","hf_repo":null,"license":"AGPL-3.0-or-later","params":null,"quant":null,"vram_gb":0,"memory_gb_estimate":null,"engine":"Python 3.12, FastAPI; difflib and an exact word-level Levenshtein; Ed25519 via cryptography","receipt_coverage":"partial","in_hosted_demo":null,"tiers":["lite","standard"],"alternative_to":null},{"id":"qwen","role":"Writes the AI first draft from the sources, and lists the claims an edit added or removed","name":"Qwen3.8-27B (NVFP4)","hf_repo":"nvidia/Qwen3.8-27B-NVFP4","license":"Apache-2.0","params":"27.8B","quant":"NVFP4 (MLP NVFP4, GDN/attention FP8) + FP8 KV cache; MTP head, 3 draft tokens","vram_gb":20,"memory_gb_estimate":null,"engine":"vLLM 0.29.0, temperature 0, thinking off; called through our gateway's metered route (hosted) or directly (self-host)","receipt_coverage":"strong","in_hosted_demo":true,"tiers":["standard"],"alternative_to":null},{"id":"c2pa","role":"Optional C2PA content credential on a DOCX copy of the published text","name":"c2pa-python 0.37 (native c2pa-rs)","hf_repo":null,"license":"MIT OR Apache-2.0","params":null,"quant":null,"vram_gb":0,"memory_gb_estimate":null,"engine":"ES256 with the provenance kit's certificate; actions c2pa.created (trainedAlgorithmicMedia) and c2pa.edited (compositeWithTrainedAlgorithmicMedia), plus an ai.decosa.editorial-ledger assertion","receipt_coverage":"none","in_hosted_demo":null,"tiers":["lite","standard"],"alternative_to":null}],"tiers":[{"id":"lite","label":"Lite · ledger only, on CPU (self-host)","summary":"Your CMS's own AI tool writes the draft; the ledger keeps it (marked as not receipted), diffs every save, computes the metrics and seals the sign-off. No model here, so no claim check.","components":["ledger","c2pa"],"hardware":"Any CPU","quality_evidence":[{"metric":"Edit metrics against scripted diffs of real drafts","value":"80 / 80 exact","source":"docs/evals/editorial-ledger.md"},{"metric":"Rubber-stamped vs heavily edited, words changed","value":"AUC 1.00; rubber-stamped at most 0.68%, heavy at least 51.1%","source":"docs/evals/editorial-ledger.md (32 rubber-stamped, 11 heavy)"},{"metric":"Tampered ledgers caught","value":"120 / 120 (15 kinds of change, 8 ledgers); 8 / 8 genuine verified","source":"docs/evals/editorial-ledger.md"}],"latency_note":"measured: a revision is saved and chained in tens of milliseconds","in_hosted_demo":false,"receipt_coverage":"none","receipt_note":"No model call here, so no receipt covers the draft: the ledger shows what your CMS said its AI wrote.","hosting":null},{"id":"standard","label":"Standard · Qwen3.8-27B drafts and checks claims (hosted demo)","summary":"The model writes the first draft from the sources with a signed receipt, and lists the claims each edit added or removed. This is what the hosted API runs.","components":["ledger","qwen","c2pa"],"hardware":"1× RTX PRO 6000 96 GB (measured) or 1× RTX 5090 32 GB (estimate)","quality_evidence":[{"metric":"Claim check on planted edits (number changed, fact deleted or added, paragraphs moved, style-only, 24 held-out paraphrases)","value":"64 / 64; recall 24/24, no false alarm in 40","source":"docs/evals/editorial-ledger.md"},{"metric":"Claim check on IteraTeR human sentence edits (test)","value":"31 / 35 meaning-changed caught; fired on 32 / 65 others (precision 0.49 against the intent label, which undercounts real fact changes)","source":"docs/evals/editorial-ledger.md"},{"metric":"Drafts with a gateway-signed receipt covering the stored text","value":"8 / 8 in the eval; 2 / 2 model calls per run in the end-to-end runs","source":"docs/evals/editorial-ledger.md; scripts/smoke/editorial-ledger.py"},{"metric":"Edit metrics, separation and tamper detection","value":"as the lite tier (same code)","source":"docs/evals/editorial-ledger.md"}],"latency_note":"measured on a shared GPU: seconds for a draft or a claim check; under half a minute for a whole piece when quiet, about a minute under heavy shared load","in_hosted_demo":true,"receipt_coverage":"strong","receipt_note":"The draft and every claim check carry gateway-signed receipts embedded in the signed ledger.","hosting":null}],"alternates":[],"services":[{"name":"decosa-api (editorial routes)","port":8445,"image":"${DECOSA_REGISTRY}/decosa-api:<tag>","purpose":"POST /editorial/pieces, /draft (SSE or JSON), /revisions, /claims, /signoff, /publish; /editorial/hooks/cms; GET /editorial/p/<id>, /editorial/p/<id>/credential.docx; POST /editorial/verify, /editorial/metrics; GET /editorial/info, /editorial/samples."},{"name":"vLLM (draft and claim check)","port":8114,"image":"vllm/vllm-openai@sha256:c2914767605584b6d8f45686b82de173ecc99e781897aa3d0a66dacd72c51ae1","purpose":"Qwen3.8-27B NVFP4 behind our gateway (hosted) or called directly (self-host). Not needed on the lite tier."}],"tools":[{"name":"POST /editorial/hooks/cms","url":null,"license":"Apache-2.0","purpose":"One webhook for a CMS, keyed by the CMS's own article id: create, draft (a draft your CMS's AI wrote), revision on every save (text or HTML), signoff and publish."},{"name":"Public ledger page (/ledger/<id>) and POST /editorial/verify","url":null,"license":"Apache-2.0","purpose":"Checks the chain, the draft's gateway receipt, the signature and the ledger rules in the reader's browser; the server also recomputes the edit metrics and checks pasted text against the signed final version."},{"name":"IteraTeR human revisions (wanyu/IteraTeR_human_sent, _human_doc)","url":"https://huggingface.co/datasets/wanyu/IteraTeR_human_sent","license":"Apache-2.0","purpose":"Eval: 100 labelled human sentence edits for the claim check, and 51 real human document revisions as a reference distribution for the metrics."},{"name":"scripts/editorial_eval.py and docs/evals/editorial-ledger.md","url":null,"license":"Apache-2.0","purpose":"Metric accuracy on scripted diffs, rubber-stamp vs heavy-edit separation, the claim check on planted edits, and tamper detection (decosa-api)."}],"hardware":[{"tier":"Any CPU, no GPU","fits":true,"notes":"Lite tier: the ledger, metrics, sealing and verification. Drafts come from your own tool; no claim check."},{"tier":"1× RTX 5090 32 GB","fits":true,"notes":"Qwen3.8-27B NVFP4 needs about 20 GB of weights plus KV cache. Estimate: same model stack as the other Qwen verticals, not run here for this one."},{"tier":"1× RTX PRO 6000 Blackwell 96 GB","fits":true,"notes":"Measured on our server: the hosted demo and the eval ran on this card, shared with other services."}],"latency":[{"lane":"AI first draft (about 560 generated tokens), hosted gateway route","typical_ms":8600,"source":"measured on our server 2026-09-25: p50 8.6 s over 8 drafts while the GPU was shared with other evaluation jobs; one draft took 21 s at a busier moment"},{"lane":"claim check of one edit (about 1,790 prompt and 57 generated tokens), hosted gateway route","typical_ms":12300,"source":"measured on our server 2026-09-25: p50 12.3 s, p90 17.9 s over 64 calls, 4 in flight, shared GPU"},{"lane":"save a revision (metrics, alignment, chain entry), local HTTP","typical_ms":30,"source":"estimate from the recorded demo: the revision step landed 23-27 ms after the draft response"},{"lane":"whole piece: draft, one revision, claim check, sign-off, publish","typical_ms":58653,"source":"measured on our server 2026-09-25: 11-24 s in four runs early in the day, then 46, 59 and 61 s (p50 59 s) in three smoke runs while other evaluation jobs loaded the shared gateway"}],"benchmark":null,"notes":["Edit metrics matched the expected counts on 80 of 80 scripted diffs of real drafts (word substitutions, sentence deletions and insertions, an edited sentence, a reflow). The first run found a real bug: a line break inside a paragraph counted as a sentence end. Fixed before the numbers above.","Rubber-stamped drafts (unchanged, reflowed, a punctuation or one-word fix) changed at most 0.68% of words; heavy edits (3 by hand, 8 simulated by the model) changed 51% to 78%. Real human document revisions from IteraTeR sit in between (median 10%). The metrics describe; they do not judge review quality.","The claim check got all 64 planted cases right, including 24 held-out paraphrases that must show no change. On IteraTeR's labels it caught 31 of 35 meaning-changed edits but also fired on 29 of 41 'clarity' edits; a manual audit found most of those did drop or add a fact. Treat the list as a pointer for the editor.","The prompt was revised once after the first run flagged style-only rewording (said/stated, will/is set to); the style-only row is therefore optimistic. The held-out paraphrases were made after that change.","All 120 tampered ledgers failed verification (15 kinds of change on 8 ledgers, including rewrites re-signed with another key); all 8 genuine ones verified.","What the ledger cannot show: that the named editor is who they say (an editor can add their own Ed25519 signature to the sign-off), or that a review with few edits was careful."]},"buyer_facts":[{"label":"What you send","value":"Sources (up to 6, 20,000 characters each) or a draft your own tool wrote, then each saved version as text or HTML, the editor's name and role, and the sign-off."},{"label":"What you get","value":"A signed ledger per piece, a public page at /ledger/<id> that checks it in the reader's browser, a copyable article badge, and a DOCX of the published text with a C2PA credential."},{"label":"Typical cost","value":"Two model calls per piece: a fraction of a cent at the gateway list price. The ledger work is CPU."},{"label":"Retention (hosted)","value":"Open pieces 7 days, published ledgers 30 days, with the texts. Choose whether the public page shows the AI draft; its hash is always there. Self-host keeps everything on your box."},{"label":"What leaves the box (self-host)","value":"Nothing: the model, the ledger and the public page can all run on your machine. On the hosted route the sources and the texts reach our server and the gateway."},{"label":"Identity","value":"The ledger records the name your key-holder sends. For stronger evidence an editor can sign the sign-off with their own Ed25519 key; there is no SSO binding yet."}],"data_handling":{"page":"/data#editorial-ledger","self_host":{"level":"confidential","leaves":"nothing","summary":"Runs on your machine; nothing is sent to Decosa or a third party by default."},"hosted":{"level":"operator-processed","demo_only":false,"summary":"TLS to Decosa's server, then decrypted and processed by Decosa's API server, with the open models run by NEAR AI through OpenRouter, with Reka AI as the only fallback under Decosa's account.","gpus":"operator-contracted","third_parties":[],"retention":"Open pieces 7 days, published ledgers 30 days, with the texts. Choose whether the public page shows the AI draft; its hash is always there. Self-host keeps everything on your box.","used_for_training":false,"encrypted_while_processed":false},"sealed_tier":{"applies":false,"note":"The sealed tier (raw chat only, never use-case pipelines) is paused at launch (/docs/sealed-tier)."},"external_calls":[]},"console":{"href":"/tools/media/editorial-ledger","input":"editorial","lanes":[{"id":"draft","title":"Retained AI draft","kind":"markdown"},{"id":"edits","title":"Human edits and claims","kind":"list"},{"id":"ledger","title":"Sign-off and signed ledger","kind":"json"}],"samples":[{"n":1,"id":"ferry-terminal","title":"Ferry terminal","deep_link":"/tools/media/editorial-ledger?sample=1&autorun=0"},{"n":2,"id":"library-hours","title":"Library hours","deep_link":"/tools/media/editorial-ledger?sample=2&autorun=0"}],"deep_link_params":{"sample":"1-based index into samples, or a sample id","autorun":"1 = start the run once the sample is loaded; 0 (default) = only preselect","reduce-motion":"1 = turn off animations"}},"api":{"base":"https://api.decosa.ai","contract":"/api/contract.json","contract_markdown":"/api/contract.md","reference":"/docs/api","keys":"/account/keys"},"prompts":{"hosted":"/prompts/editorial-ledger-hosted.md","selfhost":"/prompts/editorial-ledger-selfhost.md","assemble":"/prompts/editorial-ledger-assemble.md","mac":"/prompts/editorial-ledger-mac.md"},"rehearsal":{"bundle":"/samples/editorial-ledger.zip","bundle_url":"https://decosa.ai/samples/editorial-ledger.zip","folder":"/samples/editorial-ledger/","expected":"/samples/editorial-ledger/expected.json","files":["/samples/editorial-ledger/expected.json","/samples/editorial-ledger/inputs/editor.json","/samples/editorial-ledger/inputs/final.txt","/samples/editorial-ledger/inputs/piece.json"],"bytes":3627,"checks":["the model writes a first draft from the sources","the edit is recorded as a substantial rewrite (over 20% of words changed)","the claim check answered every item","the editor's new lede is listed as an added or edited sentence","a signed-off piece is published without an AI label","the sealed record verifies","the published text is the signed-off text, byte for byte","a record with the sign-off editor changed no longer verifies","every model call has a signed receipt"],"licence":"Synthetic: the Harbour Gazette, Port Aldane and every name, figure and quote are invented for Decosa. Part of decosa-api, AGPL-3.0-or-later.","about":"A fictional newsroom assigns a story from two fictional source documents. The model writes the first draft (receipted), the editor files a rewritten final text, the claim check lists what the edit removed and added, a named editor signs off and the piece is sealed. The sealed record must verify, including that the published text is the signed-off text, and a copy with one entry changed must not.","run":{"containers":"docker compose exec api python scripts/rehearse.py editorial-ledger","checkout":"python scripts/rehearse.py editorial-ledger --bundle editorial-ledger.zip --base-url http://127.0.0.1:8445","mac":".venv/bin/python scripts/rehearse.py editorial-ledger"},"guidance":"Set up with a coding agent (we recommend Claude Code with Claude Opus 5.5; any capable coding agent works) on mock data only, run the rehearsal until every check passes, then run your own data locally yourself. Never give the agent real data during setup."},"hardware_fit":{"check":"/self-host/hardware?use=editorial-ledger","data":"/api/hardware.json","tiers":[{"id":"lite","gpu_gb":0,"basis":null,"unknown":[]},{"id":"standard","gpu_gb":57.6,"basis":"stack","unknown":[]}],"mac":{"fit":"full","memory_gb":32}},"links":{"page":"/tools/media/editorial-ledger","json":"/use-cases/editorial-ledger.json","metrics":"/metrics/editorial-ledger","console":"/tools/media/editorial-ledger","console_sample":"/tools/media/editorial-ledger?sample=1&autorun=0","stack":"/tools/media/editorial-ledger#stack","try_live":"/tools/media/editorial-ledger","watch":"/tools/media/editorial-ledger","build":"/tools/media/editorial-ledger#build","self_host":"/tools/media/editorial-ledger#self-host","prompts":{"hosted":"/prompts/editorial-ledger-hosted.md","selfhost":"/prompts/editorial-ledger-selfhost.md","assemble":"/prompts/editorial-ledger-assemble.md","mac":"/prompts/editorial-ledger-mac.md"}}}