--- name: riigikantselei-register description: Vabariigi Valitsus session minutes and its decisions on bills - proposer, speakers, voting result, text. module: riigikantselei.mjs execution: get --- # Riigikantselei Public Document Register The Government Office public register, and the **government stage** of a bill: who put an item on the cabinet agenda, who presented it, who spoke, what was decided, how the vote went, who was absent — as structured XML, not PDF. ## Access - Register root: `https://dhs.riigikantselei.ee/avalikteave.nsf/byjournalkey?open` - Lotus Domino serving `Content-Type: text/xml`. No login, no cookies, no JavaScript, and **no request headers** — a bare fetch of every route below returned the same bytes as one sending `Accept: application/json` (verified 2026-08-03 with node; the certificates below are still required). - Views, each opened as `/avalikteave.nsf/?open`: - `govmeetingsbydate`, `govmeetingsbynumber` — Vabariigi Valitsuse istungite protokollid - `byjournalkey` — document series (sarjad) browse; **the only view full-text search reaches** - `protocolsbydate`, `protocolsbynumber`, `protocolsbyissuer` — government councils'/committees' protocols - `legalactsbydate`, `legalactsbynumber`, `legalactsbyissuer` — Government and Prime Minister acts - `incomingcorrespondencebydate`/`bynumber`, `outgoingcorrespondencebydate`/`bynumber` - `decreesbydate`, `decreesbyissuer` (Riigikantselei käskkirjad), `contractsbydate` - Any record: `/avalikteave.nsf/documents/?open` (`?open` is optional here). Attachments use the `href` on a `` child, `/avalikteave.nsf/documents//$file/`, served with their real content type (`application/pdf`, `.docx`, …). ## Retrieve ### Government session minutes and per-item decisions The richest path in this register. Walk it by date: 1. `govmeetingsbydate?open` → `` rows, one per year (2009 … current). 2. `?open&path=2026` → month categories labelled `07|Juuli`. Encode `|` as `%7C`. 3. `?open&path=2026/07%7CJuuli` → `` rows with `date` and `protocolnumber`. 4. `documents/?open` → `` with `subject`, `protocolnumber`, `date`, `meetingplace`, `meetingchair`, `meetingparticipants`, `meetingparticipantsother`, `invitedparticipants`, **`missingparticipants`**, `protocolsigners`, `protocolcreator`, `docid` (`YYYYMMDD.`), then an `` block listing every agenda item as its own `` with the numbered subject. 5. The item's own record → `` with `date`, `protocolnumber`, `agendaitem`, `itemsubject`, **`proposedby`** (Esitaja), **`presenters`** (Ettekandja), **`speakers`** (Sõnavõtja), **`votingresults`** (Hääletustulemused), `body` (Otsuse tekst), and an `` block with `` back to the minutes. Items split into sub-points behave differently: the parent record is an **umbrella** carrying only `agendaitem`, `itemsubject` and `subject`, with the sub-point records listed in its `` block. The decision and the vote live on each sub-point record, in `agendasubitem`, `subitemsubject`, `subproposedby`, `subpresenters`, `subspeakers`, `subvotingresults` and its own `body`. ### Full-text search `GET /avalikteave.nsf/byjournalkey?SearchView&Query=&count=10` - The response is `Content-Type: text/html`: the XML is wrapped in a Domino `
` between literal `@@@XML_START@@@` and `@@@XML_END@@@` markers. Cut between the markers before parsing. - Inside: `` then `` rows with `date`, `docid`, `subject`. - `Query` takes Domino syntax: `AND` / `OR`, quoted phrases, and fielded terms such as `[subject]=riigikaitsekohus` or `[DocAccess]=AK` (URL-encode `[`, `]`, `=`). - `SearchMax` raises the result cap, default 250. `SearchOrder=4` sorts by date and reports the untruncated total. `start` is **0-based** in this view. - **Search does not reach session minutes or decision records.** The same term returns 7 registry documents from `byjournalkey` and `totalhits="0"` from `govmeetingsbydate?SearchView`. To reach a cabinet decision, walk the date path above — do not conclude the register lacks it. - The fielded form at `searchform?open` is POST-only, so a GET-only agent cannot use it; use the GET `SearchView` route instead. ### Journal-series browse The root returns `` rows. Pass a category's exact label as `path`, `%20` for spaces and `/` between levels: `?open&path=02%20Vabariigi%20Valitsuse%20istungite%20ja%20n%C3%B5upidamiste%20ettevalmistamine%20ja%20korraldamine/2-5%20Vabariigi%20Valitsuse%20otsuste%20alusdokumendid` Rows are `` with named `` children; the `` block at the top of every response maps field names to their Estonian labels. Series `2-5` (Vabariigi Valitsuse otsuste alusdokumendid) holds the Riigikantselei resolutions that start a bill's government-stage circuit — they name each ministry, its task, its deadline and the EIS file number. Records with a `casenumber` end in a `` block listing every document in the same case. That is the whole government-stage paper trail for one bill in one hop. ### Councils' and committees' protocols `protocolsbyissuer?open` → issuer categories, then documents. A protocol is `` (or `frmProtokoll`) with `subject`, `docnumber`, `date`, `timebegin`, `timeset`, `chair`, `docsigners` — the substance is only in the attached PDF, and there are no per-item decision records as there are for cabinet sessions. ### Paging `` carries `totalhits`, `start`, `count`, `hits`, `from`, `to`, `prev`, `next`, plus `` / `rel="end"`. `count=100` works. Read those attributes instead of assuming a page size; `start` is 1-based in ordinary views and 0-based under `SearchView`. ### Where the reasons live A `frmDecision` `body` states what was decided, not why. The reasoning — which ministries proposed the position and on what grounds — is in the *kommenteeritud päevakord* for that session on valitsus.ee, which is fully server-rendered and quotable per item. That hop is not part of this register: use the `government-session-agendas` recipe to locate and read it. ## Return - Preserve view name, category path or query, `noteid`, the `documents/?open` URL, protocol number and session date, agenda item (and sub-item) number, every named field, and retrieval time. - Quote `votingresults` / `subvotingresults` verbatim. It is free Estonian text (e.g. "ühehäälne otsus"), not a tally — do not convert it into vote counts. - Multi-value fields (`meetingparticipants`, `missingparticipants`, `speakers`, `protocolsigners`, `body`) separate entries with the literal four characters ` \nl` — a real backslash, `n`, `l`, not a newline escape. Split on that string. - `missingparticipants` is a stated fact of record. Report who was absent when the question is who decided. - Keep absent fields null; available fields vary by form. `reference` (Kehtestatud õigusakt) is declared on `frmDecision` but was empty in every record checked. ## Limits - **The register answers, and `reachable: false` now means a real failure rather than a standing one.** `dhs.riigikantselei.ee` serves only its leaf certificate — its issuer `YR1` chains to ISRG Root YR, which Node's bundle does not carry — so it was genuinely unreachable from Node until 2026-08-02. That is fixed centrally: `certs/estonian-state-chain.pem` supplies the cross-signed certificate; the published archive ships it and its setup step installs it. Verified 2026-08-02 with Node: `byjournalkey?open` answers HTTP 200 `text/xml` with `totalhits="23"`, `govmeetingsbydate?open` with 18 year categories, and `?open&path=2026` with seven months. `riigikantselei.mjs` decides reachability at runtime and its TLS note fires only on an actual certificate error. The lesson from that episode is still worth carrying, because it is general: macOS `curl` succeeded on this host throughout, because it fetches a missing issuer itself. **A passing `curl` check proves nothing about what the agent can reach — verify with Node.** `www.riigikantselei.ee` and `riigikantselei.ee` verify fine but answer 404 for `/avalikteave.nsf/…` (still true 2026-08-02), so `dhs.` is the only host. If a call ever does come back `reachable: false`, read its note: **say the cabinet's minutes could not be retrieved — never that the government has no record** — and fall back to `government-session-agendas` for the kommenteeritud päevakord and its grounds, `riigikogu-open-data` once a bill reaches the Riigikogu, or `legal-acts-data` for an adopted regulation. A human can open the register at `https://www.riigikantselei.ee/asutus-uudised-ja-kontakt/dokumendiregister`. ```probe-limit claim verify fine but answer 404 for `/avalikteave.nsf/…` (still true 2026-08-02) # The register lives on `dhs.` alone. www.riigikantselei.ee is the Drupal site # and answers its own 404 page ("Otsitud lehekülge ei leitud!") for anything # under /avalikteave.nsf/ — 112 KB of HTML, nothing like the 225-byte Domino # 404 an unknown noteid produces. GET https://www.riigikantselei.ee/avalikteave.nsf/byjournalkey?open expect-status 404 expect /Otsitud lehek/ # The control is that host's own front page, which must answer 200. Without it # a Riigikantselei website outage would read as confirmation — and this is the # guide that once declared a whole live register dead, so a check that cannot # tell a refusal from an outage is exactly the failure to avoid here. control GET https://www.riigikantselei.ee/ ``` - Listing rows carry their data as `` CHILDREN, not as attributes on ``; only `noteid` and `href` are attributes. Reading attributes alone yields rows that are a noteid and four nulls, which reads as a register full of empty records. - This is an older Government Office document system and may overlap newer ADR records (`ministry-document-registries`). - Category labels have historical variants — two different "05 Peaministri nõustamine …" series and two different "18 Avaliku teenistuse …" series sit side by side in the root. Do not merge them solely by numeric prefix. - Detail records can omit restricted document content while retaining public metadata. An `Asutusesiseseks kasutamiseks` record keeps `companyname`, `date`, `docid`, series and `accessrestrictionreason` (e.g. "Avaliku teabe seadus § 35 lg 2 p 2") but has an empty `subject` and no `` children. `docaccesstype` values in use: `Avalik`, `Asutusesiseseks kasutamiseks`, `Avalik, väljastatakse teabenõude korral`. - Protocol numbers restart each year, so `govmeetingsbynumber` is not chronological — it opens on protocol 90 of 2020. Use `govmeetingsbydate` whenever the date is known. - Relevance-ordered search reports `totalhits` saturated at the 250 cap; add `SearchMax=1000` or `SearchOrder=4` before quoting a count. - `protocolsbyissuer` covers four councils only. Kabinetinõupidamised and press conferences are not in this register. - An unknown `noteid` answers HTTP 404 HTML ("Entry not found in index"), not an empty result. ```probe-limit claim An unknown `noteid` answers HTTP 404 HTML ("Entry not found in index") # 225 bytes of Domino error HTML, not `` with nothing in it. So a # noteid read off the wrong view fails loudly instead of looking like a # document that is not in the register. GET https://dhs.riigikantselei.ee/avalikteave.nsf/documents/NT00000000?open expect-status 404 expect /Entry not found in index/ # The control is the register root: HTTP 200 text/xml. This guide spent a # release telling the agent the register was dead while it was answering 200 # with totalhits="23", and the control is what stops that from happening in # this direction — a 404 from a host that is down proves nothing. control GET https://dhs.riigikantselei.ee/avalikteave.nsf/byjournalkey?open ``` ## Verify - Every view must answer HTTP 200 `text/xml` with root element `entries` and paging attributes, carrying `` or `` rows. - Session minutes: require `` with `protocolnumber`, `date` and an `` block holding one `` per numbered agenda item. Minutes whose `` block says "No documents found" mean the wrong `noteid`. - **Decision record vs. empty form.** Require `` whose `agendaitem` matches the item asked about, AND a non-empty `body` of Estonian decision text (it reads as a numbered instruction, e.g. "1. Mitte toetada …" or "Anda Vabariigi Valitsuse määrus …"), AND at least one of `votingresults` / `subvotingresults` populated. A record whose only populated fields are `date`, `protocolnumber`, `agendaitem`, `itemsubject` and `subject` is an umbrella item, not a decision: open the sub-point documents listed in its `` block and read those. - Attribution must come from the fetched fields — `proposedby`, `presenters`, `speakers` (or their `sub*` equivalents) — never from which minister the topic suggests. Do not state a name, date, vote or decision text that is not present in retrieved output. - Search: require `` between the `@@@XML_START@@@` / `@@@XML_END@@@` markers with `totalhits` greater than zero. A 200 containing only the Domino `` and no `` is a failed query. Zero hits on a term the register plainly holds means the search ran on a view other than `byjournalkey`, or that the target is a minutes/decision record, which search never indexes. ## Worked example (walked 2026-07-26) Government opinion on the Riigikaitsekohus bill (979 SE), cabinet session of 23 July 2026, item 7 — four requests, no search: 1. `govmeetingsbydate?open&path=2026` → category `07|Juuli` 2. `govmeetingsbydate?open&path=2026/07%7CJuuli` → `noteid="NT0041A37A"`, 23.07.2026, protocol 36 3. `documents/NT0041A37A?open` → `frmGovMeetingMinutes`, chaired by rahandusminister Jürgen Ligi, five ministers absent, `` item 7 → `noteid="NT0041A35E"` 4. `documents/NT0041A35E?open` → `frmDecision`: `proposedby` justiits- ja digiminister Liisa-Ly Pakosta, `presenters` Margus Tsahkna, `speakers` Jürgen Ligi, `votingresults` "ühehäälne otsus", `body` a numbered instruction not to support the bill and to convey the opinion to the põhiseaduskomisjon by 24 July 2026. `byjournalkey?SearchView&Query=riigikaitsekohus&count=10` finds the same bill's *preparatory* paperwork instead — 7 hits, including the Riigikantselei resolution 26-01311-2 of 25.06.2026 tasking two ministries with deadlines — but never the decision record itself. ## Module API govMinutes({date, year, month}) -> {source, page, reachable, note, path, totals, rows} govDecision(noteid) -> {source, page, reachable, note, form, protocol, date, item, subject, proposedby, presenters, speakers, votingresults, body, subitems}