{
  "id": 17733240,
  "title": "Let Course Progress Follow Evidence, Not Session Endings",
  "url": "https://urgent.news/2026/11/02/let-course-progress-follow-evidence-not-session-endings",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-11-02T02:55:47.000Z",
  "source": {
    "name": "Dev.to",
    "slug": "dev-to",
    "url": "https://dev.to/ptrgiang/let-course-progress-follow-evidence-not-session-endings-j8b"
  },
  "original_language": "en",
  "account": "Pianory is a browser-based piano practice app developed by the author. The app utilizes AI to generate this article, which has been meticulously verified against the current course source and the spec file. Upon concluding a player session, the system notifies that playback has concluded, but this alone does not signify that a course step has met its completion criteria. In Pianory's course domain model, progress is directly linked to the evidence required by each step. The process of determining course progress begins with the function courseAttemptMeetsPolicy, which mandates a completed attempt that includes the requested evidence. Following this, the step's rule is applied: a self-report necessitates a specific rating, pass count, and criteria, along with any configured delayed-review requirement; a quiz requires a minimum total score and correct answers; measured evidence requires a passing observation with supported input, sufficient confidence, and the associated capability and benchmark version. The function advanceCourseEnrollment checks that the attempt aligns with the active enrollment, the pinned course version, the current step, and the phase. An ordinary partial result advances the revision while maintaining the learner's position on the same cursor. A self-report that becomes stuck can only enter an explanation phase when the step in question has a configured recovery branch. A skip, on the other hand, can advance the cursor even though its immutable attempt remains labeled as skipped. There is also a persistence boundary to consider. The function commitCourseEnrollment both records the progress snapshot and the immutable attempt within a single IndexedDB readwrite transaction; for signed-in accounts, it also schedules the sync operation within that same transaction. Importantly, replaying the same attempt ID with identical evidence is treated as a no-op, whereas reusing it with different evidence results in a conflict. The comprehensive course-journey spec encompasses scenarios for quiz evidence, partial attempts, and explicit skips. This article elucidates the source and spec behavior; however, it is important to note that the author did not execute the test suite today, and these rules do not establish a learner outcome or conclusively prove every remote sync scenario. The primary sources utilized for this article are src/lib/domain/course.ts, src/lib/domain/course-journey.ts, src/lib/client/storage/index.ts, and src/lib/domain/course-journey.spec.ts.",
  "summary": "I build Pianory, a browser-based piano practice app. AI helped draft this article; I checked every implementation claim against the current course source and focused spec file. A finished player session tells you that playback ended. It does not, by itself, tell you that a course step met its completion rule. In Pianory’s course domain model, progress is tied to the evidence each step asks for.…",
  "key_points": [],
  "editors_take": null,
  "illustration": null,
  "coverage": {
    "outlets": 1,
    "also_reported_by": []
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}