-
released this
2026-08-25 20:43:00 -05:00 | 67 commits to main since this releaseCanvas C6:
list_discussion_entries. The tenant could read what a
discussion ASKS and not a word of what anyone SAID — so a graded discussion
that requires replying to two classmates was an assignment it could describe
and not help with. The replies are the half that was missing.This plan declined discussions three times in one sentence and was wrong all
three times. "Large free-text surfaces with no natural bound" was measured
against pages (reversed in 0.43.0), against prompts (reversed in 0.44.0), and
now against threads: the busiest thread on this account is 18 posts and 12,987
characters, smaller than the syllabus this tenant already returns. The
durable lesson is inCLAUDE.mdalready — measure a surface before declining
it — and this is its third instance rather than a new one.Added
-
list_discussion_entries(course_id, topic_id)— every reply in one
thread, in thread order. Takes the SAMEtopic_idasget_discussion, which
now names it on any topic that has replies.Built on
/viewrather than/entries, which is the measurement that
moved the design. One/viewcosts 0.1932 and returns the whole nested
tree;/entriescosts 0.3926 and returns only the top level. Half the
price for twice the content./entrieshangs arecent_repliesarray off
each entry that carried every child on the thread it was measured against —
and "recent" is the API's word, not a promise. A tool built on it looks
correct on a quiet thread and silently loses replies on a busy one.The tree is flattened, carrying
depthandin_reply_to. A model
answering "who replied to whom" from nested JSON has to hold the shape in
mind; a flat list in thread order where each row names what it answers states
the same relationship outright.Three truncations, reported separately, because they have different
fixes:more_entries(thread longer than 100),deeper_replies(nested
below 3), and per-entrymessage_truncated. A single flag would say
something was missing without saying whether it was a person, a
sub-conversation, or a paragraph. -
CANVAS_THREAD_MAX_ENTRIES(100) andCANVAS_THREAD_MAX_DEPTH(3). A
thread is the one Canvas surface whose size is a class's rather than a
field's, so capping text bounds nothing. Depth is 3 rather than the
observed 2 deliberately: every topic on this account is
discussion_type: threaded, so Canvas imposes no ceiling and the observed
depth is one class's habits rather than a limit.
Fixed
-
A
require_initial_postlock was being reported as a permission problem,
and the advice was wrong in a way that costs someone an email to their
instructor. A discussion set to hide replies until the student posts their
own answers403with a body of exactlyrequire_initial_post— measured
against the one topic on this account that still has the lock closed. The
shared 403 branch answered that with "this account is not permitted to read
that": true about the request, false about the account, and the actual fix is
thirty seconds of the student's own typing.CanvasNeedsInitialPostsubclassesCanvasRefused, so every existing
caller stays correct — the session is fine and the request was refused, which
is what the parent promises — and only the advice changes. Responses carry
needs_initial_post: truebesideneeds_reseed: false. The token is matched
whole rather than by substring, and the body is never echoed into the error
message: a 403 body on another path is an unknown quantity and error text
travels.
Privacy
-
Classmates' names are kept; their profiles are not. Canvas returns
avatar_image_url,html_url,pronounsandanonymous_idbeside each
post, plus aparticipantsroster covering people who never posted. All of
it is dropped at the client boundary anduser_nameis kept, because a
graded discussion asks the student to reply to named classmates and a tool
that anonymises them returns a draft the user re-personalises line by line.Stated plainly because the reverse gets claimed later: this is a small
reduction. The sensitive material in a discussion thread is the posts, and
the name is attached to those either way. The boundary that does the real
work is that entry text is never logged — counts, lengths and ids only,
followingget_discussion.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-