Owner Abhi

Comments phase 1 test document

Scope: Phase 1. Comments on dockets only (content_type = DOCKET, value 1).

Tier map: A = SYS_ADMIN, B = ADMIN, C = EDITOR. Policy: src/constants/comment_permissions.py. Web mirror: keystone-web/src/features/comments/permissions.ts.

ActionSYS_ADMINADMINEDITORAI JWT
CREATEyesyesyesyes
EDIT_OWNyesyesyesn/a
EDIT_ANYyesnonon/a
DELETE_OWNyesyesyesn/a
DELETE_ANYyesnonon/a
RESOLVE_ANYyesyesnon/a
REOPEN_ANYyesyesnon/a

AI JWT: create only; other calls FORBIDDEN. AI-authored comments: no PATCH; delete needs DELETE_ANY (system admin).

API: handled routes return HTTP 200; failures use JSON status failure and error.code.


Backend create POST /comments

IDCaseExpect
TC-BE-C01Human JWT, valid docket, body_type=1 (TEXT), body within limitHTTP 200 success; author_type human, status OPEN, created_by matches sub; row + audit created
TC-BE-C02Same, body_type=2 (PLATE), valid JSONHTTP 200 success; body_type 2 echoed
TC-BE-C03AI JWT, valid docketHTTP 200 success; author_type ai, created_by matches sub
TC-BE-C10Empty bodyHTTP 200 failure; INVALID_PARAMETERS
TC-BE-C11Body over 10000 charsHTTP 200 failure; INVALID_PARAMETERS
TC-BE-C12Invalid or unknown content_typeHTTP 200 failure; INVALID_PARAMETERS
TC-BE-C13DOCKET but content_id not valid ObjectId hexHTTP 200 failure; INVALID_PARAMETERS
TC-BE-C14Valid hex, docket missing for course_idHTTP 200 failure; RESOURCE_NOT_FOUND
TC-BE-C15AI JWT calls PATCH, resolve, reopen, deleteHTTP 200 failure; FORBIDDEN each

Backend list GET /comments

IDCaseExpect
TC-BE-L01Default status=openOnly OPEN, not soft-deleted
TC-BE-L02status=resolved / allMatches contract
TC-BE-L03author_type human / aiFilters on stored value
TC-BE-L04sort_order asc vs descStable order (created_at + _id tie-break per repo)
TC-BE-L05next_cursor / prev_cursorNo dupes or skips
TC-BE-L06Soft-deleted commentExcluded
TC-BE-L07limit 1..100Respected; invalid limit rejected at validation

Backend get one GET /comments/{id}

IDCaseExpect
TC-BE-G01Existing visible commentHTTP 200 success; response shape + author_name when resolvable
TC-BE-G02Wrong course_idHTTP 200 failure; RESOURCE_NOT_FOUND
TC-BE-G03Deleted or hiddenHTTP 200 failure; RESOURCE_NOT_FOUND

Backend patch PATCH /comments/{id}

IDCaseExpect
TC-BE-P01EDITOR patches own human commentHTTP 200 success; body updated; audit edited
TC-BE-P02SYS_ADMIN patches another human commentHTTP 200 success (EDIT_ANY)
TC-BE-P10EDITOR patches someone else’sHTTP 200 failure; FORBIDDEN
TC-BE-P11ADMIN patches someone else’sHTTP 200 failure; FORBIDDEN
TC-BE-P12Any role patches AI-authored commentHTTP 200 failure; FORBIDDEN
TC-BE-P13Patch DELETED commentHTTP 200 failure; pin RESOURCE_NOT_FOUND vs OPERATION_NOT_ALLOWED
TC-BE-P14Empty or oversize bodyHTTP 200 failure; INVALID_PARAMETERS
TC-BE-P15body_type in PATCH bodyIgnored or rejected (pin contract)

Backend resolve and reopen

IDCaseExpect
TC-BE-R01EDITOR tries resolve on OPENHTTP 200 failure; FORBIDDEN
TC-BE-R02ADMIN resolves OPENHTTP 200 success; RESOLVED; audit resolved
TC-BE-R03SYS_ADMIN resolves OPENHTTP 200 success; same
TC-BE-R04Resolve already RESOLVEDHTTP 200 success; idempotent (no second audit row per current repo)
TC-BE-R05ADMIN or SYS_ADMIN reopen RESOLVEDHTTP 200 success; OPEN; audit reopened
TC-BE-R06EDITOR tries reopenHTTP 200 failure; FORBIDDEN
TC-BE-R07AI JWT on resolve or reopenHTTP 200 failure; FORBIDDEN

Backend delete DELETE /comments/{id}

IDCaseExpect
TC-BE-D01EDITOR deletes own human commentHTTP 200 success; DELETED + is_deleted; audit deleted
TC-BE-D02EDITOR deletes another’sHTTP 200 failure; FORBIDDEN
TC-BE-D03ADMIN deletes another’s (non-AI)HTTP 200 failure; FORBIDDEN
TC-BE-D04SYS_ADMIN deletes another’s or AI commentHTTP 200 success
TC-BE-D05ADMIN tries delete AI commentHTTP 200 failure; FORBIDDEN
TC-BE-D06Double deletePin RESOURCE_NOT_FOUND vs idempotent success (HTTP 200 either way)

Backend counts GET /comments/counts

IDCaseExpect
TC-BE-N01Batch of docket idsMap content_id to open count
TC-BE-N02Id with zero opens0 or absent (pin contract)
TC-BE-N03Empty content_idsHTTP 200 failure; INVALID_REQUEST
TC-BE-N04Bad content_typeHTTP 200 failure; INVALID_PARAMETERS

Backend data and audit

IDCaseExpect
TC-BE-A01New comment rowparent_id root sentinel; content_type 1; course_id matches query
TC-BE-A02After resolveNo resolved_at / resolved_by on row; audit row exists
TC-BE-A03Burst creates same targetDistinct ids
TC-BE-A04Indexes on fresh DBNames in CommentDBModel.Settings

Web happy paths (keystone-web)

IDCaseExpect
TC-WEB-01Open docket preview and commentsPanel lists comments; composer if canCreate
TC-WEB-02Submit TEXT commentIn list; no success toast; counts refresh
TC-WEB-03Rich Plate submitRenders; no duplicate DnD backend
TC-WEB-04ADMIN or SYS_ADMIN sees resolve on open rowIcon works; toast; row resolved
TC-WEB-05Grid open count columnMatches API for visible dockets
TC-WEB-06Open comments collapses sidebarUser can reopen sidebar

Web edge and UX (keystone-web)

IDCaseExpect
TC-WEB-E01User lacks CREATEComposer hidden or disabled; forced call HTTP 200 + FORBIDDEN in body
TC-WEB-E02User lacks resolveNo resolve icon
TC-WEB-E03Delete own vs delete-anyConfirm copy differs
TC-WEB-E04Long plain bodyLayout ok
TC-WEB-E05Long author_nameNo overlap with actions
TC-WEB-E06Two browser tabsStaleness ok or document refresh
TC-WEB-E07Close panel animationWidth animates; badge refetch on mutations
TC-WEB-E08Over 100 commentsNo load more yet; document or add control