Skip to content

feat(people): add authoritative bitemporal Employment separation transition #314

Open

Description

@seonghobae

Verified prerequisite gap

Rehire issue #302 requires authoritative evidence that a prior Employment actually ended. Protected develop@eb9757f8649aaad026a9865508d9aad50c1a7a4f does not currently expose a governed People mutation that transitions an existing Employment to separation/termination truth.

The gap is executable, not merely documentary:

  • employment_record_version is bitemporal and protected against in-place business mutation. tests/test_bitemporal_postgres.sh explicitly proves that UPDATE employment_record_version SET employment_status_code = 'terminated' ... must fail with bitemporal correction may only close an open recorded interval.
  • Protected generic PostgresPeopleMutationPort.create_employment(...) only creates a new Employment anchor/version. It does not close/supersede an existing active/leave Employment version.
  • EmploymentMutationCommand accepts employment_status_code='terminated', but creating a new Employment initially marked terminated is not a separation transition of an existing Employment and must not be used as a workaround.
  • PR feat: add governed employment separation review packet #46 is intentionally a pre-mutation Employment separation review packet and explicitly grants no mutation authority.

Without an authoritative transition, #302 cannot safely distinguish “former employee with a completed prior Employment” from “Person who merely has another Employment record or a review packet”.

Owner / DDD boundary

Canonical owner is the existing People/Employment mutation owner (#64 or normally integrated verified successor).

people_core owns the Employment aggregate and its versioned status/effective history. Separation does not move truth into Talent, Document Records, payroll, identity, or a generic workflow context. Downstream systems consume a released/versioned Employment event/receipt; no cross-service application SQL.

A separation review packet (#46) is evidence supplied to the command. It is not the authoritative Employment state itself.

Required domain semantics

Design a governed separation command/result that, at minimum, binds:

  • tenant, Person and exact existing Employment identity;
  • current authoritative Employment version expected by the command;
  • business-effective separation/end date;
  • resulting controlled Employment status (terminated or later accepted vocabulary);
  • accountable actor, purpose, controlled reason, evidence version and human confirmation;
  • opaque reference/digest to reviewed separation evidence where applicable;
  • idempotency identity;
  • immutable audit/outbox evidence and database-owned recorded time.

The mutation must use correction-not-rewrite / supersession semantics: preserve prior recorded history, close the appropriate recorded-visible version at database-owned system time, and insert the successor version representing the changed business truth. Do not overwrite status/effective dates in place.

The exact treatment of effective_to vs a successor terminated version must be decided in an ADR against the existing bitemporal resolution semantics. Do not encode two contradictory sources of “employment ended” truth.

Required RED → GREEN

  1. Active Employment + valid reviewed separation → prior recorded-visible version is preserved/closed and one successor authoritative version represents the separation at the requested business date.
  2. In-place status/effective rewrite remains rejected.
  3. Wrong tenant, wrong Person, wrong Employment, stale expected version, already superseded/closed version, malformed evidence or unauthorized purpose fail before mutation/audit.
  4. Duplicate same-key/same-semantic request deterministically replays the first committed result; same key with changed separation semantics fails closed.
  5. Two concurrent first attempts against one Employment use a minimal Employment-scoped conflict boundary. Real PostgreSQL two-session acceptance must observe actual lock/wait ordering via database state rather than timing-only sleeps; exactly one logical transition wins.
  6. Separation cannot silently mutate or delete Assignment history. If active Assignments require an explicit close/coordination policy, fail closed and route through the released Assignment owner contract rather than cross-table convenience mutation.
  7. Audit/outbox/idempotency/version writes are atomic; rollback leaves no partial separation evidence.
  8. Failure cleanup proves all started client/server sessions quiesce before PostgreSQL teardown.
  9. FORCE RLS/NOBYPASSRLS and purpose-bound authorization remain effective for the new mutation path.
  10. A valid feat: add governed employment separation review packet #46 review packet, by itself, cannot alter Employment truth without this governed application boundary.

Synthetic structural fixtures may prove transaction/version mechanics only. Any buyer/scientific claim requires provenance-backed right-cleared data.

Transaction / operability constraints

  • READ COMMITTED remains the default unless a measured invariant proves otherwise; do not upgrade isolation just to make tests pass.
  • No long-running external workflow, LLM, payroll call, identity deprovisioning, document processing, or notification inside the Employment DB transaction/lock.
  • No broad table lock. Serialize only the Employment aggregate/conflict domain needed for correctness.
  • Use database-owned system time after the relevant conflict boundary, not caller time, for recorded-history authority.
  • Connection cleanup, retry semantics, outbox delivery and recovery must be explicit.
  • PII-minimize provenance: opaque identifiers/digests and governed codes, not free-form termination narratives or copied documents.

Dependency order

This is a prerequisite for #302's default existing Person + new Employment rehire path. It also complements #46 rather than superseding it.

Implement on #64 or its verified successor; do not open a parallel People source writer. After normal People integration, #65/#141 and other descendants non-force adopt protected truth in their existing owner order.

Before integration require code-current ADR/PRD/TRD/DATA_MODEL/ERD/UML/SECURITY/THREAT_MODEL/TEST_STRATEGY/OPERABILITY/TRACEABILITY, People owned 100% production docstring/test/edge coverage, real PostgreSQL acceptance, exact-head canonical gates and qualifying independent review. Keep this issue open until the authoritative mutation reaches protected truth; a review packet or SQL fixture is not completion.

Activity

  1. seonghobae commented on Sep 12, 2026

    @seonghobae
    ContributorAuthor

    Implementation has started on canonical People PR #64 by ordinary-forward commits. Current slice adds database/migrations/0014_employment_separation_transition.sql, Proposed ADR 0015, focused PostgreSQL contract tests/test_employment_separation_postgres.sh, and docs/traceability/employment-separation.md.

    The transition now treats terminated successor + append-only employment_separation_record as the authoritative separation fact. The preceding active/leave continuation's effective_to is only the structural half-open interval boundary. It binds tenant context before advisory locking, exact Person/Employment/expected version, DB-owned post-lock recorded_at, governed actor/purpose/reason/evidence/confirmation, audit/outbox and idempotency in one transaction. It fails closed rather than silently cancelling other future current-known Employment versions or mutating Assignments.

    Self-review found and repaired two causal defects while building the slice: caller-supplied audit time was replaced by a DB-generated envelope using the post-lock clock, and the initial exactly one recorded-current version assumption was removed because a valid bitemporal knowledge state can contain multiple disjoint current-known business intervals. The command now targets the exact expected interval and requires explicit coordination for any other current-known interval overlapping the terminal horizon.

    Runtime completion is deliberately not claimed yet. The focused PostgreSQL contract is handed to #311 for owner-neutral Foundation registration after normal stack reconciliation; ADR 0015 stays Proposed until exact-head hosted PostgreSQL evidence passes.

  2. seonghobae commented on Sep 12, 2026

    @seonghobae
    ContributorAuthor

    Canonical People implementation advanced on #64. Live exact owner head is now fdb33797fde1efc215ab0dcde474ce82e7d27dfd on protected develop@eb9757f8649aaad026a9865508d9aad50c1a7a4f, still Draft · mergeable.

    A fresh acceptance review found that the new SQL-capability contract used one fixed temporary probe role and dropped it only on the normal path. That could leak a PostgreSQL principal after an assertion/connection failure and poison later retries. fdb33797... repairs the contract ordinary-forward with a collision-resistant per-run role, best-effort cleanup on failure, and strict verified cleanup on the success path. Production separation SQL/transaction semantics were not changed by this repair.

    The separation slice itself remains incomplete as product runtime authority: migration 0014/0015, Proposed ADR 0015, traceability, the behavioral PostgreSQL contract, and the capability contract exist, but no current-head hosted PostgreSQL admission or qualifying independent approval is claimed, and the explicit application/service-role invocation boundary still must be completed through the canonical People owner rather than by granting PUBLIC access or introducing a parallel writer. Keep #314 open and ADR 0015 Proposed until that evidence and runtime boundary reach protected truth.

  3. seonghobae commented on Sep 12, 2026

    @seonghobae
    ContributorAuthor

    A second capability review found that #314 was still not safely callable by an application role. 0015 revoked PUBLIC execution but deliberately kept separate_employment_record_once(...) as SECURITY INVOKER. That means any future service principal able to call it would also need the underlying Employment/version/separation/idempotency/audit/outbox DML privileges, creating a direct-SQL bypass around the reviewed transition.

    RED b249c4392c624cff52efbf19c416ced7455d87c5 changed the capability contract to require a dedicated non-login owner, a distinct executor, SECURITY DEFINER ownership, executor-only function capability, and zero direct governed-table DML for the executor. Ordinary-forward 351e489658172aff96d18b4d0aa372590d3deec1 added 0016_employment_separation_executor_capability.sql; a0569d5f7771a9b8ded078ade72076f8758444b4 then exercised the executor boundary and retained the unrelated-role denial/cleanup contract. ADR/traceability are current through 30960c55e4b36e721d282a0880e193188de5162c.

    0016 creates collision-preflighted orgmetra_employment_separation_owner and orgmetra_employment_separation_executor roles. The owner is NOLOGIN/NOBYPASSRLS, owns the fixed-search-path SECURITY DEFINER function and receives only its reviewed People/audit/outbox privileges; temporary schema CREATE exists only for ownership handoff and is revoked before commit. The executor is also NOLOGIN/NOBYPASSRLS and receives schema USAGE + function EXECUTE only. FORCE RLS and the explicit caller tenant-context check remain active.

    Do not mark #314 complete yet. Exact-head hosted PostgreSQL evidence for this new capability model is still pending, and the People application adapter/authorized command path must consume the executor-backed function rather than direct DML before this becomes product-runtime truth.

  4. seonghobae commented on Sep 12, 2026

    @seonghobae
    ContributorAuthor

    Canonical People #64 advanced ordinary-forward after a fresh adapter transaction-boundary review. Live repair lineage for this finding is RED 4ba75c0240edda8417d17c904c8a8131473254d6 → causal fix 1e69528a659ccc0e015537de82fd28c213d58d29 → traceability cd920715c0b3db67223b6bef8df622ca38caca31.

    Finding: PostgresEmploymentSeparationPort previously left the connection context before constructing/validating EmploymentSeparationResult. Under psycopg-style connection context semantics, that makes transaction commit eligible before the adapter checks UUID/time/replay types and employment identity. A malformed or mismatched DB receipt could therefore produce a committed separation followed by an application-only integrity failure. Idempotency makes retry recoverable, but it does not justify deliberately moving a check that can still force rollback to after COMMIT.

    Repair: the adapter now validates the one-row receipt and command Employment identity inside the connection context. The focused unit contract records the connection-context exit exception and requires every malformed/mismatched receipt to exit with EmploymentSeparationIntegrityError; nominal evidence exits cleanly. The SQL transition, lock ordering, RLS/capability model, audit/outbox transaction and idempotency digest are unchanged.

    docs/traceability/employment-separation.md is current through cd920715...; it also corrects the earlier stale statement that OpenAPI publication was still planned. POST /v1/employment-separations and its focused contract are already implemented on the active PR; realistic buyer-path p95/E2E remains pending.

    Do not mark #314 complete from this repair alone. Exact-head hosted PostgreSQL/Foundation/security evidence and qualifying independent review still govern integration, and ADR 0015 remains Proposed until those acceptance boundaries are satisfied.

  5. seonghobae commented on Sep 12, 2026

    @seonghobae
    ContributorAuthor

    Hosted evidence update after the commit-boundary repair: Foundation run 34704050250 on exact cd920715c0b3db67223b6bef8df622ca38caca31 produced a real RED in Run owned unit and service contracts once. Repository validation, dependency hygiene, compile, runner-image contract and all preceding suites passed; People executed 288 tests successfully, but owned coverage fell to 98.42% because the newly added separation_http.py boundary had 32 uncovered statements and uncovered branches. PostgreSQL contracts were correctly skipped after that failure, so no PostgreSQL GREEN is inferred.

    This is a test-coverage/acceptance completeness defect, not a justification to lower fail-under=100. Ordinary successor c8d1c3993ce1eb4e8bdabfe4b666c61eda57fcff adds failure-path coverage for non-HTTP scopes, content-type/actor headers, generic authentication faults and invalid principals, tenant/actor mismatch, oversized/malformed bodies, UUID/date edge cases, not-found/conflict/internal persistence results, and malformed server-generated identities. Current exact-head workflows are running on c8d1c399...; predecessor evidence is not transferred.

  6. seonghobae commented on Sep 12, 2026

    @seonghobae
    ContributorAuthor

    Current implementation/evidence authority advanced on canonical owner #64.

    Exact current #64 head is c8d1c3993ce1eb4e8bdabfe4b666c61eda57fcff on protected develop@eb9757f8649aaad026a9865508d9aad50c1a7a4f. The separation chain now includes the rollback-capable receipt-integrity repair (4ba75c0240edda8417d17c904c8a8131473254d6 RED → 1e69528a659ccc0e015537de82fd28c213d58d29 causal fix), traceability/API currentization cd920715c0b3db67223b6bef8df622ca38caca31, and failure-boundary coverage repair c8d1c3993ce1eb4e8bdabfe4b666c61eda57fcff after the preceding exact-head Foundation run exposed owned People coverage at 98.42%.

    Fresh exact-head acceptance is now stronger than the previous issue comments: Foundation run 34704249108 is terminal SUCCESS on c8d1c399..., including the complete owned unit/service invocation and the repository PostgreSQL contract step; Recovery Rehearsal and SAST are also SUCCESS. The 100% owned coverage gate was not weakened.

    The PR is still not merge-authorized. Security run 34704249168 remains non-passing at central dependency-review support establishment even though OSV/Trivy/Scorecard succeeded. CodeQL run 34704249105 remains non-passing on the central current-head compatibility/dispatch path. Required Strix run 34704247956 / job 103581586116 failed after healthy exact-head admission and gateway preflight when the live orchestrator/free request ended with LLM CONNECTION FAILED / Error: Request timed out after about 1880 s and produced no authoritative vulnerability report. That is central runtime evidence, not a new People-source vulnerability verdict; exact canary evidence has been handed to .github#2000 for request-identity/timeout-provenance RCA and .github#2026 as a genuine incomplete/provider-unavailable typed-evidence fixture. No blind rerun, fallback, or gate weakening was used.

    Qualifying independent approval is still absent, so #64 remains Draft. Keep #314 open until the separation mutation is normally integrated into protected truth and downstream rehire #302 can consume it from that authority. Predecessor GREEN and central repairs must not be transferred onto a later head without fresh evidence.

  7. seonghobae commented on Sep 12, 2026

    @seonghobae
    ContributorAuthor

    Canonical People #64 advanced ordinary-forward to 6f89e6c26a1bf6c66d29c1125d6b7f525a67b4a7 after a fresh buyer-error-boundary review.

    New finding: the prior commit-boundary repair correctly rejected malformed/mismatched PostgreSQL receipts before COMMIT, but the adapter used the same EmploymentSeparationIntegrityError type for those internal persistence-integrity faults and for reviewed authoritative-state conflicts. separation_http.py mapped that shared type to HTTP 409, so a corrupted DB receipt or mismatched authorization/result wiring could be presented to a buyer as a client-resolvable separation_conflict with refresh/new-key advice.

    The executable regression started at 01ca8e8321bd70a21a583656f26613c7621747f2: a malformed real PostgresEmploymentSeparationPort receipt is driven through the HTTP edge and must produce sanitized 500 internal_error plus a support reference. Its first hosted run was cancelled by ordinary successor commits, so no hosted RED is claimed from that run. Repairs 362329dfd9994f7f6c7dfe9ab2d6f4359b6b7908 → 1ae78e12e5226c7edaf27dec19e418e6e4ff2379 → 05b400d28981e91297fdf49cee7b6a5c68768ed6 introduce EmploymentSeparationPersistenceIntegrityError, classify malformed receipt/authorization/result-wiring failures under it, map it to operator-visible 500, and leave reviewed SQLSTATE/business conflicts on the existing 409 path. f6db78de19054bfdaf7f5dbf6b70508d0f179b0c currentizes the adapter unit contract; 6f89e6c... updates traceability.

    A separate acceptance gap remains in #314 requirement 5. The current two-session PostgreSQL contract races the same idempotency key and therefore proves the per-key advisory lock/replay path. It does not yet prove two different idempotency keys targeting the same Employment + expected version serialize at the Employment aggregate boundary. The next PostgreSQL acceptance should observe the actual Employment-scoped blocker via database state, let one transition commit, require the second attempt to fail as stale/authoritative conflict, and prove exactly one separation/audit/outbox logical outcome. Do not treat the same-key advisory-lock graph or timing-only sleeps as equivalent evidence. Keep this issue open; canonical Foundation registration remains #311-owned rather than another filename switch in #64.

  8. seonghobae commented on Sep 12, 2026

    @seonghobae
    ContributorAuthor

    #64 current People writer advanced the remaining acceptance #5 artifact ordinary-forward.

    • a67ed4b1afec755356d1cb4149007bfabaf10090 adds tests/test_employment_separation_distinct_key_concurrency.sh as the intended companion of test_employment_separation_postgres.sh.
    • The first successful separation is held at a shell-controlled pre-commit FIFO boundary rather than by pg_sleep or a broad database lock. A second backend uses a different idempotency key against the same Employment and expected version.
    • Acceptance requires pg_blocking_pids(...) to identify the first backend while the second waits on a row/transaction lock (transactionid/tuple), explicitly not the per-key advisory lock. After the first commit, the second must fail with expected version is stale or unavailable.
    • Durable postconditions require exactly one Employment separation, one matching audit event, one outbox delivery, one linked idempotency record, and zero durable idempotency row for the losing key.
    • fbcaee1f0c8e8012e6013b27568400bb631e6785 currentizes docs/traceability/employment-separation.md and keeps the evidence boundary explicit: this companion is implemented on fix(people): protect governed mutation runtime types #64 but is not hosted PostgreSQL GREEN until canonical Foundation owner ci: make PostgreSQL Foundation discovery fail closed #311 registers it as a companion and executes it from the immutable exact-candidate tree after normal stack reconciliation.

    Issue #314 should remain open. Protected develop has not adopted the separation slice, #311 registration/hosted PostgreSQL evidence is outstanding, security/code-quality gates and qualifying independent review still govern integration, and #302 must continue to consume only protected integrated separation truth.

  9. seonghobae commented on Sep 12, 2026

    @seonghobae
    ContributorAuthor

    #314 acceptance #8에 대해 새로운 executable evidence를 #64에 ordinary-forward로 추가했습니다.

    • fix(people): protect governed mutation runtime types #64 current lineage: 92e4c36b011142f6d81baa1f0caec925484b4acd → ea9d53488a05d5c4ded038b2cbe8db2e6ea3962c → traceability 52db8ff03d1c7ec8963b9d0a24c7f1e9d7579077.
    • 새 companion tests/test_employment_separation_failure_cleanup.sh는 root contract가 먼저 실행된 동일 DB를 전제로 독립 Employment fixture를 만든 뒤, 첫 separation을 idle in transaction + ClientRead pre-commit 경계에 유지하고 다른 idempotency key의 두 번째 backend가 같은 Employment/version에서 실제 transactionid|tuple lock을 기다리며 첫 backend에 의해 block되는 것을 pg_blocking_pids(...)로 확인합니다.
    • failure path에서는 blocked loser backend를 먼저 종료해 winner lock release 후 loser가 뜻밖에 commit할 창을 없앤 다음 pre-commit winner를 종료합니다. 두 client process를 wait하고 두 named PostgreSQL backend가 pg_stat_activity에서 0이 된 것을 확인한 뒤에만 durable state를 검사합니다.
    • postcondition은 separation/audit/outbox/idempotency residue가 모두 0이고 원래 active Employment version이 recorded_to IS NULL로 current인 상태입니다. polling 시간 자체는 acceptance evidence가 아니며 DB session quiescence와 durable rollback truth가 evidence입니다.
    • self-review에서 pre-commit winner의 local psql가 server termination을 반드시 non-zero exit로 관측한다고 가정하면 false RED가 될 수 있어, ea9d534...에서 그 가정을 제거했습니다. blocked loser는 query execution 중이므로 non-zero를 요구하고, winner는 client wait + server quiescence + durable rollback으로 판정합니다.

    이 companion은 hosted PostgreSQL GREEN으로 승격하지 않았습니다. #311이 정상 stack reconciliation 이후 separation root의 reviewed companion으로 등록해 immutable exact-candidate tree에서 실행해야 합니다. #314는 protected integration 전까지 open 유지가 맞습니다.

  10. seonghobae commented on Sep 12, 2026

    @seonghobae
    ContributorAuthor

    Employment separation acceptance advanced on canonical People PR #64 without changing production semantics. Exact current head now includes 07cf1143906125dec527bd4272a5ff9c5746baf0 (tests/test_employment_separation_uncertain_commit_recovery.sh) and traceability successor c099e367f80843910face46c45d4c02b1ee0ce51.

    New executable acceptance closes the uncertain-commit gap that ordinary same-key replay does not prove: a first connection performs the separation and commits, an independent tenant-scoped connection verifies the separation/idempotency/audit/outbox rows are durably visible while the first backend is still alive in pg_sleep, then that first backend is terminated so the original client reports failure after commit. A fresh connection retries the same semantic command/idempotency key with new server-generated audit/outbox identities and must recover the exact first terminal Employment version plus DB-owned recorded_at, with exactly one durable separation/idempotency/audit/outbox truth set and zero rows for retry-only audit/outbox IDs.

    This is a root companion, not a new schema root and not hosted PostgreSQL GREEN yet. #311 must register it after tests/test_employment_separation_postgres.sh in the same disposable exact-candidate database alongside the existing distinct-key and failure-cleanup companions. #314 remains open until that canonical execution plus protected integration and remaining gates complete.

  11. seonghobae commented on Sep 12, 2026

    @seonghobae
    ContributorAuthor

    Current-head People finding on #64 (0d0b18ef9204077463d044073c92722d455dcd14): separation/Assignment coordination had a two-command TOCTOU gap even though separation already locked employment_record. Assignment creation could validate an active Employment without taking the same aggregate conflict lock and later insert contradictory truth. A same-statement SELECT ... FOR UPDATE on the version read is not sufficient under READ COMMITTED because the statement snapshot can predate the lock wait.

    Ordinary-forward repair on #64:

    • database/migrations/0017_assignment_employment_separation_serialization.sql: BEFORE INSERT guard locks the exact Employment anchor, then performs a separate post-lock current-version coverage read. The guard is SECURITY DEFINER under dedicated orgmetra_assignment_employment_guard_owner (NOLOGIN, NOBYPASSRLS) so the ordinary Assignment writer is not widened merely to obtain PostgreSQL row-lock privilege.
    • tests/test_assignment_separation_serialization_postgres.sh: real two-session Assignment-first and separation-first interleavings require pg_blocking_pids(...) plus transactionid|tuple wait evidence. Assignment-first must leave Assignment=1/separation=0; separation-first must leave separation=1/conflicting Assignment=0. A historical Assignment ending exactly at the half-open separation boundary remains accepted.
    • ADR 0015 remains Proposed and traceability now marks this as implemented on the active PR but not hosted/canonical GREEN.

    #314 remains open. Acceptance #6 is materially implemented but is not promoted to protected truth until canonical Foundation ownership admits/runs this root from the exact candidate tree, current-head security/review gates are green, and #64 integrates normally.

  12. seonghobae commented on Sep 13, 2026

    @seonghobae
    ContributorAuthor

    Fresh #64 People-owner finding/repair: authoritative Employment separation previously accepted any syntactically valid lower_snake_case separation_reason_code, despite ADR 0015 calling for a controlled reason and the review-packet lane already using a reviewed five-value vocabulary. The People mutation owner now closes this at all authoritative boundaries: application command, PostgreSQL function + table constraint, public OpenAPI enum, application/OpenAPI tests, and PostgreSQL negative acceptance. Canonical values are voluntary_resignation, retirement_transition, fixed_term_completion, position_elimination, employer_initiated_separation. Arbitrary values such as manager_notes_compensation_case fail before mutation. Current exact candidate is 1a094cbe78422a9c31812620c1b17484059dc123; protected adoption is still required before this becomes domain truth, so #314 remains open. Review packets remain evidence, not mutation authority.

  13. seonghobae commented on Sep 13, 2026

    @seonghobae
    ContributorAuthor

    Fresh current-head authority sweep found a separate docs-to-code acceptance gap and recorded it as #315 rather than widening/closing this issue. Exact #64 head 1a094cbe78422a9c31812620c1b17484059dc123 has the governed separation route/model/vocabulary implemented on the active PR, while canonical docs/API_CONTRACT.md, docs/DATA_MODEL.md, docs/ERD.md, docs/UML.md, PRD/TRD still carry pre-separation or incomplete surfaces. Treat #315 as a repair prerequisite for #314 acceptance: reconcile the sealed documents through the normal #64 owner path, deterministically reseal manifest.json, then require exact-head Foundation GREEN. #311 remains the canonical hosted PostgreSQL discovery/execution owner; #302 remains downstream and must not be promoted as shipped truth.

  14. seonghobae commented on Sep 13, 2026

    @seonghobae
    ContributorAuthor

    Employment-separation implementation/docs acceptance update from canonical People owner #64: live owner line is now d9cc516d54b4642f59fe126c331a19945fdf75f1 after ordinary adoption of a CHANGELOG-only intervening delta and causal manifest reseal.

    The active branch now carries code-current API/Data Model/ERD/UML/PRD/TRD/SECURITY/THREAT_MODEL/TEST_STRATEGY/OPERABILITY contracts for this transition. The last pre-CHANGELOG exact head dbf0f8e03cb27d799509815f1f4904efffda4627 had terminal Foundation SUCCESS (34730787348, job 103653067587), Recovery SUCCESS, and SAST SUCCESS. The new d9cc516... head has fresh runs and no predecessor GREEN is being transferred.

    #314 stays open: canonical #311 still has to discover and execute the separation root + capability root + distinct-key/failure-cleanup/uncertain-commit companions + Assignment/separation serialization on an immutable candidate; central Dependency Review and CodeQL publication/settlement issues remain independent gates; exact-head qualifying independent approval is still required; ADR 0015 stays Proposed; #302 rehire consumes only protected successful separation truth.

  15. seonghobae commented on Sep 13, 2026

    @seonghobae
    ContributorAuthor

    Fresh exact-head Strix artifact on #64 (d9cc516d54b4642f59fe126c331a19945fdf75f1, run 34731009530, artifact 10311173510) completed its scanner with 0 confirmed vulnerabilities, but it produced two source-hardening follow-ups that should remain on the Employment-separation owner path rather than disappear behind the central Strix gate failure:

    1. database/migrations/0014_employment_separation_transition.sql uses unqualified pgcrypto digest(...) in the SECURITY DEFINER transition (command digest and event-envelope digest). The current search_path = pg_catalog, public, pg_temp plus non-writable public schema makes this non-exploitable in the reviewed role model, but qualify these calls as public.digest(...) (or adopt an equivalently stricter extension-schema contract) and prove the executor/service role is not DB owner and lacks CREATE on public.
    2. docs/THREAT_MODEL.md already records forced RLS/service-owned role controls, but should state the deliberate trust boundary explicitly: database tenant RLS depends on the application setting the tenant session GUC after Keyverse-authorized request binding; a future direct-SQL client must not be assumed tenant-safe merely because the function exists.

    These are defense-in-depth repair findings, not evidence of an exploitable vulnerability and not reason to close/restart #314. The scan also independently reiterated that the separation/capability/Assignment-serialization PostgreSQL scripts need canonical hosted execution; #311 already owns that generic Foundation admission, so do not recreate a feature-specific CI switchboard here.

  16. seonghobae commented on Sep 13, 2026

    @seonghobae
    ContributorAuthor

    Exact-head separation security repair is now hosted GREEN on #64 c0ba482c57a77820128f259b4a43c06df643c0f3.

    Strix's defense-in-depth findings were repaired ordinary-forward rather than waived:

    • f4f7e12d5edd253203c237d3a46703ca7449a8ba schema-qualifies both SECURITY DEFINER pgcrypto calls as public.digest(...).
    • 71d72267be22d3368517a8171b61321592bfb958 extends the real PostgreSQL capability acceptance to prove the separation executor/owner do not own the database, retain no CREATE on public, and that a session tenant GUC differing from the command tenant fails before target lookup.
    • 120616b1de33c1ff5c0de09dceb77dfea06691b9 states the trust boundary explicitly: the tenant GUC is a routing/RLS input, not authentication; only the Keyverse-authenticated People service may establish it, and direct possession of the executor capability is trusted service infrastructure rather than a tenant credential.
    • That changed sealed evidence produced the expected Foundation manifest RED; c0ba482c57a77820128f259b4a43c06df643c0f3 reseals only the exact new fingerprints.

    Exact-head Foundation run 34747271197 is now SUCCESS, including owned unit/service contracts, isolated PostgreSQL contracts, deterministic provenance validation, and read-only validation. Recovery 34747271200 and SAST 34747271263 are also SUCCESS.

    #314 remains open. This does not yet make Employment separation protected/released truth: #311 still owns canonical protected-base PostgreSQL discovery/admission, Security remains fail-closed at the central Dependency Review 403 availability defect, CodeQL/model-backed/review gates are still settling, and there is no qualifying independent approval.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions