fix(studio): review round 2 - a conversion that fails after its commit recovers without a restart

- The convert job reloads the course on success and on failure, so learners
  get the intact import (rolled back) or the published studio course, never a
  course whose folder moved away.
- POST /convert on a course with an incomplete conversion (.converting-<id>,
  staging or retired folders) queues a job that recovers and finishes it
  instead of answering 409; the studio page shows "Conversion incomplete" with
  Retry for the owner.
- The 409 for pending import jobs names their kinds and ids; the dead withLock
  in git.ts is gone; the dot-folder discovery rule is documented in
  docs/operations.md and spec section 5.
- Route tests (SQLite and Postgres) inject a failed cross-filesystem copy, a
  checksum mismatch and a pre-commit failure.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Lucas Winther
2026-10-30 21:00:45 +01:00
co-authored by Claude Opus 5.5
parent 771d755da4
commit f02e30450c
11 changed files with 168 additions and 34 deletions
+9
View File
@@ -143,6 +143,15 @@ Things to know:
- After conversion the importer can no longer add decks, code or transcripts to that course (it only edits
`<data>/courses`). Add them in the studio.
- `<data>/media` is fixed under the data directory (there is no separate setting).
- **Discovery skips dot-folders.** Every course directory (`STC_COURSE_DIRS`, `<data>/courses`, `<data>/worktrees`)
is scanned to depth 2 for `stcourse.yaml`, and folders whose name starts with `.` are never entered. Do not give a
course folder a name that starts with a dot. The conversion's `.converting-<id>` and `.converted-<id>.<n>` folders
rely on this.
- **A failed conversion.** If the media move fails after the commit (disk full, or a copy that fails its checksum),
learners are switched to the studio course right away; its media are hard links into the hidden import folder.
The course's studio page shows **Conversion incomplete** with a **Retry** button for the owner. A retry (or the
next server start) finishes the move. A failure before the commit is rolled back, and learners keep the import
unchanged.
## Memory budget
@@ -181,6 +181,7 @@ Phase 0 (section 10) pins down the exact schema. These principles are fixed:
- The two reference courses must load by adding only a manifest and front matter, without moving or rewriting their existing files.
- Their existing tooling (test scripts, `tools/*.mjs`) must keep working.
- **Derived data lives in a cache directory that can be rebuilt from the files:** search index, slide images and text, transcripts, video posters and AI embeddings.
- **Discovery** (v1.1 note): the platform finds `stcourse.yaml` at depth 0–2 under each course directory and skips folders whose name starts with `.` (and `node_modules`). A course folder must therefore not be a dot-folder. The studio relies on this to hide an import folder while it is converted (`.converting-<id>`, `.converted-<id>.<n>`).
## 6. Accounts, roles and visibility