Skip to content

signoffs(read): let a trainee read their own complete history - #68

Merged
TusanHomichi merged 1 commit into
mainfrom
codex/49-trainee-signoff-history
Sep 12, 2026
Merged

TusanHomichi merged 1 commit into
mainfrom
codex/49-trainee-signoff-history

Conversation

@TusanHomichi

Copy link
Copy Markdown
Member

Primary Issue

Closes #49

Problem And Outcome

task_signoffs::matrix projects the enrollment's currently pinned program version and is gated by the training-history rule, so a trainee holding view_own_records could not read the signoffs recorded about them at all — and the interface disagreed with the trainee packet that already carries that history.

task_signoffs::history is a new typed, service-owned read: every retained signoff row, in recorded order within its task, with the closed kind, the recorded reason, the signer's identity and stored name snapshot, and the recorded instant, plus each task's program version and whether it is the current pin. It admits the readers lifecycle::may_read already admits, plus the trainee on their own enrollment with view_own_records; it does not widen that rule and grants no write. My records gains a read-only presentation.

Changes

  • crates/consolebook-server/src/task_signoffs.rshistory and its rows; matrix and record are unchanged, including their gates.
  • crates/consolebook-server/src/training_http.rsGET /api/enrollments/{id}/signoff-history, beside the unchanged matrix route.
  • crates/consolebook-server/tests/signoff_history.rs — 10 tests.
  • web/src/lib/api/signoffs.ts, web/src/lib/signoffs/SignoffHistoryPanel.svelte, web/src/routes/records/+page.svelte — the typed client and the read-only section on My records: current state per task, the full retained chain behind an accessible disclosure, and earlier program versions in their own labelled section. No recording, override, revoke, or contest control.
  • docs/decisions/0021-trainee-signoff-history-read.md — the read contract, its epoch limit, and the rejected alternatives.
  • docs/development.md, web/e2e/signoff-history.spec.ts.

Scope

  • In scope: the trainee's read of their own enrollment's signoff history and its presentation; the HTTP read route.
  • Out of scope: any change to matrix, to record, or to any recording authority; schema changes (none); epoch reconstruction, which stays the enrollment event stream's job.

Verification

  • Listed the exact verification commands run below
  • Added or updated tests when behavior changed
  • Added or updated an ADR when a durable decision changed
  • All fixtures and examples are invented; no real agency data
- web/: npm ci, npm run check (0 errors, 0 warnings), npm run build
- cargo fmt --check
- cargo clippy --workspace --all-targets -- -D warnings
- cargo test --workspace — all green; tests/signoff_history.rs 10 passed
- cargo build -p consolebook-server
- web/: npm run e2e (system Chromium at /usr/bin/google-chrome; CI uses Playwright's bundled chromium)
  → 10 passed, including signoff-history.spec.ts

The suite covers: the trainee's own enrollment allowed and another trainee denied; the trainee's own view_own_records grant revoked and their own enrollment refused (the case an identity-only rule would pass); assigned trainer, coordinator, and explicit administrator readers unchanged; an unassigned trainer denied; trainee writes still refused; observed/demonstrated/revoked histories with reasons; the stored name snapshot surviving a rename; same-second ordering by row identity; per-task recorded order and grouping; a version change and a real re-pin of a prior version with both epochs readable; the bound to this enrollment's own pinned vocabularies; a genuine one-connection pool; and row-for-row agreement with the packet's own signoff document.

Review And Merge Notes

  • Review focus: the authorization line (trainee identity and view_own_records, on the read's own connection inside its transaction) and the stated epoch semantics in ADR 0021.
  • User or operator impact: a trainee can finally read what was signed off about them without downloading and unzipping a packet; nothing about recording moves.

`task_signoffs::matrix` projects the currently pinned version's tasks and
is gated by the training-history rule, so a trainee holding
`view_own_records` could not read the signoffs recorded about them, and
the interface disagreed with the trainee packet that already carries the
full history (#49).

`task_signoffs::history` is a separate typed, service-owned read: driven
by the append-only rows themselves, it reports every retained signoff in
recorded order within its task, with kind, reason, signer identity, and
the stored name snapshot, plus each task's program version so a version
change leaves prior signoffs discoverable and labelled rather than hidden.
It admits the readers `lifecycle::may_read` admits, and the trainee on
their own enrollment with `view_own_records`; it does not widen that rule
and grants no write, so `matrix` and every recording rule are unchanged.

The client contract lives in `web/src/lib/api/signoffs.ts` and the
read-only presentation in `web/src/lib/signoffs/`, reachable from My
records. Proof: `tests/signoff_history.rs` covers the authorization line
including the trainee's own revoked grant, observed/demonstrated/revoked
histories, stored-name stability, same-second and per-task recorded
order, version changes and a real re-pin of a prior version, the bound to
this enrollment's own pinned vocabularies, a genuine one-connection pool,
and agreement with the packet's own signoff document row for row;
`web/e2e/signoff-history.spec.ts` shows the trainee's real full history,
that another trainee holding the same grant is refused, and that no write
control appears. ADR 0021 records the contract and its epoch limit.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 12, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-12T00:35:21.876696Z ea2cea7 PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@TusanHomichi TusanHomichi left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Source review at ea2cea7: no blocking finding identified in this slice. I inspected the service and HTTP changes, typed client, read-only presentation, ADR 0021, and the new service/browser tests. The new read admits existing history readers or the enrollment's own trainee with view_own_records; authorization and data use the same read transaction/connection. The existing matrix and record paths are unchanged. Retained earlier-version rows remain discoverable, signer names come from stored snapshots, and re-pinning behavior is explicitly documented and tested rather than silently reinterpreted.

GitHub pr-gate run 34661988482 is successful; its web install/check/build, fmt, Clippy, Rust tests, explicit binary build, browser install, and browser tests all completed successfully. There are no inline review threads on this PR at review time. I did not execute Rust or browser tests independently in this review environment; this is source/test review plus verification of GitHub's CI evidence.

This PR can merge independently of #67 and #69. Those two still require their own corrections and revalidation. #59 is not closed by this review.

@TusanHomichi
TusanHomichi merged commit 7936a4e into main Sep 12, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Trainees cannot view their own task signoff history in the web interface

1 participant