0.55.0: get_submission_feedback, and the Canvas plan that closed with it #1

Merged
joeyr merged 1 commit from canvas-submission-feedback into main 2026-09-16 12:17:56 -05:00
Owner

C7, the last tool the Canvas build plan held open, and the only phase here ever blocked by a calendar rather than by a decision — the endpoint was proved working on 2026-08-24 against zero graded submissions, and waited for a grade to exist.

get_grades returns a course total and list_assignments returns a score; neither carries a sentence. get_submission_feedback reads submission comments and the filled-in rubric, per assignment, newest first — one request per course.

Decisions worth reviewing

  • student_ids[] and grouped are both omitted deliberately. Canvas answers the bare endpoint with the calling user's submissions and refuses a student who asks for anyone else's; grouped silently disables order, so a test pins its absence.
  • Narrowing to one assignment changes endpoint, not parameters. assignment_ids[] has a standing report of returning no comments for an assignment the user has not submitted to. /submissions/self is used instead, and is also the only route carrying read state.
  • Who wrote a comment is looked up, not inferred. A peer-reviewed assignment puts classmates in the same array, so "not the student's own, therefore staff" is wrong rather than approximate. One roster request resolves it, made only when a comment exists; where it fails the field is ABSENT and the response says the role could not be confirmed.
  • Four shapes that read as emptiness are named: a withheld grade (posted_at: null), a media-only comment, a quiz's per-question feedback, and a rubric row that would not join to its criterion.

A defect the tests caught before it shipped

since is sent to Canvas as graded_since, so a windowed read comes back with a graded count of zero whether or not the course has ever been graded — and the empty-result note concluded "nothing has been graded yet" from a window that had excluded the evidence. Fixed, and generalised in CLAUDE.md under A bounded read cannot report an absence.

Not verified live

The withheld-grade path is coded from Canvas's docs and needs an instructor using a manual posting policy, which is not this account's to arrange. It is recorded in CLAUDE.md alongside the two checks Canvas already owed.

docs/canvas-plan.md is deleted

Its own rule was to delete it once the last item shipped. Most of it was safe to lose, but three live checks the tenant still owes were sitting only in that file, and docs/operations.md had an instruction pointing into it — both moved before the deletion. That gap is written up too: an outstanding item is not durable knowledge, so the rule about plans holding nothing durable did not cover it.

Canvas is at twelve tools and still has no write on its surface. Gate is green locally: ruff, mypy, 1643 tests.

🤖 Generated with Claude Code

C7, the last tool the Canvas build plan held open, and the only phase here ever blocked by a calendar rather than by a decision — the endpoint was proved working on 2026-08-24 against zero graded submissions, and waited for a grade to exist. `get_grades` returns a course total and `list_assignments` returns a score; neither carries a sentence. `get_submission_feedback` reads submission comments and the filled-in rubric, per assignment, newest first — one request per course. ## Decisions worth reviewing - **`student_ids[]` and `grouped` are both omitted deliberately.** Canvas answers the bare endpoint with the calling user's submissions and refuses a student who asks for anyone else's; `grouped` silently disables `order`, so a test pins its absence. - **Narrowing to one assignment changes endpoint, not parameters.** `assignment_ids[]` has a standing report of returning no comments for an assignment the user has not submitted to. `/submissions/self` is used instead, and is also the only route carrying read state. - **Who wrote a comment is looked up, not inferred.** A peer-reviewed assignment puts classmates in the same array, so "not the student's own, therefore staff" is wrong rather than approximate. One roster request resolves it, made only when a comment exists; where it fails the field is ABSENT and the response says the role could not be confirmed. - **Four shapes that read as emptiness are named**: a withheld grade (`posted_at: null`), a media-only comment, a quiz's per-question feedback, and a rubric row that would not join to its criterion. ## A defect the tests caught before it shipped `since` is sent to Canvas as `graded_since`, so a windowed read comes back with a graded count of zero whether or not the course has ever been graded — and the empty-result note concluded "nothing has been graded yet" from a window that had excluded the evidence. Fixed, and generalised in `CLAUDE.md` under *A bounded read cannot report an absence*. ## Not verified live The withheld-grade path is coded from Canvas's docs and needs an instructor using a manual posting policy, which is not this account's to arrange. It is recorded in `CLAUDE.md` alongside the two checks Canvas already owed. ## `docs/canvas-plan.md` is deleted Its own rule was to delete it once the last item shipped. Most of it was safe to lose, but three **live checks** the tenant still owes were sitting only in that file, and `docs/operations.md` had an instruction pointing into it — both moved before the deletion. That gap is written up too: an outstanding item is not durable knowledge, so the rule about plans holding nothing durable did not cover it. Canvas is at twelve tools and still has no write on its surface. Gate is green locally: ruff, mypy, 1643 tests. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
0.55.0: the sentence half of a grade, and the plan that closed with it
All checks were successful
CI / gate (pull_request) Successful in 1m55s
CI / image (pull_request) Has been skipped
640b957eef
`get_submission_feedback` -- C7, the last tool the Canvas build plan held
open, and the only phase here ever blocked by a calendar rather than by a
decision. The endpoint was proved working on 2026-08-24 against zero graded
submissions across three courses; it waited for a grade to exist.

`get_grades` returns a course total and `list_assignments` returns a score.
Neither carries a sentence, so "why did I lose those points" was the one
coursework question this tenant could see the evidence of and not answer --
the planner has reported `has_feedback` on items it could not open since C3.

One request per course. Submission comments joined to their HTML twins, and
the rubric assessment joined to the assignment's own criteria, because Canvas
keys the assessment by criterion id and puts the wording nowhere near it.
`student_ids[]` is omitted because Canvas answers the bare endpoint with the
calling user's submissions and refuses a student who asks for anyone else's.
`grouped` is omitted because it silently disables `order` -- a test pins that.
Narrowing to one assignment changes ENDPOINT rather than adding a filter:
`assignment_ids[]` has a standing report of returning no comments for an
assignment the user has not submitted to, and `/submissions/self` is the only
route that carries read state.

Four shapes Canvas returns that read as emptiness are named instead of
dropped: a withheld grade (`posted_at: null`), a media-only comment, a quiz's
per-question feedback, and a rubric row that would not join. Who wrote a
comment is looked up rather than inferred -- a peer-reviewed assignment puts
classmates in the same array, so "not the student's own, therefore staff" is
wrong rather than approximate -- and where the roster cannot be read the field
is ABSENT and the response says the role could not be confirmed.

A defect the tests caught before it shipped: `since` is sent to Canvas as
`graded_since`, so a windowed read comes back with a graded count of zero
whether or not the course has ever been graded -- and the empty-result note
concluded "nothing has been graded yet" from a window that had excluded the
evidence. Generalised in CLAUDE.md under *A bounded read cannot report an
absence*.

docs/canvas-plan.md is deleted, its own rule having been to delete it once the
last item shipped. Three LIVE CHECKS the tenant still owes were sitting only
in that file and moved to CLAUDE.md; docs/operations.md no longer points into
a file that is gone. That gap is written up too: an outstanding item is not
durable knowledge, so the rule about plans holding nothing durable did not
cover it.

Canvas is at twelve tools and still has no write on its surface.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
joeyr merged commit 506045db7f into main 2026-09-16 12:17:56 -05:00
joeyr deleted branch canvas-submission-feedback 2026-09-16 12:17:56 -05:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
joeyr/mcp-gateway!1
No description provided.