Repository navigation
Releases: Tranquility2/quizzing
Release list
v0.7.1 — the docs catch up with the cap
A documentation-correctness release. v0.7.0 made the question cap negotiable — default 20,
or the number the user asked for — and updated the requirements that say so. It did not
update the prose that restates the old rule as an absolute, so the docs asserted both
versions at once. Two of the corrected files ship inside the installed plugin, and plugin
components are cached at install time, so this needs a version bump to reach anyone.
No behaviour change.
Fixed
- The docs now agree with the shipped cap. Eleven places across
README.md,
docs/design.mdandSKILL.md's frontmatter still promised "no more than 20 questions"
or a "hard maximum of 20 user-visible questions". The frontmatter matters most: it is the
agent's matching surface, and it advertisedcapped (<=20)for a form that will carry 30
if the user asks. Requirements FR-008, FR-046, NFR-002 and NFR-042 were already correct. web/README.mdpointed at a directory that does not exist. Tests live intests/at
the repository root, notweb/test/, and the list named four of the seven suites.decision-matrixwas missing fromweb/README.md's question-type list. v0.3.0 fixed
exactly this omission inSKILL.mdand added a guard against it recurring — but the guard
only ever readSKILL.md, so the type stayed invisible here for four more releases. The
guard now reads both files.web/README.mddescribed security that v0.7.0 replaced. It still claimed the server
checks onlyquestionnaire.id; submissions are now checked for identity, shape and
referential integrity before anything is written.docs/development.mdmiscounted the manifests (seven files carrying tenversion
fields, not six), omittedtest-build,test-followupand thefollowuptarget, and had
no row fordocs/plan/.
Changed
- The README gallery no longer opens by repeating the hero screenshot. The single-select
cell used the same image shown directly above it, and the boolean cell was redundant with
the contradiction check, which is itself a yes/no question. Both types are still named in
the surrounding captions; the grid is now 3x2.
v0.7.0 — the declared contract becomes the enforced one
A contract-integrity release. An audit of all five plans and seven releases found the same
defect three times: the JSON schema declared a constraint that no shipped code enforced.
skills/quizzing/web/ is deliberately dependency-free, so nothing on the shipped path ever
runs the schema — make validate is a dev-only target. The schema had been quietly acting
as documentation while reading as a guarantee. No new features; three false promises made
true and one requirement corrected to describe the product that actually shipped.
Changed
questionCapis negotiable and enforced. The schema pinnedmaximum: 20while
build.jsenforced whatever cap it was handed, so a questionnaire declaring
questionCap: 30built and served normally and failedmake validate. The fixed maximum
is gone: the declared cap is the maximum, the default is still 20, andSKILL.mdnow
carries the rule that a different cap is legitimate only when the user asked for one. No
code can tell a user-requested cap from an agent-inflated one, sobuild.jsreports a
non-default cap on every run rather than applying it silently.FR-052reworded to the model that shipped. It required "custom-answer requirements
when Other is chosen", but Quizzing has no "Other" option — free text is a separate
customInputchannel. The implementable rule replaces it and is now enforced.NFR-026(non-browser fallback) formally withdrawn. v0.4.0 deleted the implementation
and left the requirement asserted, alongsideSKILL.mdtext saying the opposite.
Fixed
- "No external network calls" is now true.
diagram.contentwas documented as a data URI
and typed as a bare string, andapp.jsassigned it straight to<img src>, so a remote
URL passed validation and was fetched under a banner reading "self-contained: no external
network calls". The schema now constrains image content to a base64 data URI, andapp.js
re-checks it independently, since nothing on the build path runs the schema. - The CSS route to the network is closed. The SVG sanitiser checked
href,xlink:href,
andsrconly, so<style>@import url(https://…)</style>andstyle="fill:url(https://…)"
both survived, as didfilter,mask,clip-path, and the marker attributes.<style>is
now dropped whole like<script>, and any attribute containing aurl()that is not a
same-documenturl(#id)is dropped. - Submitted answers are actually validated.
serve.jsaccepted a submission after
checking that it was an object, thatresponseswas an array, and that the questionnaire
id matched. Newlib.validateSubmissionadds the referential half: unknown question ids,
unknown option ids, duplicate answers, and mismatched version or loop id are rejected with
400 before anything is written, and every issue is reported at once.followup.jsruns the
same check on its inputs, where a mismatch would have carried phantom questions into the
next round. This is hand-rolled rather than schema validation, deliberately and explicitly. FR-049andFR-051implemented.docs/design.mdstated thatFR-048–FR-052"are
checked as each question is answered"; three of the five were not implemented. A
rangeValueof 999 against a 1–5 scale and a ranking of["a","a"]both validated clean.- The
SKILL.mddangling pointer. Two passages told the agent to "skip to No Node.js?
Fall back to conversational delivery" — a section deleted in v0.4.0 — four lines from text
saying there is no non-browser adapter and none should be improvised. - Stale plan claims corrected. "ES5-compatible" (
CON-302,CON-401) has never been true
of a directory usingconst,let, and arrows throughout;FILE-305/TASK-310named a
web/style.cssthat does not exist (it isapp.css);TASK-330shipped in v0.5.0 unticked;
andREQ-205/FILE-208/TEST-206/RISK-204still promised the three extra exemplars that
v0.4.0 replaced with one broad example, having been left behind when only the task row was
reworded.
Added
- A two-way contract-coverage guard (
tests/docs.test.js). The existing guards ran one
way — catching runtime code that reads a field the schema forbids — and so could never have
caught any of the above. The new table asserts the reverse: every constraint the project
declares names the code that enforces it. tests/build.test.js— the question-cap contract, pinned from both the runtime and the
schema side.
v0.6.1 — ledger accuracy
A ledger-accuracy release. No behaviour changes.
Fixed
architecture-quizzing-roadmap-1.mdsections 5–7 refreshed. The task tables were kept current
at every release, but the Files, Testing, and Risks sections were not part of that habit and had
drifted since v0.4.0:app.jswas still described as the site of "outstanding autosave work"
delivered in v0.3.0,examples/as pending expansion when v0.4.0 deliberately consolidated it to
one broad exemplar,TEST-103as a live requirement for a Markdown adapter closed won't-do, and
TEST-105/RISK-101as open when v0.4.0 narrowed thedeliveryMethodenum and added the guard
test.FILE-108andTEST-106were added for the v0.6.0 follow-up generator.RISK-103(this ledger drifting from reality) is recorded as partly realised rather than
merely mitigated, since it is what happened.GUD-101now says explicitly that every section is
part of the ledger, not just the task tables.web/README.md:build.jsis described as shared bygenerate.jsandserve.jsrather than
"both CLIs" —followup.jsis a third CLI and does not use it.
v0.6.0 — the loop closes itself
A loop release. Quizzing has always promised convergence in a few short rounds, but the
next round was re-authored by hand — while the answers artifact was already recording
exactly which items the last round left open. Those signals are now read back, so a
follow-up is derived rather than retyped.
Added
web/followup.js, a third entry point.node web/followup.js <questionnaire.json> <answers.json> [output.json]drafts the next loop's questionnaire from a completed round.
Lineage is wired without the agent touching it:parentLoopId,parentSessionId, a fresh
loopId,versionreset to 1, andbearingSummarycarried forward. This closes
TASK-119and satisfiesFR-047.- Three signals carried forward. A
deferredresponse is copied verbatim — it was
authored well the first time, and rewording it makes the user answer what looks like a
different question. ArecommendationDispositionofoverriddenbecomes a free-text
question asking what made the chosen answer right, naming the labels the user saw rather
than question ids. Awarninginvalidation.checkswithoutacknowledged: truebecomes
a single-select built from that check's ownsuggestcorrections, plus "Keep it as it is". - An acknowledged warning is deliberately not carried. It is a trade-off the user saw
explained and took on purpose; bringing it back every round would punish them for
answering. - Optional
provenanceon a question.{ source, fromQuestionId, fromCheckId, fromLoopId }records why a generated question exists, making loop lineage auditable per
question rather than only between questionnaires. Additive and optional; nothing reads it
at runtime, and the form renders it unchanged. - It drafts, it does not author. No options, recommendations, or rationales are invented.
Carry-over that would exceed the questionnaire'squestionCapfails loudly with the count
rather than emitting an over-cap form, and a round that deferred nothing, overrode nothing
and left no warning open produces no file at all — with a report saying so. tests/followup.test.js(14 tests),npm run test:followup,make test-followup, and a
make followuptarget. The load-bearing test closes the loop end to end: generate a
follow-up from the example answers, build it, drive it to submission in jsdom, and assert
the emitted answers point back at the round they refine.
Fixed
- Session lineage no longer breaks on submission.
buildAnswershard-coded
session.parentSessionIdtonullunless a caller passed one, and the browser never did —
so a follow-up's link to the session it refined was dropped the moment it was submitted. It
now falls back to the questionnaire's ownparentSessionId. Found by the round-trip test.
v0.5.0 — Consistency checks
A coherence release. Quizzing asks one question at a time, which until now meant nothing
noticed when two answers contradicted each other — the incoherent design reached the agent
intact. The form now checks answers against one another, explains what is wrong, and offers
to fix it.
Added
- Cross-question consistency checks. A questionnaire may declare a top-level
consistencyarray. Each check fires when every rule in itswhenarray holds, using the
same condition shape asbranching(questionIdwithequals,includes,gte, or
lte) — no new operators were introduced. This closesFR-053,FR-054, andFR-055. - Two severities, because blocking is not always right. An
errorstops the Next button
on the question that created the conflict, so the problem is raised while the user is
still thinking about it. Awarningis explained at the review screen, does not block, and
can be accepted deliberately. A detector that only ever hard-blocks becomes a trap the
moment a check is subtly wrong. - One-click corrections. A check may
suggestfixes, each a button that sets named
answer fields. A correction only sets what it names and never clears anything else. - Checks explain themselves.
explainsays why the combination is a problem and
evidencecarries the environmental facts behind it — the place where a fact discovered
during the bearing phase does visible work. validation.warningsandvalidation.checksinanswers.schema.json. Every firing
check is recorded with its severity, and an accepted warning carriesacknowledged: true,
so an agent can tell a considered trade-off from an oversight.validation.statusbecomes
partialwhen only warnings are present. This is additive:issuesandstatuskeep
their existing meaning and shape.- The bundled
file-uploadsexample declares three checks, including a contradiction
that was already latent in it, and its answers artifact now shows an accepted trade-off
rather than an empty validation block.
Fixed
- Roadmap ledger accuracy.
TASK-125(questionnaire versioning and safe resumption) was
still described as missing detection and disclosure, which is precisely what v0.4.0
shipped. It is now marked delivered at v0.4.0, along with itsTEST-104.
v0.4.0 — delivery contract and safe resumption
A contract and resumption release. Quizzing now only advertises adapters it actually has,
tells you when a saved draft cannot be restored intact, and ships one worked example that
demonstrates every question type rather than a handful.
Changed
deliveryMethodinanswers.schema.jsonis narrowed tohtmlandlocal-server.
Themarkdownandtuivalues were removed: neither adapter was ever built, so the
schema was advertising a contract nothing could satisfy. A consumer that branches on
those values will no longer receive them.delivery.adaptersanddelivery.selectedin
questionnaire.schema.jsonare narrowed to match. This is the reason for the minor bump.- A browser is now a stated prerequisite rather than something the skill tries to work
around. Every host CLI is an npm application, so Node is present by construction; the
browser is the real variable, and Quizzing is human-in-the-loop by definition. The
conversational fallback inSKILL.md, which guarded an impossible no-Node case, is gone. - The example corpus is a single questionnaire,
file-uploads, replacing
project-sharing. It is broad enough that every question type is the natural way to ask
something in it, and it covers both declarative diagram formats, all threerequired
modes, and branching. A test now fails the build if a question type or diagram format has
no example using it.
Added
- A resumed draft now discloses what it could not restore. Drafts carry a fingerprint of
the question set, so a questionnaire edited without a version bump is detected: the resume
notice reports how many answers were dropped instead of silently losing them. - Drafts stranded by a version bump are surfaced with a discard control. Previously they
sat inlocalStorageforever, invisible and unreachable. recommended.booleanValueis now valid inquestionnaire.schema.json, so boolean
questions can carry a seeded recommendation.- Four new documentation screenshots covering multi-select, boolean, free text, and ranking.
Fixed
- Connected mode mislabelled its output.
buildAnswersdefaulteddeliveryMethodto
htmland no call site ever passed anything else, so every answers file written by
serve.jssince v0.1.0 claimed to be a static submission. It now reportslocal-server.
Found by the test asserting every advertised enum value is emitted by something. - Boolean recommendations were unreachable.
app.jsreadrec.booleanValue, but
recommendedisadditionalProperties: falseand never declared it, so the schema
rejected the only spelling the form understood. Dead since boolean questions shipped. - Edge labels on predominantly vertical diagram edges no longer have the arrow drawn
through them. - Five documentation screenshots were cropped mid-content; viewport heights are now the
measured content height of each screen.
v0.3.1 — clearer Skip/Defer, reduced-motion support
A small clarity and accessibility release.
Added
- Skip and Defer now explain themselves. Each carries an always-visible sub-label —
Skip is "No opinion — don't ask again", Defer is "Matters — ask me next round" — so the
two are told apart without hovering. Both also gain anaria-labelcombining the two. - The Skip/Defer semantics, including the fact that Defer satisfies the
requiredgate
while Skip is offered only on optional questions, are now documented inSKILL.md.
Fixed
prefers-reduced-motion: reducenow disables the card fade-in and progress-bar
transition. This is an accessibility fix, and it also de-flaked headless screenshot
capture, which could otherwise photograph a card mid-fade.
v0.3.0
A hardening release: a correctness fix to the answers contract, a documentation gap that
made an implemented feature unreachable, the project's first CI, and a set of robustness,
security, and UX fixes. See
docs/plan/refactor-quizzing-hardening-1.md
for the plan this release implements.
Changed — answers JSON
A response marked skipped or deferred no longer carries an answer value. The form
pre-seeds each question with the agent's recommended answer, and skipping previously left
that value in place, so {"skipped": true, "rangeValue": 3} could be read back as the user
accepting the recommendation. Skipped and deferred responses now emit only questionId,
skipped, and deferred.
This changes the shape of emitted answers JSON. Artifacts produced by 0.2.0 will not
round-trip identically, though both old and new output remain valid against
answers.schema.json, which never required the value fields. Consumers that read a value
without first checking skipped were reading the agent's own recommendation, not an answer.
Added
decision-matrixis now documented inSKILL.md— the type was fully implemented,
schema-backed, and shown in the README screenshots, but absent from the agent's authoring
surface, so no agent would ever produce one.- Continuous integration (
.github/workflows/ci.yml): the test suite on Node 18, 20 and 22,
JSON-schema validation of the example fixtures, and a manifest version-sync check. tests/docs.test.jsasserts every questiontypeanddiagram.formatthe schema accepts
is named inSKILL.md, so this documentation gap cannot recur silently.tools/check-version-sync.js(make check-version) checks the tenversionfields spread
across the six distribution manifests and the lockfile.- The form now resumes after a reload. Progress is saved to
localStorage, keyed by
questionnaire id and version, announced once with a "Start over" affordance, and cleared on
submit. Access is best-effort, so afile://origin or disabled storage degrades to the
previous behaviour. The review screen discloses where answers are kept.
Fixed
- Author-supplied SVG is sanitised at build time. Diagram content is rendered through
innerHTML, so a hand-authoredformat: "svg"diagram carrying<script>or anon*
attribute would execute in the user's browser.<script>and<foreignObject>elements,
event-handler attributes, comments, and any URL that is not a#fragmentordata:image/…
are now stripped. Generatedflowandlayeredoutput is unaffected. serve.jscreates missing parent directories of--outinstead of failing withENOENT
after the user has already completed the form.serve.jsvalidates a submission before writing it: it must be an object with an array of
responsesand aquestionnaire.idmatching the questionnaire being served. Previously any
parseable JSON was written over the answers file and acknowledged as success.serve.jsreports write failures on stderr; they were previously visible only to the browser.--portand--timeoutare validated as integers rather than passed through
parseInt(...) || default, which read--timeout soonas 1800 and discarded an explicit
--timeout 0.--timeout 0now means "wait indefinitely".- Pressing Enter while typing in a single-line custom-input field no longer jumps to the next
question. Radios, checkboxes and buttons still advance. tests/form.test.jsfails instead of silently passing when jsdom is missing under CI.
Removed
- Unused
osrequire inserve.js.