{
  "$schema": "https://openhelvetia.swiss/ns/modules/0.1/schema",
  "recorded": "2026-09-02",
  "state_vocabulary": [
    "in-operation",
    "prepared",
    "in-progress",
    "draft",
    "open",
    "internal"
  ],
  "modules": [
    {
      "id": "mcp-gateway",
      "name": {
        "de": "MCP-Gateway",
        "en": "MCP-Gateway"
      },
      "plan_item": "L2.3",
      "layer": "L2",
      "kind": "service",
      "license": null,
      "summary": {
        "de": "Die Maschinen-Tür der Plattform: dieselben Werkzeuge über MCP und eine JSON-Schnittstelle — 52 Fähigkeiten aus zwei Domänen — mit Abruf-Budget und typisierten Absagen.",
        "en": "The platform's machine door: the same tools over MCP and a JSON shell — 52 capabilities from two domains — with a call budget and typed refusals."
      },
      "description": {
        "de": "Der Gateway ist die Maschinen-Tür der Plattform: dieselben 52 Fähigkeiten über MCP und über eine minimale JSON/HTTP-Schale, beide durch denselben Dispatcher. Die Politik liegt damit an genau einer Stelle — Abruf-Budget, Ratenbegrenzung und typisierte Absagen geschehen einmal, gleich welche Tür der Aufrufer benutzt hat. Die Entdeckung läuft in zwei Stufen: «meta.tools» nennt jedes Werkzeug mit einzeiliger Beschreibung, Domäne und Preis, ohne ein einziges Eingabeschema; «meta.schemas» liefert die Schemata nur der Werkzeuge, die ein Agent auch benannt hat. Dahinter hängen zwei Schnittstellen zu Bundesinfrastruktur, fedlex mit 35 und LINDAS mit 8 Werkzeugen, und ihre Stufe-eins-Zeilen sind wortgleich die des jeweiligen Servers, festgenagelt durch einen Test. Was er nicht tut: die JSON-Schale ist ausdrücklich kein Produktionstransport — eine Verbindung aufs Mal, kein Keep-alive, kein TLS, keine Sitzungen —, und ein abgelehnter Aufruf kostet nichts, weil beide Schranken vor jeder Belastung geprüft werden. Einen öffentlichen Endpunkt serviert er bis heute nicht.",
        "en": "The gateway is the platform's machine door: the same 52 capabilities over MCP and over a minimal JSON/HTTP shell, both through one dispatcher. Policy therefore lives in exactly one place — the call budget, the rate limit and the typed refusals happen once, whichever door the caller used. Discovery runs in two stages: «meta.tools» names every tool with a one-line summary, its domain and its price, and carries no input schema at all; «meta.schemas» hands over the schemas of only the tools an agent actually named. Two interfaces to federal infrastructure are mounted behind it, fedlex with 35 tools and LINDAS with 8, and their stage-one lines are the servers' own, verbatim, pinned by a test. What it refuses to be: the JSON shell is explicitly not the production transport — one connection at a time, no keep-alive, no TLS, no sessions — and a refused call costs nothing, because both bounds are checked before either is charged. It serves no public endpoint to this day."
      },
      "state": "prepared",
      "public_endpoint": false,
      "since": null,
      "source": {
        "path": "mcp/gateway",
        "repo": {
          "available": false,
          "reason": {
            "de": "Der Quellcode wird mit der Publikations-Strecke öffentlich; das Repository ist noch nicht freigeschaltet.",
            "en": "The source becomes public with the publication lane; the repository is not yet switched public."
          }
        }
      },
      "release": {
        "available": false,
        "reason": {
          "de": "Noch kein getaggtes Release; das erste folgt mit der Publikations-Strecke.",
          "en": "No tagged release yet; the first follows the publication lane."
        }
      },
      "image": {
        "available": false,
        "reason": {
          "de": "Noch kein Container-Image veröffentlicht.",
          "en": "No container image published yet."
        }
      },
      "crate": null,
      "run": {
        "available": true,
        "requires": [
          {
            "de": "Rust (stable über rustup) und Git; alle Befehle laufen aus der Wurzel des Korpus-Checkouts.",
            "en": "Rust (stable via rustup) and Git; every command runs from the root of the corpus checkout."
          }
        ],
        "commands": [
          "cargo run --locked --manifest-path mcp/gateway/Cargo.toml -- --root . --http 8700 --fedlex-fixtures mcp/servers/fedlex/tests/fixtures --lindas-fixtures mcp/servers/lindas/tests/fixtures"
        ],
        "expect": "gateway on 127.0.0.1:8700",
        "note": {
          "de": "Mit den Fixture-Flags antworten beide Schnittstellen aus aufgezeichneten Dateien, ohne Netz. Ohne die Flags fragt der Gateway die öffentlichen Endpunkte des Bundes.",
          "en": "With the fixture flags both interfaces answer from recorded files, without network. Without them the gateway asks the federal public endpoints."
        }
      },
      "test": {
        "available": true,
        "command": "cargo test --locked --manifest-path mcp/gateway/Cargo.toml",
        "fixtures": "mcp/gateway/tests",
        "offline": true
      },
      "access": {
        "public": {
          "available": false,
          "reason": {
            "de": "Kein öffentlicher Endpunkt: weder Zone noch Route noch Deployment sind aufgeschaltet.",
            "en": "No public endpoint: zone, route and deployment are not switched on."
          }
        },
        "local": "http://127.0.0.1:8700 — GET /tools, POST /tool/<id>, POST /mcp",
        "contracts": [
          {
            "label": {
              "de": "Werkzeug-Inventar (Stufe eins)",
              "en": "Tool inventory (stage one)"
            },
            "path": "mcp/gateway/tool-inventory.json"
          },
          {
            "label": {
              "de": "RFC-9728-Metadaten",
              "en": "RFC 9728 metadata"
            },
            "path": "mcp/gateway/oauth-protected-resource.json"
          }
        ],
        "example": {
          "label": {
            "de": "Ein Domänenwerkzeug über die JSON-Hülle aufrufen",
            "en": "Call a domain tool through the JSON shell"
          },
          "request": "curl -s -X POST http://127.0.0.1:8700/tool/lindas.list_cubes -H 'content-type: application/json' -d '{}'",
          "response": "{\"cubes\":[{\"cube\":\"https://politics.ld.admin.ch/fc/cube-chancellor\",\"description\":\"Bundeskanzler der Schweiz mit Partei, Kanton und Amtszeiten.\",\"family\":\"fc\",\"name\":\"Bundeskanzler\",\"observations\":15, …}, …]}"
        }
      },
      "cli_help": "usage: oh-mcp-gateway --root <repo root> [--budget <n>] [--rate <n/min>] [--burst <n>] [--trust-forwarded-for] [--upstream-rate <n/s>] [--fedlex-fixtures <dir>] [--lindas-fixtures <dir>] [--http <port>] [--model-key-file <path>] [--model-cap <answers/client/day>]",
      "depends_on": [
        "fedlex-engine",
        "political-data-engine",
        "api-spine"
      ],
      "used_by": [
        "a2a-agent"
      ],
      "docs": "docs/how-to/call-the-gateway/",
      "evidence": [
        {
          "label": {
            "de": "Fähigkeiten im Inventar",
            "en": "Capabilities in the inventory"
          },
          "value": "52",
          "source": "mcp/gateway/tool-inventory.json",
          "recorded": "2026-09-02",
          "derived": true,
          "note": {
            "de": "52, aufgeteilt auf 8 Domänen: 35 fedlex, 8 lindas, 3 meta, 2 facts, je 1 directory, manifest, publish, standard",
            "en": "52, aufgeteilt auf 8 Domänen: 35 fedlex, 8 lindas, 3 meta, 2 facts, je 1 directory, manifest, publish, standard"
          },
          "recount": {
            "kind": "json-length",
            "file": "mcp/gateway/tool-inventory.json",
            "pointer": ""
          }
        },
        {
          "label": {
            "de": "Tests",
            "en": "Tests"
          },
          "value": {
            "de": "48, keiner davon übersprungen (5 im lib, 14 e2e, 14 http_shell, 6 inventory, 3 policy, 6 resource)",
            "en": "48, none of them skipped (5 in lib, 14 e2e, 14 http_shell, 6 inventory, 3 policy, 6 resource)"
          },
          "source": "mcp/gateway",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Was das Inventar vor dem Abdriften hält",
            "en": "What holds the inventory from drifting"
          },
          "value": {
            "de": "Drei Flächen, eine Quelle: der Tool-Router, die committete tool-inventory.json und der REST-Endpunkt der API-Spine müssen identisch sein — als Test und zusätzlich als Diff in der Prüfstrecke",
            "en": "Three surfaces, one source: the tool router, the committed tool-inventory.json and the API spine's REST endpoint must be identical — as a test and again as a diff in the check gate"
          },
          "source": "mcp/gateway",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Was das Budget tut",
            "en": "What the budget does"
          },
          "value": {
            "de": "Harte gewichtete Schranke je Sitzung (--budget n): eine lokale Registerlesung wiegt 1, jeder Aufruf an eine montierte Domäne (fedlex.*, lindas.*) wiegt 2; es erholt sich nie, ohne Flag ist es unbegrenzt",
            "en": "A hard weighted cap per session (--budget n): a local register read weighs 1, every call into a mounted domain (fedlex.*, lindas.*) weighs 2; it never recovers, and without the flag it is unlimited"
          },
          "source": "mcp/gateway",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Was die Ratenbegrenzung tut",
            "en": "What the rate limit does"
          },
          "value": {
            "de": "Token-Bucket je Client, in denselben Gewichtseinheiten: standardmässig 60 pro Minute mit Burst 20 (nie unter 2, sonst käme kein Domänenaufruf durch); sie erholt sich von selbst, die Absage nennt retry_after_ms, und die Zähler liegen nur im Prozessspeicher",
            "en": "A token bucket per client, in the same weight units: 60 per minute by default with a burst of 20 (never below 2, or no domain call would get through); it recovers on its own, the refusal names retry_after_ms, and the counters live in process memory only"
          },
          "source": "mcp/gateway",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Öffentlicher Endpunkt",
            "en": "Public endpoint"
          },
          "value": {
            "de": "Nicht serviert. Der Identifikator mcp.openhelvetia.swiss/mcp steht im Code, die beiden eigenen Einträge stehen seit 02.09.2026 im Register und tragen den Prüfstand «nie geprüft», bis der Endpunkt antwortet",
            "en": "Not served. The identifier mcp.openhelvetia.swiss/mcp is in the code; the two own entries have been in the register since 02.09.2026 and carry the verification state «never checked» until the endpoint answers"
          },
          "source": "mcp/gateway",
          "recorded": "2026-09-01",
          "derived": false
        }
      ],
      "missing": [
        {
          "text": {
            "de": "Es fehlt der öffentliche Endpunkt: die streamable-HTTP-Tür existiert im Code, aber weder Zone noch Route noch Deployment — und daran hängt die tägliche Liveness-Prüfung ebenso wie die Publikation der beiden vorbereiteten Einträge. Budget- und Ratenzähler leben nur im Prozessspeicher, ein Autorisierungsserver für die deklarierte RFC-9728-Kette existiert nicht, und der Orchestrator, dessen erster Schritt die zweistufige Entdeckung ist, ist nicht gebaut.",
            "en": "The public endpoint is missing: the streamable-HTTP door exists in the code, but there is no zone, no route and no deployment — and the daily liveness probe as well as the publication of both prepared entries hang on exactly that. Budget and rate counters live in process memory only, no authorization server exists for the declared RFC 9728 chain, and the orchestrator whose first step two-stage discovery is has not been built."
          },
          "blocks": "in-operation"
        }
      ],
      "history": []
    },
    {
      "id": "fedlex-engine",
      "name": {
        "de": "fedlex-Engine",
        "en": "fedlex-Engine"
      },
      "plan_item": "L2.2",
      "layer": "L2",
      "kind": "service",
      "license": null,
      "summary": {
        "de": "Der Eigenbau über dem öffentlichen Fedlex-Endpunkt des Bundes: SR-Nummern, Fassungen, Artikeltexte — jede Antwort mit Beleg. Der erste ausgebaute Bereich.",
        "en": "The own build over the Confederation's public Fedlex endpoint: SR numbers, versions, article texts — every answer with provenance. The first built area."
      },
      "description": {
        "de": "Der fedlex-Server liest das Bundesrecht dort, wo der Bund es publiziert: über den öffentlichen SPARQL-Endpunkt fedlex.data.admin.ch/sparqlendpoint und die Akoma-Ntoso-Fassungen im selben Filestore. 35 Werkzeuge — eine SR-Nummer auflösen, die Fassungen einer Erlassfamilie listen, einen Artikel im Wortlaut lesen, ein Zitat gegen den gelesenen Normtext prüfen, die Fundstelle bilden —, und jede Antwort trägt ihre Herkunft und den Moment, in dem sie wirklich geholt wurde. Vor dem Server stand die Datenkunde: 123 Regeln aus zwei Regelwerken, und für jede sagt eine Konformitätstabelle, ob dieser Server sie einhält, ihr widerspricht oder bloss nicht geprüft ist. Ein Test liest diese Tabelle aus: eine Zeile, die «honoured» behauptet, muss einen Test benennen, den es gibt und der auch läuft — «sieht richtig aus» heisst untested, nie honoured. Was er nicht tut: er erfindet keinen Text, ein zwischengespeicherter Erlass wird nie an die Stelle einer Antwort gesetzt, die der Graph verweigert hat, und gegen den Bund geht höchstens eine höfliche Anfrage aufs Mal — zwei pro Sekunde, sonst eine typisierte Absage statt einer Warteschlange.",
        "en": "The fedlex server reads federal law where the Confederation publishes it: over the public SPARQL endpoint fedlex.data.admin.ch/sparqlendpoint and the Akoma Ntoso versions in the same filestore. 35 tools — resolve an SR number, list the versions of an act, read an article in its wording, check a quote against the norm text that was read, build the canonical citation — and every answer carries its provenance and the moment it was really retrieved. The data knowledge came before the server: 123 rules from two rulebooks, and for each one a conformance table says whether this server honours it, contradicts it or merely happens not to be tested. A test parses that table: a row claiming «honoured» must name a test that exists and actually runs — «it looks right» is untested, never honoured. What it refuses to do: it invents no text, a cached act is never served in place of an answer the graph refused, and it makes at most one polite request at a time to the federal host — two a second, beyond that a typed refusal rather than a queue."
      },
      "state": "prepared",
      "public_endpoint": false,
      "since": null,
      "source": {
        "path": "mcp/servers/fedlex",
        "repo": {
          "available": true,
          "url": "https://github.com/OpenHelvetia/mcp-fedlex-oh"
        }
      },
      "release": {
        "available": false,
        "reason": {
          "de": "Noch kein getaggtes Release; das erste folgt mit der Publikations-Strecke.",
          "en": "No tagged release yet; the first follows the publication lane."
        }
      },
      "image": {
        "available": false,
        "reason": {
          "de": "Noch kein Container-Image veröffentlicht.",
          "en": "No container image published yet."
        }
      },
      "crate": null,
      "run": {
        "available": true,
        "requires": [
          {
            "de": "Rust (stable über rustup) und Git; alle Befehle laufen aus der Wurzel des Korpus-Checkouts.",
            "en": "Rust (stable via rustup) and Git; every command runs from the root of the corpus checkout."
          }
        ],
        "commands": [
          "cargo run --locked --manifest-path mcp/gateway/Cargo.toml -- --root . --http 8700 --fedlex-fixtures mcp/servers/fedlex/tests/fixtures --lindas-fixtures mcp/servers/lindas/tests/fixtures"
        ],
        "expect": "gateway on 127.0.0.1:8700",
        "note": {
          "de": "Der Server spricht MCP über stdin/stdout und hat keine eigene Netzadresse; der einfachste Start ist hinter dem Gateway mit Fixtures. Direkt: cargo run --locked --manifest-path mcp/servers/fedlex/Cargo.toml -- --fixtures mcp/servers/fedlex/tests/fixtures, dann verbindet sich ein MCP-Client über stdio.",
          "en": "The server speaks MCP over stdin/stdout and has no network address of its own; the simplest start is behind the gateway with fixtures. Directly: cargo run --locked --manifest-path mcp/servers/fedlex/Cargo.toml -- --fixtures mcp/servers/fedlex/tests/fixtures, then an MCP client connects over stdio."
        }
      },
      "test": {
        "available": true,
        "command": "cargo test --locked --manifest-path mcp/servers/fedlex/Cargo.toml",
        "fixtures": "mcp/servers/fedlex/tests/fixtures",
        "offline": true
      },
      "access": {
        "public": {
          "available": false,
          "reason": {
            "de": "Kein öffentlicher Endpunkt: weder Zone noch Route noch Deployment sind aufgeschaltet.",
            "en": "No public endpoint: zone, route and deployment are not switched on."
          }
        },
        "local": "über das Gateway: POST http://127.0.0.1:8700/tool/fedlex.<werkzeug>",
        "contracts": [
          {
            "label": {
              "de": "Werkzeugvertrag v1",
              "en": "Tool contract v1"
            },
            "path": "mcp/servers/fedlex/TOOLSET-v1.md"
          },
          {
            "label": {
              "de": "Regelwerk",
              "en": "Rulebook"
            },
            "path": "docs/reference/fedlex-data-rules.md"
          },
          {
            "label": {
              "de": "Engine-Manifest",
              "en": "Engine manifest"
            },
            "path": "mcp/servers/fedlex/engine.manifest.json"
          }
        ],
        "example": {
          "label": {
            "de": "Die fedlex-Zeilen der Werkzeugliste",
            "en": "The fedlex rows of the tool list"
          },
          "request": "curl -s http://127.0.0.1:8700/tools",
          "response": "[{\"id\":\"directory.get\",\"domain\":\"directory\",\"summary\":\"The directory envelope (v0.2, authority: manifest). …\",\"weight\":1}, … 52 rows]"
        }
      },
      "cli_help": null,
      "depends_on": [],
      "used_by": [
        "mcp-gateway"
      ],
      "docs": "docs/how-to/call-the-gateway/",
      "evidence": [
        {
          "label": {
            "de": "Werkzeuge",
            "en": "Tools"
          },
          "value": "35",
          "source": "mcp/gateway/tool-inventory.json",
          "recorded": "2026-09-02",
          "derived": true,
          "note": {
            "de": "35 (der 8er-Spine von TOOLSET-v0.md, 12 Navigator-Werkzeuge, 13 der zweiten Welle, dazu das Zitat-Paar)",
            "en": "35 (der 8er-Spine von TOOLSET-v0.md, 12 Navigator-Werkzeuge, 13 der zweiten Welle, dazu das Zitat-Paar)"
          },
          "recount": {
            "kind": "json-count-where",
            "file": "mcp/gateway/tool-inventory.json",
            "pointer": "",
            "field": "domain",
            "equals": "fedlex"
          }
        },
        {
          "label": {
            "de": "Tests",
            "en": "Tests"
          },
          "value": {
            "de": "114 laufen (31 im lib, 76 e2e, 7 Regel-Gate); 15 weitere sind bewusste Aufnahmeläufe mit #[ignore], die live an den Bund gehen",
            "en": "114 run (31 in lib, 76 e2e, 7 rule gate); 15 more are deliberate recording runs marked #[ignore] that go live to the Confederation"
          },
          "source": "mcp/servers/fedlex",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Regelwerk und Konformitätstabelle",
            "en": "Rulebook and conformance table"
          },
          "value": {
            "de": "docs/reference/fedlex-data-rules.md: 123 Regeln (80 JOLux-Regeln J…, 43 Akoma-Ntoso-Regeln X…) — 99 honoured, 15 untested, 3 violated, 6 not_applicable",
            "en": "docs/reference/fedlex-data-rules.md: 123 rules (80 JOLux rules J…, 43 Akoma Ntoso rules X…) — 99 honoured, 15 untested, 3 violated, 6 not_applicable"
          },
          "source": "mcp/servers/fedlex",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Das Gate über der Tabelle",
            "en": "The gate over the table"
          },
          "value": {
            "de": "mcp/servers/fedlex/tests/rules_table.rs, 7 laufende Tests: eine «honoured»-Zeile muss eine Funktion mit #[test]/#[tokio::test] ohne #[ignore] benennen, eine «untested»-Zeile darf keinen toten Namen tragen, und ein Status ausserhalb der fünf zulässigen ist ein Fehler",
            "en": "mcp/servers/fedlex/tests/rules_table.rs, 7 running tests: an «honoured» row must name a function marked #[test]/#[tokio::test] without #[ignore], an «untested» row may not carry a dead name, and a status outside the five permitted ones is an error"
          },
          "source": "mcp/servers/fedlex",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Fixture-Mechanismus",
            "en": "Fixture mechanism"
          },
          "value": {
            "de": "102 aufgezeichnete Dateien (94 JSON-SPARQL-Antworten, 8 Akoma-Ntoso-XML) unter SEMANTISCHEN Schlüsseln — Werkzeug plus Parameter, nie Query-Bytes; INDEX.txt führt genau 102 Zeilen mit Schlüssel und Aufnahmedatum, sodass eine umgeschriebene Query neu aufgezeichnet werden muss statt still am Fixture vorbeizulaufen",
            "en": "102 recorded files (94 JSON SPARQL answers, 8 Akoma Ntoso XML) under SEMANTIC keys — tool plus parameters, never query bytes; INDEX.txt holds exactly 102 lines with key and recording date, so a rewritten query has to be re-recorded instead of silently missing the fixture"
          },
          "source": "mcp/servers/fedlex",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Vendierte Fremdcrates",
            "en": "Vendored upstream crates"
          },
          "value": {
            "de": "Drei: fedlex-akn, fedlex-jolux, fedlex-core unter third_party/mcp-fedlex, Apache-2.0, byte-identisch am Pin 64e0ec3fdce3cc6841fa9f659456a520c1e21083 (Upstream-Commit vom 09.07.2026), mit SHA-256 je Crate im PROVENANCE.md",
            "en": "Three: fedlex-akn, fedlex-jolux, fedlex-core under third_party/mcp-fedlex, Apache-2.0, byte-identical at pin 64e0ec3fdce3cc6841fa9f659456a520c1e21083 (upstream commit of 09.07.2026), with a SHA-256 per crate in PROVENANCE.md"
          },
          "source": "mcp/servers/fedlex",
          "recorded": "2026-09-01",
          "derived": false
        }
      ],
      "missing": [
        {
          "text": {
            "de": "Drei Regeln stehen offen als «violated» statt als grünes Häkchen: find_treaties sucht einen Staatsvertrag noch als eine zusammenhängende Zeichenkette und verfehlt ihn unter seinem amtlichen mehrwortigen Titel (J3.5); get_article_history sieht die Wirkungen nicht, die als blosser Kommentar auf Erlassebene hängen (J6.3); und der vendierte Textschreiber erzeugt für ein <br/> gar nichts — die Zählung über die acht aufgezeichneten Fassungen findet 74 Zeilenumbrüche, von denen 21 zwei Wörter zusammenlaufen lassen (X6.1). Weitere 15 Regeln sind untested, es gibt keinen öffentlichen Endpunkt, und die semantische Stufe über der Basis ist nicht gebaut.",
            "en": "Three rules stand open as «violated» rather than as a green tick: find_treaties still searches a treaty as one contiguous string and misses it under its official multi-word title (J3.5); get_article_history does not see impacts that hang as a mere comment at act level (J6.3); and the vendored text writer produces nothing at all for a <br/> — the census over the eight recorded versions finds 74 line breaks, 21 of which run two words together (X6.1). A further 15 rules are untested, there is no public endpoint, and the semantic tier above the base has not been built."
          },
          "blocks": "in-operation"
        }
      ],
      "history": [
        {
          "date": "2026-09-03",
          "text": {
            "de": "Quellcode als eigenes Repository auf GitHub publiziert (Publikations-Strecke, Welle 1).",
            "en": "Source published as its own repository on GitHub (publication lane, wave 1)."
          }
        }
      ],
      "entry": "openhelvetia-fedlex-mcp"
    },
    {
      "id": "political-data-engine",
      "name": {
        "de": "Politikdaten-Engine",
        "en": "Politikdaten-Engine"
      },
      "plan_item": "L2.7",
      "layer": "L2",
      "kind": "service",
      "license": null,
      "summary": {
        "de": "Der Eigenbau über dem öffentlichen LINDAS-Endpunkt der Bundeskanzlei: Volksabstimmungen je Kanton samt Ständemehr, Referendumsvorlagen, Volksinitiativen, Bundesrat und Nationalratswahlen — 44 Würfel, jede Zahl mit ihrer Herkunft.",
        "en": "The own build over the Federal Chancellery's public LINDAS endpoint: popular votes per canton with the Ständemehr, referendum bills, popular initiatives, the Federal Council and National Council elections — 44 cubes, every figure with its provenance."
      },
      "description": {
        "de": "Der LINDAS-Server liest die politischen Datenwürfel des Bundes über den öffentlichen SPARQL-Endpunkt lindas.admin.ch/query — 44 Würfel unter politics.ld.admin.ch: Volksabstimmungen, Referendumsvorlagen, Volksinitiativen, die Nationalratswahlen 2019, 2023 und 2027, der Bundesrat und das Register der Interessenbindungen der Bundeskanzlei. Acht Werkzeuge: die Liste der Würfel mit ihren Zuständen, die Suche nach einem Wort des Namens, die deklarierten Dimensionen eines Würfels, die Werte einer Dimension, die Zeilen selbst mit Filtern, die Fassungen einer Familie, alles zu einer IRI und die Auflösung einer IRI zu ihrer Beschriftung. Die Reihenfolge ist der Punkt: zuerst wurde der Bestand gemessen, daraus wurden 58 Regeln, daraus 38 nummerierte Vertragspunkte, und erst dann dieser Server. Er rechnet nicht: das Ständemehr wird aus der Zeile GELESEN, nie aus den Kantonen gezählt — Zählen ergibt 17, wo die Bundeskanzlei 15.5 ausweist —, und ein Abstimmungsausgang kommt aus seiner eigenen Dimension, nie aus dem Ja-Anteil. Zustände sind Antworten, keine Fehler: ein publizierter Würfel ohne Beobachtungen sagt, dass er einer ist, und «nicht angegeben» bleibt «nicht angegeben», nie 0. Eine Lizenz nennt die Quelle nicht, und jede Antwort sagt das.",
        "en": "The LINDAS server reads the Confederation's political data cubes over the public SPARQL endpoint lindas.admin.ch/query — 44 cubes under politics.ld.admin.ch: popular votes, referendum bills, popular initiatives, the National Council elections of 2019, 2023 and 2027, the Federal Council and the Federal Chancellery's register of vested interests. Eight tools: the list of cubes with their states, search by a word of the name, a cube's declared dimensions, the values one dimension takes, the rows themselves with filters, the versions of a family, everything the store says about one IRI, and an IRI resolved to its label. The order is the point: the holding was measured first, the measurements became 58 rules, the rules became 38 numbered contract points, and only then this server. It does no arithmetic: the Ständemehr is READ from the row, never counted from the cantons — counting gives 17 where the Chancellery states 15.5 — and a ballot outcome comes from its own dimension, never from the yes share. States are answers, not faults: a published cube holding no observations says that it is one, and «not stated» stays «not stated», never 0. No licence is stated at the source, and every answer says so."
      },
      "state": "prepared",
      "public_endpoint": false,
      "since": null,
      "source": {
        "path": "mcp/servers/lindas",
        "repo": {
          "available": true,
          "url": "https://github.com/OpenHelvetia/mcp-lindas-politics-oh"
        }
      },
      "release": {
        "available": false,
        "reason": {
          "de": "Noch kein getaggtes Release; das erste folgt mit der Publikations-Strecke.",
          "en": "No tagged release yet; the first follows the publication lane."
        }
      },
      "image": {
        "available": false,
        "reason": {
          "de": "Noch kein Container-Image veröffentlicht.",
          "en": "No container image published yet."
        }
      },
      "crate": null,
      "run": {
        "available": true,
        "requires": [
          {
            "de": "Rust (stable über rustup) und Git; alle Befehle laufen aus der Wurzel des Korpus-Checkouts.",
            "en": "Rust (stable via rustup) and Git; every command runs from the root of the corpus checkout."
          }
        ],
        "commands": [
          "cargo run --locked --manifest-path mcp/gateway/Cargo.toml -- --root . --http 8700 --fedlex-fixtures mcp/servers/fedlex/tests/fixtures --lindas-fixtures mcp/servers/lindas/tests/fixtures"
        ],
        "expect": "gateway on 127.0.0.1:8700",
        "note": {
          "de": "Wie die fedlex-Engine: MCP über stdio, einfachster Start hinter dem Gateway. Direkt: cargo run --locked --manifest-path mcp/servers/lindas/Cargo.toml -- --fixtures mcp/servers/lindas/tests/fixtures.",
          "en": "Like the fedlex engine: MCP over stdio, simplest start behind the gateway. Directly: cargo run --locked --manifest-path mcp/servers/lindas/Cargo.toml -- --fixtures mcp/servers/lindas/tests/fixtures."
        }
      },
      "test": {
        "available": true,
        "command": "cargo test --locked --manifest-path mcp/servers/lindas/Cargo.toml",
        "fixtures": "mcp/servers/lindas/tests/fixtures",
        "offline": true
      },
      "access": {
        "public": {
          "available": false,
          "reason": {
            "de": "Kein öffentlicher Endpunkt: weder Zone noch Route noch Deployment sind aufgeschaltet.",
            "en": "No public endpoint: zone, route and deployment are not switched on."
          }
        },
        "local": "über das Gateway: POST http://127.0.0.1:8700/tool/lindas.<werkzeug>",
        "contracts": [
          {
            "label": {
              "de": "Werkzeugvertrag v0",
              "en": "Tool contract v0"
            },
            "path": "mcp/servers/lindas/TOOLSET-v0.md"
          },
          {
            "label": {
              "de": "Regelwerk",
              "en": "Rulebook"
            },
            "path": "docs/reference/lindas-cube-rules.md"
          },
          {
            "label": {
              "de": "Engine-Manifest",
              "en": "Engine manifest"
            },
            "path": "mcp/servers/lindas/engine.manifest.json"
          }
        ],
        "example": {
          "label": {
            "de": "Alle 44 Würfel auflisten",
            "en": "List all 44 cubes"
          },
          "request": "curl -s -X POST http://127.0.0.1:8700/tool/lindas.list_cubes -H 'content-type: application/json' -d '{}'",
          "response": "{\"cubes\":[{\"cube\":\"https://politics.ld.admin.ch/fc/cube-chancellor\",\"description\":\"Bundeskanzler der Schweiz mit Partei, Kanton und Amtszeiten.\",\"family\":\"fc\",\"name\":\"Bundeskanzler\",\"observations\":15, …}, …]}"
        }
      },
      "cli_help": null,
      "depends_on": [],
      "used_by": [
        "mcp-gateway"
      ],
      "docs": "docs/how-to/call-the-gateway/",
      "evidence": [
        {
          "label": {
            "de": "Werkzeuge",
            "en": "Tools"
          },
          "value": "8",
          "source": "mcp/gateway/tool-inventory.json",
          "recorded": "2026-09-02",
          "derived": true,
          "note": {
            "de": "8: list_cubes, find_cube, describe_cube, dimension_values, observations, list_versions, describe, resolve_label",
            "en": "8: list_cubes, find_cube, describe_cube, dimension_values, observations, list_versions, describe, resolve_label"
          },
          "recount": {
            "kind": "json-count-where",
            "file": "mcp/gateway/tool-inventory.json",
            "pointer": "",
            "field": "domain",
            "equals": "lindas"
          }
        },
        {
          "label": {
            "de": "Tests",
            "en": "Tests"
          },
          "value": {
            "de": "64 laufen (22 im lib, 7 Vertrags-Gate, 35 e2e); 5 weitere sind bewusste Aufnahmeläufe mit #[ignore], die live an lindas.admin.ch gehen",
            "en": "64 run (22 in lib, 7 contract gate, 35 e2e); 5 more are deliberate recording runs marked #[ignore] that go live to lindas.admin.ch"
          },
          "source": "mcp/servers/lindas",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Vertrag und sein Gate",
            "en": "Contract and its gate"
          },
          "value": {
            "de": "mcp/servers/lindas/TOOLSET-v0.md führt 38 nummerierte Punkte P1–P38; 37 sind durch einen laufenden Test festgenagelt, 1 (P18, verwandte Würfel) ist mit Grund zurückgestellt — das Gate tests/contract_table.rs lässt keinen dritten Zustand zu",
            "en": "mcp/servers/lindas/TOOLSET-v0.md lists 38 numbered points P1–P38; 37 are pinned by a running test, 1 (P18, related cubes) is deferred with a reason — the gate tests/contract_table.rs admits no third state"
          },
          "source": "mcp/servers/lindas",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Regelwerk",
            "en": "Rulebook"
          },
          "value": {
            "de": "docs/reference/lindas-cube-rules.md: 58 Regeln C0.1 bis C14.1 über 14 Kapitel (Umfang, Identifikatoren, Schema, Werte, Beschriftungen, Status, Mengen, Relationen, Abstimmungen, Referenden, Wahlen, das apg-Register, Endpunktverhalten, Vollständigkeit) — jede mit ihrer Messzahl vom 29./30.08.2026",
            "en": "docs/reference/lindas-cube-rules.md: 58 rules C0.1 to C14.1 over 14 chapters (scope, identifiers, schema, values, labels, status, sets, relations, votes, referendums, elections, the apg register, endpoint behaviour, completeness) — each with its measured figure of 29./30.08.2026"
          },
          "source": "mcp/servers/lindas",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Aufnahmelauf",
            "en": "Recording pass"
          },
          "value": {
            "de": "104 Anfragen über 78 Schlüssel — die Zahl wird gemessen, bevor sie geglaubt wird: ein Zähl-Backend spielt dieselbe Aufruffolge nach und ein Test hält das Ergebnis; dieselbe Zahl steht in README, ENGINE.md und Manifest und wird von der Prüfstrecke aus der Testdatei ausgelesen",
            "en": "104 requests over 78 keys — the figure is measured before it is believed: a counting backend replays the same call sequence and a test holds the result; the same figure stands in README, ENGINE.md and the manifest and is read from the test file by the check gate"
          },
          "source": "mcp/servers/lindas",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Nie eine Zahl ableiten",
            "en": "Never deriving a figure"
          },
          "value": {
            "de": "Vertragspunkte P19 und P20: der Ausgang wird aus der Dimension «ergebnis» gelesen, das Ständemehr aus standesstimmenJa/-Nein und den Kantonszählern — kein Werkzeug zählt Kantone und keines summiert kantonale Zeilen. Der Test liest für den 07.02.1971 standesstimmenJa 15.5, standesstimmenNein 6.5 und «14 3/2», nicht die 17, die Zählen ergäbe",
            "en": "Contract points P19 and P20: the outcome is read from the «ergebnis» dimension, the cantonal majority from standesstimmenJa/-Nein and the cantonal counters — no tool counts cantons and none sums cantonal rows. For 07.02.1971 the test reads standesstimmenJa 15.5, standesstimmenNein 6.5 and «14 3/2», not the 17 that counting would give"
          },
          "source": "mcp/servers/lindas",
          "recorded": "2026-09-01",
          "derived": false
        }
      ],
      "missing": [
        {
          "text": {
            "de": "Ein öffentlicher Endpunkt fehlt: der Eintrag Nr. 2 ist vollständig, validiert und steht seit 02.09.2026 im Register, Prüfstand «nie geprüft», bis der Endpunkt antwortet. Ein Vertragspunkt ist zurückgestellt (P18 — verwandte Würfel werden gar nicht genannt, weil das Register keine Verknüpfung trägt), Verknüpfungen über Würfel hinweg und jede Graph-Aufzählung sind bewusst nicht gebaut, vier der 44 Würfel sind bisher leere Platzhalter, und die Regel-Zahlen sind Messungen vom 29./30.08.2026 an einem Bestand, der gepflegt wird und damit altert.",
            "en": "A public endpoint is missing: entry no. 2 is complete, validated and listed in the register since 02.09.2026, verification state «never checked» until the endpoint answers. One contract point is deferred (P18 — related cubes are not named at all, because the register carries no link), joins across cubes and any graph enumeration are deliberately not built, four of the 44 cubes are still empty placeholders, and the rulebook's figures are measurements of 29/30 August 2026 against a holding that is maintained and therefore ages."
          },
          "blocks": "in-operation"
        }
      ],
      "history": [
        {
          "date": "2026-09-03",
          "text": {
            "de": "Quellcode als eigenes Repository auf GitHub publiziert (Publikations-Strecke, Welle 1).",
            "en": "Source published as its own repository on GitHub (publication lane, wave 1)."
          }
        }
      ],
      "entry": "openhelvetia-lindas-mcp"
    },
    {
      "id": "registry-standard",
      "name": {
        "de": "Registry-Standard",
        "en": "Registry-Standard"
      },
      "plan_item": "L0",
      "layer": "L0",
      "kind": "standard",
      "license": null,
      "summary": {
        "de": "Manifest-Standard, Schemas, Ontologie und Kontext, auf denen das Verzeichnis steht.",
        "en": "The manifest standard, schemas, ontology and context the directory stands on."
      },
      "description": {
        "de": "Der Registry-Standard ist das Regelwerk, auf dem das Verzeichnis steht: ein Manifest-Profil über DCAT-AP-CH mit einer Erweiterung für KI-Schnittstellen, dazu JSON-Schema, JSON-LD-Kontext, SHACL-Shapes und die oh:-Ontologie. Ein Manifest ist gewöhnliches JSON in genau einer normierten Gestalt — bis hinunter zu den Bytes: feste Schlüsselreihenfolge, zwei Leerzeichen Einzug, LF, Schlusszeile, damit ein Git-Diff Inhalt trägt und nicht Stil. Das Werkzeug oh-validate fährt vier Stufen über den ganzen Korpus: JSON-Schema, JSON-LD-Rundlauf gegen den mitgelieferten Kontext, SHACL gegen die versionierten Shapes, und zuletzt den Zusammenzug aller Dokumente zu einem einzigen Graphen mit RDFC-1.0-Fingerabdruck und kritischen Invarianten als SPARQL-Abfragen. Alle Prozessoren laufen offline auf den mitgelieferten Kopien; ein fremder IRI wird verweigert statt aufgelöst. Zwei weitere Tore hängen daran: ein Siegelregister, das jede Änderung an einem Vertragsartefakt zu einer bewussten Handlung macht, und ein Deckungstor, das jeden Begriff der veröffentlichten Artefakte in der Ontologie nachweist. Was der Standard nicht tut: er nimmt niemanden auf, misst nichts und beansprucht keine Verbindlichkeit — v0.1 ist Entwurf, normativ erst nach Ratifikation durch die Standard-Kommission nach Art. 13 der Statuten.",
        "en": "The registry standard is the rulebook the directory stands on: a manifest profile over DCAT-AP-CH with an extension for AI interfaces, plus JSON Schema, a JSON-LD context, SHACL shapes and the oh: ontology. A manifest is plain JSON in exactly one normalized shape — down to the bytes: fixed key order, two-space indent, LF, trailing newline, so a git diff carries content and never style. The oh-validate tool runs four stages over the whole corpus: JSON Schema, a JSON-LD round trip against the vendored context, SHACL against the versioned shapes, and finally the merge of every document into one single graph with an RDFC-1.0 fingerprint and the critical invariants as SPARQL queries. Every processor runs offline on the vendored copies; a foreign IRI is refused rather than resolved. Two further gates hang off it: a seal register that turns any change to a contract artifact into a conscious act, and a coverage gate that proves every term the published artifacts emit is covered by the ontology. What the standard does not do: it admits nobody, measures nothing, and claims no binding force — v0.1 is a draft, normative only after ratification by the standards commission under Art. 13 of the statutes."
      },
      "state": "draft",
      "public_endpoint": false,
      "since": null,
      "source": {
        "path": "registry/standard",
        "repo": {
          "available": true,
          "url": "https://github.com/OpenHelvetia/standard-manifest-oh"
        }
      },
      "release": {
        "available": false,
        "reason": {
          "de": "Noch kein getaggtes Release; das erste folgt mit der Publikations-Strecke.",
          "en": "No tagged release yet; the first follows the publication lane."
        }
      },
      "image": {
        "available": false,
        "reason": {
          "de": "Noch kein Container-Image veröffentlicht.",
          "en": "No container image published yet."
        }
      },
      "crate": {
        "available": false,
        "reason": {
          "de": "oh-validate ist noch nicht auf crates.io veröffentlicht.",
          "en": "oh-validate is not yet published on crates.io."
        }
      },
      "run": {
        "available": true,
        "requires": [
          {
            "de": "Rust (stable über rustup) und Git; alle Befehle laufen aus der Wurzel des Korpus-Checkouts.",
            "en": "Rust (stable via rustup) and Git; every command runs from the root of the corpus checkout."
          }
        ],
        "commands": [
          "cargo run --locked --manifest-path registry/standard/oh-validate/Cargo.toml -- registry/standard/schema/manifest.schema.json registry/standard/test-corpus --stage2 registry/standard/context/v1.jsonld --stage3 registry/standard/shapes/manifest-v1.ttl --stage4"
        ],
        "expect": "checked 19 file(s): OK",
        "note": {
          "de": "Die vier Prüfstufen über den Testkorpus, ohne Netz. Das Siegelregister prüft: cargo run --locked --manifest-path registry/standard/seal/Cargo.toml -- --root registry/standard",
          "en": "The four validation stages over the test corpus, without network. The seal register is checked with: cargo run --locked --manifest-path registry/standard/seal/Cargo.toml -- --root registry/standard"
        }
      },
      "test": {
        "available": true,
        "command": "cargo test --locked --manifest-path registry/standard/oh-validate/Cargo.toml",
        "fixtures": "registry/standard/test-corpus",
        "offline": true
      },
      "access": {
        "public": {
          "available": false,
          "reason": {
            "de": "Die Website ist noch nicht unter openhelvetia.swiss aufgeschaltet; die Artefakte werden mit ihr unter /ns/ byte-identisch ausgeliefert.",
            "en": "The website is not yet served at openhelvetia.swiss; the artifacts ship with it under /ns/, byte-identical."
          }
        },
        "local": "im Website-Build unter /ns/",
        "contracts": [
          {
            "label": {
              "de": "Manifest-Schema (datiert)",
              "en": "Manifest schema (dated)"
            },
            "path": "registry/standard/schema/manifest.schema.json"
          },
          {
            "label": {
              "de": "JSON-LD-Kontext",
              "en": "JSON-LD context"
            },
            "path": "registry/standard/context/v1.jsonld"
          },
          {
            "label": {
              "de": "SHACL-Shapes",
              "en": "SHACL shapes"
            },
            "path": "registry/standard/shapes/manifest-v1.ttl"
          },
          {
            "label": {
              "de": "Verzeichnis-Umschlag v0.2",
              "en": "Directory envelope v0.2"
            },
            "path": "registry/standard/directory.schema.json"
          },
          {
            "label": {
              "de": "Siegelregister",
              "en": "Seal register"
            },
            "path": "registry/standard/artifacts.json"
          }
        ],
        "example": null
      },
      "cli_help": "usage: oh-validate <manifest.schema.json> <file-or-dir>... [--stage2 <context/v1.jsonld>] [--stage3 <shapes/manifest-v1.ttl>] [--stage4] [--write]",
      "depends_on": [],
      "used_by": [
        "checker",
        "api-spine",
        "mcp-gateway"
      ],
      "docs": "docs/reference/manifest-standard/",
      "evidence": [
        {
          "label": {
            "de": "Prüfkette",
            "en": "Validation chain"
          },
          "value": "19",
          "source": "registry/standard/test-corpus",
          "recorded": "2026-09-02",
          "derived": true,
          "note": {
            "de": "Vier Stufen über 23 Manifestdateien, grün — «checked 23 file(s): OK» / four stages over 23 manifest files, green",
            "en": "Vier Stufen über 23 Manifestdateien, grün — «checked 23 file(s): OK» / four stages over 23 manifest files, green"
          },
          "recount": {
            "kind": "files",
            "dir": "registry/standard/test-corpus",
            "extension": "json"
          }
        },
        {
          "label": {
            "de": "Gesamtgraph-Fingerabdruck",
            "en": "Whole-graph fingerprint"
          },
          "value": {
            "de": "RDFC-1.0/SHA-256 = 9cc2180a93866dbe1c8a1bbeac33848c717022f158948f0b073794ce4b646b8c, geprüft gegen 9 SPARQL-Invarianten",
            "en": "RDFC-1.0/SHA-256 = 9cc2180a93866dbe1c8a1bbeac33848c717022f158948f0b073794ce4b646b8c, checked against 9 SPARQL invariants"
          },
          "source": "registry/standard",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Siegelregister",
            "en": "Seal register"
          },
          "value": "8",
          "source": "registry/standard/artifacts.json",
          "recorded": "2026-09-02",
          "derived": true,
          "note": {
            "de": "8 Zeilen, alle mit Status «draft», keine einzige «published»; derselbe Torwächter über 5 Register mit zusammen 19 Zeilen / 8 rows, all draft, none published; the same gate over 5 registers, 19 rows in total",
            "en": "8 Zeilen, alle mit Status «draft», keine einzige «published»; derselbe Torwächter über 5 Register mit zusammen 19 Zeilen / 8 rows, all draft, none published; the same gate over 5 registers, 19 rows in total"
          },
          "recount": {
            "kind": "json-length",
            "file": "registry/standard/artifacts.json",
            "pointer": "/artifacts"
          }
        },
        {
          "label": {
            "de": "Ontologie-Deckungstor",
            "en": "Ontology coverage gate"
          },
          "value": {
            "de": "44/44 oh:-Terme, 11/11 fremde Terme, 19/19 Werte gedeckt; 10 Stützterme, 0 Waisen, 0 Fehler — und oh.md deckt sich mit seiner Neuerzeugung aus oh.ttl",
            "en": "44/44 oh: terms, 11/11 foreign terms, 19/19 values covered; 10 supporting terms, 0 orphans, 0 errors — and oh.md matches its regeneration from oh.ttl"
          },
          "source": "registry/standard",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Tests",
            "en": "Tests"
          },
          "value": {
            "de": "80 Tests in den drei Tor-Crates (oh-validate 54, oh-seal 13, oh-coverage 13), alle grün; 99 grün über alle fünf Crates des Standards, 1 ignoriert",
            "en": "80 tests in the three gate crates (oh-validate 54, oh-seal 13, oh-coverage 13), all green; 99 green over all five crates of the standard, 1 ignored"
          },
          "source": "registry/standard",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Verbindlichkeit",
            "en": "Binding force"
          },
          "value": {
            "de": "keine — v0.1 ist Entwurf; normativ erst nach Ratifikation durch die Standard-Kommission (Art. 13 Statuten), die nicht bestellt ist",
            "en": "none — v0.1 is a draft; normative only after ratification by the standards commission (Art. 13 statutes), which is not constituted"
          },
          "source": "registry/standard",
          "recorded": "2026-09-01",
          "derived": false
        }
      ],
      "missing": [
        {
          "text": {
            "de": "Kein einziges Artefakt trägt den Status «published» — die Byte-Sperre hat also noch nie gebunden, und die Kette beweist sich bisher nur am 19-Dateien-Testkorpus, an zwei Beispielen und an zwei eigenen Eintragsentwürfen; das Register selbst enthält null Einträge. Von den acht versiegelten Artefakten werden ausserdem nur vier unter /ns/ ausgeliefert (Kontext v1, Manifest-Schema, Verzeichnis-Schema, Karten-Schema); Ontologie-Master, erzeugte Ontologie-Doku, SHACL-Shapes und der Rundlauf-Frame haben keinen Auslieferungspfad.",
            "en": "Not one artifact carries the status «published» — the byte freeze has therefore never bound, and the chain so far proves itself only on the 19-file test corpus, two examples and two drafts of the association's own entry; the register itself holds zero entries. And of the eight sealed artifacts only four are served under /ns/ (context v1, manifest schema, directory schema, card schema); the ontology master, its generated documentation, the SHACL shapes and the round-trip frame have no serving path."
          },
          "blocks": "in-operation"
        }
      ],
      "history": [
        {
          "date": "2026-09-03",
          "text": {
            "de": "Quellcode als eigenes Repository auf GitHub publiziert (Publikations-Strecke, Welle 2).",
            "en": "Source published as its own repository on GitHub (publication lane, wave 2)."
          }
        }
      ]
    },
    {
      "id": "checker",
      "name": {
        "de": "Prüfwerkzeug (oh-check)",
        "en": "Prüfwerkzeug (oh-check)"
      },
      "plan_item": "L1.2",
      "layer": "L1",
      "kind": "tool",
      "license": null,
      "summary": {
        "de": "Prüft Einträge live gegen ihre deklarierten Endpunkte; seine Messungen zeigt die Eintragsseite — bestanden, gescheitert und «nie geprüft» als eigene Zustände.",
        "en": "Probes entries live against their declared endpoints; its measurements are what the entry page shows — passed, failed and «never checked» as distinct states."
      },
      "description": {
        "de": "oh-check misst, ob ein Eintrag hält, was sein Manifest deklariert. Es liest die Probe-Hinweise aus den Manifesten und feuert genau den minimalen, harmlosen Aufruf, den der Eintrag selbst angegeben hat — fünf Arten, darunter zwei für MCP, weil MCP zwei Epochen hat und ein Aufruf an die falsche Epoche nichts beweist. Jede Ausführung wird als eine Zeile an eine append-only-Historie angehängt; Korrekturen sind neue Zeilen, nie Änderungen an alten. Daraus liest die Website drei Zustände ab — «nie geprüft», «bestanden», «gescheitert» —, und auch das Abzeichen rundet nie auf: aus teilweise geprüft wird gelb, nicht grün. Ohne --run geht das Werkzeug gar nicht ins Netz, es druckt nur den Plan. Was es nicht tut: fremde Endpunkte ausserhalb der deklarierten Bedingungen anfassen — der Probe-Hinweis im Manifest ist die Erlaubnis der Betreiberin, und im Commit-Tor läuft keine einzige Anfrage.",
        "en": "oh-check measures whether an entry keeps what its manifest declares. It reads the probe hints out of the manifests and fires exactly the minimal, harmless call the entry itself named — five kinds, two of them for MCP, because MCP has two eras and a call to the wrong era proves nothing. Every execution is appended as one line to an append-only history; corrections are new lines, never edits to old ones. From that the website reads three states — «never checked», «passed», «failed» — and the badge never rounds up either: partially checked becomes yellow, not green. Without --run the tool does not touch the network at all; it prints the plan. What it does not do: touch a third-party endpoint outside the declared conditions — the probe hint in the manifest is the operator's permission, and not one request runs in the commit gate."
      },
      "state": "prepared",
      "public_endpoint": false,
      "since": null,
      "source": {
        "path": "registry/checker",
        "repo": {
          "available": true,
          "url": "https://github.com/OpenHelvetia/checker-oh"
        }
      },
      "release": {
        "available": false,
        "reason": {
          "de": "Noch kein getaggtes Release; das erste folgt mit der Publikations-Strecke.",
          "en": "No tagged release yet; the first follows the publication lane."
        }
      },
      "image": {
        "available": false,
        "reason": {
          "de": "Noch kein Container-Image veröffentlicht.",
          "en": "No container image published yet."
        }
      },
      "crate": null,
      "run": {
        "available": true,
        "requires": [
          {
            "de": "Rust (stable über rustup) und Git; alle Befehle laufen aus der Wurzel des Korpus-Checkouts.",
            "en": "Rust (stable via rustup) and Git; every command runs from the root of the corpus checkout."
          }
        ],
        "commands": [
          "cargo run --locked --manifest-path registry/checker/Cargo.toml -- registry/standard/test-corpus"
        ],
        "expect": "amtsdruckschriften-bar #0 DownloadInterface — http-head https://www.amtsdruckschriften.bar.admin.ch/ (expect response) — never checked",
        "note": {
          "de": "Ohne --run druckt oh-check nur den Probenplan und den Verlauf; kein Netzzugriff. --run prüft live und schreibt die Historie.",
          "en": "Without --run oh-check prints only the probe plan and the gradient; no network. --run probes live and appends the history."
        }
      },
      "test": {
        "available": true,
        "command": "cargo test --locked --manifest-path registry/checker/Cargo.toml",
        "fixtures": "registry/checker/tests",
        "offline": true,
        "note": {
          "de": "Die HTTP-Fälle laufen gegen lokale Server im Test.",
          "en": "The HTTP cases run against local servers inside the test."
        }
      },
      "access": null,
      "cli_help": "usage: oh-check <manifest-dir>... [--state <dir>] [--run] [--badges <dir>] [--timeout-ms <n>] [--probe-origin <origin>]",
      "depends_on": [
        "registry-standard"
      ],
      "used_by": [],
      "docs": "docs/reference/probes/",
      "evidence": [
        {
          "label": {
            "de": "Probe-Arten",
            "en": "Probe kinds"
          },
          "value": {
            "de": "fünf, nicht vier: sparql-ask, http-get, http-head, mcp-initialize, mcp-discover",
            "en": "five, not four: sparql-ask, http-get, http-head, mcp-initialize, mcp-discover"
          },
          "source": "registry/checker",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Verlauf und Abzeichen",
            "en": "Gradient and badge"
          },
          "value": {
            "de": "3 Zustände (nie geprüft · bestanden · gescheitert); das Abzeichen aggregiert in 4 Meldungen — failed/red, passed/brightgreen, partially checked/yellow, never checked/lightgrey",
            "en": "3 states (never checked · passed · failed); the badge aggregates into 4 messages — failed/red, passed/brightgreen, partially checked/yellow, never checked/lightgrey"
          },
          "source": "registry/checker",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Historie",
            "en": "History"
          },
          "value": {
            "de": "append-only JSONL, eine Zeile pro Ausführung, die jüngste Zeile gewinnt; die Website leitet keinen eigenen Befund ab, sondern liest dieselbe Datei",
            "en": "append-only JSONL, one line per run, the youngest line wins; the website derives no finding of its own but reads the same file"
          },
          "source": "registry/checker",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Signatur-Drift",
            "en": "Signature drift"
          },
          "value": {
            "de": "4 Listenzustände (listed · re-verification-due · grace · quarantine); Gnade eskaliert nach 14 Tagen, es gibt keinen Zustand «entfernt»",
            "en": "4 listing states (listed · re-verification-due · grace · quarantine); grace escalates after 14 days, there is no state «removed»"
          },
          "source": "registry/checker",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Tests und Netzgrenze",
            "en": "Tests and network boundary"
          },
          "value": {
            "de": "41 Tests, alle grün — die HTTP-Fälle gegen einen echten lokalen Server auf 127.0.0.1; im Commit-Tor läuft keine einzige Anfrage",
            "en": "41 tests, all green — the HTTP cases against a real local server on 127.0.0.1; not a single request runs in the commit gate"
          },
          "source": "registry/checker",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Messstand",
            "en": "Measurements on record"
          },
          "value": {
            "de": "37 Schnittstellen im Korpus, 37 mit Probe, alle «nie geprüft»; im Repository existiert keine Historiendatei",
            "en": "37 interfaces in the corpus, 37 with a probe, all «never checked»; no history file exists in the repository"
          },
          "source": "registry/checker",
          "recorded": "2026-09-01",
          "derived": false
        }
      ],
      "missing": [],
      "history": [
        {
          "date": "2026-09-03",
          "text": {
            "de": "Quellcode als eigenes Repository auf GitHub publiziert (Publikations-Strecke, Welle 2).",
            "en": "Source published as its own repository on GitHub (publication lane, wave 2)."
          }
        }
      ]
    },
    {
      "id": "memory",
      "name": {
        "de": "Gedächtnis (Memory)",
        "en": "Gedächtnis (Memory)"
      },
      "plan_item": "L4.1",
      "layer": "L4",
      "kind": "internal",
      "license": "MIT",
      "summary": {
        "de": "Versioniertes Faktengedächtnis der Plattform mit Rechteprüfung auf jedem Zugriff.",
        "en": "The platform's versioned fact memory, permission-checked on every access."
      },
      "description": {
        "de": "Das Gedächtnis der Plattform speichert Fakten als versionierte Zeilen über PostgreSQL 18: jede Zeile trägt beide Zeitachsen — seit wann eine Aussage gilt und wann wir sie aufgezeichnet haben — dazu ihre Herkunft und ihre Aufbewahrungsfrist. Eine Korrektur ändert deshalb nichts; sie ist eine neue Zeile, die benennt, was sie ablöst, und die alte bleibt stehen und lesbar. Jede Zeile liegt verschlüsselt (XChaCha20-Poly1305, ein frisch gezogener Nonce je Zeile) unter einem Schlüssel je Subjekt — einen Schlüssel zu vernichten ist die Löschung selbst und nicht ein Vermerk darüber. Fünf Handlungen hat ein Eigentümer über sein Gedächtnis: einsehen, exportieren, importieren, löschen und in die Organisation übertragen — und jede geht durch eine Rechteprüfung, bevor sie eine Zeile berührt. Der Export folgt einem eigenen Profil über Portable Agent Memory, damit ein Mensch sein Gedächtnis wirklich mitnehmen kann. Was der Kern nicht tut: er hängt an keiner ausgelieferten Fläche — weder der Gateway noch der Chat noch die A2A-Tür kennen ihn, und eine anonyme Sitzung hat gar kein Subjekt, unter dem sie schreiben könnte.",
        "en": "The platform's memory keeps facts as versioned rows over PostgreSQL 18: every row carries both time axes — since when a statement holds, and when we recorded it — plus its provenance and its retention date. A correction therefore changes nothing; it is a new row that names what it supersedes, and the old one stays and stays readable. Every row is sealed (XChaCha20-Poly1305, a freshly drawn nonce per row) under a per-subject key — destroying a key is the deletion itself, not a note about one. An owner has five acts over their memory: inspect, export, import, delete, and promote into the organisation — and each passes an authorization decision before it touches a row. The export follows the association's own profile over Portable Agent Memory, so a person can actually take their memory with them. What the core does not do: it hangs on no served surface — neither the gateway nor the chat nor the A2A door knows it, and an anonymous session has no subject to write under at all."
      },
      "state": "internal",
      "public_endpoint": false,
      "since": null,
      "source": {
        "path": "memory/",
        "repo": {
          "available": false,
          "reason": {
            "de": "Der Quellcode wird mit der Publikations-Strecke öffentlich; das Repository ist noch nicht freigeschaltet.",
            "en": "The source becomes public with the publication lane; the repository is not yet switched public."
          }
        }
      },
      "release": {
        "available": false,
        "reason": {
          "de": "Noch kein getaggtes Release; das erste folgt mit der Publikations-Strecke.",
          "en": "No tagged release yet; the first follows the publication lane."
        }
      },
      "image": {
        "available": false,
        "reason": {
          "de": "Noch kein Container-Image veröffentlicht.",
          "en": "No container image published yet."
        }
      },
      "crate": null,
      "run": {
        "available": false,
        "reason": {
          "de": "Bewusst intern: eine anonyme öffentliche Fläche darf das Gedächtnis des Vereins nicht lesen; kein ausgelieferter Dienst hängt am Kern. Der Code ist prüfbar, ein Betrieb ist nicht vorgesehen.",
          "en": "Internal by decision: an anonymous public surface must not read the association's memory; no delivered service hangs on the core. The code can be inspected, operation is not intended."
        }
      },
      "test": {
        "available": true,
        "command": "cargo test --locked --manifest-path memory/store/Cargo.toml",
        "offline": true
      },
      "access": null,
      "cli_help": null,
      "depends_on": [],
      "used_by": [],
      "docs": null,
      "evidence": [
        {
          "label": {
            "de": "Speicherform",
            "en": "Storage shape"
          },
          "value": {
            "de": "5 Tabellen; memory_fact: PRIMARY KEY (subject_id, fact_key, recorded_at, valid_period WITHOUT OVERLAPS) plus EXCLUDE memory_fact_originals_do_not_overlap (WHERE corrects IS NULL)",
            "en": "5 tables; memory_fact: PRIMARY KEY (subject_id, fact_key, recorded_at, valid_period WITHOUT OVERLAPS) plus EXCLUDE memory_fact_originals_do_not_overlap (WHERE corrects IS NULL)"
          },
          "source": "memory/",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Verschlüsselung",
            "en": "Encryption"
          },
          "value": {
            "de": "XChaCha20-Poly1305; 24-Byte-Zufalls-Nonce je Siegelung; gespeichert als nonce ‖ ciphertext ‖ tag; Abhängigkeit exakt gepinnt: chacha20poly1305 = \"=0.11.0\"",
            "en": "XChaCha20-Poly1305; 24-byte random nonce per seal; stored as nonce ‖ ciphertext ‖ tag; dependency pinned exactly: chacha20poly1305 = \"=0.11.0\""
          },
          "source": "memory/",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Tests",
            "en": "Tests"
          },
          "value": {
            "de": "oh-memory 36 · oh-memory-control 30 (27 laufen, 3 sind #[ignore]-Regeneratoren) · oh-memory-embed 3 (überspringen ohne Modell)",
            "en": "oh-memory 36 · oh-memory-control 30 (27 run, 3 are #[ignore] regenerators) · oh-memory-embed 3 (skip without the model)"
          },
          "source": "memory/",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Mitnahme-Profil",
            "en": "Portability profile"
          },
          "value": {
            "de": "ch.openhelvetia Portable Agent Memory 0.1 über arXiv:2605.11032v1; zwei Stufen: structural + verified; pam-profile.schema.json sha256 11fb544642f51ebed96e5854eaa50d32efc28a5a00e63df32b3cd67b1b577aef",
            "en": "ch.openhelvetia Portable Agent Memory 0.1 over arXiv:2605.11032v1; two levels: structural + verified; pam-profile.schema.json sha256 11fb544642f51ebed96e5854eaa50d32efc28a5a00e63df32b3cd67b1b577aef"
          },
          "source": "memory/",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Das Gate",
            "en": "The gate"
          },
          "value": {
            "de": "CI-Job test-memory-schema: die Migration läuft gegen einen echten postgres:18, danach fünf Prüfungen — vier erwarten ein Scheitern und prüfen sqlstate UND Constraint-Namen",
            "en": "CI job test-memory-schema: the migration is applied to a real postgres:18, then five gates run — four expect a failure and assert both sqlstate and constraint name"
          },
          "source": "memory/",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Warum intern",
            "en": "Why internal"
          },
          "value": {
            "de": "oh-memory erscheint als Abhängigkeit in genau 3 Manifesten: memory/control, memory/embed, testing/suites/ch-behoerden-memory/gate — nicht im Gateway, nicht im API-Spine, nicht im Chat, nicht in der A2A-Tür",
            "en": "oh-memory appears as a dependency in exactly 3 manifests: memory/control, memory/embed, testing/suites/ch-behoerden-memory/gate — not in the gateway, not in the API spine, not in the chat, not in the A2A door"
          },
          "source": "memory/",
          "recorded": "2026-09-01",
          "derived": false
        }
      ],
      "missing": [],
      "history": []
    },
    {
      "id": "skills",
      "name": {
        "de": "Skills",
        "en": "Skills"
      },
      "plan_item": "L4.4",
      "layer": "L4",
      "kind": "data",
      "license": null,
      "summary": {
        "de": "Fähigkeits-Bausteine für Agenten-Abläufe.",
        "en": "Capability building blocks for agent workflows."
      },
      "description": {
        "de": "Ein Skill ist ein Verzeichnis mit einer SKILL.md: ein YAML-Kopf und ein englischer Text, der einem Agenten ein Vorgehen beibringt — das Format von agentskills.io, unverändert übernommen. OpenHelvetia hat zwei eigene: fedlex-research für die Recherche im Bundesrecht und lindas-research für die politischen Datenwürfel des Bundes, beide mit deutscher Fassung. Neben jeder SKILL.md liegt ein Profildokument im eigenen ch.openhelvetia-Profil — Metadaten, Version, Signatur, Sprachen, Fähigkeiten; alles Eigene steht ausschliesslich im Namensraum ch.openhelvetia.*, damit ein Host, der ihn nicht kennt, den Skill trotzdem findet und richtig einsetzt. Das ist ein Test und keine Zusage: ein blinder Host wird nachgebaut, und fehlte ihm etwas, wäre der Befund gegen das Profil gerichtet und nicht gegen den Host. Beide Skills stecken wörtlich in den Anweisungen des Chats dieser Website, und ein Test hält die eingebaute Kopie an die veröffentlichte Datei. Was ein Skill hier nicht ist: gelistet und signiert — Listung ist ein entschiedener Akt durch den Katalog, und jedes Profildokument sagt von sich selbst «design-declared».",
        "en": "A skill is a directory holding a SKILL.md: YAML frontmatter and an English body that teaches an agent a procedure — the agentskills.io format, adopted unchanged. OpenHelvetia has two of its own: fedlex-research for researching federal law and lindas-research for the Confederation's political data cubes, both with a German version. Beside every SKILL.md sits a profile document in the association's own ch.openhelvetia profile — metadata, version, signing, languages, capabilities; everything added lives only under ch.openhelvetia.*, so a host that never heard of the namespace still finds the skill and routes it correctly. That is a test, not a promise: a blind host is modelled, and if something were missing from it the finding would be against the profile rather than against the host. Both skills sit verbatim in this website's chat instructions, and a test holds the bundled copy to the published file. What a skill here is not: listed and signed — listing is a decided act through the catalog, and every profile document says «design-declared» about itself."
      },
      "state": "in-progress",
      "public_endpoint": false,
      "since": null,
      "source": {
        "path": "skills/own",
        "repo": {
          "available": false,
          "reason": {
            "de": "Der Quellcode wird mit der Publikations-Strecke öffentlich; das Repository ist noch nicht freigeschaltet.",
            "en": "The source becomes public with the publication lane; the repository is not yet switched public."
          }
        }
      },
      "release": {
        "available": false,
        "reason": {
          "de": "Noch kein getaggtes Release; das erste folgt mit der Publikations-Strecke.",
          "en": "No tagged release yet; the first follows the publication lane."
        }
      },
      "image": {
        "available": false,
        "reason": {
          "de": "Noch kein Container-Image veröffentlicht.",
          "en": "No container image published yet."
        }
      },
      "crate": null,
      "run": {
        "available": false,
        "reason": {
          "de": "Skills sind SKILL.md-Dokumente, keine Programme; der Chat dieser Website lädt sie ein.",
          "en": "Skills are SKILL.md documents, not programs; this website's chat loads them."
        }
      },
      "test": {
        "available": true,
        "command": "cargo test --locked --manifest-path skills/catalog/Cargo.toml",
        "offline": true,
        "note": {
          "de": "Die Konformitätstests des Katalogs prüfen die eigenen SKILL.md-Dateien.",
          "en": "The catalog's conformance tests check the own SKILL.md files."
        }
      },
      "access": null,
      "cli_help": null,
      "depends_on": [],
      "used_by": [],
      "docs": "docs/infrastructure/module-skills/",
      "evidence": [
        {
          "label": {
            "de": "Eigene Skills",
            "en": "Own skills"
          },
          "value": {
            "de": "2 — fedlex-research, lindas-research; je 4 Dateien: SKILL.md (kanonisch englisch), SKILL.de.md, ch.openhelvetia.json, frontmatter.json",
            "en": "2 — fedlex-research, lindas-research; 4 files each: SKILL.md (canonical English), SKILL.de.md, ch.openhelvetia.json, frontmatter.json"
          },
          "source": "skills/own",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Format",
            "en": "Format"
          },
          "value": {
            "de": "Agent Skills SKILL.md; Frontmatter-Schlüssel metadata.ch.openhelvetia.profile = https://ld.openhelvetia.swiss/ns/skills/0.1/profile; Sidecar ch.openhelvetia.json mit fünf Schichten",
            "en": "Agent Skills SKILL.md; frontmatter key metadata.ch.openhelvetia.profile = https://ld.openhelvetia.swiss/ns/skills/0.1/profile; sidecar ch.openhelvetia.json with five layers"
          },
          "source": "skills/own",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Im Chat im Einsatz",
            "en": "In use in the chat"
          },
          "value": {
            "de": "Beide SKILL.md werden per include_str! wörtlich in den System-Prompt des Chats gelegt; 6 Tests halten die Kopie an die veröffentlichte Datei",
            "en": "Both SKILL.md files are pulled verbatim into the chat's system prompt by include_str!; 6 tests hold the copy to the published file"
          },
          "source": "skills/own",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Genannte Werkzeuge",
            "en": "Tools named"
          },
          "value": {
            "de": "fedlex-research nennt 30 der 35 fedlex-Werkzeuge des Gateways, lindas-research alle 8 lindas-Werkzeuge — jede genannte Kennung existiert im Inventar",
            "en": "fedlex-research names 30 of the gateway's 35 fedlex tools, lindas-research all 8 lindas tools — every id named exists in the inventory"
          },
          "source": "skills/own",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Das Gate",
            "en": "The gate"
          },
          "value": {
            "de": "CI-Job test-skills: 20 Konformitätstests + 10 Katalogtests + Siegel-Gate über skills/standard; skill-profile.schema.json sha256 c6d0ccf6f6ce9211bda42cd9d3882266f162cfc2078716fbd5f21e34874bcc35",
            "en": "CI job test-skills: 20 conformance tests + 10 catalogue tests + seal gate over skills/standard; skill-profile.schema.json sha256 c6d0ccf6f6ce9211bda42cd9d3882266f162cfc2078716fbd5f21e34874bcc35"
          },
          "source": "skills/own",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Signatur",
            "en": "Signing"
          },
          "value": {
            "de": "Jedes Profildokument: signing.status = design-declared, mode = sigstore-keyless, identity.kind kennt genau ein Wort — workload",
            "en": "Every profile document: signing.status = design-declared, mode = sigstore-keyless, identity.kind has exactly one member — workload"
          },
          "source": "skills/own",
          "recorded": "2026-09-01",
          "derived": false
        }
      ],
      "missing": [
        {
          "text": {
            "de": "Kein eigener Skill ist gelistet — Listung geht durch den Katalog (Prüfung vor Listung, Administratorstufe UND Governance, ein Maschinenkonto wird abgewiesen), und dieser Schritt ist nicht getan; signiert ist ebenfalls keiner, weil die Sigstore-Laufzeit offen ist. Die Profil-IRI ist gemünzt und versiegelt, aber noch nicht auflösbar: im gebauten Website-Baum gibt es keinen Pfad /ns/skills/, und der tägliche Abgleich «erklärt gegen beobachtet» ist als Naht benannt und bewusst nicht verdrahtet.",
            "en": "Neither own skill is listed — listing runs through the catalog (review before listing, administrator level AND governance, a machine principal refused) and that step has not been taken; neither is signed, because the Sigstore runtime is open. The profile IRI is minted and sealed but not resolvable yet: the built site tree holds no /ns/skills/ path, and the daily «declared versus observed» comparison is a named seam that is deliberately not wired."
          },
          "blocks": "prepared"
        }
      ],
      "history": []
    },
    {
      "id": "a2a-agent",
      "name": {
        "de": "A2A-Agent",
        "en": "A2A-Agent"
      },
      "plan_item": "L2.4",
      "layer": "L2",
      "kind": "service",
      "license": "MIT",
      "summary": {
        "de": "Die Agent-zu-Agent-Tür: benannte Fähigkeiten auf Anfrage, keine Konversation.",
        "en": "The agent-to-agent door: named capabilities on request, not conversation."
      },
      "description": {
        "de": "Die Agent-zu-Agent-Tür beantwortet genau, was A2A message/send heisst: eine Nachricht, deren Text den Namen einer Fähigkeit aus dem veröffentlichten Register trägt, beantwortet durch eine fertige Task — über dieselbe Kernfunktion, die auch das MCP-Werkzeug und die REST-Operation rufen. Der Code ist Eigenbau: es gibt kein offizielles Rust-SDK, und ein fremdes 0.x-SDK träfe die Spezifikation nicht; das Referenz-SDK steht nur auf der anderen Seite der Leitung, in der Wire-Suite. Die Agentenkarte wird gegen das mitgelieferte A2A-Schema v1.0.1 geprüft, und zwar auf dem Auslieferungsweg — der Prozess startet mit einer ungültigen Karte gar nicht erst, denn ein Bau-Gate beweist etwas über eine Datei, während eine Gegenstelle eine Antwort abholt. Was die Tür nicht kann und auch nicht behauptet: freie Sprache verstehen, planen, sich über Züge hinweg erinnern, streamen oder Push senden; nach Fähigkeiten mit Parametern gefragt, sagt sie ab, statt halb zu antworten. In Betrieb ist sie nicht: supportedInterfaces der ausgelieferten Karte ist leer, weil kein A2A-Endpunkt läuft — die Karte verspricht keinen. Unsigniert ist sie ebenfalls mit Absicht: das Signatur-Element erscheint nur, wenn dem Bau ein echter Schlüssel übergeben wird, und mit Testschlüsseln wird nicht signiert.",
        "en": "The agent-to-agent door answers exactly what A2A message/send means: a message whose text names a capability id from the published register, answered by a completed Task — through the same core function the MCP tool and the REST operation call. The code is our own: there is no official Rust SDK, and a third-party 0.x SDK would not hit the specification; the reference SDK lives only on the other side of the wire, in the wire suite. The agent card is validated against the vendored A2A v1.0.1 schema on the serving path — the process refuses to start with an invalid card, because a build gate proves something about a file while a counterparty fetches an answer. What the door cannot do and does not claim: understand free language, plan, remember across turns, stream, or push; asked for a parameterised capability it refuses rather than half-answering. It is not in operation: the served card's supportedInterfaces is empty because no A2A endpoint runs — the card advertises none. It is unsigned on purpose too: the signature member appears only when a real key is handed to the build, and test keys never sign."
      },
      "state": "prepared",
      "public_endpoint": false,
      "since": null,
      "source": {
        "path": "agents/a2a",
        "repo": {
          "available": false,
          "reason": {
            "de": "Der Quellcode wird mit der Publikations-Strecke öffentlich; das Repository ist noch nicht freigeschaltet.",
            "en": "The source becomes public with the publication lane; the repository is not yet switched public."
          }
        }
      },
      "release": {
        "available": false,
        "reason": {
          "de": "Noch kein getaggtes Release; das erste folgt mit der Publikations-Strecke.",
          "en": "No tagged release yet; the first follows the publication lane."
        }
      },
      "image": {
        "available": false,
        "reason": {
          "de": "Noch kein Container-Image veröffentlicht.",
          "en": "No container image published yet."
        }
      },
      "crate": null,
      "run": {
        "available": true,
        "requires": [
          {
            "de": "Rust (stable über rustup) und Git; alle Befehle laufen aus der Wurzel des Korpus-Checkouts.",
            "en": "Rust (stable via rustup) and Git; every command runs from the root of the corpus checkout."
          }
        ],
        "commands": [
          "cargo run --locked --manifest-path public/web/site-gen/Cargo.toml -- --entries registry/entries --schema registry/standard/schema/manifest.schema.json --config public/web/site-config.json --assets public/web/ui/design --standard registry/standard --out public/web/build/site",
          "cargo run --locked --manifest-path agents/a2a/Cargo.toml -- --root . --card public/web/build/site/.well-known/agent-card.json --http 8720"
        ],
        "expect": "a2a http shell on 127.0.0.1:8720",
        "note": {
          "de": "Der erste Befehl baut die Website, weil die Agentenkarte dort entsteht; der zweite serviert message/send gegen diese Karte.",
          "en": "The first command builds the website because the agent card is made there; the second serves message/send against that card."
        }
      },
      "test": {
        "available": true,
        "command": "cargo test --locked --manifest-path agents/a2a/Cargo.toml",
        "offline": true,
        "note": {
          "de": "Fünf der sechs Fälle brauchen die gebaute Agentenkarte über OH_AGENT_CARD (siehe agents/a2a/README.md).",
          "en": "Five of the six cases need the built agent card via OH_AGENT_CARD (see agents/a2a/README.md)."
        }
      },
      "access": {
        "public": {
          "available": false,
          "reason": {
            "de": "Kein öffentlicher Endpunkt: weder Zone noch Route noch Deployment sind aufgeschaltet.",
            "en": "No public endpoint: zone, route and deployment are not switched on."
          }
        },
        "local": "http://127.0.0.1:8720",
        "contracts": [
          {
            "label": {
              "de": "Agentenkarten-Schema",
              "en": "Agent card schema"
            },
            "path": "registry/standard/card/agent-card.schema.json"
          }
        ],
        "example": null
      },
      "cli_help": null,
      "depends_on": [
        "api-spine"
      ],
      "used_by": [],
      "docs": null,
      "evidence": [
        {
          "label": {
            "de": "Mitgeliefertes Schema",
            "en": "Vendored schema"
          },
          "value": {
            "de": "A2A v1.0.1 (Tag v1.0.1, Commit 3303592), sha256 ba4b702b5edbdcbfe972c272484eb38e1fcd72af3c0b7eaa114b50e97455d8dd — byte-identisch in beiden Repositories",
            "en": "A2A v1.0.1 (tag v1.0.1, commit 3303592), sha256 ba4b702b5edbdcbfe972c272484eb38e1fcd72af3c0b7eaa114b50e97455d8dd — byte-identical in both repositories"
          },
          "source": "the agent card and its serving path",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Prüfung auf dem Auslieferungsweg",
            "en": "Validated on the serving path"
          },
          "value": {
            "de": "validate_card() läuft in Platform::new UND erneut bei jedem message/send; die Binärdatei weigert sich, ohne gültige Karte zu starten",
            "en": "validate_card() runs in Platform::new AND again on every message/send; the binary refuses to start without a valid card"
          },
          "source": "the agent card and its serving path",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Die ausgelieferte Karte",
            "en": "The served card"
          },
          "value": {
            "de": "supportedInterfaces: [] und kein signatures-Element; capabilities: streaming false, pushNotifications false, extendedAgentCard false",
            "en": "supportedInterfaces: [] and no signatures member; capabilities: streaming false, pushNotifications false, extendedAgentCard false"
          },
          "source": "the agent card and its serving path",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Tests",
            "en": "Tests"
          },
          "value": {
            "de": "7 in agents/a2a/tests/transport.rs, alle grün auch mit OH_WIRE_REQUIRED=1; 5 davon brauchen Artefakte des Schwester-Repos (4 die Karte, 1 die Schema-Kopie)",
            "en": "7 in agents/a2a/tests/transport.rs, all green even with OH_WIRE_REQUIRED=1; 5 of them need the sibling web repo's artifacts (4 the card, 1 the schema copy)"
          },
          "source": "the agent card and its serving path",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Was sie beantwortet",
            "en": "What it answers"
          },
          "value": {
            "de": "5 der 14 Zeilen des Fähigkeitsregisters: meta.capabilities, meta.tools, directory.get, standard.artifacts, publish.info — die Liste ist ausdrücklich aufgeschrieben, nicht aus dem Register abgeleitet",
            "en": "5 of the register's 14 rows: meta.capabilities, meta.tools, directory.get, standard.artifacts, publish.info — the list is written out, not derived from the register"
          },
          "source": "the agent card and its serving path",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Gegen das echte SDK",
            "en": "Against the real SDK"
          },
          "value": {
            "de": "3 A2A-Fälle der Wire-Suite gegen das Referenz-SDK a2a-sdk==1.1.2, das nur auf der Gegenseite läuft",
            "en": "3 A2A cases in the wire suite against the reference SDK a2a-sdk==1.1.2, which runs only on the far side"
          },
          "source": "the agent card and its serving path",
          "recorded": "2026-09-01",
          "derived": false
        }
      ],
      "missing": [
        {
          "text": {
            "de": "Kein Endpunkt ist serviert: die HTTP-Hülle ist handgeschrieben, dependency-frei und bedient eine Verbindung nach der anderen — sie existiert, damit ein echter A2A-Client in der Wire-Suite über einen Socket herankommt, nicht als Betrieb. Unsigniert bleibt die Karte bis zur Schlüssel-Zeremonie, und tasks/get, Streaming, Push und Mehrfach-Züge sind nicht gebaut; Fähigkeiten mit Parametern (etwa manifest.get) werden abgelehnt, weil v0 keine Task-Form dafür festgelegt hat.",
            "en": "No endpoint is served: the HTTP shell is hand-rolled, dependency-free and serves one connection at a time — it exists so a real A2A client can reach the transport across a socket in the wire suite, not as operation. The card stays unsigned until the key ceremony, and tasks/get, streaming, push and multi-turn context are not built; parameterised capabilities (manifest.get among them) are refused, because v0 has defined no task shape for them."
          },
          "blocks": "in-operation"
        }
      ],
      "history": []
    },
    {
      "id": "api-spine",
      "name": {
        "de": "API-Spine",
        "en": "API-Spine"
      },
      "plan_item": "L2.5",
      "layer": "L2",
      "kind": "service",
      "license": null,
      "summary": {
        "de": "Das maschinenlesbare Rückgrat (OpenAPI) hinter den Fassaden der Website.",
        "en": "The machine-readable spine (OpenAPI) behind this website's facades."
      },
      "description": {
        "de": "Der API-Spine ist der eine typisierte Kern hinter den Fassaden: die REST-Spezifikation wird aus dem Code erzeugt, der Client wird aus der Spezifikation erzeugt, und die MCP-Werkzeugfläche bindet an dieselben Funktionen — nie eine zweite Implementierung derselben Semantik. Vierzehn Operationen, jede genau einer Zeile eines im Code stehenden Fähigkeitsregisters zugeordnet; ein Test prüft, dass Register und Spezifikation sich exakt decken, statt es zu behaupten. Datenquelle ist in dieser Phase das Register-Repository selbst, streng lesend: einen Schreibpfad gibt es im Code nicht, und /directory liefert heute null Einträge. Bei jedem Commit laufen vier Abgleiche zwischen dem, was der Code erzeugt, und dem, was eingecheckt ist — Spezifikation, erzeugter Client, RFC-9728-Metadaten und Werkzeug-Inventar; jeder Unterschied hält den Commit an. Was der Spine nicht tut: nach aussen servieren — oh-api serve bindet an 127.0.0.1, und die Website erzeugt ihre Fassaden statisch und ruft ihn nie auf; geteilt wird das Schema, nicht der Prozess.",
        "en": "The API spine is the one typed core behind the facades: the REST specification is emitted from code, the client is generated from the specification, and the MCP tool surface binds to the same functions — never a second implementation of the same semantics. Fourteen operations, each mapped to exactly one row of a capability register that lives in code; a test proves register and specification cover each other exactly rather than asserting it in prose. The data source in this phase is the registry repository itself, strictly read-only: there is no write path in the code, and /directory serves zero entries today. On every commit four comparisons run between what the code emits and what is committed — specification, generated client, RFC 9728 metadata and the tool inventory; any difference stops the commit. What the spine does not do: serve anything outwards — oh-api serve binds to 127.0.0.1, and the website builds its facades statically and never calls it; what they share is the schema, not the process."
      },
      "state": "prepared",
      "public_endpoint": false,
      "since": null,
      "source": {
        "path": "registry/api",
        "repo": {
          "available": true,
          "url": "https://github.com/OpenHelvetia/api-spine-oh"
        }
      },
      "release": {
        "available": false,
        "reason": {
          "de": "Noch kein getaggtes Release; das erste folgt mit der Publikations-Strecke.",
          "en": "No tagged release yet; the first follows the publication lane."
        }
      },
      "image": {
        "available": false,
        "reason": {
          "de": "Noch kein Container-Image veröffentlicht.",
          "en": "No container image published yet."
        }
      },
      "crate": null,
      "run": {
        "available": true,
        "requires": [
          {
            "de": "Rust (stable über rustup) und Git; alle Befehle laufen aus der Wurzel des Korpus-Checkouts.",
            "en": "Rust (stable via rustup) and Git; every command runs from the root of the corpus checkout."
          }
        ],
        "commands": [
          "cargo run --locked --manifest-path registry/api/spine/Cargo.toml -- serve --root . --port 8710"
        ],
        "expect": "oh-api serving on 127.0.0.1:8710"
      },
      "test": {
        "available": true,
        "command": "cargo test --locked --manifest-path registry/api/spine/Cargo.toml",
        "offline": true
      },
      "access": {
        "public": {
          "available": false,
          "reason": {
            "de": "Kein öffentlicher Endpunkt: weder Zone noch Route noch Deployment sind aufgeschaltet.",
            "en": "No public endpoint: zone, route and deployment are not switched on."
          }
        },
        "local": "http://127.0.0.1:8710",
        "contracts": [
          {
            "label": {
              "de": "OpenAPI 3.0.3",
              "en": "OpenAPI 3.0.3"
            },
            "path": "registry/api/openapi.json"
          },
          {
            "label": {
              "de": "Erzeugter Client",
              "en": "Generated client"
            },
            "path": "registry/api/client"
          }
        ],
        "example": {
          "label": {
            "de": "Das Fähigkeitsregister",
            "en": "The capability register"
          },
          "request": "curl -s http://127.0.0.1:8710/capabilities",
          "response": "[{\"id\":\"meta.capabilities\",\"operation_id\":\"get_capabilities\",\"method\":\"GET\",\"path\":\"/capabilities\",\"summary\":\"The machine-readable capability register with published client coverage\", …}, … 14 rows]"
        }
      },
      "cli_help": "usage: oh-api emit-openapi | serve --root <dir> [--port <n>]",
      "depends_on": [
        "registry-standard"
      ],
      "used_by": [
        "mcp-gateway",
        "a2a-agent"
      ],
      "docs": "docs/reference/machine-surfaces/",
      "evidence": [
        {
          "label": {
            "de": "Operationen",
            "en": "Operations"
          },
          "value": "14",
          "source": "registry/api/openapi.json",
          "recorded": "2026-09-02",
          "derived": true,
          "note": {
            "de": "14 Operationen in openapi.json (OpenAPI 3.0.3, 19 Komponenten-Schemas), 14 Zeilen im Fähigkeitsregister, 1:1 durch einen Test bewiesen",
            "en": "14 Operationen in openapi.json (OpenAPI 3.0.3, 19 Komponenten-Schemas), 14 Zeilen im Fähigkeitsregister, 1:1 durch einen Test bewiesen"
          },
          "recount": {
            "kind": "openapi-operations",
            "file": "registry/api/openapi.json"
          }
        },
        {
          "label": {
            "de": "Erzeugter Client",
            "en": "Generated client"
          },
          "value": {
            "de": "aus der Spezifikation erzeugt (progenitor =0.14.0), nie von Hand berührt, 1462 Zeilen; die Spezifikation selbst kommt aus dem Code (dropshot =0.17.1)",
            "en": "generated from the specification (progenitor =0.14.0), never touched by hand, 1462 lines; the specification itself comes from the code (dropshot =0.17.1)"
          },
          "source": "registry/api",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Drift-Tore bei jedem Commit",
            "en": "Drift gates on every commit"
          },
          "value": {
            "de": "vier Abgleiche emittiert-gegen-eingecheckt, alle vier grün: OpenAPI-Spezifikation, erzeugter Client, RFC-9728-Metadaten, Werkzeug-Inventar",
            "en": "four emitted-against-committed comparisons, all four green: OpenAPI specification, generated client, RFC 9728 metadata, tool inventory"
          },
          "source": "registry/api",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Datenquelle",
            "en": "Data source"
          },
          "value": {
            "de": "das Register-Repository selbst, streng lesend — kein Schreibpfad im Code; /directory liefert die zwei eigenen Einträge in der Form des Verzeichnis-Schemas, /ns/artifacts spiegelt die 8 Zeilen des Siegelregisters",
            "en": "the register repository itself, strictly read-only — no write path in the code; /directory serves the two own entries in the shape of the directory schema, /ns/artifacts mirrors the 8 rows of the seal register"
          },
          "source": "registry/api",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Geteilter Vertrag",
            "en": "Shared contract"
          },
          "value": {
            "de": "die Verzeichnis-Hülle der API wird gegen dasselbe registry/standard/directory.schema.json geprüft, aus dem die Website ihre eigene Hülle stempelt — geteiltes Schema statt kopierter Logik",
            "en": "the API's directory envelope is validated against the same registry/standard/directory.schema.json from which the website stamps its own envelope — a shared schema instead of copied logic"
          },
          "source": "registry/api",
          "recorded": "2026-09-01",
          "derived": false
        },
        {
          "label": {
            "de": "Fähigkeitsregister",
            "en": "Capability register"
          },
          "value": {
            "de": "14 Zeilen: 8 über MCP und den Client belegt, 6 Login-Zeilen (REST und UI, nie MCP); die Tests prüfen gegen das Register, nicht gegen eine feste Zahl",
            "en": "14 rows: 8 covered over MCP and the client, 6 login rows (REST and UI, never MCP); the tests check against the register, not against a fixed number"
          },
          "source": "registry/api/spine/src/lib.rs",
          "recorded": "2026-09-03",
          "derived": false
        }
      ],
      "missing": [
        {
          "text": {
            "de": "Der Spine ist an keiner öffentlichen Adresse erreichbar: oh-api serve bindet an 127.0.0.1, das Serving hängt am ld.*-Umschalter, und die Website teilt mit ihm nur das Schema. Die veröffentlichte Deckungszahl ist zurzeit nicht bewiesen — der End-zu-End-Test, der jede Registerzeile durch den erzeugten Client fährt, scheitert an einer fest verdrahteten 8, und registry/api/README.md nennt weiterhin fünf Fähigkeiten und «api-client 5/5 = 100 %», während das Register vierzehn Zeilen hat.",
            "en": "The spine is reachable at no public address: oh-api serve binds to 127.0.0.1, serving rides the ld.* switch-on, and the website shares only the schema with it. The published coverage number is currently unproven — the end-to-end test that walks every register row through the generated client fails on a hardcoded 8, and registry/api/README.md still names five capabilities and «api-client 5/5 = 100 %» while the register holds fourteen rows."
          },
          "blocks": "in-operation"
        }
      ],
      "history": [
        {
          "date": "2026-09-03",
          "text": {
            "de": "Quellcode als eigenes Repository auf GitHub publiziert (Publikations-Strecke, Welle 2).",
            "en": "Source published as its own repository on GitHub (publication lane, wave 2)."
          }
        }
      ]
    }
  ]
}
