Skip to content

Add an AI policy guide over Every AI Policy Ever - #110

Draft
bdb-dd wants to merge 13 commits into
mainfrom
feat/ai-policy-guide
Draft

bdb-dd wants to merge 13 commits into
mainfrom
feat/ai-policy-guide

Conversation

@bdb-dd

@bdb-dd bdb-dd commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #109 (the Parquet source). Review that one first. This PR's own diff is the four commits on top of it.

What

A local-config example that uses the Parquet source on a public dataset, Every AI Policy Ever (CC-BY-4.0). The dataset is a register of about 400 AI laws, regulations, frameworks and strategies from 87 countries and international bodies, plus defined terms quoted verbatim.

  • Two datasets with weekly pipelines from Hugging Face:
    • digdir/ai-policy: the records, filterable by jurisdiction, country, region, instrument type, legal force, status, verification level, safety topics and year.
    • digdir/ai-policy-definitions: the definitions, filterable by term, term group and language.
  • The record text carries short title, dates published, in force and last updated, the English version and its translator, and the verification note. Answers can then build timelines and say when an instrument binds.
  • KI-regelverksguiden, an agent-loop service over both datasets. For each instrument it gives jurisdiction, type, legal force, status, dates, identifier and verification level, warns at level C, says the summaries are AI-made, and ends with the CC-BY attribution.
  • Four skills, pinned by the guide: compare jurisdictions, quote definitions (original language plus the English rendering), build a timeline, and check whether something is binding.
  • Two step flows with services:
    • ai-policy-brief: binding instruments on a topic, as a table and a short brief.
    • ai-policy-comparison: a side-by-side table across jurisdictions.
  • A draft test set, packages/eval/testsets/ai-policy-guide-draft.yaml: 10 cases, including one not-covered case, all needsReview.
  • Seeding: local config now seeds skills/ before services/, so a service that pins a seeded skill is no longer skipped with "no published skill". README and development docs mention it.

Tests

  • definition-sources.test.ts:
    • seeds skills before services;
    • every pinned skill is seeded at the pinned version;
    • every skill is valid, named after its file and has a must_reject case.
  • testsets.test.ts: the draft stays a draft, has sources in both datasets, and has a not-covered case.
  • Pipeline seed tests validate both pipelines.
  • Checked end to end locally: ingest, then answers through the API and the portal playground. Citations were valid against the register in every round checked: 19 of 19 for the guide, and 37 of 37 and 11 of 11 for the flows.

Notes

Draft, for review.

Follow-up commit (b624e7d)

  • Eval grounding. Every judged case states that the register is a dated snapshot whose 2025–26 instruments are real, and when the answer passes. The criteria judge only sees the reference text, so it had graded against its own knowledge. Two eval runs scored 0.73 and 0.82, with no "made up" verdicts.
  • New train case: deepfake labelling, where the EU AI Act was missed.
    • The binding-check skill now filters on both the narrow and the broad topic.
    • The guide reranks in the same round as it reads, because generate_response without a rerank sees only the first ten chunks in insertion order.
    • It passes chunk ids to read_chunks.
    • EU-03 was cited in 0 of 3 runs before and 3 of 4 after.
  • Definitions take status, dates and verification level from the law with the same Record id, instead of "ikke oppgitt". Colorado was right in 3 of 3 runs, against 0 of 5 before.
  • scripts/ai-policy-jurisdictions.ts regenerates the comparison flow's jurisdiction list from records.parquet, or checks it with --check, which reports 141 names matching. Tests keep the bokmål mapping inside the list. The flow says a name outside its list is unknown to it, not missing from the register.

Independent verification

A separate verifier found three issues, all fixed:

  • A comparison where every jurisdiction was unknown ran an unfiltered search. It now answers without searching.
  • The context limit could silently drop the sixth jurisdiction. Comparisons are now capped at 4 jurisdictions, 3 chunks each, with a context sized for the worst case. A fifth requested jurisdiction is reported, not dropped.
  • The pipelines read main weekly while the answers claimed a fixed snapshot. Both pipelines are now pinned to Release v1.18 (2026-10-19), with no schedule, and the texts state that version.

@bdb-dd
bdb-dd force-pushed the feat/parquet-source branch from 3137b58 to 40a9d51 Compare October 23, 2026 22:14
@bdb-dd
bdb-dd force-pushed the feat/ai-policy-guide branch from 1c8e400 to 69d9485 Compare October 23, 2026 22:14
bdb-dd added 13 commits October 24, 2026 00:24
ADR 0039: a pipeline with source kind parquet reads one file from an https
url, or from a Hugging Face dataset as { dataset, file, revision }, and maps
rows to documents the way database sources map table rows.

- @genai/ingest gains parquetSource and the ParquetReader interface. Each
  row becomes one document whose id depends only on the file's origin and
  the row id, with the title on a bold first line so it stays in the
  searched text, the text columns, and the metadata as lines.
- Metadata columns are stored as document fields: lists stay lists, nulls
  are dropped, constants are added and year is a number from a date
  column, so multiselect and range filters work on them.
- Equality filters (eq, neq, in, not_in, is_null, not_null) and maxRows
  limit the rows read; a mapped column the file lacks fails the run by
  name.
- The file comes through the ingestion's guarded fetch: every redirect
  checked, private addresses refused, no host allowlist (Hugging Face
  redirects to regional CDN hosts), a two-minute read timeout and maxBytes
  (default 100 MB, at most 500 MB).
- @genai/providers-parquet decodes with hyparquet and hyparquet-compressors
  (pure JavaScript, MIT) and is wired in by the composition root; the
  dependency rules keep the parser in provider packages.
…tion

Normalize IPv6 addresses before checking embedded IPv4 ranges, and carry the execution signal into the guarded download alongside its timeout. Regressions cover private mapped URLs and cancellation of an in-flight Parquet fetch.
Add the source kind and labels in both portal languages so datasets created through the API can be listed and opened. The regressions exercise the dataset list model in Bokmål and English.
Document the embedded WebAssembly Snappy decoder and the shared guard’s remaining DNS rebinding gap. Regenerate the architecture atlas from the corrected module description.
The local configuration gains the dataset digdir/ai-policy on platform-pg,
filled weekly by two parquet pipelines from the Hugging Face dataset
kelkalot/every-ai-policy-ever (CC-BY-4.0).

- ai-policy-records reads data/records.parquet: one document per
  instrument, with summary and notes as text, official_url as the link,
  and jurisdiction, country, region, level, instrument type, legal force,
  status, verification level, safety topics, issuing body and official
  identifier as fields, plus record_id, year and doc_kind record.
- ai-policy-definitions reads data/definitions.parquet: one document per
  defined term, with the verbatim definition (and its English translation
  when there is one) as text, and record_id, term, term group, language,
  locator and doc_kind definition as fields.
- The dataset declares those fields as multiselect filters, the free-text
  ones also as text, and year also as an integer range.
- Chunking keeps short documents (minimumLength 1), so a brief record or
  definition is still indexed.
- Record documents carry Short title, Date published, Date in force,
  Date last updated, English version, English version by and
  Verification note lines, so answers can build timelines, say when an
  instrument binds and point to an official translation.
- A definition's English text is labelled "English rendering", with who
  rendered it, instead of an unlabelled paragraph.
- Definitions go to digdir/ai-policy-definitions, filterable by record
  id, term, term group and language. Two pipelines promoting into one
  dataset replaced each other's index, so only the last one was
  searchable.
- Record documents chunk with a maximum of 8000 characters, so each
  record stays one chunk with its title and fields; the longest is
  about 6200.
A guide, two step-flow services and four skills help users get value
from Every AI Policy Ever (kelkalot, CC-BY-4.0) in digdir/ai-policy and
digdir/ai-policy-definitions.

- KI-regelverksguiden (ai-policy-guide) is an agent loop with a bokmål
  prompt. It cites each instrument with its jurisdiction, legal force,
  status, dates and verification level, warns on level C, says the
  summaries are AI-made and that legal work must quote the original,
  uses the dataset filters, and ends with the CC-BY attribution. Its
  answer rules follow the skills, because generate_response sees only
  the generation prompt, not a skill loaded with use_skill.
- Four skills, pinned by the guide: compare jurisdictions, find
  definitions (quoted verbatim, never filtered by jurisdiction, which
  definitions lack), make a timeline, and check whether a topic is
  binding somewhere. Each has its own test set with a must_reject case,
  and works with or without search tools.
- Step flows: ai-policy-brief retrieves binding instruments only and
  writes a brief with a table; ai-policy-comparison extracts the
  jurisdictions (from the register's own names) and English queries,
  searches each jurisdiction separately, and writes a side-by-side
  table. Both write English queries, since the register is English.
- Local configuration seeds a skills/ directory between flows/ and
  services/, so a service can pin a skill seeded with it.
- A draft test set, ai-policy-guide-draft, has nine sourced cases over
  both datasets and one not-covered case.
- The draft test set states, in every judged case, that the register is
  a 2026-10-18 snapshot whose 2025-26 instruments are real, and when the
  answer passes. The criteria judge sees only the reference text, so it
  graded against its own knowledge and called real instruments made up.
- A new train case asks which countries bind deepfake labelling; the
  guide missed the EU AI Act (EU-03). The binding-check skill now filters
  on both the narrow and the broad topic, because EU-03 is tagged
  transparency & labelling but not deepfakes, and also searches the
  broad AI acts by name.
- The guide reranks in the same round as it reads, because without a
  rerank generate_response sees only the first ten chunks in the
  workspace; it passes chunk ids, not doc ids, to read_chunks; and it
  keeps broad laws in binding answers.
- The definitions skill searches the law alongside the definition, and
  the answer takes a definition's status, dates and verification level
  from the law with the same Record id instead of saying "ikke oppgitt".
- scripts/ai-policy-jurisdictions.ts regenerates the comparison flow's
  jurisdiction enum from records.parquet, or checks it with --check. The
  flow says a jurisdiction outside its list is unknown to it, not missing
  from the register, and a test keeps every name in the bokmål mapping
  in the enum.
Return a guide referral when the comparison recognizes no requested jurisdiction. Cover that branch and mixed known and unknown requests with flow regression tests.
Limit comparisons to four jurisdictions and three chunks each, keeping an 80000-character context in jurisdiction order. Report additional requested jurisdictions even when synthesis omits them, and cover full-length source texts and overflow requests.
Pin both imports to the same immutable revision and disable scheduled refresh. Correct release dates throughout the instructions and evaluation references, derive jurisdiction regeneration from that revision, and test the shared pin and provenance rules.
@bdb-dd
bdb-dd force-pushed the feat/parquet-source branch from 40a9d51 to 39414e4 Compare October 23, 2026 22:27
@bdb-dd
bdb-dd force-pushed the feat/ai-policy-guide branch from 69d9485 to ae6aca2 Compare October 23, 2026 22:27
Base automatically changed from feat/parquet-source to main October 28, 2026 13:41

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant