Central Station / YPM-FEATURE-REVISION-FLOW

Revision flow

features/revision-flow.md · Updated 2026-05-26
GET /api/tickets/YPM-FEATURE-REVISION-FLOW

Summary

May 26 call reconfirmed side-by-side revision as high priority; recover/finish PR work

7Questions 0Links 0Comments 2PRs
Open questions 7 items
  1. 1 Does a revision require teacher action to "accept"? **No.** The student can revise unilaterally; teacher sees the new revision in their gradebook ungraded. Policy (classroom norms, teacher instruction) is the brake, not a hard technical gate — keeping it soft preserves flexibility without requiring code changes to adjust. (Kevin)
  2. 2 Do inline comments on the previous revision get carried forward as read-only annotations on the new revision's editor? **No.** The three-column layout keeps the graded submission and its comments visible on the left while the student writes on the right — so the feedback is always in view without injecting it into the editor. Comments stay scoped to the submission they belong to. (Kevin)
  3. 3 What happens to a revision-in-progress (draft state) if the teacher un-releases a grade? **Not applicable — un-releasing doesn't exist.** Grade release is a one-way transition: `releasedAt` is set once and there is no UI, endpoint, or data-model path to null it out. Revisit if un-release ever ships.
  4. 4 Limit on number of revisions? **No cap, no warning.** If teachers report being spammed by revision submissions in practice, we can revisit adding a soft warning at that point. (Kevin)
  5. 5 **Feature flag seeding in production/preview** — the flag only exists in the e2e seed. Needs a manual SQL insert in any environment where you want to test with real data. Bryant to decide: deploy runbook, or automate seeding as disabled-by-default?
  6. 6 **Submit flow destination** — after the student submits a revised essay, show a confirmation popup (same pattern as the existing "Submit Version N" dialog, which shows submission title and previous submission history). After dismissing, keep the student in the side-by-side revision view — don't navigate away. They leave when they choose to. (Kevin)
  7. 7 **Old flow removal timing** — old `?revise=1` flow must stay active during flag-gated rollout. Bryant to decide the removal trigger and open a follow-up ticket at that point.
Spec body Markdown
# Revision flow

Students can revise a submitted submission directly from the submissions page, without navigating back to the document. Comments and grade summary stay visible alongside the editor so the feedback loop is tight.

## Current status

`yawp-2.0` PR #102 is open and CI has been green. Engineering can keep moving. Decision from the May 7 sync: seed the new flow disabled-by-default in preview/prod, enable intentionally for pilots, and do not remove the old `?revise=1` path until the new flow has proven itself in real production use.

May 26 update: the summer priorities call reconfirmed this as important and aligned with how Yawp teaches revision. Kevin observed students working hard to raise revised essays above an 85, but working around the current revision path because it sends them back to the document page and the two-panel/three-panel layouts get cramped at half-screen widths. Bryant said to recover the lost thread and finish the side-by-side work; send unresolved product questions back to Kevin/Brian if needed.

Repo check from May 26: side-by-side revision is `yawp-2.0` PR #102, not PR #144. PR #102 is open/non-draft but stale and conflicting against current `main`; previous checks were green on May 7. PR #144 is already merged and covers teacher/class pilot feature flags.

## Problem

Today, when a student receives a graded submission and wants to revise, they have to leave the submissions page, go back to the underlying document at `/app/documents/:id`, edit there, and resubmit. The teacher's feedback (grade summary, inline comments) is in a different surface than the writing they're trying to revise. Students lose context every time they switch panels, and the act of "revising" is indistinguishable from "starting a new submission" — which discourages iteration.

This is the most-requested change from the UA professor's pilot cohort. Revision should be a first-class flow, not a workflow hack.

## Goals

- A student viewing a graded submission can revise it without leaving the page.
- Teacher feedback (grade summary, inline comments) stays visible while the student writes.
- The revised submission is clearly a revision of the original — not a brand-new submission with no lineage.
- Teachers can see revision history on a submission and grade revisions distinctly from the original.

## Non-goals

- Real-time collaboration between teacher and student in the editor. Out of scope; revision is asynchronous.
- Revising a submission that hasn't been graded yet. If a teacher hasn't released a grade, the student should still be editing the underlying document, not "revising."
- Versioning beyond linear revisions (no branching). Each revision supersedes the previous one for grading purposes; previous versions are read-only history.

## Domain notes

Today's model:
- A `Document` is the editable writing surface.
- A `Submission` is an immutable snapshot of the document at submission time.
- Once submitted, the document continues to be editable but the submission is frozen.

Revision flow extends `Submission` to support a chain of related submissions:
- A "revision" is a new `Submission` linked to the original via a parent reference.
- The chain forms a linear history; the most recent revision is the "current" submission for grading purposes.
- Inline comments on a previous revision stay attached to that revision (don't follow the student's edits).

This relates closely to [multi-submission-support](multi-submission-support.md), which proposed allowing multiple independent submissions per document. Revision flow is a more constrained, opinionated version of that — submissions are explicitly chained, not parallel. Keeping multi-submission as a separate planned item in case we need parallel submissions later (e.g., a student submitting two essays for the same assignment), but for the iteration-loop use case, revision is the answer.

## UX sketch

Revision happens on a dedicated route: `/app/submissions/:submissionId/revise`. This is a new page — not a transformation of the existing submissions view — with a three-column layout.

```
┌─────────────────────────────────┬──────────────────────────────────┐
│ ← Back to feedback   Title  77% │         Submit Revised Version → │
├──────────┬──────────────────────┼──────────────────────────────────┤
│  Grade   │  Original essay      │  Your Revision                   │
│  Summary │  (with inline        │  (revision editor,               │
│          │   highlights)        │   seeded from submission)        │
│  Rubric  │                      │                                  │
│          │                      │                                  │
│  Grade   │                      │                                  │
│  Comments│                      │                                  │
└──────────┴──────────────────────┴──────────────────────────────────┘
```

Left panel (existing feedback surface, restacked):
- Grade summary (score, rubric breakdown per criterion)
- Original essay text with inline highlights
- Grade comments

Right panel (new revision editor):
- Seeded from the graded submission's content snapshot — not the live document. Student starts from what was submitted and edits from there.
- Full formatting toolbar
- Autosave (debounced → IndexedDB + server sync every 5 min of idle editing)
- Auth heartbeat (locks editor on session expiry; non-dismissible session-expired dialog with "Log In" preserving redirect URL)
- Editable document title (saves on blur)
- Version history
- Submit button (disabled when empty, confirmation dialog)

Nav bar:
- "← Back to feedback" link (left)
- Document title + grade badge (center)
- "Submit Revised Version →" button (right)

The existing submissions page (`/app/submissions/:id`) gains a "Revise Essay" button that links to the new route when the flag is on and the submission has been released. When the flag is off, "Revise Essay" continues to use the old `?revise=1` flow.

For the teacher viewing a revised submission, the grade summary shows revision history as a breadcrumb: `Original · Revision 1 · Revision 2 (current)`. Clicking a previous version opens it read-only.

For the student on a submission that has not been released yet, the `/revise` route shows a placeholder explaining they'll be able to revise once the teacher releases the grade. Editor is not interactive.

## Data model implications

`Submission` table gains a nullable `parentSubmissionId` foreign key referencing `Submission(id)`.

- `null` means original submission.
- non-null means revision of the referenced submission.

Backward-compat migration:
1. Add column nullable, default null. Deploy.
2. No backfill needed — all existing submissions are originals.
3. New writes start populating `parentSubmissionId` when the revision flow ships.

A "revision chain" is computed by walking parent references. Don't denormalize a chain ID; the chain is short (typically 1-2 revisions) and recomputing is cheap.

For grade aggregation: when a teacher's gradebook displays a submission, show the grade of the most recent revision. The earlier revisions' grades remain attached to those rows for history but don't roll up.

Inline comments are scoped to a single submission (not a chain). When a student revises, they start with no comments on the new submission. The previous revision's comments are visible read-only via the breadcrumb.

## File paths in `yawp-2.0` likely to change

- `app/routes/app_.submissions_.$submissionId_.revise/route.tsx` — new route (three-column layout)
- `app/routes/app_.submissions_.$submissionId/route.tsx` — "Revise Essay" button points to new route when flag is on
- `app/utils/feature-flags.server.ts` — `REVISION_FLOW` flag + `isRevisionFlowEnabled()`
- `app/routes/api.submissions.create-revision/route.ts` — new, or extend existing create-submission route; sets `parentSubmissionId`
- `packages/db/schema/submissions.ts` — add `parentSubmissionId`
- `packages/db/migrations/...` — new migration
- `app/lib/submissions/chain.ts` — new helper for walking parent chain
- `e2e/seed-e2e.ts` — seeds the feature flag for e2e tests
- `e2e/tests/student.revision-view.spec.ts` — new e2e tests for the revision view

Reference: PR #102 on `yawp-2.0` (branch `claude/plan-feedback-resubmission-FbxDo`) has early groundwork for the route and editor.

May 26 repo pointers from PR #102:

- `services/web-app/app/routes/app_.submissions_.$submissionId_.revise/route.tsx`
- `services/web-app/app/routes/app_.submissions_.$submissionId/route.tsx`
- `services/web-app/app/utils/feature-flags.server.ts`
- `services/web-app/e2e/tests/student.revision-view.spec.ts`
- `docs/work/side-by-side-revision-view.md`

## Open questions

- [x] Does a revision require teacher action to "accept"? **No.** The student can revise unilaterally; teacher sees the new revision in their gradebook ungraded. Policy (classroom norms, teacher instruction) is the brake, not a hard technical gate — keeping it soft preserves flexibility without requiring code changes to adjust. (Kevin)
- [x] Do inline comments on the previous revision get carried forward as read-only annotations on the new revision's editor? **No.** The three-column layout keeps the graded submission and its comments visible on the left while the student writes on the right — so the feedback is always in view without injecting it into the editor. Comments stay scoped to the submission they belong to. (Kevin)
- [x] What happens to a revision-in-progress (draft state) if the teacher un-releases a grade? **Not applicable — un-releasing doesn't exist.** Grade release is a one-way transition: `releasedAt` is set once and there is no UI, endpoint, or data-model path to null it out. Revisit if un-release ever ships.
- [x] Limit on number of revisions? **No cap, no warning.** If teachers report being spammed by revision submissions in practice, we can revisit adding a soft warning at that point. (Kevin)
- [ ] **Feature flag seeding in production/preview** — the flag only exists in the e2e seed. Needs a manual SQL insert in any environment where you want to test with real data. Bryant to decide: deploy runbook, or automate seeding as disabled-by-default?
- [x] **Submit flow destination** — after the student submits a revised essay, show a confirmation popup (same pattern as the existing "Submit Version N" dialog, which shows submission title and previous submission history). After dismissing, keep the student in the side-by-side revision view — don't navigate away. They leave when they choose to. (Kevin)
- [ ] **Old flow removal timing** — old `?revise=1` flow must stay active during flag-gated rollout. Bryant to decide the removal trigger and open a follow-up ticket at that point.

## Edge cases

- Student loads the submissions page for an unreleased submission: right column shows placeholder, editor disabled.
- Teacher viewing the page: no editor on the right; teacher's existing grade-and-comment workflow unchanged. Revisions show as a breadcrumb in the header.
- Student revises, teacher grades the revision, student revises again: chain of 3 submissions, each with its own grade.
- Document underlying the submission has been edited in the meantime (student kept working on the doc): the revision editor should start from the previous submission's content, not the live document. The document and submissions are separate trees once a submission is made.
- Student has multiple assignments using the same document (rare but possible if revision chains span assignment types): scope revisions strictly to a single assignment chain.
- Teacher deletes a submission mid-revision: the in-progress revision draft errors gracefully and shows "this submission has been removed." (Edge — confirm we even allow submission deletion.)

## Test plan

Unit:
- Submission creation with `parentSubmissionId` set: validates parent exists, validates ownership, validates the chain is linear (no cycles).
- Chain-walking helper: given a leaf submission, returns the full chain in order.

Integration:
- E2E: student submits, teacher grades and releases, student revises, teacher sees revision in gradebook with new "ungraded" status.
- E2E: student tries to revise an unreleased submission → editor disabled, no API call possible.
- Reference existing submission tests at `services/web-app/app/routes/app.submissions.$id/route.test.tsx` as the starting point.

Manual QA:
- Mobile: two-column layout collapses to stacked editor-on-top, feedback-below on narrow viewports.
- Half-width desktop/windowed mode: feedback and editor remain usable and do not squash into unreadable columns.
- Comment counts on the previous revision stay correct after the new revision is submitted.
- Empty state when there are no comments on the original (right column should still work).

Follow-up signal: students may also need an exemplar/model-essay library so they can see that a 97-level essay is possible. That belongs in [Essay Examples](essay-examples.md), not this revision-flow PR.

## Rollout

Feature flag: `revision_flow_enabled`. DB-driven via the existing `Setting` table. Default OFF.

To enable:
```sql
INSERT INTO "Setting" (name, value, "valueType")
VALUES ('revision_flow_enabled', 'true', 'boolean');
```

To disable:
```sql
UPDATE "Setting" SET value = 'false' WHERE name = 'revision_flow_enabled';
```

Pilot order:
1. Internal testing (manual SQL insert per environment).
2. UA professor's cohort (single power user, fastest feedback).
3. Washington schools.
4. Birmingham City Schools.
5. Broader release — after ~2 weeks of production stability, remove old `?revise=1` flow and the flag.

Backward compat: data model change is additive; old submissions continue to work. Old `?revise=1` flow stays active while the flag is off.

## Engineering next action

Revive PR #102 by rebasing/conflict-fixing onto current `main`, especially around feature flags and submission/document routes, then rerun:

- `bun run --cwd services/web-app typecheck`
- `SESSION_SECRET=test-secret bun run --cwd services/web-app test`
- `cd services/web-app && ./node_modules/.bin/playwright test --project=chromium e2e/tests/student.revision-view.spec.ts`

## Engineering handoff checklist

- [x] Domain context covered
- [x] File paths in `yawp-2.0` listed
- [x] Data model implications spelled out, including backward-compat plan
- [x] UX sketch in prose
- [x] Edge cases enumerated
- [x] Test plan written
- [x] Rollout plan decided
- [ ] Open questions resolved (2 remaining for Bryant — flag seeding and old flow removal; unblocking for engineering)
Repo sync Metadata
{
  "url": "https://github.com/The-Connell-School/yawp-2.0/pull/102",
  "repo": "The-Connell-School/yawp-2.0",
  "draft": false,
  "state": "OPEN",
  "title": "feat(revision): prototype side-by-side feedback + editor revision view",
  "branch": "claude/plan-feedback-resubmission-FbxDo",
  "checks": {
    "total": 5,
    "failing": 1,
    "pending": 0,
    "successful": 4
  },
  "number": 102,
  "syncedAt": "2026-05-26T21:38:23.523Z",
  "mergeable": "DIRTY"
}