{
  "schema": "csoai.press/0.1",
  "license": "CC-BY-4.0",
  "publisher": "Council of AI (CSOAI Ltd, UK Companies House 16939677)",
  "doctrine": "Measurement, never certification. Verification is free and needs no account. Every line below carries the command that checks it.",
  "window": {
    "from": "2026-09-05",
    "to": "2026-09-11",
    "derivation": "The 7 days ending at the newest date any committed artifact carries. NOT the clock: two requests any interval apart return the same window.",
    "proof": "curl -s https://councilof.ai/api/press.json | jq .window"
  },
  "corrections_this_window": {
    "value": 6,
    "total": 47,
    "kind": "counted",
    "note": "Entries are things we got wrong about ourselves, how they were caught, and the fix. Publishing them is the credibility engine: the body that publishes the number also publishes when it was wrong.",
    "proof": "curl -s https://councilof.ai/api/corrections | jq '.corrections|length'",
    "feed": "https://councilof.ai/feeds/corrections.xml",
    "items": [
      {
        "id": "C-2026-0905-02",
        "date": "2026-09-05",
        "what_was_wrong": "26 SWIFT rail cards were published under public/interop/swift-signed-2026-09/ as signed-swift-<bank>.json with a populated sig_ed25519 field and signed_at timestamp. The field held base64(sha256(card)), not a signature; sig_algo said SHA256-placeholder and the index said the same. A relying party reading the field name, the file name or the directory name was told these were Ed25519-signed. They were not. Nothing verifies.",
        "how_caught": "Outside review of the estate on 2026-09-05 named the 26 placeholder cards as the single most damaging thing an inspector could find. Confirmed against master: 26 of 26 files, sig_algo SHA256-placeholder, producer scripts/badger/csoai-swift-aware.py writing a digest when no key was present.",
        "fix": "Producer changed: with no key it now writes sig_ed25519 null, sig_algo UNSIGNED, signed_at null, a signature_note, into swift-staged-2026-09/ as staged-swift-*.json; the OIDC board-sign path is the only signer. The 26 artifacts were rewritten the same way and moved; swift-signed-index.json is superseded by swift-staged-index.json (total_signed 0, total_staged_unsigned 26). No card here is signed or MEASURED.",
        "proof": "curl -s https://councilof.ai/api/corrections | jq '.corrections[]|select(.id==\"C-2026-0905-02\")'"
      },
      {
        "id": "C-2026-0905-03",
        "date": "2026-09-05",
        "what_was_wrong": "Three public endpoints turned a source they could not read into a number, and two of them published a figure that was wrong while they did it. (1) /api/hub-cards fans out to four Hub index files and totalled whatever came back. Two of the four were answering nothing to the Worker, and both held ONLY UNMEASURED rows, so the endpoint served 682 cells / 647 MEASURED / 35 UNMEASURED when the published population was 717 / 647 / 70. It understated the unmeasured count by exactly half, and the error therefore ran in the flattering direction — the one direction a measurement body may never round. The endpoint did disclose the partial read, but it did so in an honesty field while counts kept publishing quotable integers beside it; a disclosure next to a wrong number does not repair the number, and downstream quotes the number. (2) /api/dashboard/stats derived fleet.online from `.online ?? .nodes?.length ?? 0`. /api/oracle-fleet emits neither field — it answers 200 with a single host's health — so the dashboard published online: 0, meaning no nodes online, against a fleet that was up and answering with 26.9 days of uptime. That is a claim the fleet endpoint never made, invented from two absent keys. The same file coalesced every other aggregate with `?? 0`, so an unreadable /api/gspc would have published measured_axes: 0 while the board carries 22, under a header that claimed honest empty states — but zero is a measurement, not an empty state. (3) /api/hf-spaces returned an empty list on any non-OK response and counted the survivors, so one upstream throttle would publish models: 0, indistinguishable from the org having no models. That one was latent: it agreed with the Hub on the day it was found.",
        "how_caught": "A top-down alignment pass on 2026-09-05 re-ran the estate brief's own verification commands instead of trusting the brief, and /api/hub-cards disagreed with it. Reading all four Hub index files directly showed all four answering 200 and non-empty to a plain client at dataset commit c52587b, while the endpoint's own indexes_read field said 2 of 4. A sweep for the same shape — any endpoint that fans out to N sources and reports whatever came back — found the other two. The dashboard defect had a passing test over it: the fixture mocked /api/oracle-fleet as an object carrying online and nodes, a shape the real endpoint does not return, so a test that invented the upstream could not catch a misread of the real one.",
        "fix": "Every one of the three now distinguishes an unread source from an empty one. A total is published only when all of its sources answered; otherwise the totals are null, what was actually read is offered under a separate name documented as a floor, and each missing source is named with its reason. An index or listing that answers with zero rows counts as READ — the previous code treated any empty result as unreachable, which would have let a legitimately empty source suppress the totals forever. hub-cards additionally retries a failed index once outside the Cloudflare cache, because the fetch carried cacheEverything and a cached non-OK response keeps a source dark for the whole ten-minute window. dashboard/stats gained a sources block naming each upstream's state and a note stating that a null is an unread value and never a measured zero; its fleet.online carries its own note explaining why it is null, so a bare null cannot be re-read as zero. The dashboard UI already rendered a missing value as an em dash, so the honest empty state was available all along and was simply not being sent. Tests were watched failing against the unpatched handlers before being accepted.",
        "proof": "curl -s https://councilof.ai/api/corrections | jq '.corrections[]|select(.id==\"C-2026-0905-03\")'"
      },
      {
        "id": "C-2026-0905-04",
        "date": "2026-09-05",
        "what_was_wrong": "Six public manifests under /interop advertised 36 endpoint references that do not exist: custom-gpt-bridge.json told Custom GPTs to POST /api/measure, /api/verify and /api/xrpl/evidence; chatgpt-features-finish.json listed 14 'features' (/api/voice, /api/vision, /api/calendar, /api/email, ...) each with an endpoint; deep-research-integration.json described a four-endpoint /api/research pipeline; persona-tests.json, chatgpt-skills.json and anchor.json cited /api/anchor, /api/insurance/attest, /api/xrpl/rlusd, /api/xrpl/usdc and /api/scheduler. Every one answered HTTP 404 to GET and POST on 2026-09-05. All six were written by two generators under scripts/badger/ that assemble manifests from a wish-list and never probe a route.",
        "how_caught": "A top-down pass on 2026-09-05 found /api/verify returning 404 and followed the references: three files first, then every /api/ path in the six generated manifests, each probed live with GET and POST.",
        "fix": "Each artifact now carries claims_audit_2026-09-05 naming the dead paths; every dead reference is marked NOT_IMPLEMENTED in place, and the three Custom GPT actions a client would actually call were removed and listed under actions_removed. Both generators now exit at main() with the reason and cannot regenerate the fiction. The rule (an endpoint advertised outward must answer non-404 live) is the one scripts/outward-claims-guard.mjs enforces post-deploy.",
        "proof": "curl -s https://councilof.ai/api/corrections | jq '.corrections[]|select(.id==\"C-2026-0905-04\")'"
      },
      {
        "id": "C-2026-0905-05",
        "date": "2026-09-05",
        "what_was_wrong": "A merged commit and its PR (#1321) stated that a confirmed x402 settlement never reached the revenue ledger: \"a real payment settled and the ledger never saw it\". That is false. The settlement WAS recorded. The reading behind the claim was taken 6 seconds after the settle, and Cloudflare KV list operations are eventually consistent — the record had not propagated yet. Re-read ~20 minutes later, /api/revenue one_number showed settlements 1, all_time 1, records_unreadable 0. No payment was ever lost.",
        "how_caught": "Re-checking the same endpoint later in the same session instead of trusting the first reading. curl -s https://councilof.ai/api/revenue | python3 -c \"import sys,json;print(json.load(sys.stdin)['one_number'])\" — run twice, minutes apart, and the two disagree while nothing else changed.",
        "fix": "This entry records the false claim; the commit message cannot be rewritten. The code change that shipped with it stands on its own merits and is unaffected: recordSettlement had swallowed every KV error into an empty catch, so a failed write and no settlement really were indistinguishable, and it now returns {stored,reason}. What was wrong was the diagnosis, not the fix. A second defect found while re-reading IS real and is corrected in the same change: one zero-value settle from an ephemeral wallet moved one_number.all_time from 0 to 1, counting a wallet we created and controlled, paying nothing, as a distinct non-self buyer — so settlement records now carry zero_value, because the payer-exclusion list can never enumerate a throwaway key.",
        "proof": "curl -s https://councilof.ai/api/corrections | jq '.corrections[]|select(.id==\"C-2026-0905-05\")'"
      },
      {
        "id": "C-2026-0906-01",
        "date": "2026-09-06",
        "what_was_wrong": "CSOAI-ORG/proofof-ai-mcp shipped detect_deepfake_image with a substring-blacklist path check ('/etc/', '/var/', '..'). A blacklist is not a boundary: any path outside the list, and any symlink into a listed directory, was readable — a Local File Inclusion. A security researcher reported it on 2026-06-12 (issue #8) and the report sat unanswered for 86 days.",
        "how_caught": "The 2026-09-06 HF + GitHub audit listed every open issue across the org older than 7 days; the only security report was this one, with zero comments.",
        "fix": "PR #20 on that repository: an allowlist under PROOFOF_ALLOWED_DIR (default ./uploads), realpath-resolved, regular files only, symlink escapes rejected; verified against /etc/hosts, ../ traversal, an escaping symlink and ~/.ssh/id_rsa. The reporter was answered on the issue.",
        "proof": "curl -s https://councilof.ai/api/corrections | jq '.corrections[]|select(.id==\"C-2026-0906-01\")'"
      },
      {
        "id": "C-2026-0905-01",
        "date": "2026-09-05",
        "what_was_wrong": "The ONE root (public/root.json) is documented as republished hourly. Between 2026-09-02T04:14Z (last successful public-root run) and 2026-09-03T06:20Z (first successful run after GitHub reinstated Actions on the CSOAI-ORG account) it was not republished at all: the hourly runs from 05:14Z to 19:58Z on 2 Sep never started (Actions disabled for the account, Support ticket #4720908), and the eight runs from 2026-09-02T20:58Z to 2026-09-03T06:16Z failed at runner start. Cards signed in that window were not in any root a reader could fetch, and the witness pointer kept reporting the 04:14Z root as current, which it was — but nothing said the cadence had stopped.",
        "how_caught": "Run history of .github/workflows/public-root.yml read back on 2026-09-05 after reinstatement: one success at 04:14Z, a gap with no runs at all, eight failures, then success at 06:20Z on 3 Sep. The gap is visible only in the run list; the root, the pointer and the site all looked normal during it.",
        "fix": "This entry records the window. No root bytes were edited (none existed to edit). The as_of field on the root and the checked_at field on the pointer are the only honest freshness signals; HOW-TO-VERIFY-ROOT.md already tells a reader to re-fetch and compare rather than trust a MATCH observation. Structural fix, same day: the witness now also reports a CONFLICT state when two witnessed roots carry the same as_of and different merkle_root values, so a stalled or forked cadence is named rather than inferred.",
        "proof": "curl -s https://councilof.ai/api/corrections | jq '.corrections[]|select(.id==\"C-2026-0905-01\")'"
      }
    ]
  },
  "public_root": {
    "merkle_root": "94e99db52a67931aa38ca6b0aa4574c28a600204107b26ad3beef9b9e366e292",
    "leaves": 169,
    "as_of": "2026-09-11T12:45:44Z",
    "signature_state": "SIGNED",
    "scope": "A valid OpenTimestamps proof over root.json covers root.json BYTES ONLY. It does not anchor the signed-card index and it does not anchor GSPC.",
    "proof": "curl -s https://councilof.ai/root.json | jq '{merkle_root,card_count,as_of}'",
    "feed": "https://councilof.ai/feeds/roots.xml"
  },
  "signed_cards": {
    "indexed": 335,
    "added_this_window": 0,
    "corpus_note": "This is the SIGNED CARD INDEX. It shares no members with the public-root leaf set or the on-disk wrapper count — three corpora, zero identifier overlap.",
    "proof": "curl -s https://councilof.ai/api/state | jq .signed_cards.corpus_relation",
    "verify_one": "curl -s https://councilof.ai/signed/verify-card.mjs  # the same verifier we run",
    "feed": "https://councilof.ai/feeds/cards.xml"
  },
  "doi": {
    "base_dataset_doi": "10.5281/zenodo.21991104",
    "proof": "curl -s https://councilof.ai/api/gspc | jq -r .doi"
  },
  "distribution_surfaces": {
    "live": null,
    "by_status": {
      "queued": 3,
      "drafted": 24
    },
    "kind": "unmeasured",
    "note": "NO surface is confirmed live. The spray log records drafted and queued rows only, every one owner-gated. A drafted row is not a published surface, and this field stays null rather than 0 so the gap is legible rather than counted as an achievement.",
    "proof": "jq '[.[].status]|group_by(.)|map({(.[0]):length})|add' scripts/badger/_spray-log-v2.json"
  },
  "faq": [
    {
      "q": "Do you certify AI systems?",
      "a": "No. We measure, and we do not certify: no conformity marks, no accreditation, no conformity assessments. A grade is never sold, and verification is free and needs no account, permanently."
    },
    {
      "q": "How many corrections have you issued about your own published figures?",
      "a": "47 to date, 6 in the 2026-09-05 to 2026-09-11 window. Each records what was wrong, how it was caught — usually by our own instrument — and the fix. The full ledger is at /api/corrections and the feed is /feeds/corrections.xml."
    },
    {
      "q": "What is the most recent thing you got wrong?",
      "a": "C-2026-0906-01 (2026-09-06). CSOAI-ORG/proofof-ai-mcp shipped detect_deepfake_image with a substring-blacklist path check ('/etc/', '/var/', '..'). A blacklist is not a boundary: any path outside the list, and any symlink into a listed directory, was readable — a Local File Inclusion. A security researcher reported it on 2026-06-12 (issue #8) and the report sat unanswered for 86 days. It was caught: The 2026-09-06 HF + GitHub audit listed every open issue across the org older than 7 days; the only security report was this one, with zero comments. The fix: PR #20 on that repository: an allowlist under PROOFOF_ALLOWED_DIR (default ./uploads), realpath-resolved, regular files only, symlink escapes rejected; verified against /etc/hosts, ../ traversal, an escaping symlink and ~/.ssh/id_rsa. The reporter was answered on the issue."
    },
    {
      "q": "What have you NOT measured?",
      "a": "Revenue: /api/revenue holds every count null until a receipt settles — a count is null, never 0, when there is no source. Distribution: no surface is confirmed live; the spray log holds drafted and queued rows only, so the count is published as null rather than 0. The board publishes its own unmeasured slots rather than hiding them: quote totals.unmeasured_axes from /api/gspc."
    },
    {
      "q": "Can I verify one of your measurements myself, without an account?",
      "a": "Yes, and without asking us. Each signed card carries an Ed25519 signature over a canonical body whose id is the sha-256 of those bytes. Fetch the card, recompute the id, and check the signature against the key published at did:web:csoai.org using the same verifier we run: https://councilof.ai/signed/verify-card.mjs. A signature is an integrity claim, not a truth claim — it says these are the bytes that were signed, not that the measurement inside them is correct."
    },
    {
      "q": "What does your public root actually prove?",
      "a": "It commits to its own leaf list — 169 leaves under merkle_root 94e99db52a67931a… as of 2026-09-11T12:45:44Z. Stranger inclusion means membership in that list. Its OpenTimestamps proof covers root.json bytes only: it does not anchor the signed-card index, and it does not anchor GSPC. Those are separate corpora with zero identifier overlap."
    }
  ],
  "not_announced": [
    {
      "subject": "first settlement",
      "state": "NOT HAPPENED",
      "why": "/api/revenue holds every count at null until a receipt settles: 'a count is null, never 0, when there is no source'. There is nothing to announce and a draft written now would be a press release about a future.",
      "proof": "curl -s https://councilof.ai/api/revenue | jq ."
    },
    {
      "subject": "N sites live",
      "state": "NOT HAPPENED",
      "why": "The spray log carries drafted and queued rows and no live ones. Announcing a number of live surfaces would be counting drafts as placements.",
      "proof": "jq '[.[]|select(.status==\"live\")]|length' scripts/badger/_spray-log-v2.json"
    }
  ]
}