drafts(attribution): daily evaluation drafts with contributor history - #29
Conversation
Milestone 3 slice 3 (ADR 0008): an evaluation_record is the continuing identity of a daily evaluation — stamped with the covered session's version, typed by a pinned daily_report form via composite foreign key, covering sessions through a join the database holds to the record's own enrollment and version. One daily draft per session is v1 policy in the service, deliberately not schema. Attribution is a metadata-only append-only contributor stream; the current owner moves only when the latest event records exactly that transfer, and the recipient is notified. Consecutive saves by one contributor coalesce into one contributed event per working stretch. The working copy validates every save against the pinned scale kinds and vocabulary ids; submission snapshots the full content and freezes the copy at the service and the database until review. Module owners: evaluation_drafts (record lifecycle, gates per #22 decision 2, derived status), draft_content (working copy, validation, coalesced attribution), drafts_http (handlers). Web: a draft workspace with debounced autosave and visible attribution, entered from the enrollment sessions panel and My sessions. Refs #28. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DNP3dkn9c84v2YoNwx7KTg
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ade3c37883
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
… saves Round-1 review fixes, all against the configured-vocabulary and collaboration contracts: The rating controls now present exactly what the pinned scales define: anchored scales offer every value in their configured bounds with anchors labeling the values they define (anchors may be sparse), and pass/fail options carry the agency-configured anchor labels instead of hard-coded terms. When a version pins several daily forms, a picker (backed by a session-scoped daily-forms read, gated like starting the draft) appears exactly when the choice is real, so multi-form configurations no longer dead-end at form_required. Collaborative saves gain an optimistic-concurrency contract: every save carries the revision it read and bumps it; a stale full replacement is a typed stale_save refusal — never a silent overwrite of another contributor's work — and the workspace reloads visibly when it loses that race. Submission flushes any pending or in-flight autosave first and declines to submit content it just reloaded sight unseen, so the snapshot always anchors what the owner saw. Refs #28. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DNP3dkn9c84v2YoNwx7KTg
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d288bedf26
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Round-2 review fixes, extending the revision contract until no path can freeze or overwrite content nobody saw: The workspace serializes autosaves into one chain — an edit made while a request is in flight marks the chain dirty and re-sends the latest state with the returned revision, so overlapping requests never race each other into a false conflict that reloads away newer local edits. Submission now carries the revision the submitter viewed, rechecked atomically in the submit transaction beside the ownership recheck that transfer also gained: a raced transfer cannot let a former owner act, and a concurrent save is a typed stale refusal with a visible reload, never a snapshot frozen sight unseen. Anchored scales wider than a usable select render a bounded numeric input instead of enumerating the whole configured range. Refs #28. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DNP3dkn9c84v2YoNwx7KTg
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: da22444293
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…bric Round-3 review fixes: Draft write paths (create, save, transfer, submit) now begin immediate write transactions via storage::write_tx — the write lock is taken up front, so every check-then-write validates against the committed state and a concurrent writer waits out the busy timeout instead of failing its read snapshot. Typed refusals stay typed under real concurrency: a racing save resolves as stale_save, a racing create as draft_already_exists, a racing cancel as session_cancelled. This is the immediate-write-reservation direction #27 weighs, adopted for the new draft paths; retrofitting the earlier deferred paths stays with #27. Creation rereads the session inside its transaction and migration 0008 adds the database backstop: a cancelled session takes no coverage, so the typed refusal cannot be raced past even by raw writes. The workspace now presents the agency's pinned rubric: each rated row carries a collapsible scale guide rendering the anchor definitions the skeleton already served, for numeric and pass/fail scales alike. Refs #28. Refs #27. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DNP3dkn9c84v2YoNwx7KTg
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 98b64e038a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…cels Round-4 review fixes: The workspace read is now one database snapshot: detail, form skeleton, and working copy assemble in a single read transaction, so the returned revision answers for exactly the content beside it — a concurrent save moves the whole view or none of it, and the client's next save can no longer be poisoned by a torn read. A documented session cannot become one that never happened: cancelling a covered session is a typed refusal at the service, a trigger at the database, and the interface withholds Cancel once a draft exists — interrupted and completed remain the honest closes for worked sessions. The save chain keeps its metadata refresh inside the loop, so an edit made while any await is outstanding marks the chain dirty and re-runs the save; nothing typed during a refresh is dropped from the copy a later submission freezes. Refs #28. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DNP3dkn9c84v2YoNwx7KTg
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b06421faf9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Primary Issue
Closes #28
Refs #22
Problem And Outcome
Milestone 3 slice 3:
EvaluationRecordas a collaborative daily draft, on the session substrate from #26. After merge: trainers document a training session together in one mutable working copy typed by the pinned form, with metadata-only attribution from the first keystroke — so collaborative documentation never has an unattributed era — and submission produces the snapshot the slice-4 review anchors to.Changes
0008_drafts.sql:evaluation_record(enrollment, stamped version = the covered session's stamp, pinneddaily_reportform held by composite foreign key — invariant 5 — and a current owner),evaluation_sessioncoverage join (many-to-many schema; the database holds each covered session to the record's own enrollment and version; one-daily-draft-per-session is v1 policy in the service, per ADR 0008 deliberately not schema), append-onlycontributor_eventcarrying the full closed kind set (created, contributed, ownership_transferred, submitted_for_review, review_decided — the last written by slice 4), the working-copy tables (draft_rating,draft_rating_modifier,draft_narrative) with composite foreign keys to the pinned vocabulary, submitted-freeze triggers on all three, event-mediated owner updates (the 0006 version-change pattern), and append-onlydraft_snapshot(reasons: submission, change_request_return)evaluation_drafts(record lifecycle — creation with form resolution, gates per Milestone 3 design: sessions, drafts, and attribution (owner decisions needed) #22 decision 2:assign_training, orauthor_evaluationwith an active assignment or covered-session membership; event-mediated transfer with a recipient notice; submission with its full-content snapshot; workflow status derived from the stream, never stored),draft_content(the working copy: pinned form skeleton, full-replacement saves validated against scale kinds — anchored bounds, pass/fail domain, narrative-only takes no value — and vocabulary ids, with consecutive saves by one contributor coalescing into one contributed event per working stretch),drafts_http(handlers and refusal mapping)draft_created/draft_ownership_transferred/draft_submittedwithSubject::Record; contributed saves stay in the contributor stream, not the audit log; notice kinddraft_ownership_receiveddraft_id(fan-out-safe scalar subselect), so the interface routes session → draft/drafts/[id]workspace — the pinned form rendered by scale kind (anchor selects, pass/fail, narrative-only), modifiers, narrative prompts, debounced autosave with visible save state, the attribution stream, transfer and submit for the owner or a coordinator, frozen presentation once submitted; entry from the enrollment sessions panel and My sessionstests/evaluation_drafts.rs— create gates, cancelled-session refusal, one-per-session policy, form resolution (none/several/named/wrong-type), scale-kind validation per kind plus foreign-vocabulary refusals and the composite-FK backstop, coalescing with interleaved contributors, append-only streams, event-mediated transfer with notice and audit asserts, submission snapshot content, service and database freeze, API round trip;web/e2e/drafts.spec.tsdrives create → collaborate → transfer → submit in a real browserScope
Verification
Review And Merge Notes
draft_content::save, and the eligibility rule for transfer recipients🤖 Generated with Claude Code
https://claude.ai/code/session_01DNP3dkn9c84v2YoNwx7KTg
Generated by Claude Code