Conversation
`expand_courses_with_prerequisites` ran a Phase-2 redundancy prune that could delete a course from the original plan when it was also an OR-prerequisite alternative for another course — e.g. a `type: all` core course CS320 that is also an option of an elective's `CS320 | CS370` prereq was silently dropped from generated plans whenever the sibling CS370 was present. Now only courses ADDED during expansion may be pruned; original plan courses (and user --include `protected_courses`) are preserved. Adds regression test test_expand_preserves_required_or_alternative. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…layout only) Database layout for the upcoming `db import` feature — store imported degree programs as queryable rows instead of an opaque YAML blob. Not yet applied to the live database. - docs/database/programs-schema.sql: `programs` (+ lossless `document` JSONB as source of truth), shared `courses` catalog + `program_courses` M:N junction, `program_requirements` (recursive requirement tree flattened via req_path/parent_path), `degree_types` lookup, and metrics tables (`analysis_runs` / `analysis_course_metrics` / `analysis_plans`) keyed by run_key so trimmed-vs-full and differing iteration counts coexist. Indexes (pg_trgm on courses.name, GIN on programs.tags) + RLS cloned from the `degrees` pattern. Idempotent (IF NOT EXISTS / DROP POLICY) — safe to re-run on a live DB. - docs/database/program-lookup-seed.sql: seeds `degree_types`. - src/core/database/mod.rs: tables:: consts for the new tables. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Import a degree-first analysis report (or a plain unified degree) into the
normalized program tables. One report populates the program, its shared courses
+ junction, the flattened requirement tree, and — when the report carries an
`analysis` block — one analysis run with its per-course metrics and sample plans.
- core `src/core/database/import.rs`: pure `build_import_plan` (report → rows,
used by --dry-run) + async `execute_import` (institution resolution →
existence/verified decision → ordered writes, children first / program last).
`program_key` includes catalog_year so different years coexist; `full` is the
canonical upload, non-`full` variants attach a run only. sha256 content hashes.
- models: Stored{Program,Course,ProgramCourse,ProgramRequirement,AnalysisRun,
AnalysisCourseMetric,AnalysisPlan}.
- `degree.unitid` (IPEDS id) added to the Degree model — fast-path institution
linking; falls back to name+cip resolution, else an institution-name slug.
- CLI `nuanalytics db import <FILES>... [--variant] [--unitid] [--cip] [--catalog]
[--degree-id] [--force|--replace|--skip-existing] [--dry-run] [-j]`: single-file
detailed outcome (institution, variations, sample plans, row counts) + batch
isolation with import_failures.log.
- sha2 dependency, gated to the `database` feature.
Verified via --dry-run against full_degree/metrics reports (name+cip institution
resolution, idempotent skip on unchanged hash) and a live-DB field review
(3 programs / 305 courses / 80 requirements / 3 runs / 216 course-metrics /
21 plans; no orphans; requirement-tree adjacency intact). Clippy
(--all-targets --all-features -D warnings) clean; import unit tests pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
New MCP tool wrapping the shared import core: imports a degree-first report (or unified degree) JSON into the normalized program tables. DB-gated like the other database tools (only exposed when a session exists). - params: json_content | json_path (+ variant/unitid/cip/catalog/degree_id/ force/replace/skip_existing/dry_run); lenient scalar/bool deserializers. - response: result tag (created|updated|skipped|needs_confirmation| institution_ambiguous|rejected) + counts + institution/variations_run/ sample_type; institution_candidates on ambiguity, reason/errors otherwise. - registered in server.rs via call_db. 9 offline unit tests (request deserialization, exactly-one-source validation, outcome→JSON mapping for every ImportResult variant). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`degree analyze` can now pull a program's canonical degree from the database
instead of a local file. Resolve ladder: exact program_key → exact degree_id →
name ILIKE. One match analyzes it (reusing the normal single-degree pipeline via
the extracted `analyze_program` seam); zero → error; many → prints the candidate
programs (program_key · name · institution · catalog_year) so the caller can
re-run more specifically.
- `--from-db <NAME>` on Analyze; positional FILES now optional, with a
one-of-{files, --from-db} check in the dispatcher.
- the stored `document` is rehydrated via parse_degree_auto (recovers the
structured prerequisites).
- dedupe: degree.rs reuses db.rs's `make_runtime` (now pub(super)).
Offline tests: candidate formatting, row parsing (malformed / non-array),
document round-trip, invalid-document panic-safety.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Analysis report JSONs for the three sample degrees (csu/neu/uhm), produced by `degree analyze`, kept as reference samples of the degree-first report format and as convenient `db import` fixtures. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rom-db - CHANGELOG: new [Unreleased] section (normalized program schema, db import, import_degree, analyze --from-db, degree.unitid). - docs/degree.md: `--from-db <NAME>` option + "Analyze a stored program" section. - docs/mcp.md: `import_degree` tool (params/response/example) + search_institutions cross-reference for unitid lookup. - docs/database/setup.md: programs-schema.sql + program-lookup-seed.sql in the run order, and a "Stored programs (normalized)" section (8 tables + db import). - Readme: degree database import / stored-programs feature bullet. - docs/degree-ingestion-plan.md: status note that the import path is implemented. - programs-schema.sql: fix stale program_key comment (prog: form, not id:/nat:). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Normalized program storage schema (programs/courses/program_courses/ program_requirements + analysis_runs/analysis_course_metrics/analysis_plans + degree_types), the `db import` CLI, the `import_degree` MCP tool, `degree analyze --from-db`, and the `degree.unitid` field. Additive — no breaking changes from 0.4.1. Closes out the CHANGELOG [Unreleased] section as [0.5.0]. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`cargo doc --no-deps --all-features` (CI's Documentation job, RUSTDOCFLAGS=-D warnings) failed on two `[`DegreeProgram`]` intra-doc links in degree.rs: in the bin crate the type is referenced by full path (`nu_analytics::core::DegreeProgram`) and isn't in scope as a bare name, so rustdoc couldn't resolve the link. Demote both to plain code spans. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release v0.5.0
Additive — no breaking changes from 0.4.1. Adds a database-backed degree-storage subsystem: a normalized, queryable projection of imported degree programs alongside the lossless source document, plus the CLI, MCP, and analyze paths that write to and read from it.
Highlights
docs/database/programs-schema.sql+program-lookup-seed.sql): 8 tables —degree_types,programs(losslessdocumentJSONB + queryable scalar projection),courses(shared per-institution catalog),program_courses(M:N junction),program_requirements(requirement tree flattened byreq_path/parent_path),analysis_runs/analysis_course_metrics/analysis_plans. Hybrid storage, FK-free natural keys, RLS auth-required, idempotent generation-stamped re-sync.db import <FILES>...— import degree-first reports (or unified/YAML degrees) into the tables; institution resolution (degree.unitid→ name+CIP → slug; ambiguous → candidates),catalog_year-awareprogram_key,--variant/--dry-run/--force/--replace/-j, batch isolation.import_degreeMCP tool — the same import core over MCP (DB-gated;dry_runpreview;institution_candidateson ambiguity).degree analyze --from-db <NAME>— analyze a stored program pulled from the DB (program_key → degree_id → name ILIKE; ambiguous → candidate list).degree.unitidfield on the degree model for institution linking.Verification
cargo fmt --check,cargo clippy --all-targets --all-features -D warnings, full test suite — all green.db import --dry-runagainst realfull_degree/metricsreports (name+CIP resolution, idempotent skip), a live-DB field review across all 8 tables (no orphans; requirement-tree adjacency intact), theimport_degreetool, andanalyze --from-db(unique + ambiguous paths).See CHANGELOG.md
[0.5.0]for the full entry.🤖 Generated with Claude Code