Skip to content

Curriculum map: skills, outcomes and ABET coverage across the program - #1

Open
snow-jallen wants to merge 3 commits into
mainfrom
curriculum-map
Open

snow-jallen wants to merge 3 commits into
mainfrom
curriculum-map

Conversation

@snow-jallen

Copy link
Copy Markdown

What this adds

A Curriculum page (/curriculum) that follows an academic program's plan (from Scheduling → Academic Programs) and shows:

  • Skill threads: every skill down the side, the program's courses in semester order across the top, marked Introduced / Reinforced / Mastered. It flags skills that first show up already "reinforced" and skills taught before the skill they build on.
  • ABET coverage: SLOs 1–7 and the program criteria against the courses. It compares the department matrix with the "(ABET SLO n)" tags in each master syllabus, and highlights where they disagree.
  • Prerequisite map: courses by semester with the prerequisite and corequisite edges from the master syllabi. Pick a skill or an ABET outcome and the courses that touch it light up.
  • Skills: the catalog, with "builds on" links between skills (cycles are refused).
  • Course pages: the master-syllabus outcomes, marked when an outcome was added or removed since the first read; each skill with the earlier and later courses that touch it; ABET coverage; and any waiting suggestions.
  • Suggestions: a "Re-read & suggest" run, described below.

Re-read & suggest

  1. Reads every course's master syllabus from snow.edu (course.html → syllabus.html?q=…) and mirrors its outcomes. Outcomes no longer listed are retired rather than deleted, so changes show up.
  2. Asks the AI, once per course through the existing AsyncCompletions queue, which skills the course teaches and at what level. Its evidence is the master syllabus, the latest three terms of SnowSE/faculty materials (every instructor's folder for those terms), and the section syllabi already synced from Simple Syllabus.
  3. Asks once more which of the proposed skills duplicate each other or the catalog, and proposes merges.

Nothing changes until an editor accepts a suggestion. Accepting a merge renames the merged skill in the other waiting suggestions. Rejected suggestions are not asked again. "Re-read master syllabi only" skips the AI.

Access

Every approved user can read the map; this is a new open area in Access. Editing, running the review, accepting suggestions and importing the ABET matrix need the new curriculum_admin group. CurriculumAccess refuses every curriculum-edit:* event from viewers on the server, and refuses any event it doesn't recognise.

ABET matrix

Upload the workbook on the ABET tab. It defaults to the newest SLO sheet (Fall2025_Catalog_Matrix) and takes the program criteria from Main table, with a preview before importing. The file is never committed, since this repo is public. ? marks are kept as tentative.

To deploy

  • No manual SQL is needed: CurriculumDomainManager creates its tables on start, like the other managers. schema.sql has them for tests.
  • Set CURRICULUM_GITHUB_TOKEN to a fine-grained, read-only token for SnowSE/faculty. Without it the review skips faculty materials and says so in the run notes.
  • Add people to curriculum_admin in Admin.
  • Upload the ABET matrix, then run Re-read & suggest from the Suggestions tab.

Notes

  • No new dependencies. Pages are parsed with mochiweb_html (already present via html_sanitize_ex) and the xlsx with OTP :zip + :xmerl; :xmerl was added to extra_applications.
  • Seeds the skills we named (command line, Git CLI, GitHub, .NET SDK CLI, VS Code, Visual Studio, unit testing, TDD, BDD, dependency injection, mocks & fakes, DDD, onion architecture) with obvious "builds on" links, but only into an empty catalog.
  • Found while testing against the live site: SE 4620's master syllabus lists CS 2680 as a prerequisite, and that course doesn't exist. It is probably CS 2860.
  • The curriculum pages are added to page_smoke_test.exs and to the snapshot dump / screenshots.sh.

Checks

  • mix compile --warnings-as-errors, mix format --check-formatted (on the files in this PR), mix deps.unlock --check-unused, and the full suite (291 tests, run several times) all pass.
  • Dialyzer: no new warnings. The existing ones are in discord_domain_manager.ex and telemetry/events.ex.
  • mix hex.audit reports an existing mint advisory; mix.lock is unchanged here.

A new /curriculum page shows, for an academic program's plan, where each
skill is introduced, reinforced and mastered; the course outcomes from the
approved master syllabi; and which courses cover each ABET student outcome
and program criterion. It replaces the 2019 snow-jallen/ProgramPlanning
desktop tool.

- Skill threads, ABET coverage, a prerequisite map that highlights a skill
  or ABET outcome, the skill catalog, and a page per course.
- "Re-read & suggest" reads every course's master syllabus from snow.edu
  (outcomes are mirrored; added and removed outcomes are flagged), then asks
  the AI which skills each course teaches, using the master syllabus, the
  latest three terms of SnowSE/faculty materials and the section syllabi,
  and finally which proposed skills duplicate each other. Nothing changes
  until an editor accepts a suggestion; rejected ones are not asked again.
- The ABET matrix workbook is uploaded on the page, never committed.
- Every approved user can read the map; curriculum_admin edits it.
- Seeds the skills the department named (command line, git, GitHub, the
  dotnet CLI, VS Code, Visual Studio, TDD, BDD, DDD, mocks & fakes, onion
  architecture, ...) and ABET SLOs 1-7.

Tables bootstrap themselves on start like the other domain managers;
schema.sql carries them for tests. The faculty repository is private, so
reading it needs CURRICULUM_GITHUB_TOKEN; without it the review uses the
other sources and says so.
Copilot AI balanced review requested due to automatic review settings October 8, 2026 03:08

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It is a very large, multi-module feature whose central orchestration files (curriculum_domain_manager.ex, curriculum_live.ex, course_view.ex) and an external AI/network-driven review flow were not fully reviewable from the provided diff, warranting human review.

1 open finding
What changed in this PR

This PR adds a new Curriculum feature to the Phoenix app: a /curriculum LiveView that visualizes an academic program's skills, outcomes, and ABET coverage. It introduces skill threads (Introduced/Reinforced/Mastered), an ABET SLO/criteria coverage matrix, a prerequisite/corequisite graph, a skill catalog with "builds on" links, per-course pages, and an AI-powered "Re-read & suggest" flow that mirrors master syllabi from snow.edu, consults SnowSE/faculty materials plus section syllabi, and proposes skills and merges for an editor to accept. It adds a new open area plus a curriculum_admin group to the access model, creates its tables on domain-manager start (mirrored in schema.sql), and wires the pages into smoke/snapshot tests.

Changes:

  • New curriculum domain (DB modules, domain manager, parsing for master syllabi + ABET xlsx, suggestion builder/decisions) and web layer (LiveView + threads/skills/suggestions/graph/ABET views, server-side CurriculumAccess gate).
  • Access-control changes in access.ex to support an open-to-all-approved-users area alongside the curriculum_admin edit tier.
  • Supporting wiring: application.ex supervision, schema.sql tables, runtime.exs/mix.exs (:xmerl, CURRICULUM_GITHUB_TOKEN), and comprehensive new test suites.
File Description
lib/​snow_se_tools/​data/​access.ex Adds the open curriculum area + curriculum_admin; adjusts can?, accessible_areas, role_position.
lib/​snow_se_tools/​curriculum/​curriculum_db.ex Bootstraps tables and seeds skills/dependencies/ABET SLOs idempotently.
lib/​snow_se_tools/​curriculum/​{skill_db,outcome_db,abet_db,suggestion_db}.ex Query modules for skills, outcomes, ABET matrix, and suggestions.
lib/​snow_se_tools/​curriculum/​{suggestion_builder,suggestion_decisions}.ex Builds AI suggestions/fingerprints; transactional accept/merge/rename logic.
lib/​snow_se_tools/​curriculum/​{master_syllabus,abet_matrix,xlsx_reader,course_code,term_label,faculty_materials}.ex Parsing/selection helpers for syllabi, xlsx, course codes, terms, faculty files.
lib/​snow_se_tools/​curriculum/​curriculum_domain_manager.ex Orchestrates fetching, AI runs, DB writes, PubSub (large; central).
lib/​snow_se_tools_web/​curriculum/​*.ex LiveView, course view, threads/skills/suggestions/graph/ABET views, shared components, CurriculumAccess gate.
lib/​snow_se_tools/​application.ex Supervises CurriculumDomainManager under the DB-domain gating.
schema.sql Adds curriculum_* tables for tests/first-start.
config/​runtime.exs, mix.exs CURRICULUM_GITHUB_TOKEN config; adds :xmerl to extra_applications.
test/​snow_se_tools/​curriculum/​*, test/​snow_se_tools_web/​curriculum/​*, smoke/​snapshot tests New unit, DB, and LiveView coverage.

One concrete, low-severity issue was flagged inline: the tentative legend swatch in graph_view.ex uses a non-existent ring-dashed Tailwind class, so it renders inconsistently with the dashed graph node. The access-control, parsing, suggestion, and DB logic I was able to inspect are internally consistent with their (thorough) tests.

🧠 Review effort: Balanced


Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.

defp swatch("reinforced"), do: "bg-violet-700 ring-1 ring-violet-400"
defp swatch("mastered"), do: "bg-emerald-700 ring-1 ring-emerald-400"
defp swatch("covered"), do: "bg-indigo-700 ring-1 ring-indigo-400"
defp swatch("tentative"), do: "ring-1 ring-dashed ring-indigo-300"
snow-jallen and others added 2 commits October 8, 2026 17:37
The endpoint, model and key were read from application env at the call
site, so pointing the app at a different model server meant editing
prod.env and restarting. A new box on /admin edits all three, and
SnowSeTools.AI.Settings resolves them per completion instead.

A row in ai_settings overrides the environment field by field: NULL means
"use what prod.env set", so repointing the model does not also mean
restating the endpoint. Every read falls back to the environment if the
database cannot answer -- a database outage should not take the AI down
too, and during boot the table may not exist yet.

The API key is write-only. It is stored but never sent to a browser, so a
blank key box means "keep the current key"; clearing an override is the
explicit revert button rather than an empty field. That also means a live
credential now lives in Postgres, and so in backups and database dumps.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A course with no faculty materials and no section syllabi has nothing the
prompt can be answered from: it asks for skills the sources show students
practising, and there are no sources. Asking anyway invited the model to
invent skills from the master syllabus blurb, and in practice it kept
generating until it ran the server's context window out -- MATH 1210,
whose whole input is a 571-character stub, failed with "Context size has
been exceeded".

Such a course is now reported as not reviewed instead. It still has to
report in: the run finishes when it has heard once about every course, so
a course that is never sent would otherwise leave the run waiting for an
answer nobody asked for. The test asserts the count, not just the note.

Course reviews also now send max_tokens, so a runaway generation fails as
a completion the run can report rather than as an opaque engine 500.

The review stub in the LiveView test had no clause for the faculty
repository, so fetch_tree/0 crashed the task that enqueues the reviews
whenever CURRICULUM_GITHUB_TOKEN was set -- the suite passed only on a
machine without a token, and hung on one with it.

Co-Authored-By: Claude Opus 5 (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.

2 participants