From d124abc5aef3e317e81ff92b206605ed52e36d79 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 23 Aug 2026 03:05:22 -0700 Subject: [PATCH 01/23] test(document-records): define package quality contract --- .../document-record-evidence/pyproject.toml | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 packages/document-record-evidence/pyproject.toml diff --git a/packages/document-record-evidence/pyproject.toml b/packages/document-record-evidence/pyproject.toml new file mode 100644 index 000000000..53aa9b75a --- /dev/null +++ b/packages/document-record-evidence/pyproject.toml @@ -0,0 +1,24 @@ +[build-system] +requires = ["setuptools>=69"] +build-backend = "setuptools.build_meta" + +[project] +name = "orgmetra-document-record-evidence" +version = "0.1.0" +description = "Value-minimized HR document-record evidence for Orgmetra." +requires-python = ">=3.14.7,<3.15" + +[project.optional-dependencies] +test = ["pytest>=8.3", "pytest-cov>=5.0"] + +[tool.setuptools.packages.find] +where = ["src"] + +[tool.pytest.ini_options] +testpaths = ["tests"] +addopts = [ + "--cov=orgmetra_document_record_evidence", + "--cov-branch", + "--cov-report=term-missing", + "--cov-fail-under=100", +] From 8d0b1defd861a631dcc9bbb728cd53c4920dcb7b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 23 Aug 2026 03:05:35 -0700 Subject: [PATCH 02/23] test(document-records): add RED document evidence contract --- .../tests/test_evidence.py | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 packages/document-record-evidence/tests/test_evidence.py diff --git a/packages/document-record-evidence/tests/test_evidence.py b/packages/document-record-evidence/tests/test_evidence.py new file mode 100644 index 000000000..4e7c962f1 --- /dev/null +++ b/packages/document-record-evidence/tests/test_evidence.py @@ -0,0 +1,95 @@ +"""Executable contract for value-minimized HR document-record evidence.""" + +from datetime import datetime, timedelta, timezone +from uuid import UUID, uuid4 + +import pytest + +from orgmetra_document_record_evidence import build_document_record_evidence + + +def values() -> dict[str, object]: + """Return one valid caller-owned document-record input set.""" + now = datetime.now(timezone.utc) + return { + "tenant_record_id": str(uuid4()), + "person_record_reference": f"person_record:{uuid4()}", + "employment_record_reference": f"employment_record:{uuid4()}", + "uploader_actor_reference": f"actor:{uuid4()}", + "document_category_code": "employment_contract", + "artifact_reference": f"document_artifact:{uuid4()}", + "artifact_digest": "a" * 64, + "source_provenance_digest": "b" * 64, + "retention_policy_reference": f"retention_policy:{uuid4()}", + "retention_policy_digest": "c" * 64, + "received_at": now - timedelta(seconds=1), + } + + +def test_builds_value_minimized_document_evidence() -> None: + """Build one canonical record without copying document content or HR values.""" + evidence = build_document_record_evidence(**values()) + document = evidence.canonical_document() + assert document["schema_version"] == "orgmetra.document_record_evidence.v1" + assert document["classification_code"] == "restricted_hr" + assert document["content_storage_state"] == "artifact_reference_only" + assert document["decision_authority_state"] == "not_authorized_for_employment_decision" + assert document["document_category_code"] == "employment_contract" + assert document["artifact_digest"] == "a" * 64 + assert document["source_provenance_digest"] == "b" * 64 + assert "document_content" not in document + assert "document_title" not in document + assert len(evidence.sha256_digest()) == 64 + assert evidence.canonical_json() == evidence.canonical_json() + assert repr(evidence) == "DocumentRecordEvidence()" + + +def test_generates_packet_owned_reference_and_system_time() -> None: + """Generate packet identity and recorded time inside the Orgmetra issuance boundary.""" + before = datetime.now(timezone.utc) + evidence = build_document_record_evidence(**values()) + after = datetime.now(timezone.utc) + reference = evidence.document_record_reference + assert reference.startswith("document_record:") + assert UUID(reference.split(":", 1)[1]).version == 4 + assert before <= evidence.recorded_at <= after + assert evidence.recorded_at.tzinfo is timezone.utc + + +@pytest.mark.parametrize( + ("field_name", "bad_value"), + [ + ("tenant_record_id", "not-a-uuid"), + ("person_record_reference", "person_record:"), + ("employment_record_reference", "employment_record:"), + ("uploader_actor_reference", "actor:Jane-Doe"), + ("document_category_code", "free_form_category"), + ("artifact_reference", "document_artifact:"), + ("artifact_digest", "A" * 64), + ("source_provenance_digest", "b" * 63), + ("retention_policy_reference", "retention_policy:"), + ("retention_policy_digest", "not-a-digest"), + ], +) +def test_rejects_malformed_trust_evidence(field_name: str, bad_value: object) -> None: + """Fail closed before malformed trust evidence can enter canonical audit correlation.""" + payload = values() + payload[field_name] = bad_value + with pytest.raises(ValueError): + build_document_record_evidence(**payload) + + +def test_rejects_future_received_time() -> None: + """Do not record a document as received after its system issuance time.""" + payload = values() + payload["received_at"] = datetime.now(timezone.utc) + timedelta(days=1) + with pytest.raises(ValueError, match="received_at cannot be in the future"): + build_document_record_evidence(**payload) + + +def test_rejects_non_utc_received_time() -> None: + """Require detached built-in UTC business-event time at the evidence boundary.""" + payload = values() + payload["received_at"] = datetime.now().replace(tzinfo=None) + with pytest.raises(ValueError, match="received_at must be an exact built-in UTC datetime"): + build_document_record_evidence(**payload) From 6e4b346be794163fa643a34c24d39a6e0b6971f9 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 23 Aug 2026 03:05:46 -0700 Subject: [PATCH 03/23] test(document-records): run exact-head document evidence quality --- .../document-record-evidence-quality.yml | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 .github/workflows/document-record-evidence-quality.yml diff --git a/.github/workflows/document-record-evidence-quality.yml b/.github/workflows/document-record-evidence-quality.yml new file mode 100644 index 000000000..d41242aae --- /dev/null +++ b/.github/workflows/document-record-evidence-quality.yml @@ -0,0 +1,73 @@ +name: Document Record Evidence Quality + +on: + pull_request: + branches: + - develop + paths: + - "packages/document-record-evidence/**" + - ".github/requirements/foundation-test.txt" + - ".github/workflows/document-record-evidence-quality.yml" + - "docs/doctoring/document-record-evidence-references.md" + - "docs/traceability/document-record-evidence.md" + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: document-record-evidence-quality-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + unit: + name: Document record evidence contract and 100% coverage + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Checkout exact candidate + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + persist-credentials: false + - name: Prove exact candidate checkout + env: + ORGMETRA_EXPECTED_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} + run: test "$(git rev-parse HEAD)" = "$ORGMETRA_EXPECTED_HEAD_SHA" + - name: Set up exact Python + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.14.7" + check-latest: false + - name: Install reviewed test and build toolchain + run: | + python -m pip install --require-hashes --no-deps --only-binary=:all: -r .github/requirements/foundation-test.txt + printf '%s\n' 'setuptools==84.0.0 --hash=sha256:51a52592b3b99e102b609654876bd65f19f999935166d1352678931132b0c670' > /tmp/orgmetra-document-record-build.txt + python -m pip install --require-hashes --no-deps --only-binary=:all: -r /tmp/orgmetra-document-record-build.txt + python -m pip check + - name: Compile package and tests + run: python -m compileall -q packages/document-record-evidence/src packages/document-record-evidence/tests + - name: Build and install exact package artifact + run: | + rm -rf /tmp/orgmetra-document-record-build-src /tmp/orgmetra-document-record-dist /tmp/orgmetra-document-record-venv + cp -a packages/document-record-evidence /tmp/orgmetra-document-record-build-src + mkdir -p /tmp/orgmetra-document-record-dist + python -m pip wheel --no-deps --no-build-isolation --wheel-dir /tmp/orgmetra-document-record-dist /tmp/orgmetra-document-record-build-src + test "$(find /tmp/orgmetra-document-record-dist -maxdepth 1 -type f -name '*.whl' | wc -l)" -eq 1 + python -m venv /tmp/orgmetra-document-record-venv + /tmp/orgmetra-document-record-venv/bin/python -m pip install --require-hashes --no-deps --only-binary=:all: -r "$GITHUB_WORKSPACE/.github/requirements/foundation-test.txt" + wheel_path="$(find /tmp/orgmetra-document-record-dist -maxdepth 1 -type f -name '*.whl' -print -quit)" + wheel_sha="$(sha256sum "$wheel_path" | awk '{print $1}')" + printf 'orgmetra-document-record-evidence[test] @ file://%s --hash=sha256:%s\n' "$wheel_path" "$wheel_sha" > /tmp/orgmetra-document-record-install.txt + /tmp/orgmetra-document-record-venv/bin/python -m pip install --require-hashes --no-deps -r /tmp/orgmetra-document-record-install.txt + /tmp/orgmetra-document-record-venv/bin/python -m pip check + - name: Test installed artifact with exact statement and branch coverage + env: + COVERAGE_FILE: /tmp/orgmetra-document-record.coverage + run: | + cd /tmp + /tmp/orgmetra-document-record-venv/bin/python -m pytest -c "$GITHUB_WORKSPACE/packages/document-record-evidence/pyproject.toml" "$GITHUB_WORKSPACE/packages/document-record-evidence/tests" + - name: Require clean checkout + run: | + git diff --exit-code + test -z "$(git status --porcelain)" From 6e4e4ff304657615c6e58b9594bf7c74d36cd5ab Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 23 Aug 2026 03:06:26 -0700 Subject: [PATCH 04/23] feat(document-records): implement value-minimized document evidence --- .../evidence.py | 205 ++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 packages/document-record-evidence/src/orgmetra_document_record_evidence/evidence.py diff --git a/packages/document-record-evidence/src/orgmetra_document_record_evidence/evidence.py b/packages/document-record-evidence/src/orgmetra_document_record_evidence/evidence.py new file mode 100644 index 000000000..b480f6c06 --- /dev/null +++ b/packages/document-record-evidence/src/orgmetra_document_record_evidence/evidence.py @@ -0,0 +1,205 @@ +"""Value-minimized evidence for one HR document artifact. + +This module records document metadata and provenance only. It deliberately does +not carry document bytes, titles, free-form notes, credentials, HR field values, +or employment-decision authority. Durable immutability and authorization belong +to Orgmetra's authoritative document-records and audit/outbox persistence. +""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from datetime import datetime, timezone +from hashlib import sha256 +import json +import re +from typing import Any +from uuid import UUID, uuid4 + +_DIGEST_PATTERN = re.compile(r"^[0-9a-f]{64}$") +_ALLOWED_DOCUMENT_CATEGORIES = frozenset( + {"employment_contract", "policy_acknowledgement", "qualification_document"} +) +_CLASSIFICATION_CODE = "restricted_hr" +_CONTENT_STORAGE_STATE = "artifact_reference_only" +_DECISION_AUTHORITY_STATE = "not_authorized_for_employment_decision" +_SCHEMA_VERSION = "orgmetra.document_record_evidence.v1" + + +def _validate_operational_uuid(value: str, field_name: str) -> None: + """Require exact canonical non-sentinel UUID text without fixing its version.""" + if type(value) is not str: + raise ValueError(f"{field_name} must be canonical UUID text") + try: + parsed = UUID(value) + except (ValueError, AttributeError, TypeError) as exc: + raise ValueError(f"{field_name} must be canonical UUID text") from exc + if str(parsed) != value or parsed.int in (0, (1 << 128) - 1): + raise ValueError(f"{field_name} must be a canonical operational UUID") + + +def _validate_uuid4_reference(value: str, prefix: str, field_name: str) -> None: + """Require one bounded namespaced UUIDv4 correlation reference.""" + if type(value) is not str: + raise ValueError(f"{field_name} must be an opaque {prefix}: UUIDv4 reference") + if len(value) > 160 or not value.startswith(f"{prefix}:"): + raise ValueError(f"{field_name} must be an opaque {prefix}: UUIDv4 reference") + suffix = value.split(":", 1)[1] + try: + parsed = UUID(suffix) + except (ValueError, AttributeError, TypeError) as exc: + raise ValueError(f"{field_name} must be an opaque {prefix}: UUIDv4 reference") from exc + if str(parsed) != suffix or parsed.version != 4: + raise ValueError(f"{field_name} must be an opaque {prefix}: UUIDv4 reference") + + +def _validate_digest(value: str, field_name: str) -> None: + """Require exact lowercase SHA-256 evidence text.""" + if type(value) is not str or _DIGEST_PATTERN.fullmatch(value) is None: + raise ValueError(f"{field_name} must be lowercase SHA-256 hex") + + +def _validate_received_at(value: datetime, recorded_at: datetime) -> None: + """Require detached UTC event time no later than system-recorded issuance.""" + if type(value) is not datetime or value.tzinfo is not timezone.utc: + raise ValueError("received_at must be an exact built-in UTC datetime") + if value > recorded_at: + raise ValueError("received_at cannot be in the future relative to recorded_at") + + +def _new_reference() -> str: + """Return a packet-owned opaque document-record correlation reference.""" + return f"document_record:{uuid4()}" + + +def _now_utc() -> datetime: + """Return one built-in UTC system-recorded issuance instant.""" + return datetime.now(timezone.utc) + + +@dataclass(frozen=True, slots=True, repr=False) +class DocumentRecordEvidence: + """Governed metadata evidence for one HR document artifact. + + The object is a transport-neutral evidence value. It is not document content, + a storage credential, a legal retention decision, or authority for any + employment action. + """ + + tenant_record_id: str + person_record_reference: str + employment_record_reference: str + uploader_actor_reference: str + document_category_code: str + artifact_reference: str + artifact_digest: str + source_provenance_digest: str + retention_policy_reference: str + retention_policy_digest: str + received_at: datetime + document_record_reference: str = field(default_factory=_new_reference, init=False) + recorded_at: datetime = field(default_factory=_now_utc, init=False) + classification_code: str = field(default=_CLASSIFICATION_CODE, init=False) + content_storage_state: str = field(default=_CONTENT_STORAGE_STATE, init=False) + decision_authority_state: str = field(default=_DECISION_AUTHORITY_STATE, init=False) + schema_version: str = field(default=_SCHEMA_VERSION, init=False) + + def __post_init__(self) -> None: + """Validate all caller-controlled trust evidence before export.""" + _validate_operational_uuid(self.tenant_record_id, "tenant_record_id") + _validate_uuid4_reference( + self.person_record_reference, "person_record", "person_record_reference" + ) + _validate_uuid4_reference( + self.employment_record_reference, + "employment_record", + "employment_record_reference", + ) + _validate_uuid4_reference( + self.uploader_actor_reference, "actor", "uploader_actor_reference" + ) + if type(self.document_category_code) is not str: + raise ValueError("document_category_code must use the reviewed vocabulary") + if self.document_category_code not in _ALLOWED_DOCUMENT_CATEGORIES: + raise ValueError("document_category_code must use the reviewed vocabulary") + _validate_uuid4_reference( + self.artifact_reference, "document_artifact", "artifact_reference" + ) + _validate_digest(self.artifact_digest, "artifact_digest") + _validate_digest(self.source_provenance_digest, "source_provenance_digest") + _validate_uuid4_reference( + self.retention_policy_reference, + "retention_policy", + "retention_policy_reference", + ) + _validate_digest(self.retention_policy_digest, "retention_policy_digest") + _validate_received_at(self.received_at, self.recorded_at) + + def __repr__(self) -> str: + """Avoid exposing HR document correlations in routine logs.""" + return "DocumentRecordEvidence()" + + def canonical_document(self) -> dict[str, Any]: + """Return deterministic, value-minimized document metadata evidence.""" + return { + "artifact_digest": self.artifact_digest, + "artifact_reference": self.artifact_reference, + "classification_code": self.classification_code, + "content_storage_state": self.content_storage_state, + "decision_authority_state": self.decision_authority_state, + "document_category_code": self.document_category_code, + "document_record_reference": self.document_record_reference, + "employment_record_reference": self.employment_record_reference, + "person_record_reference": self.person_record_reference, + "received_at": self.received_at.isoformat().replace("+00:00", "Z"), + "recorded_at": self.recorded_at.isoformat().replace("+00:00", "Z"), + "retention_policy_digest": self.retention_policy_digest, + "retention_policy_reference": self.retention_policy_reference, + "schema_version": self.schema_version, + "source_provenance_digest": self.source_provenance_digest, + "tenant_record_id": self.tenant_record_id, + "uploader_actor_reference": self.uploader_actor_reference, + } + + def canonical_json(self) -> str: + """Return deterministic UTF-8-safe JSON for immutable audit correlation.""" + return json.dumps( + self.canonical_document(), + sort_keys=True, + separators=(",", ":"), + ensure_ascii=True, + ) + + def sha256_digest(self) -> str: + """Return SHA-256 over the exact canonical JSON bytes.""" + return sha256(self.canonical_json().encode("utf-8")).hexdigest() + + +def build_document_record_evidence( + *, + tenant_record_id: str, + person_record_reference: str, + employment_record_reference: str, + uploader_actor_reference: str, + document_category_code: str, + artifact_reference: str, + artifact_digest: str, + source_provenance_digest: str, + retention_policy_reference: str, + retention_policy_digest: str, + received_at: datetime, +) -> DocumentRecordEvidence: + """Build one non-authorizing HR document metadata evidence value.""" + return DocumentRecordEvidence( + tenant_record_id=tenant_record_id, + person_record_reference=person_record_reference, + employment_record_reference=employment_record_reference, + uploader_actor_reference=uploader_actor_reference, + document_category_code=document_category_code, + artifact_reference=artifact_reference, + artifact_digest=artifact_digest, + source_provenance_digest=source_provenance_digest, + retention_policy_reference=retention_policy_reference, + retention_policy_digest=retention_policy_digest, + received_at=received_at, + ) From 4c9948dad8ca839edb2e53894fdc62f646a1e097 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 23 Aug 2026 03:06:34 -0700 Subject: [PATCH 05/23] feat(document-records): export document evidence contract --- .../src/orgmetra_document_record_evidence/__init__.py | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 packages/document-record-evidence/src/orgmetra_document_record_evidence/__init__.py diff --git a/packages/document-record-evidence/src/orgmetra_document_record_evidence/__init__.py b/packages/document-record-evidence/src/orgmetra_document_record_evidence/__init__.py new file mode 100644 index 000000000..19f80c5bd --- /dev/null +++ b/packages/document-record-evidence/src/orgmetra_document_record_evidence/__init__.py @@ -0,0 +1,8 @@ +"""Public Orgmetra HR document-record evidence contract.""" + +from orgmetra_document_record_evidence.evidence import ( + DocumentRecordEvidence, + build_document_record_evidence, +) + +__all__ = ["DocumentRecordEvidence", "build_document_record_evidence"] From 15e6425895d67366c805e2e6a85e2b50281ab7ab Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 23 Aug 2026 03:06:51 -0700 Subject: [PATCH 06/23] docs(document-records): explain governed evidence boundary --- packages/document-record-evidence/README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 packages/document-record-evidence/README.md diff --git a/packages/document-record-evidence/README.md b/packages/document-record-evidence/README.md new file mode 100644 index 000000000..80181a5a2 --- /dev/null +++ b/packages/document-record-evidence/README.md @@ -0,0 +1,13 @@ +# Orgmetra document-record evidence + +This package creates **value-minimized metadata evidence** for an HR document artifact. It is intended for the `document_records` bounded context described by Orgmetra's accepted architecture. + +A `DocumentRecordEvidence` binds one tenant, Person, Employment, uploader correlation, reviewed document category, immutable artifact reference and SHA-256 digest, source-provenance digest, retention-policy reference/digest, the business receipt time, and a system-generated recorded time. The evidence intentionally contains **no document bytes, document title, free-form notes, credentials, compensation, rating, or other HR field values**. + +The packet is not a storage credential, legal retention determination, or employment-decision authorization. Before content access, export, retention/disposition, or a high-impact HR action, the authoritative Orgmetra host must re-resolve tenant/actor/purpose/resource scope, retention/legal-hold state, artifact integrity and human authority, then persist immutable audit/outbox evidence through the owning service. + +`document_record_reference` and `recorded_at` are generated inside the Orgmetra issuance boundary so callers cannot claim a chosen system-recorded identity or timestamp. Caller-owned `received_at` remains separate business-event time and must be exact built-in UTC and no later than issuance. + +The closed initial document-category vocabulary is `employment_contract`, `policy_acknowledgement`, and `qualification_document`. New categories require a reviewed contract change rather than free-form metadata. + +This package does not fetch or mutate Clearfolio, NewsDOM, or any other dedicated-writer CWL service and introduces no cross-service application-table SQL. From b9d02c92d8eba6931b72602f50fd574b6002fcaa Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 23 Aug 2026 03:06:56 -0700 Subject: [PATCH 07/23] docs(document-records): record initial evidence slice --- packages/document-record-evidence/CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 packages/document-record-evidence/CHANGELOG.md diff --git a/packages/document-record-evidence/CHANGELOG.md b/packages/document-record-evidence/CHANGELOG.md new file mode 100644 index 000000000..75ea205ef --- /dev/null +++ b/packages/document-record-evidence/CHANGELOG.md @@ -0,0 +1,7 @@ +# Changelog + +## Unreleased + +- Add value-minimized HR document-record metadata evidence with Orgmetra-generated record identity and system-recorded time. +- Bind artifact integrity, source provenance and retention-policy evidence without copying document content or HR field values. +- Add an exact-head, installed-wheel quality lane with 100% owned statement/branch coverage requirement. From 2e593d196cfd6f8f1f183e76c91ed02f69a8c217 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 23 Aug 2026 03:07:04 -0700 Subject: [PATCH 08/23] docs(document-records): record primary-source design inputs --- .../document-record-evidence-references.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 docs/doctoring/document-record-evidence-references.md diff --git a/docs/doctoring/document-record-evidence-references.md b/docs/doctoring/document-record-evidence-references.md new file mode 100644 index 000000000..d24f326de --- /dev/null +++ b/docs/doctoring/document-record-evidence-references.md @@ -0,0 +1,17 @@ +# Document-record evidence references + +Reviewed 2026-08-23. + +## Primary standards inputs + +World Wide Web Consortium. (2013, April 30). *PROV-O: The PROV Ontology* (W3C Recommendation). https://www.w3.org/TR/prov-o/ + +PROV-O is used as a provenance-model design input: Orgmetra preserves explicit artifact and source-provenance correlation so evidence can later be mapped into a broader provenance graph. This slice does **not** claim PROV-O serialization conformance. + +National Institute of Standards and Technology. (2020, January). *NIST Privacy Framework: A tool for improving privacy through enterprise risk management, Version 1.0*. https://www.nist.gov/privacy-framework/privacy-framework + +NIST Privacy Framework 1.0 is used as a privacy-risk design input for data minimization and governed processing. At the review date, NIST's site separately presents Privacy Framework 1.1 as an Initial Public Draft; this document therefore does not mislabel 1.1 as a final standard and does not claim NIST certification or conformity. + +## Orgmetra interpretation + +The evidence contract stores document metadata, opaque correlations and SHA-256 provenance while excluding document bytes, titles, free-form notes, credentials and unrelated HR values. Retention-policy evidence is bound but no universal statutory retention period is encoded. Authoritative access, export, retention/disposition and employment decisions remain separate human-accountable Orgmetra boundaries. From 8415866a268b6899e3b6dd248c8c23e3bc441054 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 23 Aug 2026 03:07:13 -0700 Subject: [PATCH 09/23] docs(document-records): trace active document evidence slice --- docs/traceability/document-record-evidence.md | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 docs/traceability/document-record-evidence.md diff --git a/docs/traceability/document-record-evidence.md b/docs/traceability/document-record-evidence.md new file mode 100644 index 000000000..d5f6a903c --- /dev/null +++ b/docs/traceability/document-record-evidence.md @@ -0,0 +1,23 @@ +# Document-record evidence traceability + +## State + +- **Protected-main truth:** `develop@9e3e4847510e1e612b48474ba42b177b8ed824df` defines `document_records` as the owner of document metadata, source evidence and immutable artifact references, but has no executable document-record evidence package. +- **Active PR truth:** PR #98 adds a transport-neutral, value-minimized document metadata evidence contract. It is not protected-main/shipped truth until merged. +- **Out of scope:** document bytes/object-store implementation, Clearfolio/NewsDOM mutations, OCR, preview generation, legal retention decisions, content export, and employment-decision authority. + +## Requirement → executable evidence + +| Requirement | Evidence | +|---|---| +| Tenant, Person and Employment scope is explicit | `test_builds_value_minimized_document_evidence` plus malformed-reference regressions | +| Document content and HR values are not copied into canonical governance evidence | `test_builds_value_minimized_document_evidence` | +| Record identity and system-recorded time are Orgmetra-generated | `test_generates_packet_owned_reference_and_system_time` | +| Artifact, provenance and retention-policy integrity are SHA-256-bound | malformed digest regressions plus canonical digest assertion | +| Caller business receipt time remains distinct from system-recorded time | future/non-UTC receipt-time regressions | +| Owned production statement and branch coverage are exact 100% | `Document Record Evidence Quality` workflow | +| Installed package, not source-tree import, is tested | exact-head hash-bound wheel build/install in `Document Record Evidence Quality` | + +## Next authoritative boundary + +Before any content read, export, disposition or high-impact HR action, the owning Orgmetra service must freshly re-resolve tenant, actor, purpose, resource, artifact digest/provenance, retention/legal-hold state and human authority, then write immutable audit/outbox evidence atomically with any consequential operation. From 4ab738b4cfee3573e5900dcb158e4a9db8a6e79e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 23 Aug 2026 03:07:22 -0700 Subject: [PATCH 10/23] docs(document-records): add document evidence ADR --- .../0098-governed-document-record-evidence.md | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 docs/adr/0098-governed-document-record-evidence.md diff --git a/docs/adr/0098-governed-document-record-evidence.md b/docs/adr/0098-governed-document-record-evidence.md new file mode 100644 index 000000000..081c6f547 --- /dev/null +++ b/docs/adr/0098-governed-document-record-evidence.md @@ -0,0 +1,27 @@ +# ADR 0098: Governed HR document-record evidence + +**Status: Proposed** + +## Context + +Orgmetra's accepted architecture assigns document metadata, source evidence and immutable artifact references to `document_records`. Protected `develop` has no executable value object for that boundary, creating a commercial diligence gap: a buyer cannot yet point to code that binds an HR document artifact to HR scope, provenance, retention-policy evidence and system-recorded time without copying content into a second evidence store. + +## Decision + +Add a transport-neutral `DocumentRecordEvidence` value that binds tenant, Person, Employment, pseudonymous uploader correlation, one reviewed document category, an opaque artifact reference plus SHA-256 digest, source-provenance SHA-256, retention-policy reference/digest, caller-owned business receipt time, and Orgmetra-generated document-record identity/system-recorded time. + +Canonical evidence is classified `restricted_hr`, records only `artifact_reference_only`, and is explicitly `not_authorized_for_employment_decision`. The initial category vocabulary is closed. Document bytes, titles, free-form notes, credentials, compensation, ratings and unrelated HR values are excluded. + +`received_at` and `recorded_at` remain distinct: receipt time is business/event time supplied by the source boundary; recorded time is generated by Orgmetra at evidence issuance and cannot precede receipt time. + +## Consequences + +- Document metadata can be correlated to immutable artifacts and provenance without duplicating content. +- The packet does not authorize storage access, export, retention/disposition or an employment decision. +- Durable immutability, uniqueness, access control and audit ordering remain responsibilities of authoritative `document_records`/`audit_provenance` persistence rather than an in-process Python object. +- Clearfolio and NewsDOM remain read-only external dependencies through published contracts; this ADR creates no cross-service application-table access. +- W3C PROV-O and NIST Privacy Framework 1.0 are design inputs only; no conformance or certification claim is made. + +## Follow-up + +A later bounded slice may add authoritative 3NF document metadata persistence, object-store authorization, lifecycle reconciliation, malware/content validation and governed preview/OCR adapters. Those changes must preserve tenant isolation, purpose-bound access, retention/legal-hold controls and immutable audit/outbox evidence. From 556d71948fd7c1359af0df7d28121b954a7ba60c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 23 Aug 2026 03:08:38 -0700 Subject: [PATCH 11/23] test(document-records): cover exact trust-boundary rejection branches --- packages/document-record-evidence/tests/test_evidence.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/document-record-evidence/tests/test_evidence.py b/packages/document-record-evidence/tests/test_evidence.py index 4e7c962f1..2cbd0798d 100644 --- a/packages/document-record-evidence/tests/test_evidence.py +++ b/packages/document-record-evidence/tests/test_evidence.py @@ -1,7 +1,7 @@ """Executable contract for value-minimized HR document-record evidence.""" from datetime import datetime, timedelta, timezone -from uuid import UUID, uuid4 +from uuid import UUID, uuid1, uuid4 import pytest @@ -59,10 +59,16 @@ def test_generates_packet_owned_reference_and_system_time() -> None: @pytest.mark.parametrize( ("field_name", "bad_value"), [ + ("tenant_record_id", 7), ("tenant_record_id", "not-a-uuid"), + ("tenant_record_id", "00000000-0000-0000-0000-000000000000"), + ("person_record_reference", 7), + ("person_record_reference", f"wrong_namespace:{uuid4()}"), + ("person_record_reference", f"person_record:{uuid1()}"), ("person_record_reference", "person_record:"), ("employment_record_reference", "employment_record:"), ("uploader_actor_reference", "actor:Jane-Doe"), + ("document_category_code", 7), ("document_category_code", "free_form_category"), ("artifact_reference", "document_artifact:"), ("artifact_digest", "A" * 64), From d4edde31fe5e9ff01a415410dafd8eea8209ecbd Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 23 Aug 2026 03:09:45 -0700 Subject: [PATCH 12/23] test(document-records): prove valid-value post-issuance rewrite RED --- packages/document-record-evidence/tests/test_evidence.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/document-record-evidence/tests/test_evidence.py b/packages/document-record-evidence/tests/test_evidence.py index 2cbd0798d..afe8d721b 100644 --- a/packages/document-record-evidence/tests/test_evidence.py +++ b/packages/document-record-evidence/tests/test_evidence.py @@ -99,3 +99,11 @@ def test_rejects_non_utc_received_time() -> None: payload["received_at"] = datetime.now().replace(tzinfo=None) with pytest.raises(ValueError, match="received_at must be an exact built-in UTC datetime"): build_document_record_evidence(**payload) + + +def test_rejects_valid_value_rewrite_after_issuance() -> None: + """Do not emit a second evidence truth after a frozen packet is forcibly rewritten.""" + evidence = build_document_record_evidence(**values()) + object.__setattr__(evidence, "document_category_code", "policy_acknowledgement") + with pytest.raises(ValueError, match="document record evidence changed after construction"): + evidence.canonical_json() From fdd09b1e2a912151126671604886bd7f252c0073 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 23 Aug 2026 03:11:48 -0700 Subject: [PATCH 13/23] fix(document-records): seal exact issuance evidence --- .../evidence.py | 67 ++++++++++++++----- 1 file changed, 51 insertions(+), 16 deletions(-) diff --git a/packages/document-record-evidence/src/orgmetra_document_record_evidence/evidence.py b/packages/document-record-evidence/src/orgmetra_document_record_evidence/evidence.py index b480f6c06..0e6c356dd 100644 --- a/packages/document-record-evidence/src/orgmetra_document_record_evidence/evidence.py +++ b/packages/document-record-evidence/src/orgmetra_document_record_evidence/evidence.py @@ -11,10 +11,13 @@ from dataclasses import dataclass, field from datetime import datetime, timezone from hashlib import sha256 +import hmac import json import re +from threading import RLock from typing import Any from uuid import UUID, uuid4 +from weakref import WeakKeyDictionary _DIGEST_PATTERN = re.compile(r"^[0-9a-f]{64}$") _ALLOWED_DOCUMENT_CATEGORIES = frozenset( @@ -24,6 +27,8 @@ _CONTENT_STORAGE_STATE = "artifact_reference_only" _DECISION_AUTHORITY_STATE = "not_authorized_for_employment_decision" _SCHEMA_VERSION = "orgmetra.document_record_evidence.v1" +_ISSUANCE_LOCK = RLock() +_ISSUANCE_DIGESTS: WeakKeyDictionary[DocumentRecordEvidence, str] def _validate_operational_uuid(value: str, field_name: str) -> None: @@ -77,7 +82,17 @@ def _now_utc() -> datetime: return datetime.now(timezone.utc) -@dataclass(frozen=True, slots=True, repr=False) +def _canonical_json(payload: dict[str, Any]) -> str: + """Serialize one already-snapshotted evidence payload deterministically.""" + return json.dumps(payload, sort_keys=True, separators=(",", ":"), ensure_ascii=True) + + +def _payload_digest(payload: dict[str, Any]) -> str: + """Return SHA-256 over one exact canonical payload snapshot.""" + return sha256(_canonical_json(payload).encode("utf-8")).hexdigest() + + +@dataclass(frozen=True, slots=True, weakref_slot=True, repr=False, eq=False) class DocumentRecordEvidence: """Governed metadata evidence for one HR document artifact. @@ -105,7 +120,18 @@ class DocumentRecordEvidence: schema_version: str = field(default=_SCHEMA_VERSION, init=False) def __post_init__(self) -> None: - """Validate all caller-controlled trust evidence before export.""" + """Validate caller evidence and seal the exact issuance payload outside writable slots.""" + self._validate() + payload = self._payload() + with _ISSUANCE_LOCK: + _ISSUANCE_DIGESTS[self] = _payload_digest(payload) + + def __repr__(self) -> str: + """Avoid exposing HR document correlations in routine logs.""" + return "DocumentRecordEvidence()" + + def _validate(self) -> None: + """Fail closed when caller-controlled fields violate the reviewed evidence contract.""" _validate_operational_uuid(self.tenant_record_id, "tenant_record_id") _validate_uuid4_reference( self.person_record_reference, "person_record", "person_record_reference" @@ -135,12 +161,8 @@ def __post_init__(self) -> None: _validate_digest(self.retention_policy_digest, "retention_policy_digest") _validate_received_at(self.received_at, self.recorded_at) - def __repr__(self) -> str: - """Avoid exposing HR document correlations in routine logs.""" - return "DocumentRecordEvidence()" - - def canonical_document(self) -> dict[str, Any]: - """Return deterministic, value-minimized document metadata evidence.""" + def _payload(self) -> dict[str, Any]: + """Snapshot the exact value-minimized evidence fields once.""" return { "artifact_digest": self.artifact_digest, "artifact_reference": self.artifact_reference, @@ -161,20 +183,33 @@ def canonical_document(self) -> dict[str, Any]: "uploader_actor_reference": self.uploader_actor_reference, } + def _verified_payload(self) -> dict[str, Any]: + """Validate and return the same payload snapshot whose issuance seal was verified.""" + self._validate() + payload = self._payload() + actual_digest = _payload_digest(payload) + with _ISSUANCE_LOCK: + expected_digest = _ISSUANCE_DIGESTS.get(self, f"missing:{actual_digest}") + if not hmac.compare_digest(expected_digest, actual_digest): + raise ValueError("document record evidence changed after construction") + return payload + + def canonical_document(self) -> dict[str, Any]: + """Return deterministic, value-minimized document metadata evidence.""" + return self._verified_payload() + def canonical_json(self) -> str: - """Return deterministic UTF-8-safe JSON for immutable audit correlation.""" - return json.dumps( - self.canonical_document(), - sort_keys=True, - separators=(",", ":"), - ensure_ascii=True, - ) + """Return deterministic JSON over the exact verified payload snapshot.""" + return _canonical_json(self._verified_payload()) def sha256_digest(self) -> str: - """Return SHA-256 over the exact canonical JSON bytes.""" + """Return SHA-256 over the exact verified canonical JSON bytes.""" return sha256(self.canonical_json().encode("utf-8")).hexdigest() +_ISSUANCE_DIGESTS = WeakKeyDictionary() + + def build_document_record_evidence( *, tenant_record_id: str, From 3853331b30e45b0791988c4c0b36dfe0688962f2 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 23 Aug 2026 03:12:10 -0700 Subject: [PATCH 14/23] docs(document-records): document issuance integrity boundary --- packages/document-record-evidence/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/document-record-evidence/README.md b/packages/document-record-evidence/README.md index 80181a5a2..7f137e070 100644 --- a/packages/document-record-evidence/README.md +++ b/packages/document-record-evidence/README.md @@ -8,6 +8,8 @@ The packet is not a storage credential, legal retention determination, or employ `document_record_reference` and `recorded_at` are generated inside the Orgmetra issuance boundary so callers cannot claim a chosen system-recorded identity or timestamp. Caller-owned `received_at` remains separate business-event time and must be exact built-in UTC and no later than issuance. +The Python value also keeps its creation-time canonical evidence digest in a process-local weak issuance registry outside packet-writable slots. Every export validates the live fields, snapshots them once, and compares that exact snapshot with the issuance digest before returning document or JSON evidence. This is **defense in depth against accidental or same-process post-construction rewriting**, not durable cryptographic attestation: authoritative persistence must store the already-emitted canonical evidence and digest through Orgmetra's immutable audit/outbox boundary. + The closed initial document-category vocabulary is `employment_contract`, `policy_acknowledgement`, and `qualification_document`. New categories require a reviewed contract change rather than free-form metadata. This package does not fetch or mutate Clearfolio, NewsDOM, or any other dedicated-writer CWL service and introduces no cross-service application-table SQL. From 278b4199d5d1ce4c4525b8c6d7d9f9aae79edda9 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 23 Aug 2026 03:12:15 -0700 Subject: [PATCH 15/23] docs(document-records): record post-issuance tamper repair --- packages/document-record-evidence/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/document-record-evidence/CHANGELOG.md b/packages/document-record-evidence/CHANGELOG.md index 75ea205ef..8208c22dc 100644 --- a/packages/document-record-evidence/CHANGELOG.md +++ b/packages/document-record-evidence/CHANGELOG.md @@ -4,4 +4,5 @@ - Add value-minimized HR document-record metadata evidence with Orgmetra-generated record identity and system-recorded time. - Bind artifact integrity, source provenance and retention-policy evidence without copying document content or HR field values. +- Reject valid-value post-issuance rewrites by comparing each export against a process-local creation-time canonical evidence digest; durable immutability remains owned by authoritative audit/outbox persistence. - Add an exact-head, installed-wheel quality lane with 100% owned statement/branch coverage requirement. From 2e0ba63d2cc566fb8d1e8d244f1f6fa15d57e5c0 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 23 Aug 2026 03:12:23 -0700 Subject: [PATCH 16/23] docs(document-records): trace issuance integrity repair --- docs/traceability/document-record-evidence.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/traceability/document-record-evidence.md b/docs/traceability/document-record-evidence.md index d5f6a903c..09bf9b015 100644 --- a/docs/traceability/document-record-evidence.md +++ b/docs/traceability/document-record-evidence.md @@ -15,9 +15,12 @@ | Record identity and system-recorded time are Orgmetra-generated | `test_generates_packet_owned_reference_and_system_time` | | Artifact, provenance and retention-policy integrity are SHA-256-bound | malformed digest regressions plus canonical digest assertion | | Caller business receipt time remains distinct from system-recorded time | future/non-UTC receipt-time regressions | +| A valid-value rewrite after issuance cannot emit a second canonical truth | `test_rejects_valid_value_rewrite_after_issuance`; process-local creation digest is stored outside packet-writable slots and the verified payload snapshot is reused for export | | Owned production statement and branch coverage are exact 100% | `Document Record Evidence Quality` workflow | | Installed package, not source-tree import, is tested | exact-head hash-bound wheel build/install in `Document Record Evidence Quality` | +The process-local issuance digest is defense in depth only. It is not a durable signature, MAC key-management system, or substitute for database uniqueness/immutability. Durable evidence systems persist the already-emitted canonical bytes and digest through authoritative `document_records` and immutable `audit_provenance`/outbox persistence. + ## Next authoritative boundary Before any content read, export, disposition or high-impact HR action, the owning Orgmetra service must freshly re-resolve tenant, actor, purpose, resource, artifact digest/provenance, retention/legal-hold state and human authority, then write immutable audit/outbox evidence atomically with any consequential operation. From 52812dc2c200fa96f807fae3b0fbff58ac0ebba3 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 23 Aug 2026 03:12:38 -0700 Subject: [PATCH 17/23] docs(document-records): align ADR with issuance integrity --- docs/adr/0098-governed-document-record-evidence.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/adr/0098-governed-document-record-evidence.md b/docs/adr/0098-governed-document-record-evidence.md index 081c6f547..f5f7324a6 100644 --- a/docs/adr/0098-governed-document-record-evidence.md +++ b/docs/adr/0098-governed-document-record-evidence.md @@ -14,11 +14,13 @@ Canonical evidence is classified `restricted_hr`, records only `artifact_referen `received_at` and `recorded_at` remain distinct: receipt time is business/event time supplied by the source boundary; recorded time is generated by Orgmetra at evidence issuance and cannot precede receipt time. +A process-local weak issuance registry stores the creation-time canonical evidence digest outside packet-writable slots. Canonical export validates the live fields, snapshots the payload once, compares that exact snapshot against the creation digest, and returns only the verified snapshot. This rejects valid-value `object.__setattr__` rewriting after issuance without pretending that an in-process Python object is durable cryptographic evidence. + ## Consequences - Document metadata can be correlated to immutable artifacts and provenance without duplicating content. - The packet does not authorize storage access, export, retention/disposition or an employment decision. -- Durable immutability, uniqueness, access control and audit ordering remain responsibilities of authoritative `document_records`/`audit_provenance` persistence rather than an in-process Python object. +- Process-local tamper detection is defense in depth only; durable immutability, uniqueness, access control and audit ordering remain responsibilities of authoritative `document_records`/`audit_provenance` persistence. - Clearfolio and NewsDOM remain read-only external dependencies through published contracts; this ADR creates no cross-service application-table access. - W3C PROV-O and NIST Privacy Framework 1.0 are design inputs only; no conformance or certification claim is made. From 12a66a984bef02ed535260736ff4fd0b66a44eca Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 23 Aug 2026 03:14:26 -0700 Subject: [PATCH 18/23] test(document-records): prove ADR-only changes cannot bypass quality --- .../document-record-evidence/tests/test_evidence.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/document-record-evidence/tests/test_evidence.py b/packages/document-record-evidence/tests/test_evidence.py index afe8d721b..e6bcf9acd 100644 --- a/packages/document-record-evidence/tests/test_evidence.py +++ b/packages/document-record-evidence/tests/test_evidence.py @@ -1,6 +1,7 @@ """Executable contract for value-minimized HR document-record evidence.""" from datetime import datetime, timedelta, timezone +from pathlib import Path from uuid import UUID, uuid1, uuid4 import pytest @@ -107,3 +108,12 @@ def test_rejects_valid_value_rewrite_after_issuance() -> None: object.__setattr__(evidence, "document_category_code", "policy_acknowledgement") with pytest.raises(ValueError, match="document record evidence changed after construction"): evidence.canonical_json() + + +def test_quality_workflow_watches_governance_adr() -> None: + """Ensure an ADR-only contract edit cannot bypass the dedicated package gate.""" + repository_root = Path(__file__).resolve().parents[3] + workflow = ( + repository_root / ".github" / "workflows" / "document-record-evidence-quality.yml" + ).read_text(encoding="utf-8") + assert '"docs/adr/0098-governed-document-record-evidence.md"' in workflow From 9aeeb204acce429f85b028029c9531a5b05f37e1 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 23 Aug 2026 03:15:30 -0700 Subject: [PATCH 19/23] fix(document-records): gate ADR-only contract changes --- .github/workflows/document-record-evidence-quality.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/document-record-evidence-quality.yml b/.github/workflows/document-record-evidence-quality.yml index d41242aae..5ecfe621f 100644 --- a/.github/workflows/document-record-evidence-quality.yml +++ b/.github/workflows/document-record-evidence-quality.yml @@ -8,6 +8,7 @@ on: - "packages/document-record-evidence/**" - ".github/requirements/foundation-test.txt" - ".github/workflows/document-record-evidence-quality.yml" + - "docs/adr/0098-governed-document-record-evidence.md" - "docs/doctoring/document-record-evidence-references.md" - "docs/traceability/document-record-evidence.md" workflow_dispatch: From a96dca08d36878f8b6d381ef494e39e4f88d45d1 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 28 Aug 2026 20:41:49 +0900 Subject: [PATCH 20/23] docs: record document evidence active PR --- CHANGELOG.md | 1 + manifest.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 99f4752d7..10bae6906 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ All notable changes to Orgmetra will be documented in this file. - Accepted ADRs 0001–0003 now include buyer-facing Context, Decision, and Consequences grounded in verified ISO 30400:2022, ISO 30414:2025, Uniform Guidelines (29 C.F.R. Part 1607), SIOP (2018), OpenAPI Specification v3.2.0, OpenID Connect Core 1.0 errata set 2, CloudEvents v1.0.2, Jensen and Snodgrass (1999), Snodgrass (1999), and Allen (1983) records already listed in `docs/doctoring/REFERENCES.md`. ADRs 0004 and 0005 gained APA 7th References pointers to that same bibliography without changing their Decision bodies. - Active-PR governed Job Analysis persistence/API on the canonical `JobAnalysisSnapshot` model: migration `0013_job_analysis_snapshot.sql` stores immutable tenant-scoped snapshot, Task, KSAO, Task–KSAO, FJA and write-command evidence; `POST /v1/tenants/{tenant_record_id}/job-analysis-snapshots` and matching GET enforce purpose-bound Keyverse scope, authenticated-principal actor authority, bounded/strict JSON handling, transactional Idempotency-Key serialization, parent-scope fail-closed integrity, forced RLS, and atomic audit/outbox evidence. ADR 0014 records the persistence decision while ADR 0007 remains the domain/evidence authority; validated evidence still requires accountable human review and non-LLM provenance, and the service does not make a high-impact employment decision. - Active-PR `orgmetra_selection_review` packet for PII-minimized, evidence-bound human selection review: canonical operational tenant identity, UUID-backed opaque candidate/Job/sealed-evidence/reviewer references, explicit purpose/reason/evidence version, deterministic canonical JSON and SHA-256 correlation, mandatory human decision state, redacted packet repr, and provenance-paired model evidence that remains `untrusted_draft`, with exact 100% owned statement and branch coverage required by its quality gate. +- Active-PR `DocumentRecordEvidence` for value-minimized HR document metadata: tenant/Person/Employment scope, reviewed category, opaque artifact and provenance/retention digests, separate business receipt and Orgmetra-generated system-recorded time, process-local tamper detection, and no document content or employment-decision authority. - Active performance-criterion scope hardening: `criterion_observation_scope_guard` rejects criterion outcomes for a Job the worker did not effectively hold at the observation date, observations before the relevant assignment, and observations outside the referenced performance cycle while preserving valid multiple-assignment cases and existing bitemporal correction semantics. The guard evaluates current-recorded facts, derives the date coordinate from `observed_at` in UTC so session `TimeZone` cannot alter the result, uses a trusted function search path, and adds no PII or automated employment decision authority. The Foundation PostgreSQL contract also rejects a closed `recorded_to` on each time-coordinate lookup and proves UTC midnight plus non-UTC session `TimeZone` boundaries. - Bitemporal tenant-scoped organization hierarchy validation that rejects visible indirect parent cycles and reuses single-valued recorded-time reconstruction before graph traversal. - Stacked governed job-analysis evidence contract via `JobAnalysisSnapshot`, `TaskEvidence`, `KSAORequirement`, `TaskKSAOLink`, `FunctionalJobAnalysisProfile`, and `EvidenceSource`: tenant/Job-scoped observable tasks, explicit Task-to-KSAO linkage, importance/difficulty/proficiency ratings, source/version/retrieval/SHA-256 provenance, deterministic canonical snapshot bytes, current O*NET evidence support, and historical DOT Data/People/Things compatibility. Validated snapshots require accountable human review and complete non-LLM evidence; LLM-origin material remains `analysis_draft`, and the snapshot is evidence input rather than a hiring, promotion, termination, compensation, or other high-impact employment decision. diff --git a/manifest.json b/manifest.json index 97f2bab14..00c4368e9 100644 --- a/manifest.json +++ b/manifest.json @@ -1 +1 @@ -{"package":"orgmetra-foundation-pack","version":"0.1.0","generated_for_branch":"feat/audit-outbox-envelope","files":[{"path":".github/workflows/foundation-ci.yml","sha256":"12686a3bbd6445e6fdb202b4137dae118ddeeab1efb0c7f18ea6c8fa19d62537","bytes":4379,"lines":123},{"path":".github/workflows/job-analysis-api-quality.yml","sha256":"352dc78931dd94afea3e88912d38dcc4b562a004112f199f3d7a12d22b6d637a","bytes":4159,"lines":105},{"path":".gitignore","sha256":"145fda644f5209fa1fb3e3b40c9af9258bfac6d1a634bba2520fd08fe6d77a21","bytes":375,"lines":37},{"path":"AGENTS.md","sha256":"28f7b7bc010a7739cfdc3e793fb5d39a0e74b842ea9c190e9a251e2d0cbc3a16","bytes":2246,"lines":34},{"path":"ARCHITECTURE.md","sha256":"52d68786f7359c1a50d804996021e4c70e90accd2fff6f1a27c91de1dd8df850","bytes":7864,"lines":107},{"path":"CHANGELOG.md","sha256":"32cc4ef78d1eca557fa01731026840be01211a043eb0ada552e4e6cb9eace353","bytes":17295,"lines":76},{"path":"CLAUDE.md","sha256":"add33884f466d324e20875388d103de41c6e062938a6e98727dc83a87ffe976f","bytes":1229,"lines":20},{"path":"LICENSE","sha256":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","bytes":11358,"lines":202},{"path":"NOTICE","sha256":"34b4618e946bdd8d33407d6ac5279f0a0388f5e7c8f79d2e7d8c3c47d0266042","bytes":305,"lines":4},{"path":"README.md","sha256":"1a9fc400d26d8137ae5911488794a6d3fa915957c95f27b36a48cef0fdf823c6","bytes":3785,"lines":81},{"path":"database/migrations/0001_foundation_schema.sql","sha256":"ce2ae52fc66b2f99597ea5285df82c66f90caa46174fef4930d68a8b6177d0dd","bytes":38747,"lines":916},{"path":"database/migrations/0002_sealed_evidence_digest.sql","sha256":"93d659ca8e0e9293a83d5422d043be7b1022c5470a5b22670aa3416fa334a04c","bytes":6649,"lines":202},{"path":"database/migrations/0003_audit_outbox_persistence.sql","sha256":"2aa7bbb8220923ec584537c0cd46f0cba2b692d69d431f097b7df6db75235bfc","bytes":15417,"lines":423},{"path":"database/migrations/0004_outbox_delivery_claim.sql","sha256":"d4504acf7d58528a2a8f4f03d1584b868c8d3ba9046a007b9c2e7cfef993b2ef","bytes":9451,"lines":234},{"path":"database/migrations/0005_outbox_delivery_finalization.sql","sha256":"b7e8790595b288f752d6ef5cc6cbfe4e1b6712248f5b7a3a25fa60016b6a4961","bytes":6125,"lines":170},{"path":"database/migrations/0006_outbox_delivery_dead_letter.sql","sha256":"c1fb91cdf98169fd6684984e86cb0a14fa19c8f1226028d2346a2a069df2b3c7","bytes":24919,"lines":628},{"path":"database/migrations/0007_outbox_retry_exhaustion.sql","sha256":"812f50d70ca5929c7eba964d34a208aedee660d11cc7ffc09d67688c4737e0d5","bytes":19081,"lines":476},{"path":"database/migrations/0008_audit_outbox_review_hardening.sql","sha256":"c3713a12db9d00fdc10005df1f86c07965e9555eefad78ca67e994537a739d9b","bytes":17562,"lines":448},{"path":"database/migrations/0009_candidate_worker_conversion_governance.sql","sha256":"4030666629a6b8deb383b8337ead4f09d6a945969313def2577a38f31f06cda9","bytes":11537,"lines":281},{"path":"database/migrations/0010_validity_study_case_integrity.sql","sha256":"3f594810ac9e1a6747a2bb4838e5ce65b921cb6e3d36fcdc3ff08b4a7579ebd1","bytes":11979,"lines":313},{"path":"database/migrations/0011_criterion_observation_scope.sql","sha256":"f9fe7c35f1ee7b167e1c2ba75a50a84febda9a6ccf8123b4f5726f51968694f9","bytes":7444,"lines":165},{"path":"database/migrations/0012_people_mutation_idempotency.sql","sha256":"52dbbb9ec7f9be5291593ba88f228d7fffd736dcb99547a08c1d6cad076afb69","bytes":3162,"lines":76},{"path":"database/migrations/0013_job_analysis_snapshot.sql","sha256":"b6553a5a4c94c4aa9f341a474e13bbe34db63044eda2446b3ebee178995977ee","bytes":12713,"lines":260},{"path":"docs/API_CONTRACT.md","sha256":"63533dff785da62b89e585d742a158e2aeb05913644f2bf9fb6486f281c2e589","bytes":4555,"lines":76},{"path":"docs/DATA_MODEL.md","sha256":"6ad29731ae7ee7aa5bf3a2d0bfef88894a35a2550edb2be3244d6f143d76444a","bytes":13366,"lines":85},{"path":"docs/ERD.md","sha256":"546001aa85c4fe020e0c39d881dc860daf7f69090596666fdf9092487b0725fe","bytes":6964,"lines":70},{"path":"docs/OPERABILITY.md","sha256":"82b2d3e70cec371ef35e9e0f982ac40fef84351976bc04b863b81d27023d5a62","bytes":11189,"lines":71},{"path":"docs/PRD.md","sha256":"3ad85ae633cce0fc7a93af39b21d7a7c70bb2efa786da6b12f3c5327906e34f1","bytes":5490,"lines":111},{"path":"docs/SECURITY.md","sha256":"01918512d8882060e9cff0c4aa8206e0eccbdfb61cfd7f829331123c7a9fe6ac","bytes":11185,"lines":64},{"path":"docs/STORYBOARD.md","sha256":"6e4ffb0eb03a80343f50d363ffc43b34da9348a44232dd947a9ff416ea92a3d2","bytes":1342,"lines":28},{"path":"docs/STORYBOOK.md","sha256":"82f79029b3c2b7a45393bad5ba8fabe61014d4b6149c7d4e73f70ba447f885e9","bytes":1389,"lines":50},{"path":"docs/TEST_STRATEGY.md","sha256":"d0a0bc3b54ed0fc7973747987f1afb117d6144c390b51ed9370eb571972a33f8","bytes":16534,"lines":135},{"path":"docs/THREAT_MODEL.md","sha256":"f314f375c2e41252536de224c7bc7e4a10ab8f340cb86642724e7399e32f4252","bytes":6736,"lines":23},{"path":"docs/TRACEABILITY.md","sha256":"dbf6fd91375ea28e05456d2a0c9ba629506cbac6f52f5dfda61ae68db2395f7e","bytes":11462,"lines":40},{"path":"docs/TRD.md","sha256":"23697d88a4882698e1a2782b7da3f2ccd0d3cd2d6d1bffe89b6597dc16851077","bytes":9064,"lines":101},{"path":"docs/UML.md","sha256":"fe67c37aa88e5814ceb2db7e8f7d8d85ca27a994802efbb7c75164b387adf0a9","bytes":5528,"lines":122},{"path":"docs/USER_STORIES.md","sha256":"5535b39d8c71a36c81f78e2d6dbd90a2d32e6541790f0d28f6dd4baf3ea7b45f","bytes":2670,"lines":37},{"path":"docs/WIREFRAMES.md","sha256":"b03aa6419aeaf5d42a5698c4d43a434c1633b7ac6fd0b0bd0cda979077adc56e","bytes":2005,"lines":77},{"path":"docs/adr/0001-orgmetra-authoritative-hris-record.md","sha256":"0f8055b73c63d3130321415ad53233588ff952aabd1a88952b39c71747253572","bytes":6108,"lines":53},{"path":"docs/adr/0002-federated-cwl-integration-boundaries.md","sha256":"b77165f2aacfa6f4fde994baf77d5879c6da3e8dae4fd2db0ed912d60ae9b3b2","bytes":4072,"lines":44},{"path":"docs/adr/0003-bitemporal-hris-data-contract.md","sha256":"d7f2660616622c1a7994b28aa66d99d13836bcf755735595f9609a41282ab799","bytes":4453,"lines":47},{"path":"docs/adr/0004-employment-position-version-and-assignment-binding.md","sha256":"fee89e700414abe0b1cffec2acc687e5e014634db8f5ef9e8a92abba5c3cf182","bytes":1872,"lines":30},{"path":"docs/adr/0005-exclusive-employment-and-staffable-seats.md","sha256":"10f0eb409f4fa32d2c5bed2d583d8b43be8e61b5cbef0e927e5bebb5f5c8f85b","bytes":2091,"lines":34},{"path":"docs/adr/0006-governed-audit-outbox-envelope.md","sha256":"827298ddd997b47f78a89e89911ad8ea72e517b7714303637f0329b8cb52cabd","bytes":14100,"lines":66},{"path":"docs/adr/0007-governed-job-analysis-evidence.md","sha256":"953c6d2b9864a78b461b576092ec3f198f0b76709eaaaf7d0ed0182f95182c52","bytes":5653,"lines":57},{"path":"docs/adr/0008-purpose-bound-pii-authorization.md","sha256":"c5157d3bc58f3d8d29e03104dd15eb2911cc1bb66e2c92a935b26d7164648dc7","bytes":5988,"lines":55},{"path":"docs/adr/0009-performance-criterion-observation-scope.md","sha256":"1ac10bb2747b0a5b4d62f627825cfd7f978f3fa88d7575bffc23d56371240a64","bytes":7057,"lines":57},{"path":"docs/adr/0010-naruon-calendar-intent-boundary.md","sha256":"3e1050a964cc4ed76a1a0cf1e699ae5080acf8c9336f0decdd6d5229359db3c9","bytes":3917,"lines":35},{"path":"docs/adr/0011-bitemporal-workforce-composition.md","sha256":"1656ef8b57c836ef7936a8e9cb6a824681eb7563157a1ab0a29deb25849a457b","bytes":5568,"lines":53},{"path":"docs/adr/0012-governed-migration-handoff.md","sha256":"713855d670001d3964ecb36cc653830502fb1d82a58b9e39f564b6992dd2bd80","bytes":5965,"lines":59},{"path":"docs/adr/0013-governed-requisition-review-packet.md","sha256":"70bf2cbdf903a8793d6d8bc116a08331931090118341f42010236e09c6cc1802","bytes":4693,"lines":46},{"path":"docs/adr/0014-job-analysis-snapshot-persistence.md","sha256":"a7ab6fee50aaa63f7f407516a4cb39885faeb0fc6e5035ee8fc352ed73430105","bytes":5365,"lines":49},{"path":"docs/adr/README.md","sha256":"f3b3b5ed3b3b31a40a0a3696abf0065e3c25879b6be50077f38ffae742b9d002","bytes":1838,"lines":18},{"path":"docs/doctoring/REFERENCES.md","sha256":"929f7ee36df16279f028f726fcf039982180deb377746fe3804f3c0d090778d5","bytes":6352,"lines":69},{"path":"docs/superpowers/plans/2026-08-15-orgmetra-foundation-implementation-plan.md","sha256":"b64f21abb19373e780db8b9e64deb8ba9a6219ccf9625a651f25407b8691fcbd","bytes":8227,"lines":226},{"path":"docs/superpowers/specs/2026-08-15-orgmetra-foundation-design.md","sha256":"4a0e1a7943e40d12bd3082db3757045b4085e5a089fea7bc0d8a1565ffcbcf1d","bytes":6237,"lines":187},{"path":"package.json","sha256":"59ae9e3e67c3fba9320cb18439692395cdfd16ae5c24e3c4cf30d77d63ebabb5","bytes":388,"lines":9},{"path":"packages/hris-kernel/src/orgmetra_hris_kernel/audit.py","sha256":"3e5b7190cf857dc8c1fc7e898cef303060f34aabee6c27a9034d4d9650e33190","bytes":7707,"lines":160},{"path":"packages/hris-kernel/tests/test_audit_outbox.py","sha256":"5928dd7b97fe38d6b7472ce62966437e339058a59c3b301a93a7b5c05432b40c","bytes":7556,"lines":200},{"path":"schemas/openapi.yaml","sha256":"09c1e43486779198574fe31b8bcabbd1c1f74beec7bf86245ae578061619838f","bytes":29503,"lines":1020},{"path":"scripts/foundation-contract-core.mjs","sha256":"595e8381dbd62e97093b11eef818af5f04d6473ac592d57e3985ffbc2210d445","bytes":28173,"lines":689},{"path":"scripts/foundation-contract.mjs","sha256":"5242dcdbe0935775edf074462c82600e9bc4927d9fdc50c47727af915fd4b23a","bytes":218,"lines":6},{"path":"tests/dispatcher-inventory.test.mjs","sha256":"09f5e64410e6b7a26bf8d6ce61c50b737da2ea85d955f91eba63aa21f1537261","bytes":1597,"lines":34},{"path":"tests/foundation-contract.test.mjs","sha256":"960306fd7cda7b982a52c4428a432d10a4f570430a5d39fb23aeca0b2ede0615","bytes":14860,"lines":386},{"path":"tests/openapi-contract.test.mjs","sha256":"80c1610ef1c189fa325e55389501e0e51531ddf61ee335bb94d9cb3aa55a9fdc","bytes":6438,"lines":195},{"path":"tests/test_audit_outbox_hardening_postgres.sh","sha256":"518ba2f37ba6292943e5abe22c2599452b2f031a42e453b2493aedf8714421a0","bytes":13396,"lines":333},{"path":"tests/test_audit_outbox_postgres.sh","sha256":"e57a04920a0ba97fa6a06752d15ea150016ab8d44099e998c5c4f4067592b4d2","bytes":13443,"lines":357},{"path":"tests/test_bitemporal_postgres.sh","sha256":"7684b8c2ff52c044c081135515bd5aabbfd00e2daad0d471b0868701af2df6cc","bytes":8209,"lines":230},{"path":"tests/test_candidate_worker_conversion_postgres.sh","sha256":"681cb74d6cfa859ed92c6c2439881ea20c430ef8df94ec662e2807761a377f90","bytes":14673,"lines":344},{"path":"tests/test_criterion_observation_scope_postgres.sh","sha256":"0ee9539ee57f840c27d08009f7868cdc8662669df78a01dbc8be39216b8f1a3d","bytes":17811,"lines":469},{"path":"tests/test_evidence_sealing_postgres.sh","sha256":"57d16b632a0c60ffdcb4842ceb1cfe25d19c54cefeeefb622ff4fa6e83441ad7","bytes":11349,"lines":370},{"path":"tests/test_job_analysis_snapshot_postgres.sh","sha256":"ca9c323a1dd68cfc520277efbbb7495e37fb3ca027890928c8624e5b4f57403f","bytes":13542,"lines":296},{"path":"tests/test_operational_uuid_postgres.sh","sha256":"7378f98f0d4b3000e8ea641d8701f1540dbad71410b3637d81d799969e0f6ff7","bytes":3346,"lines":101},{"path":"tests/test_outbox_claim_postgres.sh","sha256":"1027806d436ebfe34e108c25b6a4001f43b9550f1d70057c6c0d7974323b0c9b","bytes":14817,"lines":429},{"path":"tests/test_outbox_dead_letter_postgres.sh","sha256":"0d728d578e64252e6079f2d141ddaa7fa9cfbf9784e625832273596d69a6e13d","bytes":14008,"lines":377},{"path":"tests/test_people_mutation_idempotency_postgres.sh","sha256":"3f57e12f80bd1b034c9aac54b669d8530106e3e26b3795689671fb53807b3cd5","bytes":16191,"lines":381},{"path":"tests/test_tenant_isolation_postgres.sh","sha256":"dd649435ef8ab9e57f0609c101917e36656a6d40d63de9bcdbdac23d764f6c3a","bytes":15134,"lines":388},{"path":"tests/test_validity_study_case_postgres.sh","sha256":"0070ad58300323c7f9900c5645e0df3106b36ccd245ae686e982c2fd6fa4dc02","bytes":14708,"lines":301},{"path":"tests/validate_repository.py","sha256":"918cf92fd18d81572e9bd5f5daa7f033c32731e2e13f0d00661d1c1de30b12a9","bytes":27291,"lines":638}]} +{"package":"orgmetra-foundation-pack","version":"0.1.0","generated_for_branch":"feat/audit-outbox-envelope","files":[{"path":".github/workflows/foundation-ci.yml","sha256":"12686a3bbd6445e6fdb202b4137dae118ddeeab1efb0c7f18ea6c8fa19d62537","bytes":4379,"lines":123},{"path":".github/workflows/job-analysis-api-quality.yml","sha256":"352dc78931dd94afea3e88912d38dcc4b562a004112f199f3d7a12d22b6d637a","bytes":4159,"lines":105},{"path":".gitignore","sha256":"145fda644f5209fa1fb3e3b40c9af9258bfac6d1a634bba2520fd08fe6d77a21","bytes":375,"lines":37},{"path":"AGENTS.md","sha256":"28f7b7bc010a7739cfdc3e793fb5d39a0e74b842ea9c190e9a251e2d0cbc3a16","bytes":2246,"lines":34},{"path":"ARCHITECTURE.md","sha256":"52d68786f7359c1a50d804996021e4c70e90accd2fff6f1a27c91de1dd8df850","bytes":7864,"lines":107},{"path":"CHANGELOG.md","sha256":"ad6219494fe7c7ff602ba79e6cb2534d7e35c17e0f16be0f1bef5bcd8911f91b","bytes":17636,"lines":77},{"path":"CLAUDE.md","sha256":"add33884f466d324e20875388d103de41c6e062938a6e98727dc83a87ffe976f","bytes":1229,"lines":20},{"path":"LICENSE","sha256":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","bytes":11358,"lines":202},{"path":"NOTICE","sha256":"34b4618e946bdd8d33407d6ac5279f0a0388f5e7c8f79d2e7d8c3c47d0266042","bytes":305,"lines":4},{"path":"README.md","sha256":"1a9fc400d26d8137ae5911488794a6d3fa915957c95f27b36a48cef0fdf823c6","bytes":3785,"lines":81},{"path":"database/migrations/0001_foundation_schema.sql","sha256":"ce2ae52fc66b2f99597ea5285df82c66f90caa46174fef4930d68a8b6177d0dd","bytes":38747,"lines":916},{"path":"database/migrations/0002_sealed_evidence_digest.sql","sha256":"93d659ca8e0e9293a83d5422d043be7b1022c5470a5b22670aa3416fa334a04c","bytes":6649,"lines":202},{"path":"database/migrations/0003_audit_outbox_persistence.sql","sha256":"2aa7bbb8220923ec584537c0cd46f0cba2b692d69d431f097b7df6db75235bfc","bytes":15417,"lines":423},{"path":"database/migrations/0004_outbox_delivery_claim.sql","sha256":"d4504acf7d58528a2a8f4f03d1584b868c8d3ba9046a007b9c2e7cfef993b2ef","bytes":9451,"lines":234},{"path":"database/migrations/0005_outbox_delivery_finalization.sql","sha256":"b7e8790595b288f752d6ef5cc6cbfe4e1b6712248f5b7a3a25fa60016b6a4961","bytes":6125,"lines":170},{"path":"database/migrations/0006_outbox_delivery_dead_letter.sql","sha256":"c1fb91cdf98169fd6684984e86cb0a14fa19c8f1226028d2346a2a069df2b3c7","bytes":24919,"lines":628},{"path":"database/migrations/0007_outbox_retry_exhaustion.sql","sha256":"812f50d70ca5929c7eba964d34a208aedee660d11cc7ffc09d67688c4737e0d5","bytes":19081,"lines":476},{"path":"database/migrations/0008_audit_outbox_review_hardening.sql","sha256":"c3713a12db9d00fdc10005df1f86c07965e9555eefad78ca67e994537a739d9b","bytes":17562,"lines":448},{"path":"database/migrations/0009_candidate_worker_conversion_governance.sql","sha256":"4030666629a6b8deb383b8337ead4f09d6a945969313def2577a38f31f06cda9","bytes":11537,"lines":281},{"path":"database/migrations/0010_validity_study_case_integrity.sql","sha256":"3f594810ac9e1a6747a2bb4838e5ce65b921cb6e3d36fcdc3ff08b4a7579ebd1","bytes":11979,"lines":313},{"path":"database/migrations/0011_criterion_observation_scope.sql","sha256":"f9fe7c35f1ee7b167e1c2ba75a50a84febda9a6ccf8123b4f5726f51968694f9","bytes":7444,"lines":165},{"path":"database/migrations/0012_people_mutation_idempotency.sql","sha256":"52dbbb9ec7f9be5291593ba88f228d7fffd736dcb99547a08c1d6cad076afb69","bytes":3162,"lines":76},{"path":"database/migrations/0013_job_analysis_snapshot.sql","sha256":"b6553a5a4c94c4aa9f341a474e13bbe34db63044eda2446b3ebee178995977ee","bytes":12713,"lines":260},{"path":"docs/API_CONTRACT.md","sha256":"63533dff785da62b89e585d742a158e2aeb05913644f2bf9fb6486f281c2e589","bytes":4555,"lines":76},{"path":"docs/DATA_MODEL.md","sha256":"6ad29731ae7ee7aa5bf3a2d0bfef88894a35a2550edb2be3244d6f143d76444a","bytes":13366,"lines":85},{"path":"docs/ERD.md","sha256":"546001aa85c4fe020e0c39d881dc860daf7f69090596666fdf9092487b0725fe","bytes":6964,"lines":70},{"path":"docs/OPERABILITY.md","sha256":"82b2d3e70cec371ef35e9e0f982ac40fef84351976bc04b863b81d27023d5a62","bytes":11189,"lines":71},{"path":"docs/PRD.md","sha256":"3ad85ae633cce0fc7a93af39b21d7a7c70bb2efa786da6b12f3c5327906e34f1","bytes":5490,"lines":111},{"path":"docs/SECURITY.md","sha256":"01918512d8882060e9cff0c4aa8206e0eccbdfb61cfd7f829331123c7a9fe6ac","bytes":11185,"lines":64},{"path":"docs/STORYBOARD.md","sha256":"6e4ffb0eb03a80343f50d363ffc43b34da9348a44232dd947a9ff416ea92a3d2","bytes":1342,"lines":28},{"path":"docs/STORYBOOK.md","sha256":"82f79029b3c2b7a45393bad5ba8fabe61014d4b6149c7d4e73f70ba447f885e9","bytes":1389,"lines":50},{"path":"docs/TEST_STRATEGY.md","sha256":"d0a0bc3b54ed0fc7973747987f1afb117d6144c390b51ed9370eb571972a33f8","bytes":16534,"lines":135},{"path":"docs/THREAT_MODEL.md","sha256":"f314f375c2e41252536de224c7bc7e4a10ab8f340cb86642724e7399e32f4252","bytes":6736,"lines":23},{"path":"docs/TRACEABILITY.md","sha256":"dbf6fd91375ea28e05456d2a0c9ba629506cbac6f52f5dfda61ae68db2395f7e","bytes":11462,"lines":40},{"path":"docs/TRD.md","sha256":"23697d88a4882698e1a2782b7da3f2ccd0d3cd2d6d1bffe89b6597dc16851077","bytes":9064,"lines":101},{"path":"docs/UML.md","sha256":"fe67c37aa88e5814ceb2db7e8f7d8d85ca27a994802efbb7c75164b387adf0a9","bytes":5528,"lines":122},{"path":"docs/USER_STORIES.md","sha256":"5535b39d8c71a36c81f78e2d6dbd90a2d32e6541790f0d28f6dd4baf3ea7b45f","bytes":2670,"lines":37},{"path":"docs/WIREFRAMES.md","sha256":"b03aa6419aeaf5d42a5698c4d43a434c1633b7ac6fd0b0bd0cda979077adc56e","bytes":2005,"lines":77},{"path":"docs/adr/0001-orgmetra-authoritative-hris-record.md","sha256":"0f8055b73c63d3130321415ad53233588ff952aabd1a88952b39c71747253572","bytes":6108,"lines":53},{"path":"docs/adr/0002-federated-cwl-integration-boundaries.md","sha256":"b77165f2aacfa6f4fde994baf77d5879c6da3e8dae4fd2db0ed912d60ae9b3b2","bytes":4072,"lines":44},{"path":"docs/adr/0003-bitemporal-hris-data-contract.md","sha256":"d7f2660616622c1a7994b28aa66d99d13836bcf755735595f9609a41282ab799","bytes":4453,"lines":47},{"path":"docs/adr/0004-employment-position-version-and-assignment-binding.md","sha256":"fee89e700414abe0b1cffec2acc687e5e014634db8f5ef9e8a92abba5c3cf182","bytes":1872,"lines":30},{"path":"docs/adr/0005-exclusive-employment-and-staffable-seats.md","sha256":"10f0eb409f4fa32d2c5bed2d583d8b43be8e61b5cbef0e927e5bebb5f5c8f85b","bytes":2091,"lines":34},{"path":"docs/adr/0006-governed-audit-outbox-envelope.md","sha256":"827298ddd997b47f78a89e89911ad8ea72e517b7714303637f0329b8cb52cabd","bytes":14100,"lines":66},{"path":"docs/adr/0007-governed-job-analysis-evidence.md","sha256":"953c6d2b9864a78b461b576092ec3f198f0b76709eaaaf7d0ed0182f95182c52","bytes":5653,"lines":57},{"path":"docs/adr/0008-purpose-bound-pii-authorization.md","sha256":"c5157d3bc58f3d8d29e03104dd15eb2911cc1bb66e2c92a935b26d7164648dc7","bytes":5988,"lines":55},{"path":"docs/adr/0009-performance-criterion-observation-scope.md","sha256":"1ac10bb2747b0a5b4d62f627825cfd7f978f3fa88d7575bffc23d56371240a64","bytes":7057,"lines":57},{"path":"docs/adr/0010-naruon-calendar-intent-boundary.md","sha256":"3e1050a964cc4ed76a1a0cf1e699ae5080acf8c9336f0decdd6d5229359db3c9","bytes":3917,"lines":35},{"path":"docs/adr/0011-bitemporal-workforce-composition.md","sha256":"1656ef8b57c836ef7936a8e9cb6a824681eb7563157a1ab0a29deb25849a457b","bytes":5568,"lines":53},{"path":"docs/adr/0012-governed-migration-handoff.md","sha256":"713855d670001d3964ecb36cc653830502fb1d82a58b9e39f564b6992dd2bd80","bytes":5965,"lines":59},{"path":"docs/adr/0013-governed-requisition-review-packet.md","sha256":"70bf2cbdf903a8793d6d8bc116a08331931090118341f42010236e09c6cc1802","bytes":4693,"lines":46},{"path":"docs/adr/0014-job-analysis-snapshot-persistence.md","sha256":"a7ab6fee50aaa63f7f407516a4cb39885faeb0fc6e5035ee8fc352ed73430105","bytes":5365,"lines":49},{"path":"docs/adr/README.md","sha256":"f3b3b5ed3b3b31a40a0a3696abf0065e3c25879b6be50077f38ffae742b9d002","bytes":1838,"lines":18},{"path":"docs/doctoring/REFERENCES.md","sha256":"929f7ee36df16279f028f726fcf039982180deb377746fe3804f3c0d090778d5","bytes":6352,"lines":69},{"path":"docs/superpowers/plans/2026-08-15-orgmetra-foundation-implementation-plan.md","sha256":"b64f21abb19373e780db8b9e64deb8ba9a6219ccf9625a651f25407b8691fcbd","bytes":8227,"lines":226},{"path":"docs/superpowers/specs/2026-08-15-orgmetra-foundation-design.md","sha256":"4a0e1a7943e40d12bd3082db3757045b4085e5a089fea7bc0d8a1565ffcbcf1d","bytes":6237,"lines":187},{"path":"package.json","sha256":"59ae9e3e67c3fba9320cb18439692395cdfd16ae5c24e3c4cf30d77d63ebabb5","bytes":388,"lines":9},{"path":"packages/hris-kernel/src/orgmetra_hris_kernel/audit.py","sha256":"3e5b7190cf857dc8c1fc7e898cef303060f34aabee6c27a9034d4d9650e33190","bytes":7707,"lines":160},{"path":"packages/hris-kernel/tests/test_audit_outbox.py","sha256":"5928dd7b97fe38d6b7472ce62966437e339058a59c3b301a93a7b5c05432b40c","bytes":7556,"lines":200},{"path":"schemas/openapi.yaml","sha256":"09c1e43486779198574fe31b8bcabbd1c1f74beec7bf86245ae578061619838f","bytes":29503,"lines":1020},{"path":"scripts/foundation-contract-core.mjs","sha256":"595e8381dbd62e97093b11eef818af5f04d6473ac592d57e3985ffbc2210d445","bytes":28173,"lines":689},{"path":"scripts/foundation-contract.mjs","sha256":"5242dcdbe0935775edf074462c82600e9bc4927d9fdc50c47727af915fd4b23a","bytes":218,"lines":6},{"path":"tests/dispatcher-inventory.test.mjs","sha256":"09f5e64410e6b7a26bf8d6ce61c50b737da2ea85d955f91eba63aa21f1537261","bytes":1597,"lines":34},{"path":"tests/foundation-contract.test.mjs","sha256":"960306fd7cda7b982a52c4428a432d10a4f570430a5d39fb23aeca0b2ede0615","bytes":14860,"lines":386},{"path":"tests/openapi-contract.test.mjs","sha256":"80c1610ef1c189fa325e55389501e0e51531ddf61ee335bb94d9cb3aa55a9fdc","bytes":6438,"lines":195},{"path":"tests/test_audit_outbox_hardening_postgres.sh","sha256":"518ba2f37ba6292943e5abe22c2599452b2f031a42e453b2493aedf8714421a0","bytes":13396,"lines":333},{"path":"tests/test_audit_outbox_postgres.sh","sha256":"e57a04920a0ba97fa6a06752d15ea150016ab8d44099e998c5c4f4067592b4d2","bytes":13443,"lines":357},{"path":"tests/test_bitemporal_postgres.sh","sha256":"7684b8c2ff52c044c081135515bd5aabbfd00e2daad0d471b0868701af2df6cc","bytes":8209,"lines":230},{"path":"tests/test_candidate_worker_conversion_postgres.sh","sha256":"681cb74d6cfa859ed92c6c2439881ea20c430ef8df94ec662e2807761a377f90","bytes":14673,"lines":344},{"path":"tests/test_criterion_observation_scope_postgres.sh","sha256":"0ee9539ee57f840c27d08009f7868cdc8662669df78a01dbc8be39216b8f1a3d","bytes":17811,"lines":469},{"path":"tests/test_evidence_sealing_postgres.sh","sha256":"57d16b632a0c60ffdcb4842ceb1cfe25d19c54cefeeefb622ff4fa6e83441ad7","bytes":11349,"lines":370},{"path":"tests/test_job_analysis_snapshot_postgres.sh","sha256":"ca9c323a1dd68cfc520277efbbb7495e37fb3ca027890928c8624e5b4f57403f","bytes":13542,"lines":296},{"path":"tests/test_operational_uuid_postgres.sh","sha256":"7378f98f0d4b3000e8ea641d8701f1540dbad71410b3637d81d799969e0f6ff7","bytes":3346,"lines":101},{"path":"tests/test_outbox_claim_postgres.sh","sha256":"1027806d436ebfe34e108c25b6a4001f43b9550f1d70057c6c0d7974323b0c9b","bytes":14817,"lines":429},{"path":"tests/test_outbox_dead_letter_postgres.sh","sha256":"0d728d578e64252e6079f2d141ddaa7fa9cfbf9784e625832273596d69a6e13d","bytes":14008,"lines":377},{"path":"tests/test_people_mutation_idempotency_postgres.sh","sha256":"3f57e12f80bd1b034c9aac54b669d8530106e3e26b3795689671fb53807b3cd5","bytes":16191,"lines":381},{"path":"tests/test_tenant_isolation_postgres.sh","sha256":"dd649435ef8ab9e57f0609c101917e36656a6d40d63de9bcdbdac23d764f6c3a","bytes":15134,"lines":388},{"path":"tests/test_validity_study_case_postgres.sh","sha256":"0070ad58300323c7f9900c5645e0df3106b36ccd245ae686e982c2fd6fa4dc02","bytes":14708,"lines":301},{"path":"tests/validate_repository.py","sha256":"918cf92fd18d81572e9bd5f5daa7f033c32731e2e13f0d00661d1c1de30b12a9","bytes":27291,"lines":638}]} From 1feb9e671813ebd24a7affe3d28b82134b45420d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 28 Aug 2026 20:43:49 +0900 Subject: [PATCH 21/23] docs: record document evidence active PR --- CHANGELOG.md | 1 + manifest.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10bae6906..dcf2ca897 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to Orgmetra will be documented in this file. - Active-PR governed Job Analysis persistence/API on the canonical `JobAnalysisSnapshot` model: migration `0013_job_analysis_snapshot.sql` stores immutable tenant-scoped snapshot, Task, KSAO, Task–KSAO, FJA and write-command evidence; `POST /v1/tenants/{tenant_record_id}/job-analysis-snapshots` and matching GET enforce purpose-bound Keyverse scope, authenticated-principal actor authority, bounded/strict JSON handling, transactional Idempotency-Key serialization, parent-scope fail-closed integrity, forced RLS, and atomic audit/outbox evidence. ADR 0014 records the persistence decision while ADR 0007 remains the domain/evidence authority; validated evidence still requires accountable human review and non-LLM provenance, and the service does not make a high-impact employment decision. - Active-PR `orgmetra_selection_review` packet for PII-minimized, evidence-bound human selection review: canonical operational tenant identity, UUID-backed opaque candidate/Job/sealed-evidence/reviewer references, explicit purpose/reason/evidence version, deterministic canonical JSON and SHA-256 correlation, mandatory human decision state, redacted packet repr, and provenance-paired model evidence that remains `untrusted_draft`, with exact 100% owned statement and branch coverage required by its quality gate. - Active-PR `DocumentRecordEvidence` for value-minimized HR document metadata: tenant/Person/Employment scope, reviewed category, opaque artifact and provenance/retention digests, separate business receipt and Orgmetra-generated system-recorded time, process-local tamper detection, and no document content or employment-decision authority. +- Active-PR `DocumentRecordEvidence` for value-minimized HR document metadata: tenant/Person/Employment scope, reviewed category, opaque artifact and provenance/retention digests, separate business receipt and Orgmetra-generated system-recorded time, process-local tamper detection, and no document content or employment-decision authority. - Active performance-criterion scope hardening: `criterion_observation_scope_guard` rejects criterion outcomes for a Job the worker did not effectively hold at the observation date, observations before the relevant assignment, and observations outside the referenced performance cycle while preserving valid multiple-assignment cases and existing bitemporal correction semantics. The guard evaluates current-recorded facts, derives the date coordinate from `observed_at` in UTC so session `TimeZone` cannot alter the result, uses a trusted function search path, and adds no PII or automated employment decision authority. The Foundation PostgreSQL contract also rejects a closed `recorded_to` on each time-coordinate lookup and proves UTC midnight plus non-UTC session `TimeZone` boundaries. - Bitemporal tenant-scoped organization hierarchy validation that rejects visible indirect parent cycles and reuses single-valued recorded-time reconstruction before graph traversal. - Stacked governed job-analysis evidence contract via `JobAnalysisSnapshot`, `TaskEvidence`, `KSAORequirement`, `TaskKSAOLink`, `FunctionalJobAnalysisProfile`, and `EvidenceSource`: tenant/Job-scoped observable tasks, explicit Task-to-KSAO linkage, importance/difficulty/proficiency ratings, source/version/retrieval/SHA-256 provenance, deterministic canonical snapshot bytes, current O*NET evidence support, and historical DOT Data/People/Things compatibility. Validated snapshots require accountable human review and complete non-LLM evidence; LLM-origin material remains `analysis_draft`, and the snapshot is evidence input rather than a hiring, promotion, termination, compensation, or other high-impact employment decision. diff --git a/manifest.json b/manifest.json index 00c4368e9..c8b056220 100644 --- a/manifest.json +++ b/manifest.json @@ -1 +1 @@ -{"package":"orgmetra-foundation-pack","version":"0.1.0","generated_for_branch":"feat/audit-outbox-envelope","files":[{"path":".github/workflows/foundation-ci.yml","sha256":"12686a3bbd6445e6fdb202b4137dae118ddeeab1efb0c7f18ea6c8fa19d62537","bytes":4379,"lines":123},{"path":".github/workflows/job-analysis-api-quality.yml","sha256":"352dc78931dd94afea3e88912d38dcc4b562a004112f199f3d7a12d22b6d637a","bytes":4159,"lines":105},{"path":".gitignore","sha256":"145fda644f5209fa1fb3e3b40c9af9258bfac6d1a634bba2520fd08fe6d77a21","bytes":375,"lines":37},{"path":"AGENTS.md","sha256":"28f7b7bc010a7739cfdc3e793fb5d39a0e74b842ea9c190e9a251e2d0cbc3a16","bytes":2246,"lines":34},{"path":"ARCHITECTURE.md","sha256":"52d68786f7359c1a50d804996021e4c70e90accd2fff6f1a27c91de1dd8df850","bytes":7864,"lines":107},{"path":"CHANGELOG.md","sha256":"ad6219494fe7c7ff602ba79e6cb2534d7e35c17e0f16be0f1bef5bcd8911f91b","bytes":17636,"lines":77},{"path":"CLAUDE.md","sha256":"add33884f466d324e20875388d103de41c6e062938a6e98727dc83a87ffe976f","bytes":1229,"lines":20},{"path":"LICENSE","sha256":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","bytes":11358,"lines":202},{"path":"NOTICE","sha256":"34b4618e946bdd8d33407d6ac5279f0a0388f5e7c8f79d2e7d8c3c47d0266042","bytes":305,"lines":4},{"path":"README.md","sha256":"1a9fc400d26d8137ae5911488794a6d3fa915957c95f27b36a48cef0fdf823c6","bytes":3785,"lines":81},{"path":"database/migrations/0001_foundation_schema.sql","sha256":"ce2ae52fc66b2f99597ea5285df82c66f90caa46174fef4930d68a8b6177d0dd","bytes":38747,"lines":916},{"path":"database/migrations/0002_sealed_evidence_digest.sql","sha256":"93d659ca8e0e9293a83d5422d043be7b1022c5470a5b22670aa3416fa334a04c","bytes":6649,"lines":202},{"path":"database/migrations/0003_audit_outbox_persistence.sql","sha256":"2aa7bbb8220923ec584537c0cd46f0cba2b692d69d431f097b7df6db75235bfc","bytes":15417,"lines":423},{"path":"database/migrations/0004_outbox_delivery_claim.sql","sha256":"d4504acf7d58528a2a8f4f03d1584b868c8d3ba9046a007b9c2e7cfef993b2ef","bytes":9451,"lines":234},{"path":"database/migrations/0005_outbox_delivery_finalization.sql","sha256":"b7e8790595b288f752d6ef5cc6cbfe4e1b6712248f5b7a3a25fa60016b6a4961","bytes":6125,"lines":170},{"path":"database/migrations/0006_outbox_delivery_dead_letter.sql","sha256":"c1fb91cdf98169fd6684984e86cb0a14fa19c8f1226028d2346a2a069df2b3c7","bytes":24919,"lines":628},{"path":"database/migrations/0007_outbox_retry_exhaustion.sql","sha256":"812f50d70ca5929c7eba964d34a208aedee660d11cc7ffc09d67688c4737e0d5","bytes":19081,"lines":476},{"path":"database/migrations/0008_audit_outbox_review_hardening.sql","sha256":"c3713a12db9d00fdc10005df1f86c07965e9555eefad78ca67e994537a739d9b","bytes":17562,"lines":448},{"path":"database/migrations/0009_candidate_worker_conversion_governance.sql","sha256":"4030666629a6b8deb383b8337ead4f09d6a945969313def2577a38f31f06cda9","bytes":11537,"lines":281},{"path":"database/migrations/0010_validity_study_case_integrity.sql","sha256":"3f594810ac9e1a6747a2bb4838e5ce65b921cb6e3d36fcdc3ff08b4a7579ebd1","bytes":11979,"lines":313},{"path":"database/migrations/0011_criterion_observation_scope.sql","sha256":"f9fe7c35f1ee7b167e1c2ba75a50a84febda9a6ccf8123b4f5726f51968694f9","bytes":7444,"lines":165},{"path":"database/migrations/0012_people_mutation_idempotency.sql","sha256":"52dbbb9ec7f9be5291593ba88f228d7fffd736dcb99547a08c1d6cad076afb69","bytes":3162,"lines":76},{"path":"database/migrations/0013_job_analysis_snapshot.sql","sha256":"b6553a5a4c94c4aa9f341a474e13bbe34db63044eda2446b3ebee178995977ee","bytes":12713,"lines":260},{"path":"docs/API_CONTRACT.md","sha256":"63533dff785da62b89e585d742a158e2aeb05913644f2bf9fb6486f281c2e589","bytes":4555,"lines":76},{"path":"docs/DATA_MODEL.md","sha256":"6ad29731ae7ee7aa5bf3a2d0bfef88894a35a2550edb2be3244d6f143d76444a","bytes":13366,"lines":85},{"path":"docs/ERD.md","sha256":"546001aa85c4fe020e0c39d881dc860daf7f69090596666fdf9092487b0725fe","bytes":6964,"lines":70},{"path":"docs/OPERABILITY.md","sha256":"82b2d3e70cec371ef35e9e0f982ac40fef84351976bc04b863b81d27023d5a62","bytes":11189,"lines":71},{"path":"docs/PRD.md","sha256":"3ad85ae633cce0fc7a93af39b21d7a7c70bb2efa786da6b12f3c5327906e34f1","bytes":5490,"lines":111},{"path":"docs/SECURITY.md","sha256":"01918512d8882060e9cff0c4aa8206e0eccbdfb61cfd7f829331123c7a9fe6ac","bytes":11185,"lines":64},{"path":"docs/STORYBOARD.md","sha256":"6e4ffb0eb03a80343f50d363ffc43b34da9348a44232dd947a9ff416ea92a3d2","bytes":1342,"lines":28},{"path":"docs/STORYBOOK.md","sha256":"82f79029b3c2b7a45393bad5ba8fabe61014d4b6149c7d4e73f70ba447f885e9","bytes":1389,"lines":50},{"path":"docs/TEST_STRATEGY.md","sha256":"d0a0bc3b54ed0fc7973747987f1afb117d6144c390b51ed9370eb571972a33f8","bytes":16534,"lines":135},{"path":"docs/THREAT_MODEL.md","sha256":"f314f375c2e41252536de224c7bc7e4a10ab8f340cb86642724e7399e32f4252","bytes":6736,"lines":23},{"path":"docs/TRACEABILITY.md","sha256":"dbf6fd91375ea28e05456d2a0c9ba629506cbac6f52f5dfda61ae68db2395f7e","bytes":11462,"lines":40},{"path":"docs/TRD.md","sha256":"23697d88a4882698e1a2782b7da3f2ccd0d3cd2d6d1bffe89b6597dc16851077","bytes":9064,"lines":101},{"path":"docs/UML.md","sha256":"fe67c37aa88e5814ceb2db7e8f7d8d85ca27a994802efbb7c75164b387adf0a9","bytes":5528,"lines":122},{"path":"docs/USER_STORIES.md","sha256":"5535b39d8c71a36c81f78e2d6dbd90a2d32e6541790f0d28f6dd4baf3ea7b45f","bytes":2670,"lines":37},{"path":"docs/WIREFRAMES.md","sha256":"b03aa6419aeaf5d42a5698c4d43a434c1633b7ac6fd0b0bd0cda979077adc56e","bytes":2005,"lines":77},{"path":"docs/adr/0001-orgmetra-authoritative-hris-record.md","sha256":"0f8055b73c63d3130321415ad53233588ff952aabd1a88952b39c71747253572","bytes":6108,"lines":53},{"path":"docs/adr/0002-federated-cwl-integration-boundaries.md","sha256":"b77165f2aacfa6f4fde994baf77d5879c6da3e8dae4fd2db0ed912d60ae9b3b2","bytes":4072,"lines":44},{"path":"docs/adr/0003-bitemporal-hris-data-contract.md","sha256":"d7f2660616622c1a7994b28aa66d99d13836bcf755735595f9609a41282ab799","bytes":4453,"lines":47},{"path":"docs/adr/0004-employment-position-version-and-assignment-binding.md","sha256":"fee89e700414abe0b1cffec2acc687e5e014634db8f5ef9e8a92abba5c3cf182","bytes":1872,"lines":30},{"path":"docs/adr/0005-exclusive-employment-and-staffable-seats.md","sha256":"10f0eb409f4fa32d2c5bed2d583d8b43be8e61b5cbef0e927e5bebb5f5c8f85b","bytes":2091,"lines":34},{"path":"docs/adr/0006-governed-audit-outbox-envelope.md","sha256":"827298ddd997b47f78a89e89911ad8ea72e517b7714303637f0329b8cb52cabd","bytes":14100,"lines":66},{"path":"docs/adr/0007-governed-job-analysis-evidence.md","sha256":"953c6d2b9864a78b461b576092ec3f198f0b76709eaaaf7d0ed0182f95182c52","bytes":5653,"lines":57},{"path":"docs/adr/0008-purpose-bound-pii-authorization.md","sha256":"c5157d3bc58f3d8d29e03104dd15eb2911cc1bb66e2c92a935b26d7164648dc7","bytes":5988,"lines":55},{"path":"docs/adr/0009-performance-criterion-observation-scope.md","sha256":"1ac10bb2747b0a5b4d62f627825cfd7f978f3fa88d7575bffc23d56371240a64","bytes":7057,"lines":57},{"path":"docs/adr/0010-naruon-calendar-intent-boundary.md","sha256":"3e1050a964cc4ed76a1a0cf1e699ae5080acf8c9336f0decdd6d5229359db3c9","bytes":3917,"lines":35},{"path":"docs/adr/0011-bitemporal-workforce-composition.md","sha256":"1656ef8b57c836ef7936a8e9cb6a824681eb7563157a1ab0a29deb25849a457b","bytes":5568,"lines":53},{"path":"docs/adr/0012-governed-migration-handoff.md","sha256":"713855d670001d3964ecb36cc653830502fb1d82a58b9e39f564b6992dd2bd80","bytes":5965,"lines":59},{"path":"docs/adr/0013-governed-requisition-review-packet.md","sha256":"70bf2cbdf903a8793d6d8bc116a08331931090118341f42010236e09c6cc1802","bytes":4693,"lines":46},{"path":"docs/adr/0014-job-analysis-snapshot-persistence.md","sha256":"a7ab6fee50aaa63f7f407516a4cb39885faeb0fc6e5035ee8fc352ed73430105","bytes":5365,"lines":49},{"path":"docs/adr/README.md","sha256":"f3b3b5ed3b3b31a40a0a3696abf0065e3c25879b6be50077f38ffae742b9d002","bytes":1838,"lines":18},{"path":"docs/doctoring/REFERENCES.md","sha256":"929f7ee36df16279f028f726fcf039982180deb377746fe3804f3c0d090778d5","bytes":6352,"lines":69},{"path":"docs/superpowers/plans/2026-08-15-orgmetra-foundation-implementation-plan.md","sha256":"b64f21abb19373e780db8b9e64deb8ba9a6219ccf9625a651f25407b8691fcbd","bytes":8227,"lines":226},{"path":"docs/superpowers/specs/2026-08-15-orgmetra-foundation-design.md","sha256":"4a0e1a7943e40d12bd3082db3757045b4085e5a089fea7bc0d8a1565ffcbcf1d","bytes":6237,"lines":187},{"path":"package.json","sha256":"59ae9e3e67c3fba9320cb18439692395cdfd16ae5c24e3c4cf30d77d63ebabb5","bytes":388,"lines":9},{"path":"packages/hris-kernel/src/orgmetra_hris_kernel/audit.py","sha256":"3e5b7190cf857dc8c1fc7e898cef303060f34aabee6c27a9034d4d9650e33190","bytes":7707,"lines":160},{"path":"packages/hris-kernel/tests/test_audit_outbox.py","sha256":"5928dd7b97fe38d6b7472ce62966437e339058a59c3b301a93a7b5c05432b40c","bytes":7556,"lines":200},{"path":"schemas/openapi.yaml","sha256":"09c1e43486779198574fe31b8bcabbd1c1f74beec7bf86245ae578061619838f","bytes":29503,"lines":1020},{"path":"scripts/foundation-contract-core.mjs","sha256":"595e8381dbd62e97093b11eef818af5f04d6473ac592d57e3985ffbc2210d445","bytes":28173,"lines":689},{"path":"scripts/foundation-contract.mjs","sha256":"5242dcdbe0935775edf074462c82600e9bc4927d9fdc50c47727af915fd4b23a","bytes":218,"lines":6},{"path":"tests/dispatcher-inventory.test.mjs","sha256":"09f5e64410e6b7a26bf8d6ce61c50b737da2ea85d955f91eba63aa21f1537261","bytes":1597,"lines":34},{"path":"tests/foundation-contract.test.mjs","sha256":"960306fd7cda7b982a52c4428a432d10a4f570430a5d39fb23aeca0b2ede0615","bytes":14860,"lines":386},{"path":"tests/openapi-contract.test.mjs","sha256":"80c1610ef1c189fa325e55389501e0e51531ddf61ee335bb94d9cb3aa55a9fdc","bytes":6438,"lines":195},{"path":"tests/test_audit_outbox_hardening_postgres.sh","sha256":"518ba2f37ba6292943e5abe22c2599452b2f031a42e453b2493aedf8714421a0","bytes":13396,"lines":333},{"path":"tests/test_audit_outbox_postgres.sh","sha256":"e57a04920a0ba97fa6a06752d15ea150016ab8d44099e998c5c4f4067592b4d2","bytes":13443,"lines":357},{"path":"tests/test_bitemporal_postgres.sh","sha256":"7684b8c2ff52c044c081135515bd5aabbfd00e2daad0d471b0868701af2df6cc","bytes":8209,"lines":230},{"path":"tests/test_candidate_worker_conversion_postgres.sh","sha256":"681cb74d6cfa859ed92c6c2439881ea20c430ef8df94ec662e2807761a377f90","bytes":14673,"lines":344},{"path":"tests/test_criterion_observation_scope_postgres.sh","sha256":"0ee9539ee57f840c27d08009f7868cdc8662669df78a01dbc8be39216b8f1a3d","bytes":17811,"lines":469},{"path":"tests/test_evidence_sealing_postgres.sh","sha256":"57d16b632a0c60ffdcb4842ceb1cfe25d19c54cefeeefb622ff4fa6e83441ad7","bytes":11349,"lines":370},{"path":"tests/test_job_analysis_snapshot_postgres.sh","sha256":"ca9c323a1dd68cfc520277efbbb7495e37fb3ca027890928c8624e5b4f57403f","bytes":13542,"lines":296},{"path":"tests/test_operational_uuid_postgres.sh","sha256":"7378f98f0d4b3000e8ea641d8701f1540dbad71410b3637d81d799969e0f6ff7","bytes":3346,"lines":101},{"path":"tests/test_outbox_claim_postgres.sh","sha256":"1027806d436ebfe34e108c25b6a4001f43b9550f1d70057c6c0d7974323b0c9b","bytes":14817,"lines":429},{"path":"tests/test_outbox_dead_letter_postgres.sh","sha256":"0d728d578e64252e6079f2d141ddaa7fa9cfbf9784e625832273596d69a6e13d","bytes":14008,"lines":377},{"path":"tests/test_people_mutation_idempotency_postgres.sh","sha256":"3f57e12f80bd1b034c9aac54b669d8530106e3e26b3795689671fb53807b3cd5","bytes":16191,"lines":381},{"path":"tests/test_tenant_isolation_postgres.sh","sha256":"dd649435ef8ab9e57f0609c101917e36656a6d40d63de9bcdbdac23d764f6c3a","bytes":15134,"lines":388},{"path":"tests/test_validity_study_case_postgres.sh","sha256":"0070ad58300323c7f9900c5645e0df3106b36ccd245ae686e982c2fd6fa4dc02","bytes":14708,"lines":301},{"path":"tests/validate_repository.py","sha256":"918cf92fd18d81572e9bd5f5daa7f033c32731e2e13f0d00661d1c1de30b12a9","bytes":27291,"lines":638}]} +{"package":"orgmetra-foundation-pack","version":"0.1.0","generated_for_branch":"feat/audit-outbox-envelope","files":[{"path":".github/workflows/foundation-ci.yml","sha256":"12686a3bbd6445e6fdb202b4137dae118ddeeab1efb0c7f18ea6c8fa19d62537","bytes":4379,"lines":123},{"path":".github/workflows/job-analysis-api-quality.yml","sha256":"352dc78931dd94afea3e88912d38dcc4b562a004112f199f3d7a12d22b6d637a","bytes":4159,"lines":105},{"path":".gitignore","sha256":"145fda644f5209fa1fb3e3b40c9af9258bfac6d1a634bba2520fd08fe6d77a21","bytes":375,"lines":37},{"path":"AGENTS.md","sha256":"28f7b7bc010a7739cfdc3e793fb5d39a0e74b842ea9c190e9a251e2d0cbc3a16","bytes":2246,"lines":34},{"path":"ARCHITECTURE.md","sha256":"52d68786f7359c1a50d804996021e4c70e90accd2fff6f1a27c91de1dd8df850","bytes":7864,"lines":107},{"path":"CHANGELOG.md","sha256":"302832fe3f069d988c1d61f0a977e33f4e4d94f1fd5db67ed5ac0547ce4ada11","bytes":17977,"lines":78},{"path":"CLAUDE.md","sha256":"add33884f466d324e20875388d103de41c6e062938a6e98727dc83a87ffe976f","bytes":1229,"lines":20},{"path":"LICENSE","sha256":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","bytes":11358,"lines":202},{"path":"NOTICE","sha256":"34b4618e946bdd8d33407d6ac5279f0a0388f5e7c8f79d2e7d8c3c47d0266042","bytes":305,"lines":4},{"path":"README.md","sha256":"1a9fc400d26d8137ae5911488794a6d3fa915957c95f27b36a48cef0fdf823c6","bytes":3785,"lines":81},{"path":"database/migrations/0001_foundation_schema.sql","sha256":"ce2ae52fc66b2f99597ea5285df82c66f90caa46174fef4930d68a8b6177d0dd","bytes":38747,"lines":916},{"path":"database/migrations/0002_sealed_evidence_digest.sql","sha256":"93d659ca8e0e9293a83d5422d043be7b1022c5470a5b22670aa3416fa334a04c","bytes":6649,"lines":202},{"path":"database/migrations/0003_audit_outbox_persistence.sql","sha256":"2aa7bbb8220923ec584537c0cd46f0cba2b692d69d431f097b7df6db75235bfc","bytes":15417,"lines":423},{"path":"database/migrations/0004_outbox_delivery_claim.sql","sha256":"d4504acf7d58528a2a8f4f03d1584b868c8d3ba9046a007b9c2e7cfef993b2ef","bytes":9451,"lines":234},{"path":"database/migrations/0005_outbox_delivery_finalization.sql","sha256":"b7e8790595b288f752d6ef5cc6cbfe4e1b6712248f5b7a3a25fa60016b6a4961","bytes":6125,"lines":170},{"path":"database/migrations/0006_outbox_delivery_dead_letter.sql","sha256":"c1fb91cdf98169fd6684984e86cb0a14fa19c8f1226028d2346a2a069df2b3c7","bytes":24919,"lines":628},{"path":"database/migrations/0007_outbox_retry_exhaustion.sql","sha256":"812f50d70ca5929c7eba964d34a208aedee660d11cc7ffc09d67688c4737e0d5","bytes":19081,"lines":476},{"path":"database/migrations/0008_audit_outbox_review_hardening.sql","sha256":"c3713a12db9d00fdc10005df1f86c07965e9555eefad78ca67e994537a739d9b","bytes":17562,"lines":448},{"path":"database/migrations/0009_candidate_worker_conversion_governance.sql","sha256":"4030666629a6b8deb383b8337ead4f09d6a945969313def2577a38f31f06cda9","bytes":11537,"lines":281},{"path":"database/migrations/0010_validity_study_case_integrity.sql","sha256":"3f594810ac9e1a6747a2bb4838e5ce65b921cb6e3d36fcdc3ff08b4a7579ebd1","bytes":11979,"lines":313},{"path":"database/migrations/0011_criterion_observation_scope.sql","sha256":"f9fe7c35f1ee7b167e1c2ba75a50a84febda9a6ccf8123b4f5726f51968694f9","bytes":7444,"lines":165},{"path":"database/migrations/0012_people_mutation_idempotency.sql","sha256":"52dbbb9ec7f9be5291593ba88f228d7fffd736dcb99547a08c1d6cad076afb69","bytes":3162,"lines":76},{"path":"database/migrations/0013_job_analysis_snapshot.sql","sha256":"b6553a5a4c94c4aa9f341a474e13bbe34db63044eda2446b3ebee178995977ee","bytes":12713,"lines":260},{"path":"docs/API_CONTRACT.md","sha256":"63533dff785da62b89e585d742a158e2aeb05913644f2bf9fb6486f281c2e589","bytes":4555,"lines":76},{"path":"docs/DATA_MODEL.md","sha256":"6ad29731ae7ee7aa5bf3a2d0bfef88894a35a2550edb2be3244d6f143d76444a","bytes":13366,"lines":85},{"path":"docs/ERD.md","sha256":"546001aa85c4fe020e0c39d881dc860daf7f69090596666fdf9092487b0725fe","bytes":6964,"lines":70},{"path":"docs/OPERABILITY.md","sha256":"82b2d3e70cec371ef35e9e0f982ac40fef84351976bc04b863b81d27023d5a62","bytes":11189,"lines":71},{"path":"docs/PRD.md","sha256":"3ad85ae633cce0fc7a93af39b21d7a7c70bb2efa786da6b12f3c5327906e34f1","bytes":5490,"lines":111},{"path":"docs/SECURITY.md","sha256":"01918512d8882060e9cff0c4aa8206e0eccbdfb61cfd7f829331123c7a9fe6ac","bytes":11185,"lines":64},{"path":"docs/STORYBOARD.md","sha256":"6e4ffb0eb03a80343f50d363ffc43b34da9348a44232dd947a9ff416ea92a3d2","bytes":1342,"lines":28},{"path":"docs/STORYBOOK.md","sha256":"82f79029b3c2b7a45393bad5ba8fabe61014d4b6149c7d4e73f70ba447f885e9","bytes":1389,"lines":50},{"path":"docs/TEST_STRATEGY.md","sha256":"d0a0bc3b54ed0fc7973747987f1afb117d6144c390b51ed9370eb571972a33f8","bytes":16534,"lines":135},{"path":"docs/THREAT_MODEL.md","sha256":"f314f375c2e41252536de224c7bc7e4a10ab8f340cb86642724e7399e32f4252","bytes":6736,"lines":23},{"path":"docs/TRACEABILITY.md","sha256":"dbf6fd91375ea28e05456d2a0c9ba629506cbac6f52f5dfda61ae68db2395f7e","bytes":11462,"lines":40},{"path":"docs/TRD.md","sha256":"23697d88a4882698e1a2782b7da3f2ccd0d3cd2d6d1bffe89b6597dc16851077","bytes":9064,"lines":101},{"path":"docs/UML.md","sha256":"fe67c37aa88e5814ceb2db7e8f7d8d85ca27a994802efbb7c75164b387adf0a9","bytes":5528,"lines":122},{"path":"docs/USER_STORIES.md","sha256":"5535b39d8c71a36c81f78e2d6dbd90a2d32e6541790f0d28f6dd4baf3ea7b45f","bytes":2670,"lines":37},{"path":"docs/WIREFRAMES.md","sha256":"b03aa6419aeaf5d42a5698c4d43a434c1633b7ac6fd0b0bd0cda979077adc56e","bytes":2005,"lines":77},{"path":"docs/adr/0001-orgmetra-authoritative-hris-record.md","sha256":"0f8055b73c63d3130321415ad53233588ff952aabd1a88952b39c71747253572","bytes":6108,"lines":53},{"path":"docs/adr/0002-federated-cwl-integration-boundaries.md","sha256":"b77165f2aacfa6f4fde994baf77d5879c6da3e8dae4fd2db0ed912d60ae9b3b2","bytes":4072,"lines":44},{"path":"docs/adr/0003-bitemporal-hris-data-contract.md","sha256":"d7f2660616622c1a7994b28aa66d99d13836bcf755735595f9609a41282ab799","bytes":4453,"lines":47},{"path":"docs/adr/0004-employment-position-version-and-assignment-binding.md","sha256":"fee89e700414abe0b1cffec2acc687e5e014634db8f5ef9e8a92abba5c3cf182","bytes":1872,"lines":30},{"path":"docs/adr/0005-exclusive-employment-and-staffable-seats.md","sha256":"10f0eb409f4fa32d2c5bed2d583d8b43be8e61b5cbef0e927e5bebb5f5c8f85b","bytes":2091,"lines":34},{"path":"docs/adr/0006-governed-audit-outbox-envelope.md","sha256":"827298ddd997b47f78a89e89911ad8ea72e517b7714303637f0329b8cb52cabd","bytes":14100,"lines":66},{"path":"docs/adr/0007-governed-job-analysis-evidence.md","sha256":"953c6d2b9864a78b461b576092ec3f198f0b76709eaaaf7d0ed0182f95182c52","bytes":5653,"lines":57},{"path":"docs/adr/0008-purpose-bound-pii-authorization.md","sha256":"c5157d3bc58f3d8d29e03104dd15eb2911cc1bb66e2c92a935b26d7164648dc7","bytes":5988,"lines":55},{"path":"docs/adr/0009-performance-criterion-observation-scope.md","sha256":"1ac10bb2747b0a5b4d62f627825cfd7f978f3fa88d7575bffc23d56371240a64","bytes":7057,"lines":57},{"path":"docs/adr/0010-naruon-calendar-intent-boundary.md","sha256":"3e1050a964cc4ed76a1a0cf1e699ae5080acf8c9336f0decdd6d5229359db3c9","bytes":3917,"lines":35},{"path":"docs/adr/0011-bitemporal-workforce-composition.md","sha256":"1656ef8b57c836ef7936a8e9cb6a824681eb7563157a1ab0a29deb25849a457b","bytes":5568,"lines":53},{"path":"docs/adr/0012-governed-migration-handoff.md","sha256":"713855d670001d3964ecb36cc653830502fb1d82a58b9e39f564b6992dd2bd80","bytes":5965,"lines":59},{"path":"docs/adr/0013-governed-requisition-review-packet.md","sha256":"70bf2cbdf903a8793d6d8bc116a08331931090118341f42010236e09c6cc1802","bytes":4693,"lines":46},{"path":"docs/adr/0014-job-analysis-snapshot-persistence.md","sha256":"a7ab6fee50aaa63f7f407516a4cb39885faeb0fc6e5035ee8fc352ed73430105","bytes":5365,"lines":49},{"path":"docs/adr/README.md","sha256":"f3b3b5ed3b3b31a40a0a3696abf0065e3c25879b6be50077f38ffae742b9d002","bytes":1838,"lines":18},{"path":"docs/doctoring/REFERENCES.md","sha256":"929f7ee36df16279f028f726fcf039982180deb377746fe3804f3c0d090778d5","bytes":6352,"lines":69},{"path":"docs/superpowers/plans/2026-08-15-orgmetra-foundation-implementation-plan.md","sha256":"b64f21abb19373e780db8b9e64deb8ba9a6219ccf9625a651f25407b8691fcbd","bytes":8227,"lines":226},{"path":"docs/superpowers/specs/2026-08-15-orgmetra-foundation-design.md","sha256":"4a0e1a7943e40d12bd3082db3757045b4085e5a089fea7bc0d8a1565ffcbcf1d","bytes":6237,"lines":187},{"path":"package.json","sha256":"59ae9e3e67c3fba9320cb18439692395cdfd16ae5c24e3c4cf30d77d63ebabb5","bytes":388,"lines":9},{"path":"packages/hris-kernel/src/orgmetra_hris_kernel/audit.py","sha256":"3e5b7190cf857dc8c1fc7e898cef303060f34aabee6c27a9034d4d9650e33190","bytes":7707,"lines":160},{"path":"packages/hris-kernel/tests/test_audit_outbox.py","sha256":"5928dd7b97fe38d6b7472ce62966437e339058a59c3b301a93a7b5c05432b40c","bytes":7556,"lines":200},{"path":"schemas/openapi.yaml","sha256":"09c1e43486779198574fe31b8bcabbd1c1f74beec7bf86245ae578061619838f","bytes":29503,"lines":1020},{"path":"scripts/foundation-contract-core.mjs","sha256":"595e8381dbd62e97093b11eef818af5f04d6473ac592d57e3985ffbc2210d445","bytes":28173,"lines":689},{"path":"scripts/foundation-contract.mjs","sha256":"5242dcdbe0935775edf074462c82600e9bc4927d9fdc50c47727af915fd4b23a","bytes":218,"lines":6},{"path":"tests/dispatcher-inventory.test.mjs","sha256":"09f5e64410e6b7a26bf8d6ce61c50b737da2ea85d955f91eba63aa21f1537261","bytes":1597,"lines":34},{"path":"tests/foundation-contract.test.mjs","sha256":"960306fd7cda7b982a52c4428a432d10a4f570430a5d39fb23aeca0b2ede0615","bytes":14860,"lines":386},{"path":"tests/openapi-contract.test.mjs","sha256":"80c1610ef1c189fa325e55389501e0e51531ddf61ee335bb94d9cb3aa55a9fdc","bytes":6438,"lines":195},{"path":"tests/test_audit_outbox_hardening_postgres.sh","sha256":"518ba2f37ba6292943e5abe22c2599452b2f031a42e453b2493aedf8714421a0","bytes":13396,"lines":333},{"path":"tests/test_audit_outbox_postgres.sh","sha256":"e57a04920a0ba97fa6a06752d15ea150016ab8d44099e998c5c4f4067592b4d2","bytes":13443,"lines":357},{"path":"tests/test_bitemporal_postgres.sh","sha256":"7684b8c2ff52c044c081135515bd5aabbfd00e2daad0d471b0868701af2df6cc","bytes":8209,"lines":230},{"path":"tests/test_candidate_worker_conversion_postgres.sh","sha256":"681cb74d6cfa859ed92c6c2439881ea20c430ef8df94ec662e2807761a377f90","bytes":14673,"lines":344},{"path":"tests/test_criterion_observation_scope_postgres.sh","sha256":"0ee9539ee57f840c27d08009f7868cdc8662669df78a01dbc8be39216b8f1a3d","bytes":17811,"lines":469},{"path":"tests/test_evidence_sealing_postgres.sh","sha256":"57d16b632a0c60ffdcb4842ceb1cfe25d19c54cefeeefb622ff4fa6e83441ad7","bytes":11349,"lines":370},{"path":"tests/test_job_analysis_snapshot_postgres.sh","sha256":"ca9c323a1dd68cfc520277efbbb7495e37fb3ca027890928c8624e5b4f57403f","bytes":13542,"lines":296},{"path":"tests/test_operational_uuid_postgres.sh","sha256":"7378f98f0d4b3000e8ea641d8701f1540dbad71410b3637d81d799969e0f6ff7","bytes":3346,"lines":101},{"path":"tests/test_outbox_claim_postgres.sh","sha256":"1027806d436ebfe34e108c25b6a4001f43b9550f1d70057c6c0d7974323b0c9b","bytes":14817,"lines":429},{"path":"tests/test_outbox_dead_letter_postgres.sh","sha256":"0d728d578e64252e6079f2d141ddaa7fa9cfbf9784e625832273596d69a6e13d","bytes":14008,"lines":377},{"path":"tests/test_people_mutation_idempotency_postgres.sh","sha256":"3f57e12f80bd1b034c9aac54b669d8530106e3e26b3795689671fb53807b3cd5","bytes":16191,"lines":381},{"path":"tests/test_tenant_isolation_postgres.sh","sha256":"dd649435ef8ab9e57f0609c101917e36656a6d40d63de9bcdbdac23d764f6c3a","bytes":15134,"lines":388},{"path":"tests/test_validity_study_case_postgres.sh","sha256":"0070ad58300323c7f9900c5645e0df3106b36ccd245ae686e982c2fd6fa4dc02","bytes":14708,"lines":301},{"path":"tests/validate_repository.py","sha256":"918cf92fd18d81572e9bd5f5daa7f033c32731e2e13f0d00661d1c1de30b12a9","bytes":27291,"lines":638}]} From 59b809bead617d9045357396df684991548bdc30 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 28 Aug 2026 20:54:34 +0900 Subject: [PATCH 22/23] docs(document-records): remove duplicate changelog entry --- CHANGELOG.md | 1 - manifest.json | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dcf2ca897..10bae6906 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,6 @@ All notable changes to Orgmetra will be documented in this file. - Active-PR governed Job Analysis persistence/API on the canonical `JobAnalysisSnapshot` model: migration `0013_job_analysis_snapshot.sql` stores immutable tenant-scoped snapshot, Task, KSAO, Task–KSAO, FJA and write-command evidence; `POST /v1/tenants/{tenant_record_id}/job-analysis-snapshots` and matching GET enforce purpose-bound Keyverse scope, authenticated-principal actor authority, bounded/strict JSON handling, transactional Idempotency-Key serialization, parent-scope fail-closed integrity, forced RLS, and atomic audit/outbox evidence. ADR 0014 records the persistence decision while ADR 0007 remains the domain/evidence authority; validated evidence still requires accountable human review and non-LLM provenance, and the service does not make a high-impact employment decision. - Active-PR `orgmetra_selection_review` packet for PII-minimized, evidence-bound human selection review: canonical operational tenant identity, UUID-backed opaque candidate/Job/sealed-evidence/reviewer references, explicit purpose/reason/evidence version, deterministic canonical JSON and SHA-256 correlation, mandatory human decision state, redacted packet repr, and provenance-paired model evidence that remains `untrusted_draft`, with exact 100% owned statement and branch coverage required by its quality gate. - Active-PR `DocumentRecordEvidence` for value-minimized HR document metadata: tenant/Person/Employment scope, reviewed category, opaque artifact and provenance/retention digests, separate business receipt and Orgmetra-generated system-recorded time, process-local tamper detection, and no document content or employment-decision authority. -- Active-PR `DocumentRecordEvidence` for value-minimized HR document metadata: tenant/Person/Employment scope, reviewed category, opaque artifact and provenance/retention digests, separate business receipt and Orgmetra-generated system-recorded time, process-local tamper detection, and no document content or employment-decision authority. - Active performance-criterion scope hardening: `criterion_observation_scope_guard` rejects criterion outcomes for a Job the worker did not effectively hold at the observation date, observations before the relevant assignment, and observations outside the referenced performance cycle while preserving valid multiple-assignment cases and existing bitemporal correction semantics. The guard evaluates current-recorded facts, derives the date coordinate from `observed_at` in UTC so session `TimeZone` cannot alter the result, uses a trusted function search path, and adds no PII or automated employment decision authority. The Foundation PostgreSQL contract also rejects a closed `recorded_to` on each time-coordinate lookup and proves UTC midnight plus non-UTC session `TimeZone` boundaries. - Bitemporal tenant-scoped organization hierarchy validation that rejects visible indirect parent cycles and reuses single-valued recorded-time reconstruction before graph traversal. - Stacked governed job-analysis evidence contract via `JobAnalysisSnapshot`, `TaskEvidence`, `KSAORequirement`, `TaskKSAOLink`, `FunctionalJobAnalysisProfile`, and `EvidenceSource`: tenant/Job-scoped observable tasks, explicit Task-to-KSAO linkage, importance/difficulty/proficiency ratings, source/version/retrieval/SHA-256 provenance, deterministic canonical snapshot bytes, current O*NET evidence support, and historical DOT Data/People/Things compatibility. Validated snapshots require accountable human review and complete non-LLM evidence; LLM-origin material remains `analysis_draft`, and the snapshot is evidence input rather than a hiring, promotion, termination, compensation, or other high-impact employment decision. diff --git a/manifest.json b/manifest.json index c8b056220..00c4368e9 100644 --- a/manifest.json +++ b/manifest.json @@ -1 +1 @@ -{"package":"orgmetra-foundation-pack","version":"0.1.0","generated_for_branch":"feat/audit-outbox-envelope","files":[{"path":".github/workflows/foundation-ci.yml","sha256":"12686a3bbd6445e6fdb202b4137dae118ddeeab1efb0c7f18ea6c8fa19d62537","bytes":4379,"lines":123},{"path":".github/workflows/job-analysis-api-quality.yml","sha256":"352dc78931dd94afea3e88912d38dcc4b562a004112f199f3d7a12d22b6d637a","bytes":4159,"lines":105},{"path":".gitignore","sha256":"145fda644f5209fa1fb3e3b40c9af9258bfac6d1a634bba2520fd08fe6d77a21","bytes":375,"lines":37},{"path":"AGENTS.md","sha256":"28f7b7bc010a7739cfdc3e793fb5d39a0e74b842ea9c190e9a251e2d0cbc3a16","bytes":2246,"lines":34},{"path":"ARCHITECTURE.md","sha256":"52d68786f7359c1a50d804996021e4c70e90accd2fff6f1a27c91de1dd8df850","bytes":7864,"lines":107},{"path":"CHANGELOG.md","sha256":"302832fe3f069d988c1d61f0a977e33f4e4d94f1fd5db67ed5ac0547ce4ada11","bytes":17977,"lines":78},{"path":"CLAUDE.md","sha256":"add33884f466d324e20875388d103de41c6e062938a6e98727dc83a87ffe976f","bytes":1229,"lines":20},{"path":"LICENSE","sha256":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","bytes":11358,"lines":202},{"path":"NOTICE","sha256":"34b4618e946bdd8d33407d6ac5279f0a0388f5e7c8f79d2e7d8c3c47d0266042","bytes":305,"lines":4},{"path":"README.md","sha256":"1a9fc400d26d8137ae5911488794a6d3fa915957c95f27b36a48cef0fdf823c6","bytes":3785,"lines":81},{"path":"database/migrations/0001_foundation_schema.sql","sha256":"ce2ae52fc66b2f99597ea5285df82c66f90caa46174fef4930d68a8b6177d0dd","bytes":38747,"lines":916},{"path":"database/migrations/0002_sealed_evidence_digest.sql","sha256":"93d659ca8e0e9293a83d5422d043be7b1022c5470a5b22670aa3416fa334a04c","bytes":6649,"lines":202},{"path":"database/migrations/0003_audit_outbox_persistence.sql","sha256":"2aa7bbb8220923ec584537c0cd46f0cba2b692d69d431f097b7df6db75235bfc","bytes":15417,"lines":423},{"path":"database/migrations/0004_outbox_delivery_claim.sql","sha256":"d4504acf7d58528a2a8f4f03d1584b868c8d3ba9046a007b9c2e7cfef993b2ef","bytes":9451,"lines":234},{"path":"database/migrations/0005_outbox_delivery_finalization.sql","sha256":"b7e8790595b288f752d6ef5cc6cbfe4e1b6712248f5b7a3a25fa60016b6a4961","bytes":6125,"lines":170},{"path":"database/migrations/0006_outbox_delivery_dead_letter.sql","sha256":"c1fb91cdf98169fd6684984e86cb0a14fa19c8f1226028d2346a2a069df2b3c7","bytes":24919,"lines":628},{"path":"database/migrations/0007_outbox_retry_exhaustion.sql","sha256":"812f50d70ca5929c7eba964d34a208aedee660d11cc7ffc09d67688c4737e0d5","bytes":19081,"lines":476},{"path":"database/migrations/0008_audit_outbox_review_hardening.sql","sha256":"c3713a12db9d00fdc10005df1f86c07965e9555eefad78ca67e994537a739d9b","bytes":17562,"lines":448},{"path":"database/migrations/0009_candidate_worker_conversion_governance.sql","sha256":"4030666629a6b8deb383b8337ead4f09d6a945969313def2577a38f31f06cda9","bytes":11537,"lines":281},{"path":"database/migrations/0010_validity_study_case_integrity.sql","sha256":"3f594810ac9e1a6747a2bb4838e5ce65b921cb6e3d36fcdc3ff08b4a7579ebd1","bytes":11979,"lines":313},{"path":"database/migrations/0011_criterion_observation_scope.sql","sha256":"f9fe7c35f1ee7b167e1c2ba75a50a84febda9a6ccf8123b4f5726f51968694f9","bytes":7444,"lines":165},{"path":"database/migrations/0012_people_mutation_idempotency.sql","sha256":"52dbbb9ec7f9be5291593ba88f228d7fffd736dcb99547a08c1d6cad076afb69","bytes":3162,"lines":76},{"path":"database/migrations/0013_job_analysis_snapshot.sql","sha256":"b6553a5a4c94c4aa9f341a474e13bbe34db63044eda2446b3ebee178995977ee","bytes":12713,"lines":260},{"path":"docs/API_CONTRACT.md","sha256":"63533dff785da62b89e585d742a158e2aeb05913644f2bf9fb6486f281c2e589","bytes":4555,"lines":76},{"path":"docs/DATA_MODEL.md","sha256":"6ad29731ae7ee7aa5bf3a2d0bfef88894a35a2550edb2be3244d6f143d76444a","bytes":13366,"lines":85},{"path":"docs/ERD.md","sha256":"546001aa85c4fe020e0c39d881dc860daf7f69090596666fdf9092487b0725fe","bytes":6964,"lines":70},{"path":"docs/OPERABILITY.md","sha256":"82b2d3e70cec371ef35e9e0f982ac40fef84351976bc04b863b81d27023d5a62","bytes":11189,"lines":71},{"path":"docs/PRD.md","sha256":"3ad85ae633cce0fc7a93af39b21d7a7c70bb2efa786da6b12f3c5327906e34f1","bytes":5490,"lines":111},{"path":"docs/SECURITY.md","sha256":"01918512d8882060e9cff0c4aa8206e0eccbdfb61cfd7f829331123c7a9fe6ac","bytes":11185,"lines":64},{"path":"docs/STORYBOARD.md","sha256":"6e4ffb0eb03a80343f50d363ffc43b34da9348a44232dd947a9ff416ea92a3d2","bytes":1342,"lines":28},{"path":"docs/STORYBOOK.md","sha256":"82f79029b3c2b7a45393bad5ba8fabe61014d4b6149c7d4e73f70ba447f885e9","bytes":1389,"lines":50},{"path":"docs/TEST_STRATEGY.md","sha256":"d0a0bc3b54ed0fc7973747987f1afb117d6144c390b51ed9370eb571972a33f8","bytes":16534,"lines":135},{"path":"docs/THREAT_MODEL.md","sha256":"f314f375c2e41252536de224c7bc7e4a10ab8f340cb86642724e7399e32f4252","bytes":6736,"lines":23},{"path":"docs/TRACEABILITY.md","sha256":"dbf6fd91375ea28e05456d2a0c9ba629506cbac6f52f5dfda61ae68db2395f7e","bytes":11462,"lines":40},{"path":"docs/TRD.md","sha256":"23697d88a4882698e1a2782b7da3f2ccd0d3cd2d6d1bffe89b6597dc16851077","bytes":9064,"lines":101},{"path":"docs/UML.md","sha256":"fe67c37aa88e5814ceb2db7e8f7d8d85ca27a994802efbb7c75164b387adf0a9","bytes":5528,"lines":122},{"path":"docs/USER_STORIES.md","sha256":"5535b39d8c71a36c81f78e2d6dbd90a2d32e6541790f0d28f6dd4baf3ea7b45f","bytes":2670,"lines":37},{"path":"docs/WIREFRAMES.md","sha256":"b03aa6419aeaf5d42a5698c4d43a434c1633b7ac6fd0b0bd0cda979077adc56e","bytes":2005,"lines":77},{"path":"docs/adr/0001-orgmetra-authoritative-hris-record.md","sha256":"0f8055b73c63d3130321415ad53233588ff952aabd1a88952b39c71747253572","bytes":6108,"lines":53},{"path":"docs/adr/0002-federated-cwl-integration-boundaries.md","sha256":"b77165f2aacfa6f4fde994baf77d5879c6da3e8dae4fd2db0ed912d60ae9b3b2","bytes":4072,"lines":44},{"path":"docs/adr/0003-bitemporal-hris-data-contract.md","sha256":"d7f2660616622c1a7994b28aa66d99d13836bcf755735595f9609a41282ab799","bytes":4453,"lines":47},{"path":"docs/adr/0004-employment-position-version-and-assignment-binding.md","sha256":"fee89e700414abe0b1cffec2acc687e5e014634db8f5ef9e8a92abba5c3cf182","bytes":1872,"lines":30},{"path":"docs/adr/0005-exclusive-employment-and-staffable-seats.md","sha256":"10f0eb409f4fa32d2c5bed2d583d8b43be8e61b5cbef0e927e5bebb5f5c8f85b","bytes":2091,"lines":34},{"path":"docs/adr/0006-governed-audit-outbox-envelope.md","sha256":"827298ddd997b47f78a89e89911ad8ea72e517b7714303637f0329b8cb52cabd","bytes":14100,"lines":66},{"path":"docs/adr/0007-governed-job-analysis-evidence.md","sha256":"953c6d2b9864a78b461b576092ec3f198f0b76709eaaaf7d0ed0182f95182c52","bytes":5653,"lines":57},{"path":"docs/adr/0008-purpose-bound-pii-authorization.md","sha256":"c5157d3bc58f3d8d29e03104dd15eb2911cc1bb66e2c92a935b26d7164648dc7","bytes":5988,"lines":55},{"path":"docs/adr/0009-performance-criterion-observation-scope.md","sha256":"1ac10bb2747b0a5b4d62f627825cfd7f978f3fa88d7575bffc23d56371240a64","bytes":7057,"lines":57},{"path":"docs/adr/0010-naruon-calendar-intent-boundary.md","sha256":"3e1050a964cc4ed76a1a0cf1e699ae5080acf8c9336f0decdd6d5229359db3c9","bytes":3917,"lines":35},{"path":"docs/adr/0011-bitemporal-workforce-composition.md","sha256":"1656ef8b57c836ef7936a8e9cb6a824681eb7563157a1ab0a29deb25849a457b","bytes":5568,"lines":53},{"path":"docs/adr/0012-governed-migration-handoff.md","sha256":"713855d670001d3964ecb36cc653830502fb1d82a58b9e39f564b6992dd2bd80","bytes":5965,"lines":59},{"path":"docs/adr/0013-governed-requisition-review-packet.md","sha256":"70bf2cbdf903a8793d6d8bc116a08331931090118341f42010236e09c6cc1802","bytes":4693,"lines":46},{"path":"docs/adr/0014-job-analysis-snapshot-persistence.md","sha256":"a7ab6fee50aaa63f7f407516a4cb39885faeb0fc6e5035ee8fc352ed73430105","bytes":5365,"lines":49},{"path":"docs/adr/README.md","sha256":"f3b3b5ed3b3b31a40a0a3696abf0065e3c25879b6be50077f38ffae742b9d002","bytes":1838,"lines":18},{"path":"docs/doctoring/REFERENCES.md","sha256":"929f7ee36df16279f028f726fcf039982180deb377746fe3804f3c0d090778d5","bytes":6352,"lines":69},{"path":"docs/superpowers/plans/2026-08-15-orgmetra-foundation-implementation-plan.md","sha256":"b64f21abb19373e780db8b9e64deb8ba9a6219ccf9625a651f25407b8691fcbd","bytes":8227,"lines":226},{"path":"docs/superpowers/specs/2026-08-15-orgmetra-foundation-design.md","sha256":"4a0e1a7943e40d12bd3082db3757045b4085e5a089fea7bc0d8a1565ffcbcf1d","bytes":6237,"lines":187},{"path":"package.json","sha256":"59ae9e3e67c3fba9320cb18439692395cdfd16ae5c24e3c4cf30d77d63ebabb5","bytes":388,"lines":9},{"path":"packages/hris-kernel/src/orgmetra_hris_kernel/audit.py","sha256":"3e5b7190cf857dc8c1fc7e898cef303060f34aabee6c27a9034d4d9650e33190","bytes":7707,"lines":160},{"path":"packages/hris-kernel/tests/test_audit_outbox.py","sha256":"5928dd7b97fe38d6b7472ce62966437e339058a59c3b301a93a7b5c05432b40c","bytes":7556,"lines":200},{"path":"schemas/openapi.yaml","sha256":"09c1e43486779198574fe31b8bcabbd1c1f74beec7bf86245ae578061619838f","bytes":29503,"lines":1020},{"path":"scripts/foundation-contract-core.mjs","sha256":"595e8381dbd62e97093b11eef818af5f04d6473ac592d57e3985ffbc2210d445","bytes":28173,"lines":689},{"path":"scripts/foundation-contract.mjs","sha256":"5242dcdbe0935775edf074462c82600e9bc4927d9fdc50c47727af915fd4b23a","bytes":218,"lines":6},{"path":"tests/dispatcher-inventory.test.mjs","sha256":"09f5e64410e6b7a26bf8d6ce61c50b737da2ea85d955f91eba63aa21f1537261","bytes":1597,"lines":34},{"path":"tests/foundation-contract.test.mjs","sha256":"960306fd7cda7b982a52c4428a432d10a4f570430a5d39fb23aeca0b2ede0615","bytes":14860,"lines":386},{"path":"tests/openapi-contract.test.mjs","sha256":"80c1610ef1c189fa325e55389501e0e51531ddf61ee335bb94d9cb3aa55a9fdc","bytes":6438,"lines":195},{"path":"tests/test_audit_outbox_hardening_postgres.sh","sha256":"518ba2f37ba6292943e5abe22c2599452b2f031a42e453b2493aedf8714421a0","bytes":13396,"lines":333},{"path":"tests/test_audit_outbox_postgres.sh","sha256":"e57a04920a0ba97fa6a06752d15ea150016ab8d44099e998c5c4f4067592b4d2","bytes":13443,"lines":357},{"path":"tests/test_bitemporal_postgres.sh","sha256":"7684b8c2ff52c044c081135515bd5aabbfd00e2daad0d471b0868701af2df6cc","bytes":8209,"lines":230},{"path":"tests/test_candidate_worker_conversion_postgres.sh","sha256":"681cb74d6cfa859ed92c6c2439881ea20c430ef8df94ec662e2807761a377f90","bytes":14673,"lines":344},{"path":"tests/test_criterion_observation_scope_postgres.sh","sha256":"0ee9539ee57f840c27d08009f7868cdc8662669df78a01dbc8be39216b8f1a3d","bytes":17811,"lines":469},{"path":"tests/test_evidence_sealing_postgres.sh","sha256":"57d16b632a0c60ffdcb4842ceb1cfe25d19c54cefeeefb622ff4fa6e83441ad7","bytes":11349,"lines":370},{"path":"tests/test_job_analysis_snapshot_postgres.sh","sha256":"ca9c323a1dd68cfc520277efbbb7495e37fb3ca027890928c8624e5b4f57403f","bytes":13542,"lines":296},{"path":"tests/test_operational_uuid_postgres.sh","sha256":"7378f98f0d4b3000e8ea641d8701f1540dbad71410b3637d81d799969e0f6ff7","bytes":3346,"lines":101},{"path":"tests/test_outbox_claim_postgres.sh","sha256":"1027806d436ebfe34e108c25b6a4001f43b9550f1d70057c6c0d7974323b0c9b","bytes":14817,"lines":429},{"path":"tests/test_outbox_dead_letter_postgres.sh","sha256":"0d728d578e64252e6079f2d141ddaa7fa9cfbf9784e625832273596d69a6e13d","bytes":14008,"lines":377},{"path":"tests/test_people_mutation_idempotency_postgres.sh","sha256":"3f57e12f80bd1b034c9aac54b669d8530106e3e26b3795689671fb53807b3cd5","bytes":16191,"lines":381},{"path":"tests/test_tenant_isolation_postgres.sh","sha256":"dd649435ef8ab9e57f0609c101917e36656a6d40d63de9bcdbdac23d764f6c3a","bytes":15134,"lines":388},{"path":"tests/test_validity_study_case_postgres.sh","sha256":"0070ad58300323c7f9900c5645e0df3106b36ccd245ae686e982c2fd6fa4dc02","bytes":14708,"lines":301},{"path":"tests/validate_repository.py","sha256":"918cf92fd18d81572e9bd5f5daa7f033c32731e2e13f0d00661d1c1de30b12a9","bytes":27291,"lines":638}]} +{"package":"orgmetra-foundation-pack","version":"0.1.0","generated_for_branch":"feat/audit-outbox-envelope","files":[{"path":".github/workflows/foundation-ci.yml","sha256":"12686a3bbd6445e6fdb202b4137dae118ddeeab1efb0c7f18ea6c8fa19d62537","bytes":4379,"lines":123},{"path":".github/workflows/job-analysis-api-quality.yml","sha256":"352dc78931dd94afea3e88912d38dcc4b562a004112f199f3d7a12d22b6d637a","bytes":4159,"lines":105},{"path":".gitignore","sha256":"145fda644f5209fa1fb3e3b40c9af9258bfac6d1a634bba2520fd08fe6d77a21","bytes":375,"lines":37},{"path":"AGENTS.md","sha256":"28f7b7bc010a7739cfdc3e793fb5d39a0e74b842ea9c190e9a251e2d0cbc3a16","bytes":2246,"lines":34},{"path":"ARCHITECTURE.md","sha256":"52d68786f7359c1a50d804996021e4c70e90accd2fff6f1a27c91de1dd8df850","bytes":7864,"lines":107},{"path":"CHANGELOG.md","sha256":"ad6219494fe7c7ff602ba79e6cb2534d7e35c17e0f16be0f1bef5bcd8911f91b","bytes":17636,"lines":77},{"path":"CLAUDE.md","sha256":"add33884f466d324e20875388d103de41c6e062938a6e98727dc83a87ffe976f","bytes":1229,"lines":20},{"path":"LICENSE","sha256":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","bytes":11358,"lines":202},{"path":"NOTICE","sha256":"34b4618e946bdd8d33407d6ac5279f0a0388f5e7c8f79d2e7d8c3c47d0266042","bytes":305,"lines":4},{"path":"README.md","sha256":"1a9fc400d26d8137ae5911488794a6d3fa915957c95f27b36a48cef0fdf823c6","bytes":3785,"lines":81},{"path":"database/migrations/0001_foundation_schema.sql","sha256":"ce2ae52fc66b2f99597ea5285df82c66f90caa46174fef4930d68a8b6177d0dd","bytes":38747,"lines":916},{"path":"database/migrations/0002_sealed_evidence_digest.sql","sha256":"93d659ca8e0e9293a83d5422d043be7b1022c5470a5b22670aa3416fa334a04c","bytes":6649,"lines":202},{"path":"database/migrations/0003_audit_outbox_persistence.sql","sha256":"2aa7bbb8220923ec584537c0cd46f0cba2b692d69d431f097b7df6db75235bfc","bytes":15417,"lines":423},{"path":"database/migrations/0004_outbox_delivery_claim.sql","sha256":"d4504acf7d58528a2a8f4f03d1584b868c8d3ba9046a007b9c2e7cfef993b2ef","bytes":9451,"lines":234},{"path":"database/migrations/0005_outbox_delivery_finalization.sql","sha256":"b7e8790595b288f752d6ef5cc6cbfe4e1b6712248f5b7a3a25fa60016b6a4961","bytes":6125,"lines":170},{"path":"database/migrations/0006_outbox_delivery_dead_letter.sql","sha256":"c1fb91cdf98169fd6684984e86cb0a14fa19c8f1226028d2346a2a069df2b3c7","bytes":24919,"lines":628},{"path":"database/migrations/0007_outbox_retry_exhaustion.sql","sha256":"812f50d70ca5929c7eba964d34a208aedee660d11cc7ffc09d67688c4737e0d5","bytes":19081,"lines":476},{"path":"database/migrations/0008_audit_outbox_review_hardening.sql","sha256":"c3713a12db9d00fdc10005df1f86c07965e9555eefad78ca67e994537a739d9b","bytes":17562,"lines":448},{"path":"database/migrations/0009_candidate_worker_conversion_governance.sql","sha256":"4030666629a6b8deb383b8337ead4f09d6a945969313def2577a38f31f06cda9","bytes":11537,"lines":281},{"path":"database/migrations/0010_validity_study_case_integrity.sql","sha256":"3f594810ac9e1a6747a2bb4838e5ce65b921cb6e3d36fcdc3ff08b4a7579ebd1","bytes":11979,"lines":313},{"path":"database/migrations/0011_criterion_observation_scope.sql","sha256":"f9fe7c35f1ee7b167e1c2ba75a50a84febda9a6ccf8123b4f5726f51968694f9","bytes":7444,"lines":165},{"path":"database/migrations/0012_people_mutation_idempotency.sql","sha256":"52dbbb9ec7f9be5291593ba88f228d7fffd736dcb99547a08c1d6cad076afb69","bytes":3162,"lines":76},{"path":"database/migrations/0013_job_analysis_snapshot.sql","sha256":"b6553a5a4c94c4aa9f341a474e13bbe34db63044eda2446b3ebee178995977ee","bytes":12713,"lines":260},{"path":"docs/API_CONTRACT.md","sha256":"63533dff785da62b89e585d742a158e2aeb05913644f2bf9fb6486f281c2e589","bytes":4555,"lines":76},{"path":"docs/DATA_MODEL.md","sha256":"6ad29731ae7ee7aa5bf3a2d0bfef88894a35a2550edb2be3244d6f143d76444a","bytes":13366,"lines":85},{"path":"docs/ERD.md","sha256":"546001aa85c4fe020e0c39d881dc860daf7f69090596666fdf9092487b0725fe","bytes":6964,"lines":70},{"path":"docs/OPERABILITY.md","sha256":"82b2d3e70cec371ef35e9e0f982ac40fef84351976bc04b863b81d27023d5a62","bytes":11189,"lines":71},{"path":"docs/PRD.md","sha256":"3ad85ae633cce0fc7a93af39b21d7a7c70bb2efa786da6b12f3c5327906e34f1","bytes":5490,"lines":111},{"path":"docs/SECURITY.md","sha256":"01918512d8882060e9cff0c4aa8206e0eccbdfb61cfd7f829331123c7a9fe6ac","bytes":11185,"lines":64},{"path":"docs/STORYBOARD.md","sha256":"6e4ffb0eb03a80343f50d363ffc43b34da9348a44232dd947a9ff416ea92a3d2","bytes":1342,"lines":28},{"path":"docs/STORYBOOK.md","sha256":"82f79029b3c2b7a45393bad5ba8fabe61014d4b6149c7d4e73f70ba447f885e9","bytes":1389,"lines":50},{"path":"docs/TEST_STRATEGY.md","sha256":"d0a0bc3b54ed0fc7973747987f1afb117d6144c390b51ed9370eb571972a33f8","bytes":16534,"lines":135},{"path":"docs/THREAT_MODEL.md","sha256":"f314f375c2e41252536de224c7bc7e4a10ab8f340cb86642724e7399e32f4252","bytes":6736,"lines":23},{"path":"docs/TRACEABILITY.md","sha256":"dbf6fd91375ea28e05456d2a0c9ba629506cbac6f52f5dfda61ae68db2395f7e","bytes":11462,"lines":40},{"path":"docs/TRD.md","sha256":"23697d88a4882698e1a2782b7da3f2ccd0d3cd2d6d1bffe89b6597dc16851077","bytes":9064,"lines":101},{"path":"docs/UML.md","sha256":"fe67c37aa88e5814ceb2db7e8f7d8d85ca27a994802efbb7c75164b387adf0a9","bytes":5528,"lines":122},{"path":"docs/USER_STORIES.md","sha256":"5535b39d8c71a36c81f78e2d6dbd90a2d32e6541790f0d28f6dd4baf3ea7b45f","bytes":2670,"lines":37},{"path":"docs/WIREFRAMES.md","sha256":"b03aa6419aeaf5d42a5698c4d43a434c1633b7ac6fd0b0bd0cda979077adc56e","bytes":2005,"lines":77},{"path":"docs/adr/0001-orgmetra-authoritative-hris-record.md","sha256":"0f8055b73c63d3130321415ad53233588ff952aabd1a88952b39c71747253572","bytes":6108,"lines":53},{"path":"docs/adr/0002-federated-cwl-integration-boundaries.md","sha256":"b77165f2aacfa6f4fde994baf77d5879c6da3e8dae4fd2db0ed912d60ae9b3b2","bytes":4072,"lines":44},{"path":"docs/adr/0003-bitemporal-hris-data-contract.md","sha256":"d7f2660616622c1a7994b28aa66d99d13836bcf755735595f9609a41282ab799","bytes":4453,"lines":47},{"path":"docs/adr/0004-employment-position-version-and-assignment-binding.md","sha256":"fee89e700414abe0b1cffec2acc687e5e014634db8f5ef9e8a92abba5c3cf182","bytes":1872,"lines":30},{"path":"docs/adr/0005-exclusive-employment-and-staffable-seats.md","sha256":"10f0eb409f4fa32d2c5bed2d583d8b43be8e61b5cbef0e927e5bebb5f5c8f85b","bytes":2091,"lines":34},{"path":"docs/adr/0006-governed-audit-outbox-envelope.md","sha256":"827298ddd997b47f78a89e89911ad8ea72e517b7714303637f0329b8cb52cabd","bytes":14100,"lines":66},{"path":"docs/adr/0007-governed-job-analysis-evidence.md","sha256":"953c6d2b9864a78b461b576092ec3f198f0b76709eaaaf7d0ed0182f95182c52","bytes":5653,"lines":57},{"path":"docs/adr/0008-purpose-bound-pii-authorization.md","sha256":"c5157d3bc58f3d8d29e03104dd15eb2911cc1bb66e2c92a935b26d7164648dc7","bytes":5988,"lines":55},{"path":"docs/adr/0009-performance-criterion-observation-scope.md","sha256":"1ac10bb2747b0a5b4d62f627825cfd7f978f3fa88d7575bffc23d56371240a64","bytes":7057,"lines":57},{"path":"docs/adr/0010-naruon-calendar-intent-boundary.md","sha256":"3e1050a964cc4ed76a1a0cf1e699ae5080acf8c9336f0decdd6d5229359db3c9","bytes":3917,"lines":35},{"path":"docs/adr/0011-bitemporal-workforce-composition.md","sha256":"1656ef8b57c836ef7936a8e9cb6a824681eb7563157a1ab0a29deb25849a457b","bytes":5568,"lines":53},{"path":"docs/adr/0012-governed-migration-handoff.md","sha256":"713855d670001d3964ecb36cc653830502fb1d82a58b9e39f564b6992dd2bd80","bytes":5965,"lines":59},{"path":"docs/adr/0013-governed-requisition-review-packet.md","sha256":"70bf2cbdf903a8793d6d8bc116a08331931090118341f42010236e09c6cc1802","bytes":4693,"lines":46},{"path":"docs/adr/0014-job-analysis-snapshot-persistence.md","sha256":"a7ab6fee50aaa63f7f407516a4cb39885faeb0fc6e5035ee8fc352ed73430105","bytes":5365,"lines":49},{"path":"docs/adr/README.md","sha256":"f3b3b5ed3b3b31a40a0a3696abf0065e3c25879b6be50077f38ffae742b9d002","bytes":1838,"lines":18},{"path":"docs/doctoring/REFERENCES.md","sha256":"929f7ee36df16279f028f726fcf039982180deb377746fe3804f3c0d090778d5","bytes":6352,"lines":69},{"path":"docs/superpowers/plans/2026-08-15-orgmetra-foundation-implementation-plan.md","sha256":"b64f21abb19373e780db8b9e64deb8ba9a6219ccf9625a651f25407b8691fcbd","bytes":8227,"lines":226},{"path":"docs/superpowers/specs/2026-08-15-orgmetra-foundation-design.md","sha256":"4a0e1a7943e40d12bd3082db3757045b4085e5a089fea7bc0d8a1565ffcbcf1d","bytes":6237,"lines":187},{"path":"package.json","sha256":"59ae9e3e67c3fba9320cb18439692395cdfd16ae5c24e3c4cf30d77d63ebabb5","bytes":388,"lines":9},{"path":"packages/hris-kernel/src/orgmetra_hris_kernel/audit.py","sha256":"3e5b7190cf857dc8c1fc7e898cef303060f34aabee6c27a9034d4d9650e33190","bytes":7707,"lines":160},{"path":"packages/hris-kernel/tests/test_audit_outbox.py","sha256":"5928dd7b97fe38d6b7472ce62966437e339058a59c3b301a93a7b5c05432b40c","bytes":7556,"lines":200},{"path":"schemas/openapi.yaml","sha256":"09c1e43486779198574fe31b8bcabbd1c1f74beec7bf86245ae578061619838f","bytes":29503,"lines":1020},{"path":"scripts/foundation-contract-core.mjs","sha256":"595e8381dbd62e97093b11eef818af5f04d6473ac592d57e3985ffbc2210d445","bytes":28173,"lines":689},{"path":"scripts/foundation-contract.mjs","sha256":"5242dcdbe0935775edf074462c82600e9bc4927d9fdc50c47727af915fd4b23a","bytes":218,"lines":6},{"path":"tests/dispatcher-inventory.test.mjs","sha256":"09f5e64410e6b7a26bf8d6ce61c50b737da2ea85d955f91eba63aa21f1537261","bytes":1597,"lines":34},{"path":"tests/foundation-contract.test.mjs","sha256":"960306fd7cda7b982a52c4428a432d10a4f570430a5d39fb23aeca0b2ede0615","bytes":14860,"lines":386},{"path":"tests/openapi-contract.test.mjs","sha256":"80c1610ef1c189fa325e55389501e0e51531ddf61ee335bb94d9cb3aa55a9fdc","bytes":6438,"lines":195},{"path":"tests/test_audit_outbox_hardening_postgres.sh","sha256":"518ba2f37ba6292943e5abe22c2599452b2f031a42e453b2493aedf8714421a0","bytes":13396,"lines":333},{"path":"tests/test_audit_outbox_postgres.sh","sha256":"e57a04920a0ba97fa6a06752d15ea150016ab8d44099e998c5c4f4067592b4d2","bytes":13443,"lines":357},{"path":"tests/test_bitemporal_postgres.sh","sha256":"7684b8c2ff52c044c081135515bd5aabbfd00e2daad0d471b0868701af2df6cc","bytes":8209,"lines":230},{"path":"tests/test_candidate_worker_conversion_postgres.sh","sha256":"681cb74d6cfa859ed92c6c2439881ea20c430ef8df94ec662e2807761a377f90","bytes":14673,"lines":344},{"path":"tests/test_criterion_observation_scope_postgres.sh","sha256":"0ee9539ee57f840c27d08009f7868cdc8662669df78a01dbc8be39216b8f1a3d","bytes":17811,"lines":469},{"path":"tests/test_evidence_sealing_postgres.sh","sha256":"57d16b632a0c60ffdcb4842ceb1cfe25d19c54cefeeefb622ff4fa6e83441ad7","bytes":11349,"lines":370},{"path":"tests/test_job_analysis_snapshot_postgres.sh","sha256":"ca9c323a1dd68cfc520277efbbb7495e37fb3ca027890928c8624e5b4f57403f","bytes":13542,"lines":296},{"path":"tests/test_operational_uuid_postgres.sh","sha256":"7378f98f0d4b3000e8ea641d8701f1540dbad71410b3637d81d799969e0f6ff7","bytes":3346,"lines":101},{"path":"tests/test_outbox_claim_postgres.sh","sha256":"1027806d436ebfe34e108c25b6a4001f43b9550f1d70057c6c0d7974323b0c9b","bytes":14817,"lines":429},{"path":"tests/test_outbox_dead_letter_postgres.sh","sha256":"0d728d578e64252e6079f2d141ddaa7fa9cfbf9784e625832273596d69a6e13d","bytes":14008,"lines":377},{"path":"tests/test_people_mutation_idempotency_postgres.sh","sha256":"3f57e12f80bd1b034c9aac54b669d8530106e3e26b3795689671fb53807b3cd5","bytes":16191,"lines":381},{"path":"tests/test_tenant_isolation_postgres.sh","sha256":"dd649435ef8ab9e57f0609c101917e36656a6d40d63de9bcdbdac23d764f6c3a","bytes":15134,"lines":388},{"path":"tests/test_validity_study_case_postgres.sh","sha256":"0070ad58300323c7f9900c5645e0df3106b36ccd245ae686e982c2fd6fa4dc02","bytes":14708,"lines":301},{"path":"tests/validate_repository.py","sha256":"918cf92fd18d81572e9bd5f5daa7f033c32731e2e13f0d00661d1c1de30b12a9","bytes":27291,"lines":638}]} From 6a9f3e214079e2b46bba9776a862f194b899f0e4 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 29 Aug 2026 19:35:24 +0900 Subject: [PATCH 23/23] fix: validate document evidence system time --- .../evidence.py | 2 ++ .../tests/test_evidence.py | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/packages/document-record-evidence/src/orgmetra_document_record_evidence/evidence.py b/packages/document-record-evidence/src/orgmetra_document_record_evidence/evidence.py index 0e6c356dd..65497990f 100644 --- a/packages/document-record-evidence/src/orgmetra_document_record_evidence/evidence.py +++ b/packages/document-record-evidence/src/orgmetra_document_record_evidence/evidence.py @@ -66,6 +66,8 @@ def _validate_digest(value: str, field_name: str) -> None: def _validate_received_at(value: datetime, recorded_at: datetime) -> None: """Require detached UTC event time no later than system-recorded issuance.""" + if type(recorded_at) is not datetime or recorded_at.tzinfo is not timezone.utc: + raise ValueError("recorded_at must be an exact built-in UTC datetime") if type(value) is not datetime or value.tzinfo is not timezone.utc: raise ValueError("received_at must be an exact built-in UTC datetime") if value > recorded_at: diff --git a/packages/document-record-evidence/tests/test_evidence.py b/packages/document-record-evidence/tests/test_evidence.py index e6bcf9acd..0d6b3cc18 100644 --- a/packages/document-record-evidence/tests/test_evidence.py +++ b/packages/document-record-evidence/tests/test_evidence.py @@ -110,6 +110,23 @@ def test_rejects_valid_value_rewrite_after_issuance() -> None: evidence.canonical_json() +def test_rejects_forged_recorded_time_before_seal_verification() -> None: + """Require the system-recorded time type before canonical output can verify its seal.""" + evidence = build_document_record_evidence(**values()) + original = evidence.recorded_at + + class ForgedDateTime(datetime): + """Pretend to serialize a different datetime as the original system time.""" + + def isoformat(self, sep: str = "T", timespec: str = "auto") -> str: + """Return the original text while retaining a different underlying datetime.""" + return original.isoformat(sep=sep, timespec=timespec) + + object.__setattr__(evidence, "recorded_at", ForgedDateTime(2099, 1, 1, tzinfo=timezone.utc)) + with pytest.raises(ValueError, match="recorded_at must be an exact built-in UTC datetime"): + evidence.canonical_json() + + def test_quality_workflow_watches_governance_adr() -> None: """Ensure an ADR-only contract edit cannot bypass the dedicated package gate.""" repository_root = Path(__file__).resolve().parents[3]