Skip to content

feat(session): map POST /v1/sessions and lock command persist - #161

Closed
cursor[bot] wants to merge 37 commits into
mainfrom
cursor/bc-76da0667-1769-4fe5-bf68-fac2db1d9af1-d8e3
Closed

feat(session): map POST /v1/sessions and lock command persist#161
cursor[bot] wants to merge 37 commits into
mainfrom
cursor/bc-76da0667-1769-4fe5-bf68-fac2db1d9af1-d8e3

Conversation

@cursor

@cursor cursor Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Why

A buyer still cannot start an anonymous assessment over the public contract. Persist/load (#129) and the sequential stale-prefix reject are not enough: unpublished or locale-mismatched starts have no RFC 9457 mapping, and a concurrent Activate-only worker can still rewind Pause/Resume under READ COMMITTED.

What this PR does

Out of scope

Test plan

  • cargo test --test session_http_create --test session_http_openapi_contract --test api_problem_details_contract
  • cargo test --test session_persisted_identity --test session_aggregate_lifecycle --test session_state --test session_release_binding --test documentation_architecture_contract --test traceability_active_pr_contract
  • cargo clippy --all-targets -- -D warnings
  • cargo test --test postgres_assessment_session_persistence (needs TEST_DATABASE_URL)

Prefer this head over #146, #129, #125, #121, #109, persist-only #106, and #61. Do not merge until exact-head checks and independent last-push approval are satisfied.

Open in Web View Automation 

seonghobae and others added 30 commits August 14, 2026 10:46
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.
Treat landed PostgreSQL readiness as Implemented and keep #61 as the
Active created-session persist slice.
Treat landed migration rollback coverage as Implemented and keep #61
as the Active persist slice.
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>
cursoragent and others added 6 commits August 16, 2026 15:33
Add the headline reconstitution case: create while published, then
suspend or retire so AssessmentSession::new fails, then restore the
original Created identity and Activate. Cover numeric-like participant,
release, and version references. Point AS_BUILT_SCHEMA at Active PR #109
instead of predecessor #61. Fail closed on every later stored state and
on load against a missing table.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Store accepted session commands in assessment_session_command and
project the current lifecycle state. Load reconstitutes created
identity without re-checking publication eligibility, then replays
commands so Pause/Resume still work after process restart. Exact
command replay is idempotent; sequence reuse and evidence rebinding
fail closed. Later stored states without command history still fail
closed.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
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>
A worker that only remembers Activate must not rewind a later Pause/Resume
projection. Count stored commands after exact replay and fail closed when
the in-memory history is shorter, so load still reconstitutes the paused
session after the rejected persist.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Point traceability, as-built schema, and ERD at the successor that
rejects a shorter command history instead of rewinding Pause/Resume.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
A buyer can start a created session from a published release or receive
a reviewed RFC 9457 problem. The as-built OpenAPI document lists only
this operation. Command persist locks the session header so a concurrent
Activate-only worker cannot rewind Pause/Resume.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
@cursor
cursor Bot requested a review from seonghobae August 16, 2026 16:05
Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Stale comment

Queue

This head combines #129 persist, the header-row FOR UPDATE lock, a transport-neutral POST /v1/sessions mapping, and an as-built OpenAPI document for that one operation. Sequential stale-prefix and the lock placement are real. It does not include a live HTTP listener, GET /v1/sessions/{session_ref}, or Idempotency-Key replay.

Prefer #149 for the buyer-facing HTTP listener (POST + GET, idempotency key, OpenAPI). Prefer #154 for the persist header lock. Do not merge this combined stack in parallel with those heads. Do not APPROVE.

Next composition after those land: persist-backed HTTP create/reload, not a fourth overlapping mapping PR.

View PR

Open in Web View Automation 

Sent by Cursor Automation: Fix Issues

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Review (exact head eefbb62)

The header-row SELECT … FOR UPDATE before command insert/count is the right READ COMMITTED fence: a concurrent Activate-only persist cannot count a prefix and then rewind Pause/Resume. Sequential stale-prefix rejection is also real.

This head is still the wrong landing vehicle.

  • Prefer #154 for the persist lock. Prefer #149 for the buyer-facing HTTP listener (POST + GET, server-minted refs, Idempotency-Key, OpenAPI).
  • This mapping is transport-neutral only. A buyer still cannot send bytes to POST /v1/sessions.
  • CreateSessionHttpRequest::created_at_unix_ms is caller-supplied while the accessor and problem text call it server-issued. Keep the clock on the adapter.
  • session_ref is caller-supplied. Hosted bind should mint an opaque capability URL, as #149 does.

Do not merge this combined stack in parallel with #149 or #154. Do not APPROVE from this automation. Next composition after those land: persist-backed HTTP create/reload, not a fourth overlapping mapping PR.

Independent next buyer gap (off this branch): persist response_event so in-progress answers survive restart. Snapshot persist/reload only helps after completion.

Open in Web View Automation 

Sent by Cursor Automation: Fix Issues

Copy link
Copy Markdown
Contributor

Closing as superseded, not merged. #232 is the current session HTTP landing and explicitly replaces this older-persist route: it keeps the command-history/start-lock path, adds the later first-insert seal and exact replay behavior, and exposes durable POST/GET session operations with OpenAPI on that sealed store. Fresh comparison shows #232 carries the same session HTTP surface plus the newer persistence/start invariants. Keeping #161 open would preserve an older competing write path.

@seonghobae seonghobae closed this Aug 16, 2026
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.

2 participants