Repository navigation
test(people): prove Assignment Employment/Position conflict serialization with real PostgreSQL interleavings #272
Description
Current gap
This issue remains the real-PostgreSQL concurrency acceptance owner for Assignment. Its original causal model is now stale and must be repaired rather than closed.
On 2026-09-07, #271 correctly invalidated a redundant Assignment employment_record lock because every valid Assignment then crossed the current candidate_worker_conversion_record FOR UPDATE boundary first. #271 explicitly left a future condition: if an Employment lifecycle path can affect Assignment eligibility without crossing that converted-worker boundary, a new executable concurrency contract is required before changing the root lock.
That condition now exists on active People owner #64:
- generic Employment creation no longer treats recruiting conversion provenance as mutation authority and serializes on the stable Person root;
candidate_worker_conversion_recordis hire-origin provenance bound to a particular resulting Employment, not generic staffing authority;- migration
0017_assignment_employment_separation_serialization.sqlalready makes Employment the shared Assignment/separation conflict root and re-reads Employment coverage after the lock wait; - current Assignment production repair removes generic
_CONVERSION_SQLauthority and locks the named tenant-local Employment before reading Employment versions, then locks Position before reading the allocation portfolio.
Therefore the canonical conflict domains are now Employment aggregate + Position seat, not converted-worker provenance + Position.
Required executable acceptance
Use two independent real PostgreSQL connections against the repository migration stack and the production PostgresPeopleMutationPort. Synthetic structural rows are permitted only as transaction/lock mechanism fixtures.
- Same Employment/Person, different Positions, different idempotency keys: writer B must be observed in
pg_stat_activity/pg_blocking_pids(...)waiting on writer A's Employment row conflict boundary. After A commits0.7500, B must take a fresh READ COMMITTED Employment/Assignment snapshot and fail because the Employment allocation would exceed1.0000. - Different Employments/People, same Position: writer B must wait on the Position root and fail after A commits because visible seat allocation would exceed
1.0000. - A Person/Employment created without any candidate-worker conversion must still be assignable when Employment/Position truth, authorization, confirmation, and evidence are otherwise valid. Historical recruiting conversion must not be needed to make the concurrency test pass.
- Assignment vs Employment separation must use the same Employment root and preserve both commit orders already owned by migration 0017 / its PostgreSQL contract.
- Assert accepted/rejected results, final Assignment rows, audit/outbox/idempotency atomicity, exact blocker identity, client/server cleanup, and no durable loser residue.
Correctness ordering must come from PostgreSQL-visible locks/barriers, not timing-only sleeps. Keep READ COMMITTED. Do not use broad table locks, retry-as-correctness loops, sample reduction, synthetic verdicts, or direct provider/gate bypasses.
Cleanup acceptance
Failure-path cleanup remains part of this issue. Every started writer must quiesce before PostgreSQL teardown. Bounded join expiry is not proof of cleanup: terminate only the verified owned backend using captured PID + internal application_name, require exact one-session successful termination, then re-join with a bounded deadline and fail closed if the writer remains live.
Existing evidence to preserve
The historical libpq two-session harness and cleanup repair sequence remains valid evidence about the harness mechanics; do not discard it. However names/assertions that still describe the Employment conflict as converted_worker are now stale and must be ordinary-forward currentized to Employment-root semantics. Predecessor GREEN cannot be transferred to a head after this causal change.
Canonical source owner is #64 (or its normally integrated verified successor). Canonical PostgreSQL discovery/execution owner is #311 after its prerequisite stack integrates. Do not copy mutable #64 source into another writer or add another feature-local quality workflow.
Completion
Keep this issue open until an exact-head hosted PostgreSQL run proves both current conflict domains on the repaired production adapter, including the no-candidate-conversion Assignment case and failure cleanup, and the result is adopted through the protected owner path. Commercial/scientific claims still require right-cleared real data; synthetic concurrency fixtures are mechanism evidence only.
Activity
seonghobae commentedon Sep 7, 2026
#272 executable acceptance remains owned by #64. Fresh review of the first implementation head
fb28b01915cd8bf233260cfa3c4b562879f9ff7bfound two harness-only defects: an unusedpytestimport and_run_writercatchingBaseException. Both are valid findings because the module uses no pytest API directly, and a test worker must not swallow interpreter control-flow exceptions.Ordinary forward
015ba7ce98da5a3100194ec9e3389df8b0cedb5eremoves the unused import, narrows captured worker failures and_WriterOutcome.errortoException, and changes no production adapter/locking semantics. Exact compare from the implementation head is 1 commit ahead / 0 behind and only this acceptance file changes (+2/-4). Both inline review threads were replied to and resolved.Fresh exact-head workflows are Foundation
34106650398, Security34106650296, SAST34106650302, and CodeQL34106650323; all are currently non-terminal. Keep #272 open until Foundation executes the real two-session PostgreSQL interleavings on this exact head and the required hosted evidence is terminal.seonghobae commentedon Sep 7, 2026
Fresh acceptance audit found a separate evidence-classification defect after the harness review repair. The current PostgreSQL interleaving test constructs deterministic UUIDs and inserts its own Person/Employment/Position/Candidate/Decision rows; no repository provenance proving those rows are real/right-cleared data exists. That means the test is valid database serialization integration evidence, but it does not yet satisfy this issue's own real/right-cleared acceptance criterion and must not be represented as buyer/scientific reality evidence.
Ordinary forward
1ea5cb1dcc887cf5b83fa85f926228e146f09d3fmakes the source truthful without weakening the test: the module now states that its structural records are deterministic synthetic fixtures, the seed helper no longer calls them right-cleared, and the seeded decision reason is classified as an integration fixture. No lock, SQL path, authorization, idempotency, audit/outbox, barrier, assertion, allocation sample, or production source changed. Exact compare from015ba7ce...is 1 commit ahead / 0 behind and only this test file changes (+7/-3).#272 therefore remains open with two distinct evidence layers: (1) run the current two-session PostgreSQL integration contract on the exact head to prove lock/wait/visibility/atomicity mechanics; (2) before calling the requirement complete, add provenance-backed real/right-cleared Assignment data or an approved right-cleared fixture source through the canonical owner path and rerun the relevant behavioral acceptance. Do not fabricate provenance or relabel synthetic rows as right-cleared.
Fresh workflows for
1ea5cb1d...are Foundation34107536416, Security34107536442, SAST34107536438, and CodeQL34107536387; all are currently non-terminal.seonghobae commentedon Sep 7, 2026
Current exact-head gate classification for the implemented mechanism evidence: #64
818950960c4fe0a4e7b026bd5499fe9cca1002behas Foundation34131641452terminal SUCCESS and SAST34131642172terminal SUCCESS. Security34131642055is terminal FAILURE only at central Dependency Review support (.github#810); CodeQL34131641597remains queued. The Foundation success is the relevant executable evidence for this issue: it ran the full People test tree underORGMETRA_POSTGRES_IMAGE, including both real two-session interleavings and forced post-lock cleanup/timeout paths. Therefore PostgreSQL mechanism/integration acceptance stays GREEN on this immutable head; no Security/CodeQL result is being reinterpreted as mechanism evidence. Commercial/scientific realism remains unresolved until a permitted provenance-backed real/right-cleared source exists.seonghobae commentedon Sep 7, 2026
Current exact-head evidence supersedes the issue body's stale non-terminal gate sentence. Canonical #64 remains
818950960c4fe0a4e7b026bd5499fe9cca1002be; Foundation34131641452is terminal SUCCESS and materially executes the People suite containing both real PostgreSQL concurrency modules, while SAST34131642172is terminal SUCCESS. Security34131642055is terminal FAILURE only at the shared Dependency Review support probe (.github#810), and CodeQL34131641597is terminal FAILURE in the central current-head verdict ordering/publication path (.github#1929). Those control-plane failures do not reclassify the PostgreSQL mechanism tier as RED.The mechanism/integration tier is therefore current-head hosted GREEN. Keep #272 open solely for the explicitly separate commercial/scientific realism tier until a provenance-backed, permitted real/right-cleared data source exists and is executed without weakening the synthetic-vs-real evidence distinction.
seonghobae commentedon Sep 12, 2026
Fresh #64 domain review changes the interpretation of this issue's worker-serialization anchor, not the required concurrency outcome.
The original acceptance correctly requires same Employment/Person Assignment writers to serialize before evaluating the allocation snapshot. However,
candidate_worker_conversion_recordis now verified to be recruiting-origin provenance: its protected composite FK points to an already-existing(Employment, Person)and the confirmed-hire path materializes it from a sealed selection decision. The generic People Employment route allocates a future Employment server-side. Therefore a candidate-conversion row cannot remain the canonical generic People authorization/concurrency anchor merely because it happened to provide a convenient row lock.Current #64 RED
20e29962311b17eb004412cd775dd5ada0ca4cbapins that generic Employment persistence must stop depending on candidate conversion. Any GREEN repair must preserve this issue's real concurrency guarantee with an equivalent People-owned conflict boundary (for example, a tenant+Person transaction lock/root that is independent of recruiting provenance), and Assignment must share that boundary before portfolio snapshot validation. Do not reintroduce the previously invalid redundant Employment lock from #271, and do not widen a recruiting provenance relation into generic worker authority.Accordingly, keep the two-session acceptance and failure-cleanup evidence here. What becomes stale is only the statement that the conversion row is the permanent canonical worker lock. When #64 replaces that coupling, this issue's mechanism test must ordinary-forward to the replacement exact conflict boundary and prove the same accepted/rejected outcomes, lock evidence, audit/outbox/idempotency atomicity, and quiescence.
[-]test(people): prove Assignment conflict serialization with real PostgreSQL interleavings[/-][+]test(people): prove Assignment Employment/Position conflict serialization with real PostgreSQL interleavings[/+]