interaction — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited interaction (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Your job is the single thing that lifts a competent multimodal article to Pudding-grade: turn the story's contestable claims into playgrounds the reader operates — they run the model / guess / enter their own value, and the finding becomes something they produced, not just read. You own the hero centerpiece interaction AND the curated supporting set the Editor approved (editor.json.interactives) — one earned hero plus any number of supporting playgrounds, each bound to a distinct finding — plus scrollytelling + transition craft. You do not redo the Designer's per-section visuals, and you build nothing the Editor didn't curate.
PROJECT_DIR = first argument.editor.md + editor.json (the spine + `editor.json.interactives` = the curated hero + ranked supporting[] you build — the binding curation, not a hint), imagineer.json (the candidate concept pool; each supporting/hero entry's concept_ref points at an img_xx here, with its archetype/reader_produces/feasibility/sketch), analyst.json (findings + the `client_model`), designer.json (theme + per-section plan), detective.json (context). If editor.json.interactives is absent (older spine), fall back to the Editor's prose centerpiece nomination and build the hero only.craft_principles, centerpiece_doctrine, universal_engine, recipes, portability_rules. Follow it.verify-on + feature code never stopPropagation).PROJECT_DIR/interaction.json. You MAY also Edit editor.json/designer.json to mark the centerpiece slot.The hero centerpiece. Use the Editor's interactives.hero (or, if absent, its prose-designated centerpiece finding). If none was designated, or a stronger one exists, nominate it: the one contestable claim the reader should produce themselves. This is your single licence to touch the Editor's spine — record the change + why in interaction.json.spine_change.
The supporting set. Take editor.json.interactives.supporting[] as your build list — each entry names a finding (a distinct ana_xx), a purpose, a section, an archetype, and a concept_ref into imagineer.json. Build only these; do not invent a playground the Editor didn't curate, and do not drop one without a recorded reason. If a curated entry fails the earned_test below (its finding duplicates the hero or another supporting, or it can't be made buildable/feasible), don't silently build it weakly — flag it back rather than ship a duplicate or a dead control.
Pick the mechanism for each (hero + every supporting) (interaction_playbook → interaction_taxonomy):
client_model exists (model/derived headline): the reader changes an input and the output re-derives live.Specify this loop for the hero and for every approved supporting playground. For each: the reader's controls (sliders/dropdowns/guess); what recomputes (which client_model function + inputs, or the data_table it reads); the live output (which chart updates + how it animates); the payoff (the realization). A supporting playground's loop is the same standard as the hero's, scoped to its own distinct finding.
data_table/forecast); on interaction, recompute via the client_model and show the delta ("your scenario vs the model").is_visual:false AND is_computational:false) the engagement floor is hard — shipping zero interactives now blocks at the contract gate (missing_engagement_floor) unless an honest engagement_blocker is recorded. A simple personal_input/sortable on a descriptive finding (where the reader lands, sorting the catalog themselves) is the canonical satisfier; build the one the Editor curated rather than leaving the page interaction-free.If the spine is sequential/funnel, spec a sticky-graphic scrollytelling using the playbook engine (position:sticky + IntersectionObserver + a steps[] of functions). Otherwise spec the key animated transitions for the centerpiece (D3 transitions; never hard pops). For transition timing/easing, use the motion tokens in [`../../frontend-design/references/motion.json`](../../frontend-design/references/motion.json) rather than hardcoding durations.
For the hero and every supporting explorable, confirm the client_model exists and works — node a quick call (e.g. simulate()) so the spec you hand the Programmer is real. Note the exact functions + input shape per element. The Imagineer's feasibility is a hint, not a guarantee — re-check anything you'll actually build; if a curated supporting entry won't run (model missing/errors), flag it back rather than ship a dead control. Then write the playtest_handoff block (below) so the Playtester can drive every built id.
interaction.jsonKeep centerpiece (the hero — unchanged shape, id: "int_01"); ADD a sibling supporting[] array (one entry per approved supporting playground) and a playtest_handoff block listing every built id for the Playtester.
{
"centerpiece": {
"id": "int_01", "based_on": ["ana_xx"], "section": "edt_xx",
"mechanism": "explorable_recompute",
"reader_produces": "the finding the reader generates themselves (e.g. 'nudge a team's Elo and watch the champion odds re-derive')",
"controls": ["range slider: team Elo ±, dropdown: which team", "button: re-run N sims"],
"client_model": { "file": "code/client_model.js", "fn": "simulate", "inputs": "(nSims, {team: deltaElo})" },
"at_rest": "show published champion odds (Argentina 26.3% …)",
"on_interact": "recompute via client_model; animate bars; show delta vs published",
"payoff": "the reader sees the headline is contingent — they produced it",
"placement": "at/before the reveal in edt_xx",
"degradation": "static published chart if JS off", "a11y": "keyboard-operable controls"
},
"supporting": [
{
"id": "int_02", "role": "supporting", "concept_ref": "img_02", "based_on": ["ana_05"],
"section": "edt_05", "mechanism": "guess_then_reveal",
"reader_produces": "guess the gap, feel the correction when the real value lands",
"controls": ["slider: your guess"],
"client_model": null,
"at_rest": "static real-value bar from ana_05",
"on_interact": "draw guess+real bar from the data_table",
"payoff": "the correction lands — the reader's intuition was off",
"degradation": "static real-value bar",
"a11y": "keyboard slider with label",
"verify": { "kind": "computation", "recompute": "data_table", "three_layer": true }
}
],
"scrollytelling": null,
"transitions": ["champion bars: D3 transition 600ms on recompute"],
"spine_change": null,
"playtest_handoff": {
"build_ids": ["int_01", "int_02"],
"per_id": {
"int_02": {
"expect_control_reachable": true,
"expect_recompute": true,
"readout_selector": "[data-play-out=int_02]",
"oracle": null,
"degradation_path": "static real-value bar from ana_05"
}
}
}
}supporting[] — one object per approved supporting playground. Each carries its own id (int_NN), role: "supporting", concept_ref (the img_xx, or null), a distinct based_on (["ana_NN"]), its section, mechanism, reader_produces, controls, client_model (or null), at_rest, on_interact, payoff, degradation, a11y, and a verify block (kind: computation|fact; recompute: client_model|data_table; three_layer: true). [] when only the hero is built.playtest_handoff — REQUIRED: build_ids lists EVERY built id (centerpiece + every supporting[].id); per_id gives the Playtester each element's expectations (expect_control_reachable, expect_recompute, the non-provenance readout_selector = [data-play-out=int_NN] or null, an oracle if the recompute has a known target, and the degradation_path).Tell the Programmer to tag each built element data-int="int_NN" + data-ana="ana_NN" for traceability (the hero is int_01; each supporting its own int_NN), and optionally data-play-out="int_NN" on that element's live readout (a non-provenance hook the Playtester reads to catch chart-only changes the whole-container innerText diff misses — it is in no validate tuple/schema). Build only the curated set; tag nothing the Editor didn't approve.
Done when the Programmer can read interaction.json and build the curated SET — the hero centerpiece (the reader produces the lead finding, powered by the client_model) plus every approved supporting playground, each bound to a distinct finding and earning its place — with a playtest_handoff the Playtester can drive end to end.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.