Skip to content

feat(marking): minimum-viable in-app rubric editor#59

Open
hyperpolymath wants to merge 1 commit into
feature/composer-tutor-voicefrom
feature/composer-rubric-editor
Open

feat(marking): minimum-viable in-app rubric editor#59
hyperpolymath wants to merge 1 commit into
feature/composer-tutor-voicefrom
feature/composer-rubric-editor

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Stacked PR (8 of 8 follow-ups). Base = `feature/composer-tutor-voice` (PR #58). Merge order: #51 -> #52 -> #53 -> #54 -> #55 -> #56 -> #57 -> #58 -> this.

Summary

Adds a `/rubric-editor` route where tutors can edit any rubric pack (built-in or disk) as raw `.exs` source, save it to `priv/rubrics/`, and have the composer pick up the new pack on the very next interaction.

Approach: minimum viable

  • No structured form. The pack is shown as its inspected `.exs` source.
  • Edit the source, change the filename, click Save & reload.
  • Validation leans on the runtime-load layer from PR feat(marking): runtime-loaded rubric packs from priv/rubrics/ #56: a broken save is reported via flash but does not remove the working rubrics.
  • Revert reloads the on-disk / built-in version.
  • Delete on disk removes the `.exs` file; the built-in (if any) is used as the fallback.

New modules

  • `EtmaHandler.Marking.RubricSerialiser`
    • `to_source/1` — `inspect` + SPDX header
    • `write_to_disk/3` — writes `/.exs` (appends `.exs` if missing)
    • `delete_from_disk/2` — removes the file
  • `EtmaHandlerWeb.RubricEditorLive` — the LiveView itself

Composer integration

  • "Edit rubrics →" link next to the existing "Reload rubrics" button so tutors discover the editor from the composer.

Tests

  • 68 total, 8 new — Serialiser only; the LiveView itself needs `Phoenix.LiveViewTest` which isn't available in this sandbox
  • `to_source` round-trips through `Code.eval_string` to the same struct
  • `write_to_disk` writes `/.exs`, appends `.exs` when missing
  • `write_to_disk` returns `:no_rubric_dir` when nothing is resolvable
  • Written file is loadable by `RubricRegistry.reload` (round-trip)
  • `delete_from_disk` removes the file / returns `:enoent` for missing files

Out of scope (future follow-ups)

  • Structured form (add/remove components, indicators, questions via UI rather than raw source editing)
  • Validation preview before save (currently relies on registry skip)
  • Conflict detection when overwriting a disk file that shadows a built-in (just works — disk wins)

Test plan

  • 68/68 via standalone elixirc + ExUnit
  • LiveView parses cleanly
  • Browser: composer -> click "Edit rubrics →" -> editor opens with default rubric source
  • Edit the title field in the source, save -> reload picks it up, composer dropdown shows updated title
  • Save broken source -> flash shows skip reason, composer still works
  • Delete on disk -> falls back to built-in, composer dropdown reflects the rollback

Generated with Claude Code.

Adds a /rubric-editor route where tutors can edit any rubric pack
(built-in or disk) as raw .exs source, save it to priv/rubrics/, and
have the composer pick up the new pack on the very next interaction.

Approach: minimum viable
  - No structured form. The pack is shown as its inspected .exs source.
  - Edit the source, change the filename, click "Save & reload".
  - Validation leans on the runtime-load layer (PR #56): a broken save
    is reported via flash but does not remove the working rubrics.
  - "Revert" reloads the on-disk / built-in version.
  - "Delete on disk" removes the .exs file; the built-in (if any) is
    used as the fallback.

New modules
  - EtmaHandler.Marking.RubricSerialiser
    to_source/1     -> inspect + SPDX header
    write_to_disk/3 -> writes <dir>/<filename>.exs (appends .exs if
                       missing); returns {:ok, path} or {:error, ...}
    delete_from_disk/2 -> removes the .exs file
  - EtmaHandlerWeb.RubricEditorLive
    The LiveView itself: dropdown to load any existing pack, textarea
    with the source, filename input, four buttons (Load / Revert /
    Delete / Save & reload).

Router
  - new live "/rubric-editor", RubricEditorLive, :index

Composer integration
  - "Edit rubrics ->" link next to the existing "Reload rubrics"
    button so tutors discover the editor from the composer.

Tests (68 total, 8 new — Serialiser only; the LiveView itself needs
Phoenix.LiveViewTest which isn't available in this sandbox)
  - to_source round-trips through Code.eval_string to the same struct
  - to_source emits the SPDX header
  - write_to_disk writes <dir>/<filename>.exs
  - write_to_disk appends .exs only when missing
  - write_to_disk returns :no_rubric_dir when nothing is resolvable
  - written file is loadable by RubricRegistry.reload (round-trip)
  - delete_from_disk removes the file
  - delete_from_disk returns :enoent for missing files

Out of scope (follow-ups)
  - Structured form (add/remove components, indicators, questions
    via UI rather than raw source editing)
  - Validation preview before save (currently relies on registry skip)
  - Conflict detection when overwriting a disk file that shadows a
    built-in (just works — disk wins)

Verified locally via standalone elixirc + ExUnit (68/0).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

1 participant