Skip to content

feat: add requisite graph and structure pages - #118

Merged
HarryRandall merged 6 commits into
mainfrom
feat/requisite-graph-and-structure-page
Sep 22, 2026
Merged

HarryRandall merged 6 commits into
mainfrom
feat/requisite-graph-and-structure-page

Conversation

@HarryRandall

Copy link
Copy Markdown
Owner

Summary

This is stack 3 of 16. It contains the focused commits between refactor/admin-catalogue-tables and feat/requisite-graph-and-structure-page and targets the branch immediately below it.

Verification

  • GitHub Quality gate
  • GitHub Route gate
  • GitHub Database gate
  • GitHub Browser gate

Deployment notes

Do not deploy this branch independently. Merge the stack from the bottom upwards. The one-time hosted database rebuild remains a separate approved operation after the complete stack reaches main.

@vercel

vercel Bot commented Sep 22, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
coursemap Ready Ready Preview Sep 22, 2026 12:56pm UTC

Imports have produced a fully structured requirement tree since the
prompt began mapping ANU wording to typed conditions, but nothing
rendered it. The Bachelor of Computing carries twelve typed conditions
and thirty-six options, every one resolved to a catalogue item, and the
preview showed the requirements section's prose, then the same prose
again as the rule's source text, then the tree as a block of JSON.

The requirement kit in ui/requirements already formatted units_total,
course_set_units, structure_set, subject_units, level_units,
tagged_units and elective_units, including level ranges and the
maximum-only ceiling ANU states as "a maximum of 60 units may come from
1000-level courses". It is extended to the rest of the vocabulary rather
than replaced, and now reads a tree built from a snapshot write as
readily as one from a plan.

Structures gain a published read and a student page, neither of which
existed: published_structure_detail resolves through
catalogue_item_years.published_snapshot_id and returns details,
sections, outcomes, fees, relationships and the requirement tree to
anonymous readers, drafts excluded. The admin preview and the student
page render through one StructureDetailView, so a reviewer judges the
record as a student will see it.
An ANU section body arrives as one line per scraped element, so a study
plan is a course code, then its title, then its unit value, each on its
own line. Rendering that as pre-wrapped text ran them together as
unrelated sentences sixty lines deep.

Each line now takes a row, a bare code is set in the monospace face, and
a lone OR or AND reads as the separator it is, so a study plan scans as
a list of courses.

This is presentation over data the extractor flattened. The sections
that duplicate the requirement tree, majors and prerequisites among
them, would be better dropped than styled, and the deterministic parser
would be better keeping the list structure the page already has. Both
are worth doing and neither is this change.
The course graph was built from a flat list of course codes, so COMP3600
showed COMP1600 alone: both unit requirements vanished because they name
no single course, and the OR between them and COMP1600 was invisible. A
student reading it would take COMP1600 as the whole prerequisite.

It now builds from the reviewed rule tree the projection already carried
and nothing else read, `prerequisiteRule.relationalExpression`. Every
condition becomes a node, alternatives get a group node so an OR cannot
read as a list of separate rules, and `all_of` keeps its direct edges
except inside an alternative, where flattening would lie. Wording comes
from the requirement display kit rather than a second vocabulary.

An incompatibility is collected out of the flow and stated as an
exclusion. Course nodes carry the plan status as a word and an icon, not
only a tint, using the kit's own badge. "Unlocks" only ran its reverse
lookup over published courses, so a draft was told nothing unlocks it;
`unlocksAreKnown` now lets it say the lookup has not run.

The structured card reads the same relational tree, so it no longer
falls back to parsed prose whenever a rule holds a kind the narrow
expression cannot model. The detected-course-reference chips went with
it: they were the graph's own course nodes without the shape.
The column stacking is arithmetic in the component, and jsdom does no
layout, so nothing would have caught a height that stopped matching its
node kind. Reading the placed offsets back is the cheapest check that
the maths still holds for a tree with a group node in it.
The graph for COMP3600, whose rule is 24 units of COMP and one of 6 units
of MATH or COMP1600, read as three alternatives. The root AND had no node,
on the reasoning that every edge into a course already means "and", but
several arrows converging on one course read as several ways in, and once
one of them left a "Choose one" node the others were taken for further
choices. The root AND is now a named junction, "All of these", beside the
"Choose one" it contains.

The edges had no heads, so nothing showed what led to what, and they were
drawn in the border colour, faint enough to lose. They now carry
arrowheads, stopping short of each node so a head never sits on a border,
in a stronger stroke. The diagram sat left in its card; it is centred, and
a column holding only a junction pill is narrower, so making the AND
explicit did not push the graph past the edge of the card.

Each requirement read as a category over a detail line: "COMP courses" in
bold, then "COMP coded courses · At least 24 units" in the smallest,
faintest text, repeating itself and burying the figure. conditionSummary
gives one line that leads with it, "24 units of COMP courses", for places
with room for one line. conditionHeading keeps the category for the
programme pages, where a progress bar already carries the number.

The card below boxed every group, so nesting drew a box in a box, under
headings, "Complete all of the following" and "Complete one of the
following", that differ in one word and read alike. Only the outermost
group is boxed now; a nested one is an indented rule. The headings say
what is needed, "You need both of these", and an alternative puts "or"
between its options.

A course with nothing on either side drew three empty boxes with no edges,
which read as a diagram that failed to render. It now says so in a line.
The information tab printed every section the ANU page carried, 22 for the
Bachelor of Computing, as scraped text. Three of them the page already
renders from structured data: the requirements are the Requirements tab's
tree, and the learning outcomes and indicative fees are cards on the
Overview. They are dropped, matched on the ANU anchor id rather than the
heading, which is stable.

Only verified duplicates go. "feeinformation" reads like a second fees
section but carries the services and amenities fee and how indicative fees
are set, and "majors-and-minors" carries guidance a bare list does not,
such as which majors earn Australian Computer Society accreditation. Both
stay.

The majors and minors sections were each a plain list of names, while the
record's relationships already hold every one with its code. They are now
links to the structures, named with their codes. A structure listed both as
an option and as merely relevant appears once.
@HarryRandall
HarryRandall force-pushed the feat/requisite-graph-and-structure-page branch from 8a4754c to c31766d Compare September 22, 2026 12:25
@HarryRandall
HarryRandall force-pushed the refactor/admin-catalogue-tables branch from 25741a0 to 713994c Compare September 22, 2026 12:25
Base automatically changed from refactor/admin-catalogue-tables to main September 22, 2026 12:38
@HarryRandall
HarryRandall merged commit c31766d into main Sep 22, 2026
4 of 10 checks passed
@HarryRandall
HarryRandall deleted the feat/requisite-graph-and-structure-page branch September 22, 2026 12:39

This branch was successfully deployed

1 active deployment
Preview c31766dd Deployed Sep 22, 2026 by vercel[bot]
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