Inspector
Skill QinghongLin/data2story-skill/skills/data2story-pro/inspector
Data Journalist Agent: Transforming Data into Verifiable Multimodal Story
npx -y skills add QinghongLin/data2story-skill --skill inspectorAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
What its author says it does
Copied from the file, not written here
Run sentence-level traceability verification on a Data2Story blog (verify.py -> verifier.json), then emit the in-page Inspector panel (the reader-facing runnable verifier) + the verify/ artifacts (verify_map.json, run_cells.json, the reproducible notebook, cell_registry.json). Mostly Python; the runnable layer recomputes each computation in-browser from its inlined data and grades it against the published output, while the bundled notebook re-executes from raw data. Use verify.py at Stage 6.4 (after validate.py, before the Critic) and generate_viewer.py at Stage 7 after the Programmer authors the verify/ files and pastes the panel shell. Triggers: a built index.html plus the role JSONs exist, or you need the traceability map / the in-page runnable verifier.
SKILL.md
12.1 KB, as published. Nobody here has run it
Inspector
Your job is traceability verification plus standing up the runnable verify layer — a reader can recompute each computation in-browser (from its inlined data), and the bundled notebook re-executes the headline numbers from raw data (that notebook is the paper's coding verifier). You parse the blog HTML, link each visible sentence back to its evidence in the role JSONs (verify.py → verifier.json), and then build the in-page Inspector panel: a click-any-claim drawer embedded in index.html whose evidence is byte-identical to the on-disk verify/ artifacts, backed by a reproducible notebook that re-runs the headline numbers from raw data.
This whole layer is MANDATORY on every blog. A blog without a working Inspector panel, the verify/ artifacts, and a clean reproducible notebook is incomplete.
Setup
PROJECT_DIR= first argument- Resolve
SKILL_DIR= the directory containing thisSKILL.md(.../skills/data2story-pro/inspector). ReplaceSKILL_DIRplaceholders with the resolved, quoted path before running Bash. Do not hard-code machine-local paths. - Required files in PROJECT_DIR:
index.html,analyst.json,detective.json,designer.json,editor.json
Step 1: Run verify.py (sentence → evidence map) — early, at Stage 6.4
python3 SKILL_DIR/scripts/verify.py PROJECT_DIR
Produces PROJECT_DIR/verifier.json (the sentence→evidence mapping — the upstream traceability index). The output shape (format v3: stats, sentences, unused_ids) is in references/inspector_schema.json.
Ordering (important): verify.py runs early — at Stage 6.4, after the contract gate (validate.py) and before the Critic — so verifier.json already exists when the Critic reads it. Re-run verify.py inside the Critic loop each round. The panel-injection (Step 2, generate_viewer.py) happens later, at Stage 7.
Step 2: Emit the Inspector panel + verify/ artifacts
The Inspector no longer ships a standalone reader-viewer. It now emits the in-page verify panel (the reader-facing front-end) plus the auditable verify/ artifacts that back it — including the reproducible notebook, which is the paper's from-raw-data coding verifier:
-
The in-page Inspector panel (lives in
index.html). The Programmer copiesreferences/inspector_panel_reference.htmlVERBATIM intoindex.html(the.v-*<style>, the#verifyTogglebutton, the drawer/backdrop/toast markup, and thewindow.__verifyIIFE — see the programmer'sinspector_panelfamily). The.v-*CSS must stay inside a<style>element in<head>— if it lands after the document's own</style>the rules render as visible text (conspicuous on mobile). The Inspector fills the panel's two inline JSON islands:<script type="application/json" id="verifyMap">— per-element provenance, byte-identical toverify/verify_map.json<script type="application/json" id="runCells">— in-browser-runnable snippets, byte-identical toverify/run_cells.jsonClicking any element carrying adata-{ana,det,des,sct,cin}id opens the drawer for that id and renders the matching kind. Acomputationwhose snippet is runnable gets a Run button that re-executes the statement in-browser (lazy Pyodide) and grades stdout againstexpected_stdout— recomputing the figure from the snippet's inlined data (the reproducible notebook performs the paper's from-raw-data re-execution; the panel makes that reproduction one-click for the reader).
-
The
verify/artifacts (on-disk source of truth).verify/verify_map.json— the per-element provenance map (the same bytes inlined asverifyMap). Schema:references/verify_map.schema.json.verify/run_cells.json— the parallel runnable-snippet map (the same bytes inlined asrunCells). Schema:references/run_cells.schema.json.verify/<topic>_forecast.ipynb— the reproducible notebook that re-runs the pipeline from raw data andasserts the reproduced figures match the published ones (the notebook is a proof). Recipe:references/reproducible_notebook.md(+references/notebook_template.ipynbskeleton).verify/cell_registry.json— maps each notebookcell_idto the atomic claim ids it backs (the inverse ofverify_map[id].cell_id). Schema:references/cell_registry.schema.json.verify/data/— the dataset inputs the notebook reads (bundled at publish; seereproducible_notebook.md§7).
python3 SKILL_DIR/scripts/generate_viewer.py PROJECT_DIR
generate_viewer.py is the deterministic panel + redirect emitter — pure Python, no LLM. It runs at Stage 7 and requires that the upstream authoring is already in place: the Programmer must have authored verify/verify_map.json + verify/run_cells.json (per their schemas) and copied references/inspector_panel_reference.html VERBATIM into index.html (the two empty <script type="application/json" id="verifyMap"> and id="runCells"> islands plus the IIFE's var NB_PATH). Given that, the script:
- Validates the authored
verify/*.jsonagainst the schemas, and checks every pagedata-*id resolves to averify_mapkey (and vice-versa). - Injects the two payloads byte-identically into the empty islands in
index.html— the rule isinline == file_text.rstrip("\n"), raw UTF-8, escaping a literal</script>only if present (never re-serialised). The on-diskverify/*.jsonfiles stay the source of truth; the inline copies are what the panel reads at runtime. - Derives
verify/cell_registry.json— the mechanical inverse ofverify_map[id].cell_id(plus the analystcalculation.file → cell_<stem>tag) — written only if absent, or refreshed with--refresh(so hand-attachedbacks[]are preserved). - Wires
NB_PATHin the IIFE (the Download-notebook target — run locally; there is no Colab branch).
You run the script; you do not reimplement it. Its behaviour — the no-reflow overlay drawer, the kinds→renderers, the byte-identical-inline rule, the data-* contract, the lazy-Pyodide grading, and the publish wiring — is documented in the LIVE internals doc references/inspector_panel_internals.json; the verbatim UI build it copies is references/inspector_panel_reference.html. (An earlier margin-shift evidence viewer was retired and superseded by this layer — do not follow that old design.)
Kinds the panel renders
verify_map[id].kind selects the drawer renderer (matching verify_map.schema.json):
- computation — claim + code slice (
code_file+code_lines) +data_preview+expected_output+ a Run panel. Runnable snippets execute in-browser and grade; stochastic ones run a reduced-N sample graded "≈ within noise" (never a hard PASS);needs_network:true ⇒ runnable:false(shown read-only, pointing at the notebook cell infull_ref). - media — real (fetched) asset preview +
source_url+license+author+identity; multi-asset elements render a gallery (flags || assets || photos, first non-empty wins). - generated — AI-asset preview +
tool/model/prompt/disclosure+ thereal_defaultpublish-safe fallback (the real asset is the default; the AI asset is opt-in). - fact — claim + category + categorised
sources[], each with its ownfacts[]. - credits — a fact-shaped license/source aggregator (e.g. a card-deck's data + photo licences) rendered with a Credits badge (same renderer as
fact).
Byte-identical inline rule (hard)
The verifyMap / runCells islands inlined into index.html MUST be byte-identical to verify/verify_map.json / verify/run_cells.json. The on-disk files are the auditable source of truth and the publish artifacts (they are also the inputs the downloaded notebook reproduces from); the inline copies are what the panel reads at runtime. If they drift, the audited provenance no longer matches what readers see. When inlining, escape any literal </script> as <\/script> and serialise with ensure_ascii (see inspector_panel_internals.json → inline_byte_identical).
data-* contract (no new attribute)
Elements bind to provenance via data-{ana,det,des,sct,cin} — one per producing role; the value is the atomic id (e.g. data-ana="ana_01"). Reuse these five only; do not introduce a new data-* attribute. Decorative wrappers carry no id and are skipped; the innermost tagged element wins. Every data-* id on the page MUST exist as a key in verify_map.json (a dangling id is an auditor failure; a verify_map id with no element is an unused-entry report, not fatal).
Scripts
| Script | Role |
|---|---|
scripts/verify.py | sentence→evidence pass → verifier.json. Runs early, at Stage 6.4 (before the Critic). |
scripts/generate_viewer.py | the deterministic panel + redirect emitter (Stage 7): validates the authored verify/verify_map.json + verify/run_cells.json against the schemas + page data-* ids, injects them byte-identically into the panel shell already in index.html, derives verify/cell_registry.json (write-if-absent / --refresh), wires NB_PATH (the Download-notebook target — run locally). |
scripts/validate.py | the contract gate (run before verify.py; not modified here). |
Where the verify/ payloads come from: verify/verify_map.json, verify/run_cells.json, and the reproducible notebook are authored upstream by the Programmer (the claim is the Editor's published sentence; data_preview is curated; the run_cells snippets are self-contained, pre-tested Pyodide code with real expected_stdout). They are not producible by a pure analyst.json → islands transform, so they are not emitted by the Inspector. generate_viewer.py only validates, injects, derives, and wires what the Programmer authored — it never invents provenance, which is why no LLM enters the Inspector. cell_registry.json is the one artifact the script derives (mechanical inversion of verify_map[id].cell_id).
Running the steps
python3 SKILL_DIR/scripts/verify.py PROJECT_DIR
python3 SKILL_DIR/scripts/generate_viewer.py PROJECT_DIR
Output
PROJECT_DIR/verifier.json— full traceability data (withraw_evidence) — the upstream sentence→evidence map.PROJECT_DIR/index.html— now carrying the in-page Inspector panel (verbatim UI + the two byte-identical JSON islands).PROJECT_DIR/verify/verify_map.json,PROJECT_DIR/verify/run_cells.json,PROJECT_DIR/verify/<topic>_forecast.ipynb,PROJECT_DIR/verify/cell_registry.json(+verify/data/at publish) — the auditable coding-verifier artifacts.
Done when: index.html opens directly in a browser (no server) and the 🔍 Inspector toggle opens a no-reflow drawer for every traced data-* element; a computation with a runnable snippet executes in-browser and grades against expected_stdout; the inline verifyMap/runCells islands are byte-identical to the verify/ files; the reproducible notebook runs clean (every cell's assert passes).