Skip to content

Query Evaluation Semantics Specification

Query Evaluation Semantics Specification

Status: Draft v0.1.

Project: UWScrape.

Directory: docs/specs.

Audience: backend implementers, solver implementers, frontend implementers, and academic model reviewers.

Last reviewed: 2026-05-11.

Primary architecture document: docs/reference/architecture/solver-system-architecture/.

Related documents:

  • docs/reference/academic/multi-solver-academic-planning-model/
  • docs/specifications/backend-api-spec/
  • docs/specifications/student-state-schema-spec/
  • docs/specifications/graph-view-response-spec/
  • docs/specifications/frontend-backend-contract-spec/
  • docs/reference/architecture/frontend-runtime-architecture/
  • docs/decisions/0013-multi-engine-solver-layer/
  • docs/decisions/0014-direct-evaluator-as-first-runtime-engine/
  • docs/decisions/0015-solver-result-and-explanation-contract/
  • docs/decisions/0016-planning-vs-evaluation-solver-boundary/
  • docs/decisions/0018-conservative-unknown-and-engine-status-mapping/

1. Purpose

This document specifies version 1 query evaluation semantics.

Version 1 uses a deterministic direct evaluator.

Version 1 query endpoints return academic_result payloads.

Version 1 query endpoints preserve source references, unknowns, conflicts, assumptions, and explanation trees.

Version 1 does not require SAT, SMT, CP, Datalog, or package-resolver engines.

The API must leave room for those engines later.

2. Solver Boundary

The query flow is:

published index + student state + query request
-> normalized evaluation problem
-> direct evaluator
-> engine result
-> academic result

evaluation_problem is the version 1 normalized problem for fixed-state and explicit what-if queries.

planning_problem is reserved for future bounded planning.

credential-gap-summary in v1 returns conservative current-state requirement gaps without claiming full future-course feasibility.

If a future engine is invoked, engine-native statuses must be mapped through the shared academic status rules.

engine_unknown, engine_timeout, UNSAT, and unsatisfiable engine outputs are not academic statuses by themselves.

3. Academic Statuses

Every query target receives one of:

  • satisfied;
  • not_satisfied;
  • partial;
  • unknown;
  • conflict;
  • not_applicable.

satisfied means supported structured evidence proves the target under stated assumptions.

not_satisfied means supported structured evidence proves the target is not satisfied, and no relevant unknown can change that result.

partial means some relevant parts are satisfied and some are unsatisfied or unknown.

unknown means the backend cannot determine the result from available structured evidence and allowed engine work.

conflict means state facts, assumptions, or source facts are incompatible.

not_applicable means the target or requirement does not apply under the request scope.

4. Academic Result Shape

Common shape:

{
"target": {},
"status": "partial",
"completeness": "incomplete",
"state_mode": "persisted",
"evaluation_problem_id": "evaluation_problem:req_1",
"explanation_tree": {},
"satisfied_requirement_ids": [],
"unsatisfied_requirement_ids": [],
"unknown_requirement_ids": [],
"conflicting_requirement_ids": [],
"unknowns": [],
"conflicts": [],
"assumptions": [],
"source_reference_ids": [],
"engine_trace_summary": {
"routes": ["direct_evaluator"],
"complete_for_fragment": true
}
}

Required fields:

FieldTypeMeaning
targetobjectQuery target.
statusstringAcademic status.
completenessstringCompleteness status.
state_modestringQuery state mode.
explanation_treeobjectStructured explanation.
unknownsarraySemantic unknowns.
conflictsarrayConflicts.
assumptionsarrayAssumptions affecting result.
source_reference_idsarraySource references used by the result.
engine_trace_summaryobjectNon-sensitive route summary.

engine_trace_summary must not expose raw solver variables, clauses, stack traces, or cache keys.

5. Completeness Values

Completeness values:

  • complete;
  • incomplete;
  • complete_for_fragment;
  • not_attempted;
  • failed.

Direct evaluator results are complete only when all relevant supported and parsed conditions were evaluated and no relevant opaque or missing data remains.

Results are complete_for_fragment when the evaluator fully evaluated the supported fragment but relevant unsupported or opaque fragments remain.

Results are incomplete when unknowns or route limits could affect the answer.

failed is reserved for operational route failure and should usually become an HTTP error rather than academic unknown.

6. Explanation Tree Shape

Shape:

{
"node_id": "explanation:root",
"node_kind": "requirement_group",
"status": "partial",
"summary": "One prerequisite branch is satisfied and one grade-sensitive branch is unknown.",
"requirement_id": "requirement_expression:req_123",
"academic_object_id": "course_listing:CS:246",
"source_reference_ids": ["source_reference:src_1"],
"unknown_reason": null,
"conflict_reason": null,
"children": []
}

Node kinds:

  • query_target;
  • requirement_group;
  • requirement_condition;
  • course_attempt;
  • planned_course;
  • credential;
  • source_reference;
  • unknown;
  • conflict;
  • metric;
  • assumption;

The tree should mirror indexed requirement structure when evaluating requirements.

The tree may group repeated child details for compact display.

The tree must preserve requirement ids and condition ids when they affect the answer.

7. Unknown Reasons

Allowed initial unknown_reason values:

  • unparsed_requirement;
  • missing_grade;
  • missing_academic_progress;
  • missing_academic_standing;
  • missing_program_state;
  • catalog_mismatch;
  • catalog_unavailable;
  • unresolved_course_reference;
  • unresolved_credential_reference;
  • unsupported_requirement_condition;
  • engine_incomplete;
  • time_limit_reached;
  • source_conflict_unresolved.

Unknowns caused by source text must cite source references.

Unknowns caused by missing state fields should cite the missing state field.

Unknowns caused by engine incompleteness must name the route when a route exists.

Version 1 direct evaluation should rarely produce engine_incomplete; that reason is primarily for future external engines.

8. Conflict Reasons

Allowed initial conflict_reason values:

  • antirequisite_conflict;
  • duplicate_credit_conflict;
  • incompatible_program_assumption;
  • catalog_version_conflict;
  • state_fact_conflict;
  • source_patch_conflict;
  • source_conflict_unresolved;
  • planner_bound_conflict.

Conflicts are not ordinary missing prerequisites.

Conflicts require visible explanation.

The evaluator must not convert conflicts into not_satisfied without conflict detail.

9. Requirement Group Evaluation

The direct evaluator evaluates requirement groups over three internal values:

  • true;
  • false;
  • unknown.

For all_of:

  • true when every applicable child is true;
  • false when at least one required child is false and no unknown child can repair that child;
  • unknown when at least one required child is unknown and no conclusive false result is appropriate;
  • partial when some children are true and at least one child is false or unknown.

For any_of:

  • true when at least one applicable child is true;
  • false when every applicable child is false;
  • unknown when no child is true and at least one child is unknown;
  • partial may be used in the public status when the response needs to show satisfied subparts that do not satisfy the group.

For choose:

  • let t be true child count;
  • let u be unknown child count;
  • let m be required minimum;
  • let n be optional maximum;
  • false when t + u < m;
  • conflict or false when n exists and t > n, depending on whether over-selection creates a contribution conflict;
  • true when t >= m and no upper-bound uncertainty can invalidate the group;
  • unknown or partial otherwise.

The public status must preserve child evidence.

The evaluator must not flatten groups into ordinary prerequisite edges for semantic evaluation.

10. Course Completion Evaluation

A course completion condition is satisfied when:

  • a completed course entry resolves to the required course_listing_id; or
  • a completed course entry resolves to the required course_credit_id; or
  • indexed equivalence rules show the completed credit satisfies the required credit.

If user state contains only unresolved course text, the condition is unknown unless the text resolves during request normalization.

If a completed course is present but antirequisite conflict prevents contribution, the result is conflict or partial with conflict detail.

Planned courses do not satisfy completion conditions in fixed-state evaluation.

Planned courses may satisfy a future-state view only when the query explicitly requests hypothetical or planned-state evaluation.

11. Grade Threshold Evaluation

A grade threshold condition is satisfied when:

  • the relevant course attempt is completed;
  • grade_percent exists;
  • grade_percent >= threshold.

If completion exists but grade is missing, return unknown with missing_grade.

If grade is present only as a letter grade and no conversion policy exists, return unknown with missing_grade or unsupported_requirement_condition.

If grade is below threshold, return false for that condition.

The evaluator must not infer a threshold grade from completion alone.

12. Unit and Average Evaluation

Unit count conditions use indexed unit values and completed course contributions.

The evaluator must compute contribution from source-backed index rules, credit identities, antirequisites, and requirement context.

User-entered state cannot override academic contribution rules.

If a course has unknown units and can affect the count, return unknown.

Average conditions require:

  • known contributing courses;
  • known grades;
  • declared average policy;
  • exact numeric computation.

If any required grade is missing, return unknown with missing_grade.

If the average policy is unparsed or unsupported, return unknown with unsupported_requirement_condition or unparsed_requirement.

The backend should use exact scaled integers where possible in implementation.

13. Academic Progress Evaluation

Academic progress conditions compare indexed progress requirements to student_state.academic_progress.

If progress is missing and the condition matters, return unknown with missing_academic_progress.

If progress is present but unsupported, return unknown with unsupported_requirement_condition.

Academic progress is not academic standing.

The evaluator must not substitute standing for progress.

14. Academic Standing Evaluation

Academic standing conditions compare indexed standing requirements to student_state.academic_standing.

If standing is missing and the condition matters, return unknown with missing_academic_standing.

Most version 1 query fixtures should not require standing unless a parsed source condition explicitly does.

Academic standing is not academic progress.

15. Program Enrollment Evaluation

Program enrollment conditions compare indexed program restrictions to declared credentials or program-state entries.

Declared credentials may satisfy program enrollment conditions when they resolve to the required credential or program family.

Desired credentials do not satisfy declared program enrollment conditions.

If program state is missing and the condition matters, return unknown with missing_program_state.

If a user explicitly assumes program enrollment in a what-if request, the response must disclose the assumption.

16. Antirequisite and Credit Conflict Evaluation

The evaluator checks indexed antirequisite and duplicate-credit relationships.

If the state contains completed or planned courses that cannot both count, return conflict or warning depending on query context.

Course unlock queries should report antirequisite conflicts against the target course.

Credential progress queries should report duplicate-credit conflicts when two courses cannot both contribute.

If indexed source text states that students may complete only one course from a cross-listed set, the parser may model that source-backed policy as a duplicate-credit policy condition.

Such a policy condition must produce duplicate_credit_conflict only when the state contains completed courses with the same known course_credit_id.

The evaluator must not infer cross-listed equivalence from similar course titles, subject names, or unsourced text.

The evaluator should not decide institutional remedies.

It reports facts and source references.

17. Opaque Requirement Evaluation

Opaque source fragments evaluate to unknown when applicable.

An opaque fragment inside an all_of group can make the group unknown or partial.

An opaque fragment inside an any_of group can be irrelevant if another parsed child is satisfied.

An opaque fragment inside an any_of group can make the group unknown if no parsed child is satisfied.

An opaque fragment must cite its source reference.

The evaluator must not assume opaque fragments are satisfied.

The evaluator must not assume opaque fragments are irrelevant without an applicability reason.

18. Catalog Mismatch Evaluation

V1 backend loads one active index and one active catalog for normal evaluation.

If student_state.catalog_version_id equals active catalog_version_id, evaluation proceeds.

If they differ, the response must include catalog_mismatch.

If the state catalog is not loaded, exact requirement evaluation should return unknown with catalog_unavailable or a transport-level catalog_unavailable error when the endpoint cannot produce any useful response.

The backend must not silently reinterpret the state under the active catalog.

Migration preview is advisory and separate from query evaluation.

19. Course Unlock Query

Endpoint:

POST /api/v1/query/course-unlock

Request data:

{
"state_mode": "persisted",
"targets": {
"course_codes": ["CS 246"]
},
"include": {
"explanation_tree": true,
"source_references": true
}
}

Response data:

{
"results": [
{
"target": {
"course_listing_id": "course_listing:CS:246",
"course_code": "CS 246"
},
"status": "partial",
"academic_result": {}
}
]
}

Evaluation includes:

  • prerequisites;
  • corequisites when modeled;
  • grade thresholds;
  • academic progress;
  • program restrictions;
  • parsed enrollment restrictions;
  • antirequisite conflicts;
  • opaque fragments.

Corequisites should be reported separately from prerequisites.

The response should distinguish “not yet satisfied” from “unknown because source or state is incomplete.”

20. Credential Progress Query

Endpoint:

POST /api/v1/query/credential-progress

Request data:

{
"state_mode": "persisted",
"targets": {
"credential_ids": ["credential:math_honours"]
},
"include": {
"contribution_map": true,
"remaining_requirements": true,
"optionality": true
}
}

Evaluation includes:

  • credential requirement groups;
  • course credit contribution;
  • cross-listed credit handling;
  • duplicate-credit conflicts;
  • unit counts;
  • grade and average thresholds when represented;
  • unparsed credential requirements;
  • planned-course possible contribution when requested.

The response should include:

  • satisfied requirements;
  • unsatisfied requirements;
  • partial requirements;
  • unknown requirements;
  • contributing completed courses;
  • non-contributing completed courses;
  • potentially contributing planned courses;
  • remaining choice sets;
  • source references.

The evaluator must not invent one canonical path when multiple choice groups remain open.

21. What-If Query

Endpoint:

POST /api/v1/query/what-if

Request data:

{
"state_mode": "persisted_with_changes",
"changes": {
"add_completed_courses": [
{
"course_code": "MATH 136",
"grade_percent": 75
}
]
},
"targets": {
"course_codes": ["MATH 237"],
"credential_ids": ["credential:math_honours"]
}
}

What-if evaluation constructs:

S_before = baseline state
S_after = baseline state plus request-local changes

The endpoint evaluates both states under the same active index and policy.

The endpoint returns changes:

  • newly satisfied requirements;
  • newly unsatisfied requirements;
  • newly unlocked courses;
  • newly blocked or conflicting courses;
  • unknowns introduced;
  • unknowns resolved;
  • source references explaining changes.

The endpoint must not persist changes.

22. Advisory Query

Endpoint:

POST /api/v1/query/advisory

Version 1 advisory is a bounded product helper over query and graph evidence.

It is not a complete degree planner.

It is not official academic advice.

Request data:

{
"state_mode": "supplied",
"student_state": {},
"targets": {
"course_codes": ["CS 246"],
"credential_ids": ["credential:statistics_joint_cs"]
},
"include": {
"source_references": true,
"explanation_tree": true
}
}

State mode support:

State modeV1 behavior
suppliedEvaluate against request student_state.
persistedEvaluate against authenticated current state.
persisted_with_changesRejected for advisory; use what-if.

Response data contains one result per requested course or credential target.

Each advisory result may include:

  • missing_requirements;
  • alternative_paths;
  • course_signals;
  • academic_result;
  • engine_trace_summary.

missing_requirements describe source-backed requirement nodes that are not_satisfied, partial, unknown, or conflict.

Candidate courses attached to missing requirements must come from indexed requirement conditions.

The backend must not infer candidate courses from unsourced prose.

alternative_paths are conservative bounded hints.

They may group course options for a requirement or surface bounded prerequisite chains.

They must include rank and estimated_missing_course_count when ranking is available.

Ranking may count already completed or planned courses as known.

Ranking must not upgrade the academic status to satisfied.

course_signals feed the course library and Canva overlays.

Allowed initial signal kinds:

  • missing_prerequisite;
  • missing_prerequisite_chain;
  • missing_requirement_option;
  • future_unlock.

Every signal that comes from source-backed requirements must preserve source-reference ids.

Advisory may use:

  • direct evaluator output;
  • bounded indexed prerequisite relation traversal;
  • bounded Datalog-style closure over indexed requires relations;
  • resolver-style grouping for explicit alternatives.

These routes are implementation aids.

They do not make v1 a complete SAT, SMT, CP, or schedule planner.

Engine-native timeout, incomplete search, and route failure must remain separate from academic unknowns.

Advisory responses must keep semantic unknowns and conflicts visible as 200 OK academic data when the request itself is valid.

23. Course Impact Query

Endpoint:

POST /api/v1/query/course-impact

Request data:

{
"state_mode": "supplied",
"student_state": {},
"targets": {
"course_codes": ["MATH 135"]
},
"bounds": {
"max_depth": 3,
"max_results": 200
}
}

Impact response includes:

  • target;
  • status: "not_applicable" because impact metrics are relationship evidence, not academic satisfaction;
  • academic_result.status: "not_applicable" with a route summary identifying indexed relation traversal;
  • direct unlocks;
  • transitive unlocks within bounds;
  • credentials mentioning the course listing;
  • credentials mentioning the course credit identity;
  • subject diversity;
  • credential relevance;
  • bottleneck-like contribution metrics;
  • conflicts;
  • unknown dependency count.

The backend computes raw metrics.

The frontend decides visual sizing.

The frontend runtime architecture and atlas spec define how visual sizing can use backend-provided metrics without becoming academic truth.

Impact metrics are not academic statuses by themselves.

24. Credential Gap Summary Query

Endpoint:

POST /api/v1/query/credential-gap-summary

Version 1 returns conservative current-state gap evidence.

It does not run a complete future schedule solver.

Request data:

{
"state_mode": "persisted",
"targets": {
"credential_ids": ["credential:statistics_minor"]
}
}

Response status values still use academic status vocabulary.

Data may include:

  • current credential progress status;
  • remaining requirement groups;
  • blocked requirement groups;
  • conflicts;
  • missing grades;
  • missing academic progress;
  • unparsed requirements;
  • source references;
  • unknown reasons.

V1 must not claim global feasibility or global infeasibility.

V1 may say that the current state has no known blocker only when all relevant represented conditions were evaluated and no relevant unknown remains.

A future CP, SAT, SMT, or resolver-style route may add stronger planning results.

If such a route times out, the result must be unknown or partial with time_limit_reached, not not_satisfied.

If such a route returns UNSAT or unsatisfiable, the result can become bounded infeasible only when the encoding is complete for the declared bounds.

25. Assumption Reporting

Every result affected by an assumption must report it.

Assumptions include:

  • expected future grades;
  • hypothetical course completions;
  • hypothetical program enrollment;
  • future academic progress;
  • course offering availability;
  • manual equivalence.

Assumption shape:

{
"assumption_id": "assumption:req_1",
"assumption_kind": "expected_grade",
"target_id": "course_listing:MATH:237",
"value": {
"grade_percent": 80
},
"scope": "request"
}

The explanation tree should reference assumptions when they change a status.

26. Source References

Every decisive source-derived condition should contribute a source reference id.

Every opaque requirement unknown must include a source reference id.

Every conflict caused by source data should cite all known relevant source references.

The query endpoint may include compact source reference summaries in the common envelope.

The explanation tree may reference those ids.

27. Route Summary

Version 1 route summary:

{
"routes": ["direct_evaluator"],
"direct_evaluator": {
"complete_for_supported_conditions": true,
"unsupported_condition_count": 0,
"unparsed_requirement_count": 1
}
}

Future route summary may include Datalog, SAT, SMT, CP, or resolver-style routes.

Route summary is diagnostic.

It is not the academic explanation.

28. Test Scenarios

Query semantics tests should cover:

  • all-of group satisfied;
  • all-of group partial;
  • any-of group satisfied;
  • any-of group unknown because only opaque branch remains;
  • choose group lower bound satisfied;
  • choose group lower bound impossible;
  • course completion by listing;
  • course completion by credit identity;
  • grade threshold satisfied;
  • grade threshold below threshold;
  • grade threshold missing grade;
  • unit count satisfied;
  • unit count unknown units;
  • academic progress satisfied;
  • missing academic progress;
  • academic standing not confused with progress;
  • declared credential satisfies program restriction;
  • desired credential does not satisfy declared program restriction;
  • antirequisite conflict;
  • duplicate-credit conflict;
  • catalog mismatch;
  • catalog unavailable;
  • what-if does not persist changes;
  • credential progress preserves optionality;
  • course impact returns bounded metrics;
  • gap summary does not claim global possibility or impossibility from incomplete planning.

29. Acceptance Criteria

An implementation satisfies this spec when:

  • every query endpoint returns common envelopes;
  • every query target returns an academic status;
  • direct evaluator fixtures pass;
  • unknowns include machine-readable reasons;
  • conflicts include machine-readable reasons;
  • source-backed results include source references;
  • catalog mismatch is explicit;
  • query endpoints do not mutate persisted state;
  • engine-native unknown and timeout cannot become academic not_satisfied;
  • unsatisfiable future engine results require complete encoding before becoming bounded infeasible.