Skip to content

feat(document-records): 반환·파기 완료 receipt 권위 계약과 복구 불가능성 evidence #308

Description

@seonghobae

Buyer / control gap

PR #307의 CandidateDocumentDisposition은 현재 return_destroyed, statutory_retention_expired_destroyed, destroyed 같은 완료 상태를 표현하지만, protected develop에는 document_records가 발행하는 반환/파기 완료 receipt의 released/versioned contract가 없다. return_delivered_at이나 statutory_retain_until은 선행 조건/정책 경계일 뿐 파기 실행 완료의 권위 증거가 아니다.

Issue #303과 ADR 0303은 artifact lifecycle 실행과 completion receipt 권위를 document_records에 둔다. 따라서 talent_acquisition/people_core가 자체 timestamp만으로 artifact가 반환·파기됐다고 확정하면 DDD ownership, 감사 추적성, legal-hold/recovery 통제가 동시에 깨진다.

Canonical owner / boundary

document_records가 다음 truth를 소유한다.

  • canonical document/artifact identity/hash/provenance
  • hold/return/export/delete disposition 실행
  • idempotency/UPSERT 및 retry/compensation outcome
  • retention_policy_version/digest, anchor, retain_until, legal-hold evaluation
  • return/destruction completion receipt
  • 파기 뒤 search index/cache/export queue/replica/backup/restore 경로에서 buyer-visible content가 되살아나지 않는 recovery-aware deletion evidence

talent_acquisition과 people_core는 released API/event/ACL의 opaque receipt reference만 소비한다. raw artifact/source copy, cross-service application-table SQL, mutable branch dependency는 금지한다.

Required contract

최소 receipt는 raw PII를 담지 않고 다음을 검증 가능하게 해야 한다.

  • tenant-scoped immutable receipt identity와 artifact/document opaque reference
  • disposition command/idempotency identity 및 disposition kind (return, delete 등)
  • authoritative completion result와 completed_at
  • 적용한 policy version/digest 및 legal-hold decision evidence
  • executor/actor 또는 service-principal provenance
  • artifact content/provenance digest 또는 동등한 tamper-evident linkage
  • 파기인 경우 normal store뿐 아니라 index/cache/replica/backup/recovery 경로의 처리 상태를 연결하는 recovery evidence reference
  • duplicate delivery/retry가 동일 receipt/result로 수렴하는 idempotency

Receipt는 append-only/immutable이어야 하며 과거 receipt를 policy 변경으로 rewrite하지 않는다.

Acceptance

  1. document_records owner에서 contract/API/event schema, DDD aggregate/invariant, ADR/UML/TRD/SECURITY/THREAT_MODEL/OPERABILITY/TEST_STRATEGY를 code-current하게 만든다.
  2. same-tenant valid completion receipt, wrong-tenant receipt, forged/malformed reference, duplicate command, retry/compensation, active legal hold, policy-version mismatch, stale receipt를 RED→GREEN으로 검증한다.
  3. destruction completion은 실제 artifact lifecycle result 없이는 발행되지 않는다. legal hold 중 파기는 fail closed한다.
  4. recovery rehearsal에서 파기 완료 artifact가 DB/index/cache/export/restore 경로로 재등장하지 않음을 right-cleared 현실 evidence로 검증한다.
  5. released/versioned immutable contract를 만든 뒤 consumer #307은 exact version/ACL만 소비하고, *_destroyed 완료 상태를 해당 authoritative receipt와 결합할 때만 허용한다.
  6. #307은 이 owner contract가 protected/released 되기 전에는 completed destruction을 integration-ready evidence로 주장하지 않는다. 임시 source copy나 leaf-local receipt schema로 우회하지 않는다.

Dependency / traceability

이 issue는 #303을 대체하지 않고 document_records의 canonical prerequisite를 분리한다.

Activity

  1. seonghobae commented on Sep 11, 2026

    @seonghobae
    ContributorAuthor

    Fresh document_records dependency audit found that #308 is not a root executable slice. Protected develop@eb9757f8649aaad026a9865508d9aad50c1a7a4f still has no integrated document_records production package/service; the existing canonical owner stack is #98 governed DocumentRecordEvidence → #107 immutable metadata persistence. #107 had been one parent commit behind #98, so it was ordinary-forward restacked first: new exact head a8ca94b1ada6f96f9e4e396970704e6370e1179d is a normal two-parent merge of prior #107 78e67a... with current #98 6a9f3e.... Fresh compare proved the parent delta touched only evidence.py and test_evidence.py, with no overlap against #107-owned persistence files; no force/rebase or copied source was used. The resulting #107 diff against current #98 remains nine owned files and GitHub reports Draft · mergeable.

    Canonical order for this issue is therefore: (1) repair #98 onto fresh protected develop without resurrecting superseded per-feature workflow topology; (2) integrate package-neutral Foundation #258/#259 or verified successor so document-record packages cannot false-green by omission; (3) integrate/release #107 durable document_records persistence; (4) implement this issue's return/destruction completion receipt and recovery-aware deletion on top of that released owner foundation; (5) only then let #307 consume the exact released receipt contract/ACL. #308 must not invent a parallel root document authority, duplicate #98/#107 schemas, or use return_delivered_at / retention deadlines as destruction completion evidence.

  2. seonghobae commented on Sep 11, 2026

    @seonghobae
    ContributorAuthor

    Canonical document_records prerequisite advanced again. #98 remains ordinary-forward reconciled to protected develop@eb9757f8649aaad026a9865508d9aad50c1a7a4f at exact ec39bfa9bcb73b2b7730a0a6115b2e484d78acb2, preserving the governed evidence package/docs without reviving retired feature-local workflows.

    #107 has now repaired the stale descendant rather than waiting on it: ordinary two-parent commit 6592288464afcc180f681d242e60bdd81c421a1c adopted #98 ec39bfa... with prior #107 as first parent, using #98's current tree as authority and reapplying only the valid persistence migration/docs/PostgreSQL-contract delta. The obsolete persistence-local workflow and stale root Foundation/manifest registrations were deliberately not carried forward. GitHub now reports #107 mergeable against current #98.

    A fresh persistence audit also found that jsonb normalization could collapse duplicate keys before the existing 17-key/typed-field checks. #107 added a test-first duplicate-key packet with SHA-256 recomputed over the actual duplicate-key bytes, then migration 0022_document_record_evidence_unique_keys.sql bound raw canonical_evidence_json to PostgreSQL 16 IS JSON OBJECT WITH UNIQUE KEYS. This prevents a syntactically valid duplicate-key evidence representation from masquerading as the reviewed canonical object after jsonb normalization.

    The remaining integration order is: #258/#259 (or verified successor) must make canonical Foundation acceptance non-vacuous for newly owned Python packages and PostgreSQL contracts; then #98/#107 can reacquire exact-head hosted acceptance and integrate/release normally; only then should #308 implement completion/destruction receipt + recovery-invisibility evidence. #307 must consume that future released/versioned receipt contract by exact version/ACL rather than mutable #98/#107/#308 branches.

  3. seonghobae commented on Sep 11, 2026

    @seonghobae
    ContributorAuthor

    Fresh document_records owner ordering after #107 exact 937406173fd4afd303a3802e2889e8cd42fd2efe: #107 now owns immutable persisted evidence plus raw unique-key and deterministic v1 byte identity. Separate Issue #309 owns the initial metadata-persistence uncertain-retry contract (tenant idempotency identity + semantic digest + same-semantic convergence/conflicting replay rejection + real PostgreSQL concurrency/connection-loss recovery). #308 should reuse the released owner-level idempotency semantics where appropriate for return/delete commands, while keeping its distinct lifecycle/completion-receipt and recovery-aware deletion truth. Avoid two incompatible idempotency models inside one bounded context. Preferred owner order is #98 evidence → #107 immutable persistence → #309 idempotent persistence command/result → #308 lifecycle completion receipt/recovery deletion, unless the canonical implementation proves a smaller shared prerequisite. #307 remains a released-contract consumer only.

  4. seonghobae commented on Sep 12, 2026

    @seonghobae
    ContributorAuthor

    Upstream owner authority update only; #308 source should still wait for normal prerequisite integration.

    #309 implementation successor #312 is now exact 4535d9fea7b2b995be627a23316a65474d714957 on #107. Besides tenant-bound replay coordination, observable advisory-lock serialization, behavioral FORCE-RLS, Read Committed fail-close, timezone-stable/direct durable-result binding, and cleanup controls, it now includes a real post-commit connection-loss recovery companion. The companion runs after the main idempotency root, proves the receipt is externally visible before terminating the committed original backend, requires that client to fail, then requires a fresh same-command connection to recover the exact durable first identity/references/digests/database-owned time without duplication.

    This remains creation/retry authority only. It is not return/destruction completion evidence and does not reduce #308's owner scope. Preserve the order #98/#107 → #309/#312 → #308 → #307, then consume only released/versioned creation/retry contracts when #308 eventually implements completion/recovery truth.

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