feat(session): load created sessions without rechecking publication - #109
feat(session): load created sessions without rechecking publication#109cursor[bot] wants to merge 31 commits into
Conversation
Store participant and published-release identity for SessionState::Created with exact replay and fail-closed rebinding. Command-replay persistence stays outside this first slice.
Assert the Database error message and source, and fail the replay SELECT after ON CONFLICT by redirecting search_path so classify runs instead of the insert.
Linux llvm-cov leaves the isolated query_one ? tail uncovered unless the Err arm is an explicit match. Keep the search_path redirect test.
Linux branch coverage missed the later AND operands of exact-replay classification. Rebind each stored field independently, and prove a domain-legal u64::MAX creation time fails closed as ValueOutOfRange.
The replay SELECT failure constructed Database evidence without checking its safe display text or source, leaving those two production lines uncovered on Linux.
SHOW transaction_isolation can fail after the caller transaction is already aborted. Persist must surface that as a typed database error instead of leaving the probe Result uncovered.
Satisfy clippy::manual_let_else in the library test that instantiates AssessmentSessionPersistenceError::Database.
Name instrument_version_ref in the public persist contract and assert the committed version column. Keep TRACEABILITY, changelog, and as-built schema at Active PR #61 rather than promoting the slice to protected-main truth. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Restore persisted created-session identity from PostgreSQL without asking whether the original release still accepts new sessions, so later suspend or retire cannot rewrite provenance. Missing rows return none; later stored states and malformed lookup references fail closed. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Name the opened successor so TRACEABILITY, as-built schema, and ERD point at the persist-and-load head instead of the persist-only #106 slice. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
There was a problem hiding this comment.
Stale comment
Review (
ff82de8)Created-session persist/load is correct for this slice.
AssessmentSession::from_persisted_creatednever takes anInstrumentReleaseand never callsaccepts_new_sessions().load_assessment_sessionreconstitutes through that constructor. Persist stays Created-only, exact replay, fail-closed rebinding. Docs stay Active PR, not Implemented.No blocking resume-correctness defect on this head. A stored Created row can be loaded after the live release is suspended or retired. Missing rows return
None. Later stored states and numeric-like lookup refs fail closed.Do not self-approve or merge until exact-head checks and independent last-push approval land. Prefer this head over persist-only #106 and #61. Do not land draft #100 over
0014.Non-blocking follow-ups on this slice:
AS_BUILT_SCHEMA.mdtable still cites predecessor #61 while the body/TRACEABILITY/ERD cite #109.- Headline invariant is not yet proven in one test: persist while published → suspend/retire →
AssessmentSession::newisInstrumentReleaseUnavailable→ load/from_persisted_createdstill returns the original Created identity andActivatestill works.from_persisted_createdInvalidReferenceis only asserted forsession_ref; participant/release/version numeric-like cases are missing.- Load
query_optdatabase failure is untested (persist has the analogous case).HTTP session start must keep using
AssessmentSession::new(publication + locale gate). Reconstitution is load-only. Next buyer-facing gap after this lands is HTTP session-creation (needs #87 RFC 9457) or later-state/command-history persist so Activate/Resume survives restart.Sent by Cursor Automation: Fix Issues
There was a problem hiding this comment.
Stale comment
Review outcome
COMMENT on head
ff82de8d6d7763a4a6be54a36251a22ce05f9584(this automation cannot REQUEST_CHANGES on its own PR).The load design is sound.
AssessmentSession::from_persisted_createddoes not take a liveInstrumentReleaseand never callsaccepts_new_sessions(). Persist stays Created-only, exact-replay, fail-closed rebinding. Missing load returns none; later stored states and numeric-like lookups fail closed. Docs stay Active PR, not Implemented.Do not merge this head. Production error arms this slice added are untested, and the 100% owned-production line/branch gate will fail.
Must-fix before land
- Load
query_optDatabasearm is uncovered. Persist already covers missing-table failure on insert. Drop the relation or abort the transaction, callload_assessment_session, and assertDatabase(_).from_persisted_createdInvalidReferenceis only tested forsession_ref. Add three cases with a numeric-like value in the participant, release, and version slots.- Load
InvalidStoredIdentityis untested. Persist a created row, weaken one identity CHECK, corrupt that column, and assertInvalidStoredIdentity.- Load
ValueOutOfRangeis untested. Drop the timestamp CHECK, store-1, and assertValueOutOfRange.docs/architecture/AS_BUILT_SCHEMA.mdstill names Active PR #61. Point that table cell at #109.#109 is a strict superset of persist-only #106. Prefer this over #106 and #61 after those holes. Do not land draft #100 (
0020) over this0014slice. Independent last-push approval is still required.Sent by Cursor Automation: Fix Issues
There was a problem hiding this comment.
Stale comment
Review (PR #109 @
ff82de8)No security fail-open, tenant leak, IDOR, or publication-bypass in the load path.
from_persisted_createddoes not callaccepts_new_sessions(). Missing rows return none; later stored states and numeric-like lookup refs fail closed. Persist stays Created-only with exact replay. TRACEABILITY says Active PR, not Implemented.This head is not merge-ready. Required 100% owned line/branch coverage does not take the load
query_opterror arm, the laterfrom_persisted_createdreference?tails, or load-pathInvalidStoredIdentity/ValueOutOfRange. The as-built physical-schema table still names persist-only #61.Prefer the successor branch that covers those arms and retargets the as-built table to #109. Do not land #106, #61, or draft #100 (
0020) over this slice.HTTP start must keep using
AssessmentSession::new(live published release). HTTP resume must not treatload_assessment_session(session_ref)as authorization. Independent last-push approval and exact-head checks are still required after the coverage and as-built pointer land.Sent by Cursor Automation: Fix Issues
Point TRACEABILITY, as-built schema, and ERD at the successor that stores assessment_session_command and replays Activate after restart. Keep #109 named as the persist-and-load predecessor. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Processing consumption rows now require claim_deadline_at after #81. Seed the wall-clock deadline and prove binary restore preserves it.
|
Exact-head RCA: Runtime CI would fail at |
There was a problem hiding this comment.
Review (PR #109 @ d6b284c vs a763735)
d6b284c is the right recovery RCA. After #81/0019, a processing consumption row must carry claim_deadline_at. The seed now writes a wall-clock deadline and the restore assertion compares source and restored timestamps exactly. That is the buyer-visible backup contract: a claimed inbox item must come back with the same database-authoritative deadline, not a rewritten clock.
The session load path is still sound and still not merge-ready.
Sound
from_persisted_creatednever takes a liveInstrumentReleaseand never callsaccepts_new_sessions(). A later suspend or retire cannot rewrite stored provenance.- Persist stays Created-only, exact replay, fail-closed rebinding.
- Missing row → none. Later stored state →
UnsupportedStoredState. Numeric-like lookup →InvalidReference. - TRACEABILITY, CHANGELOG, ERD, and ADR-0005 stay Active PR, not Implemented.
Still blocking this head
The four ff82de8 findings are unchanged. Required 100% owned line/branch coverage does not take the load query_opt error arm, load-path InvalidStoredIdentity / ValueOutOfRange, or the later from_persisted_created reference ? tails. The as-built table still names persist-only #61.
ValueOutOfRange in session_persist_requires_read_committed_and_surfaces_database_failure is persist-only (u64::MAX insert). Display-only construction of the load variants does not cover those production lines.
What to do next
Do not land #109, persist-only #106, #61, coverage-only #121, or draft #100. Prefer #164 for Created persist/load/start-from-stored-release. Later-state lock remains #154. HTTP start remains #87 + #149 after #164. Do not add routes here.
HTTP start must keep using AssessmentSession::new (live published release). HTTP resume must not treat load_assessment_session(session_ref) as authorization. Independent last-push approval and exact-head checks are still required after coverage and the as-built pointer land. Do not update this branch for those fixes; they already exist on the successor.
Sent by Cursor Automation: Fix Issues
| &[&session_ref], | ||
| ) { | ||
| Ok(row) => row, | ||
| Err(error) => return Err(AssessmentSessionPersistenceError::from(error)), |
There was a problem hiding this comment.
This query_opt Err arm is still production code that this head never takes. Persist missing-table is covered; load after DROP TABLE is not. Required line-coverage CI will fail this line. Add a realistic load-path database failure and assert AssessmentSessionPersistenceError::Database plus the safe display/source contract. Covered on successor #164 / #121. Do not patch it on this branch.
| created_at_unix_ms, | ||
| ) | ||
| .map(Some) | ||
| .map_err(|_| AssessmentSessionPersistenceError::InvalidStoredIdentity) |
There was a problem hiding this comment.
Buyer resume/start HTTP will hit this reconstitution mapping. Tests still never produce InvalidStoredIdentity from load_assessment_session, and never produce load ValueOutOfRange. The persist-path u64::MAX case does not cover these lines. CHECK (created_at_unix_ms > 0) makes the negative-timestamp arm unreachable unless a test drops the constraint. Cover a CHECK-passing or constraint-dropped corrupt row, or delete the unreachable arm so 100% branch coverage is honest. Covered on the successor. Do not patch it here.
| ) -> Result<Self, SessionReconstitutionError> { | ||
| let session_ref = normalized_reference(session_ref) | ||
| .ok_or(SessionReconstitutionError::InvalidReference)?; | ||
| let participant_ref = normalized_reference(participant_ref) |
There was a problem hiding this comment.
from_persisted_created is the HTTP resume reconstitution gate. tests/session_persisted_identity.rs on this head still only fails session_ref ("12345"). These later normalized_reference(...).ok_or(InvalidReference)? arms never return None. This repository has already failed Linux llvm-cov on isolated ? tails. Add independent invalid participant_ref, instrument_release_ref, and instrument_version_ref cases (numeric-like and blank). Covered on the successor. Do not patch it here.
| | `scoring_job_state` | scoring | Implemented subset | | ||
| | `instrument_release` | instrument publication | Implemented subset | | ||
| | `integration_consumption` | integration | **Active PR** #58 (not protected-main truth) | | ||
| | `assessment_session` | session | **Active PR** #61 (not protected-main truth) | |
There was a problem hiding this comment.
This table still says Active PR #61. The section immediately below, TRACEABILITY, and ERD name Active PR #109. #61 is the persist-only predecessor and must not be the as-built pointer for this persist-and-load head. Change the table cell to #109. Do not mark Implemented. Fixed on successor #164. Do not patch it here.
| const VERSION_REF: &str = "instrument_version_big_five_ko_v1"; | ||
|
|
||
| #[test] | ||
| fn persisted_created_identity_restores_without_a_live_release() { |
There was a problem hiding this comment.
This reconstitutes without a live release, so it never shows that AssessmentSession::new would now fail. Add the headline buyer case: create while published → suspend or retire → new returns InstrumentReleaseUnavailable → from_persisted_created still restores the original Created identity and Activate still works. Prefer that proof on #164 rather than this branch.
| ) | ||
| .expect("restored claim-deadline evidence should remain comparable") | ||
| .get(0); | ||
| assert!( |
There was a problem hiding this comment.
This is the correct #81/0019 contract. A processing row must keep the same claim_deadline_at after binary COPY restore, not a regenerated clock_timestamp(). Keep this exact-equality assertion; do not weaken it back to IS NOT NULL only.


Superseded by repaired durable-session line
Close this predecessor without merge. Its Created-session persist/load contract and the later coverage/error-path fixes have been carried through the repaired command-history/start lineage into #232; its one branch-only recovery delta is isolated on #177.
Fresh evidence immediately before closure:
d6b284cad9596179fda6f00c0fa855f6a0982a5cc7b45145c9b693951fae498e0779d58cbe170f868a0db4611a684285185f9edadf086a1808444ab9main:a7637351be8f0f90c12651d3bcafd959bc52ac81Current #109 review says the core load design is sound but this exact head remains non-mergeable because required load error/reference branches and the as-built pointer are incomplete; later review explicitly directs Created persist/load/start to a successor rather than updating #109. The session lineage subsequently passed through #125 and the stale-shorter-history repair #129; fresh ancestry proves current #232 is directly ahead of #129 and therefore carries that corrected persist/load/command-history foundation plus stored-release start locking and public start/reload HTTP.
A fresh #109↔#232 comparison shows the only #109-side commit delta absent from #232 is
tests/postgres_recovery_invariants.rs(27 additions / 3 deletions), theclaim_deadline_atCOPY/restore concern already isolated on #177.Do not reinterpret #109's review findings as fixed on this head; they remain evidence for closure. #232 and #177 remain Active PR work and must satisfy their own unchanged exact-head CI/security/review gates before merge.