Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions .github/workflows/job-qualification-rule-persistence-quality.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
name: Job Qualification Rule Persistence Quality

on:
pull_request:
branches:
- develop
- feat/job-qualification-rule-review
paths:
- "database/migrations/0019_job_qualification_rule_persistence.sql"
- "tests/test_job_qualification_rule_persistence_postgres.sh"
- "docs/adr/0105-job-qualification-rule-persistence.md"
- "docs/traceability/job-qualification-rule-persistence.md"
- "docs/doctoring/job-qualification-rule-persistence-references.md"
- ".github/workflows/job-qualification-rule-persistence-quality.yml"
workflow_dispatch:

permissions:
contents: read

concurrency:
group: job-qualification-rule-persistence-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
postgres_contract:
name: Governed Job qualification-rule persistence contract
runs-on: ubuntu-latest
timeout-minutes: 10
services:
postgres:
image: postgres:16.14@sha256:33f923b05f64ca54ac4401c01126a6b92afe839a0aa0a52bc5aeb5cc958e5f20
env:
POSTGRES_USER: orgmetra
POSTGRES_PASSWORD: orgmetra
POSTGRES_DB: orgmetra
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U orgmetra -d orgmetra"
--health-interval 5s
--health-timeout 5s
--health-retries 10
env:
DATABASE_URL: postgresql://orgmetra:orgmetra@localhost:5432/orgmetra
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: Print deterministic qualification-rule persistence provenance
run: |
python - <<'PY'
import hashlib
import json
from pathlib import Path

paths = [
"tests/test_job_qualification_rule_persistence_postgres.sh",
".github/workflows/job-qualification-rule-persistence-quality.yml",
]
optional = [
"database/migrations/0019_job_qualification_rule_persistence.sql",
"docs/adr/0105-job-qualification-rule-persistence.md",
"docs/traceability/job-qualification-rule-persistence.md",
"docs/doctoring/job-qualification-rule-persistence-references.md",
]
rows = []
for path_text in paths + [path for path in optional if Path(path).is_file()]:
data = Path(path_text).read_bytes()
rows.append(
{
"path": path_text,
"sha256": hashlib.sha256(data).hexdigest(),
"bytes": len(data),
"lines": len(data.decode("utf-8").splitlines()),
}
)
print(json.dumps(rows, separators=(",", ":")))
PY
- name: Run Job qualification-rule persistence regressions
run: bash tests/test_job_qualification_rule_persistence_postgres.sh
- name: Require clean checkout
run: |
git diff --exit-code
test -z "$(git status --porcelain)"
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ All notable changes to Orgmetra will be documented in this file.
- 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.
- Active-PR normalized Job qualification-rule persistence on migration `0019_job_qualification_rule_persistence.sql`: tenant-scoped bitemporal rule anchors and reviewed versions bound to the same validated Job Analysis snapshot, exact provenance digests, immutable audit/outbox evidence, transaction-owned system time, append-only history, trusted trigger-function search paths, FORCE RLS, and no candidate-evaluation or employment-decision authority. The PostgreSQL contract executes the complete migration chain before exercising same-Job, human-reviewed, audit/outbox, history, truncation, and tenant-isolation guards.
- Stacked governed audit/outbox slice via `AuditOutboxEvent`, `audit_event_record`, `outbox_delivery_record`, and `outbox_delivery_escalation_record`: CloudEvents 1.0-compatible PII-minimized metadata, exact canonical JSON bytes, database-verified SHA-256 digests, mandatory human confirmation for high-impact events, immutable audit evidence, tenant RLS, atomic audit/outbox insertion, guarded pending/leased/delivered/dead-lettered delivery state, tenant-safe `claim_outbox_delivery(...)` with deterministic due-work ordering, `FOR UPDATE ... SKIP LOCKED`, opaque worker identity, bounded future leases, immutable envelope return, and atomic takeover of genuinely expired leases only while retry attempts remain; owner-bound `complete_outbox_delivery(...)` and `retry_outbox_delivery(...)`; database-budget-governed `dead_letter_outbox_delivery(...)`; and a separately privileged `operator_dead_letter_expired_outbox_delivery(...)` recovery path for an exhausted final lease whose recorded worker identity is permanently unavailable. `maximum_attempt_count` is persisted on the delivery row, defaults to 5, is constrained to 1 through 100, and cannot be lowered by a dispatcher during finalization. Migration 0007 prevents retry or expired-lease takeover from creating attempt N+1; migration 0008 adds TRUNCATE guards, trusted function search paths, a concurrently built due-work partial index, session-independent immutable envelope validation, and operator recovery backed by separate NOLOGIN/NOBYPASSRLS owner/capability roles so the externally assignable operator role can invoke recovery without receiving direct transport-table read/write rights. Migration 0008 also rejects pre-existing reserved recovery-role names before project DDL, atomically contains the temporary schema-creation privilege used for function ownership handoff, and forces deferred escalation binding while the narrow SECURITY DEFINER owner is still active. Exponential/backoff policy selection, policy-specific producer configuration, and external delivery receipts remain subsequent work.
- `orgmetra_hris_kernel` 0.4.0 with exclusive-versus-concurrent employment, staffable position coverage, exclusive-seat capacity, and `validate_assignment_write` at 100% statement and branch coverage.
- `POST /v1/employment-records`, `POST /v1/position-records`, and `POST /v1/assignment-records` with the same Keyverse mutation context, confirmation, and versioned evidence composition as other high-impact commands.
Expand Down
Loading