Skip to content

fix: finished skips a part the core marks as sub-content, parent or not - #25

Merged
alekswebnet merged 2 commits into
mainfrom
fix/finished-sub-content
Oct 14, 2026
Merged

alekswebnet merged 2 commits into
mainfrom
fix/finished-sub-content

Conversation

@alekswebnet

@alekswebnet alekswebnet commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Closes #24.

finished no longer treats a part's result as the content's when the part was created without a parent. That happens with Interactive Book's chapters, Game Map's exercises and Virtual Tour's interactions.

The rule

isResult in the runtime's src/finished.ts still requires a completed or answered statement with no context.contextActivities.parent, which is H5P core's rule. It now also refuses a statement whose object carries http://h5p.org/x-api/h5p-subContentId:

  • H5P core's XAPIEvent.setObject writes that extension for every instance that has a subContentId.
  • The main content never has one.

This departs from H5P's setFinished on purpose. Checking for a parent was core's stand-in for "from the content itself"; the extension says that directly.

Measured

On 2026-10-14, against the library pack:

Content type finished before finished now
Interactive Book 1.15, with reporting chapter one, chapter one, the book the book
Game Map 1.5 the exercise, then the map the map
Multiple Choice, Question Set, Column their own unchanged
  • Marker: every chapter and exercise statement carries the extension, and the content's own statements don't.
  • Rest of the pack: across the sweep of all 55 content types, every statement with a parent also carries it, and Interactive Book was the only type whose finished changed. The walk doesn't open a Game Map stage, so Game Map was played with the first cut's steps from git history, twice. All of these numbers come from Chromium.
  • Virtual Tour 0.5 creates its interactions with no parent, as found in its code; the sweep can't open a scene to play it.
  • AR Scavenger also creates its exercises with no parent, but it sends a result of its own, so it still finishes.

Behaviour change for hosts

  • cmi5: a unit holding Interactive Book (with reporting) or Game Map now completes on the content's result. Before, it completed on its first chapter or stage.
  • Content that reports nothing of its own never raises finished. This covers Interactive Book without reporting and Virtual Tour.
    • Before, a book finished on every chapter and a tour on every question answered in it.
    • A cmi5 unit holding a book needs reporting, and one holding a Virtual Tour never completes; docs/cmi5.md and the README now say so.
  • Parts without an id: a part saved without a subContentId has no marker, so it still counts as the content, as under H5P's rule. That covers content from before H5P's editor wrote one, and content written by hand or by a tool that writes none.

Changes

  • packages/runtime/src/finished.ts: the rule, with SUB_CONTENT_EXTENSION exported.
  • packages/runtime/tests/finished.test.ts: two new tests, covering a marked part without a parent and an object without the marker.
  • Fixture: the content type takes looseChild, which is sub-content run without a parent. finished.h5p carries one.
  • tests/browser/finished.test.ts: pressing Complete in that part raises an xapi with no parent and the marker, and no finished.
  • Sweep: it records the marker, and the report's * now means a statement with a parent or the marker. The Interactive Book and Game Map notes are updated.
  • Docs:
    • AGENTS.md: the finished invariant and the layout line.
    • README: the finished row.
    • docs/cmi5.md.

Testing

Run Result
Runtime unit tests 180/180
finished.test.ts, Chromium, on the old rule (control) the new test fails, 3 pass
finished.test.ts, Chromium, on the new rule 4/4
pnpm sweep, all 55 types, trusted, with the marker recorded 55/55
pnpm sweep on Interactive Book, Multiple Choice, Question Set and Column, both modes, new rule 8/8; one finished each
Sweep generator tests 12/12
pnpm typecheck clean

Release

Runtime patch, 0.2.3. The rule is in the boot script, which the runtime ships, so the player, embed and verify don't change. Embed 0.6.1 accepts runtime 0.2.3. The README row reaches npm with the next player release.

🤖 Generated with Claude Code

H5P's rule counts a completed or answered statement with no parent as the
content's result. Interactive Book 1.15 runs its chapters, Game Map 1.5 its
exercises and Virtual Tour 0.5 its interactions without a parent, so a part's
result was raised as the content's, and a cmi5 unit completed on its first
chapter or stage. The core writes h5p-subContentId on every statement from
sub-content and never on the content's own; isResult now refuses those too.

Closes #24.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@alekswebnet alekswebnet self-assigned this Oct 14, 2026
… never completes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@alekswebnet
alekswebnet merged commit ec04baf into main Oct 14, 2026
8 checks passed
@alekswebnet
alekswebnet deleted the fix/finished-sub-content branch October 15, 2026 17:07
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.

finished: a part created without a parent is raised as the content's result

1 participant