diff --git a/AGENTS.md b/AGENTS.md index fb8c0470c..8e341ff79 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -8,7 +8,8 @@ Build Orgmetra as a commercial-grade, evidence-centered HRIS and HCM platform th - Never bypass branch protection, required checks, independent review, OpenCode, Noema, Strix, SAST, or Security Scan gates. - Never self-approve or manufacture approval evidence. -- Never use `COPILOT_GITHUB_TOKEN` as a development model credential. Use `NVIDIA_NIM_API_KEY` for model-backed tests and OpenCode development paths. +- Model-backed product and GitHub Actions behavior must consume a released `contextual-orchestrator` contract. GitHub Actions use `orchestrator/free` through the approved gateway token; Orgmetra does not require direct provider credentials, hard-code provider/model/group selection, or select a paid fallback. Repository-scoped `GITHUB_TOKEN` and an approved gateway token are consumer authentication material, not provider-routing authority. +- If a required model capability is unavailable through the released Contextual Orchestrator contract, fail closed and repair the capability in the Contextual Orchestrator owner. Provider-key discovery, routing, timeout defaults, user cancellation, provider-end, and administrator-timeout semantics remain Contextual Orchestrator responsibilities and are not reimplemented in Orgmetra. - Never make LLM output an autonomous high-impact employment decision. - Never copy another CWL product into Orgmetra when an adapter/package/API/event boundary is sufficient. - Never directly query another service's application database. diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 1bdc13b5a..76bb86680 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -2,7 +2,7 @@ ## Architecture thesis -Orgmetra is a monorepo-hosted, modular, MSA-ready HRIS/HCM platform. It owns employment truth and integrates CWL specialist systems through explicit, versioned contracts. +Orgmetra is a monorepo-hosted, modular, MSA-ready HRIS/HCM platform. It owns employment truth and integrates CWL specialist systems only through explicit, released/versioned owner contracts and Orgmetra ACLs. Repository SHAs may preserve provenance but are not production consumer authority by themselves. ```mermaid flowchart LR @@ -50,8 +50,8 @@ flowchart LR integration -. versioned adapter .-> keyverse[Keyverse] integration -. versioned adapter .-> naruon[Naruon] - validation -. snapshot contract .-> psych[Psychometrics Commons] - validation -. temporal analysis contract .-> tepp[TEPP] + validation -. released snapshot contract; admission gated .-> psych[Psychometrics Commons] + validation -. released temporal contract; admission gated .-> tepp[TEPP] jobs -. ontology contract .-> semantic[Semantic Data Portal] jobs -. draft-only workflow .-> orchestrator[Contextual Orchestrator] documents -. artifact adapter .-> doc_services[Clearfolio and NewsDOM] @@ -60,13 +60,15 @@ flowchart LR The diagram shows one physical PostgreSQL cluster for the initial modular deployment, not a shared application schema. Each bounded context owns a separate schema, database role, migration history, and generated data-access layer. +External edges express bounded-context ownership and intended contract shape, not a claim that every contract is currently production-admissible. Current specialist admission is fail-closed: Psychometrics Commons and TEPP are `release_missing`; fast-mlsirm is `contract_projection_missing`. Their owner paths are Psychometrics Commons #452, TEPP #638, and fast-mlsirm #2086. Until a supported immutable owner release/projection exists and Orgmetra consumer conformance passes, the corresponding production capability is unavailable rather than reconstructed from a branch, copied schema, raw commit pin, floating `latest`, or digest-only reference. + ## Runtime layers 1. **Role workspaces**: employee, manager, recruiter, HR, analyst, and admin. 2. **Orgmetra Gateway**: API aggregation, tenant context, purpose-bound authorization, idempotency, and event-envelope handling. 3. **Domain services**: `people_core`, `organization_core`, `job_architecture`, `talent_acquisition`, `performance_management`, `workforce_validation`, `document_records`, `integration_hub`, and `audit_provenance`. 4. **Stores**: service-owned PostgreSQL schemas, evidence object store, audit/provenance store, and search/vector store. -5. **External CWL services**: Keyverse, Naruon, Psychometrics Commons, TEPP, Semantic Data Portal, Contextual Orchestrator, Clearfolio, NewsDOM, MHTML ETL Gateway, and mightyETL. +5. **External CWL services**: Keyverse, Naruon, Psychometrics Commons, TEPP, Semantic Data Portal, Contextual Orchestrator, Clearfolio, NewsDOM, MHTML ETL Gateway, and mightyETL. A named external system is not automatically an admitted runtime dependency; admission requires its released owner contract plus Orgmetra compatibility/conformance evidence. ## Database ownership and access @@ -96,7 +98,7 @@ Both stores require encryption in transit and at rest, deny-by-default tenant an ## Data ownership -Orgmetra is authoritative for employment facts. It stores foreign references to external artifacts but not external service internals. External products can provide evidence and computation but do not own employment truth. +Orgmetra is authoritative for employment facts. It stores foreign references to external artifacts but not external service internals. External products can provide evidence and computation but do not own employment truth. Production use of specialist evidence additionally requires a supported owner contract identity/version, immutable artifact/package digest, owner locator, and executable Orgmetra consumer conformance; provenance-only source SHAs and generic releases without the consumed projection remain non-authorizing. ## Service extraction strategy diff --git a/CHANGELOG.md b/CHANGELOG.md index 16454da3d..2466d8546 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,14 +7,14 @@ All notable changes to Orgmetra will be documented in this file. ### Added - 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. +- Protected governed job-analysis evidence contract and 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. +- Protected `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 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. - 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. +- Protected governed People mutation runtime: `POST /v1/employment-records`, `POST /v1/position-records`, and `POST /v1/assignment-records` use the same Keyverse mutation context, confirmation, and versioned evidence composition as other high-impact commands. - `employment_record_version.employment_concurrency_code` constrained to `exclusive` or `concurrent`. - ADR 0005 for exclusive employment and staffable seats. - `orgmetra_hris_kernel` 0.3.0 with identity-scoped bitemporal resolution, assignment-employment coverage, allocation-portfolio checks, and a Memorial Hospital RN correction case at 100% statement and branch coverage. @@ -38,6 +38,7 @@ All notable changes to Orgmetra will be documented in this file. ### Changed - Consolidated repository-owned PR validation from twelve workflows into one Foundation CI job, while keeping the dual-cluster recovery rehearsal separately path-scoped. Central required review and security workflows remain organization-owned. +- Routed model-backed repository guidance through the released `contextual-orchestrator` consumer boundary: GitHub Actions use `orchestrator/free` with the approved gateway token, direct provider credentials and provider/model/group or paid-fallback selection are not Orgmetra authority, and missing capabilities fail closed for owner repair. - New predictive-validity membership must use one normalized worker-level case; the three independent validity-study decision/evidence/outcome link relations are historical read surfaces only and can no longer accept new rows. A case insert also rejects a criterion observation whose recorded interval is already closed at `linked_at`. - Canonicalized service identifiers as two-or-more-word `snake_case` across architecture, deployment, ACL, metrics, and client contracts. - Separated fast-mlsirm, TEPP, and Psychometrics Commons into immutable external scientific contracts. @@ -74,4 +75,4 @@ All notable changes to Orgmetra will be documented in this file. ### Notes -- Protected `develop` at `e7ddb7a78a5e1460410005d10f43ebf18c5e12e4` includes normalized validity-study and criterion integrity, bitemporal workforce composition, governed candidate-to-worker conversion, purpose-bound PII authorization, GET-only People reads, governed People mutation/idempotency API, and the accepted ADR 0001–0003 source expansion integrated by #37. Job Analysis persistence/API and the selection-review packet remain active-PR truth until their unchanged exact heads satisfy fresh gates and merge. +- Protected `develop` is the shipped repository truth for integrated capability. Open PRs and draft branches, including this protected-truth reconciliation lane, are non-shipped until they integrate and satisfy fresh exact-head gates. The current protected branch already contains governed Job Analysis persistence/API, selection-review evidence, consolidated Foundation CI, and the other capabilities marked `implemented_on_protected_main` in `docs/TRACEABILITY.md`. \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md index 33818e4c0..bb5741921 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -13,7 +13,11 @@ Do not treat Orgmetra as a resume parser, ATS-only system, psychometric engine, - TEPP owns temporal/event/multilevel analysis artifacts. - Semantic Data Portal owns occupation/skill/ability ontology and semantic catalog. - Naruon owns mail/calendar/file control-plane integrations. -- Contextual Orchestrator owns bounded LLM orchestration traces. +- Contextual Orchestrator owns model routing, provider-key discovery, capability selection, timeout/cancellation/provider-end semantics, and bounded LLM orchestration traces. + +## Model-backed automation + +Consume only a released `contextual-orchestrator` API/client/schema. Model-backed GitHub Actions use `orchestrator/free` through the approved gateway token; Orgmetra must not hard-code provider/model/group routing, require direct provider API keys, or choose a paid fallback. If the released orchestrator cannot provide the required capability, fail closed and repair the Contextual Orchestrator owner rather than adding local provider logic. Repository-scoped `GITHUB_TOKEN` and an approved gateway token may authenticate the consumer path but do not confer provider-routing authority. ## Writing guidance diff --git a/README.md b/README.md index 47bb087a3..adbcbcae8 100644 --- a/README.md +++ b/README.md @@ -78,4 +78,8 @@ Job evidence ## Status -Protected `develop` includes the employment-truth kernel, governed candidate-to-worker conversion, purpose-bound PII authorization, normalized worker-bound validity studies, criterion-observation scope, bitemporal workforce-composition evidence, the governed Naruon intent adapter, and requisition review packets. This active PR adds durable purpose-bound People mutation and confirmed-hire materialization paths for Employment, Position, and Assignment with atomic audit/outbox evidence and tenant-scoped idempotency; treat those write paths as active-PR truth until this exact head passes all fresh protected-base gates and merges. +Protected `develop` is the sole shipped repository truth. It includes the normalized bitemporal HRIS foundation; exclusive/concurrent employment and staffable-seat invariants; acyclic organization reconstruction; governed candidate-to-worker conversion; purpose-bound PII authorization; governed People reads plus purpose-bound People mutation and confirmed-hire materialization with atomic audit/outbox evidence and tenant-scoped idempotency; governed Job Analysis snapshot persistence and API evidence with Task/FJA/KSAO linkage; Job/cycle/staffing-scoped criterion observations; normalized validity-study cases; immutable audit and transactional outbox persistence with bounded recovery; bitemporal workforce-composition snapshots; executable PostgreSQL restore rehearsal evidence; governed Naruon calendar intents; governed migration handoff; requisition review; and human selection-review evidence. + +`implemented_on_protected_main` is the stable maturity enum for capability evidence integrated into Orgmetra's protected branch; in this repository that protected branch is `develop`. The enum is a compatibility vocabulary value, not a literal Git branch named `main`. + +Capabilities on open PRs are not shipped until integrated into protected `develop`. Use `docs/TRACEABILITY.md` as the canonical maturity map and treat `implemented_on_active_pr` as non-protected evidence only. diff --git a/docs/OPERABILITY.md b/docs/OPERABILITY.md index 31f3ff23e..4dba67159 100644 --- a/docs/OPERABILITY.md +++ b/docs/OPERABILITY.md @@ -43,11 +43,16 @@ ### Other dependencies -- Psychometrics Commons unavailable: assessment-result fetches show an unavailable state, not invented scores. -- TEPP unavailable: temporal analyses remain unavailable; authoritative HRIS facts remain readable under normal authorization. +Contract admission and runtime health are separate operational states. A dependency whose required owner release/projection does not exist is **not** an admitted runtime dependency and must fail closed before network execution; an admitted dependency can separately become runtime-unavailable after compatibility/conformance has been established. + +- Psychometrics Commons: current production admission is `release_missing` pending owner #452. Assessment-result execution/fetch remains unavailable rather than reconstructed from a commit, branch, copied schema, callback payload, or invented score. After a released handoff is admitted, a later runtime outage still presents an explicit unavailable state and never authorizes employment/scientific conclusions. +- TEPP: current production admission is `release_missing` pending owner #638. Temporal analysis remains unavailable while authoritative HRIS facts stay readable under normal authorization. A later admitted runtime outage remains distinct from release/compatibility admission failure. +- fast-mlsirm: immutable releases exist, but the required downstream scientific-result provenance projection is `contract_projection_missing` pending owner #2086. A generic package release, raw commit, floating `latest`, or digest-only reference does not satisfy admission. - Contextual Orchestrator unavailable: AI drafting is disabled; manual workflows continue. - Semantic Data Portal unavailable: ontology enrichment is disabled; approved job profiles continue. +Admission failures and runtime outages use different operator-safe evidence. Admission evidence records owner/context/contract/version, immutable artifact/package digest, owner locator, compatibility/conformance outcome and failure class. Runtime outage evidence is emitted only for a previously admitted contract and records the exact admitted version plus the observed transport/provider failure. Neither class is silently converted into local scientific or HR truth. + ## Backups - HRIS PostgreSQL requires encrypted backups, point-in-time recovery, and restore rehearsals. @@ -64,7 +69,8 @@ - outbox lease/retry/dead-letter or delivery-state corruption - missing or tampered outbox escalation evidence - lost final-attempt dispatcher identity requiring audited operator recovery -- integration outage +- specialist contract admission failure or incompatibility +- admitted integration runtime outage - bitemporal corruption - LLM draft hallucination detected - validation study discrepancy diff --git a/docs/SECURITY.md b/docs/SECURITY.md index fd6dd3ea6..410dda16e 100644 --- a/docs/SECURITY.md +++ b/docs/SECURITY.md @@ -29,6 +29,12 @@ - Service database roles cannot query another service's application tables. - Client error responses expose a random `support_reference`, never an internal trace/span identifier or encoded infrastructure context. +## Model-backed automation boundary + +Orgmetra is a consumer of released `contextual-orchestrator` contracts, not a provider-routing authority. Model-backed GitHub Actions use `orchestrator/free` through the approved gateway token. Repository-scoped `GITHUB_TOKEN` and the gateway token authenticate the consumer path; Orgmetra must not require direct provider credentials, hard-code provider/model/group routing, or select a paid fallback. + +If the released orchestrator cannot provide a required capability, the consumer fails closed. Provider-key discovery, provider routing, capability availability, default model timeout, user cancellation, provider-end, and administrator-timeout semantics are repaired in the Contextual Orchestrator owner rather than copied into Orgmetra. This prevents provider credentials and routing policy from becoming an additional Orgmetra trust boundary. + ## Purpose-bound PII authorization Orgmetra evaluates PII access before protected field values leave the authoritative HR boundary. Keyverse supplies authenticated identity and scope attributes through its published contract; Orgmetra owns the HR authorization policy and decision. @@ -41,7 +47,7 @@ Authorization evidence contains only governance metadata, including the opaque a ## Mutation security contract -Every mutating HTTP operation and its server-side command handler requires one validated `Idempotency-Key` that crosses the command boundary into durable transactional replay state. The published OpenAPI employment, position, assignment, person, job-profile, and selection-decision command families require `X-Tenant-Reference`, `X-Actor-Reference`, and `X-Purpose-Code`; those values must match the authenticated Keyverse principal and the operation-specific least-privilege scope. The executable People mutation handlers added on this branch currently implement employment, position, and assignment creation with those headers. Person, job-profile, and selection-decision remain published foundation API contracts until their server handlers are integrated; their OpenAPI presence is not runtime evidence. Confirmed-hire materialization instead binds the tenant in `/v1/tenants/{tenant_record_id}/candidate-worker-conversions`, the business purpose in its exact query parameter, and the actor through the authenticated principal. It does not accept weaker duplicate actor/tenant/purpose header authorities. +Every mutating HTTP operation and its server-side command handler requires one validated `Idempotency-Key` that crosses the command boundary into durable transactional replay state. The published OpenAPI employment, position, assignment, person, job-profile, and selection-decision command families require `X-Tenant-Reference`, `X-Actor-Reference`, and `X-Purpose-Code`; those values must match the authenticated Keyverse principal and the operation-specific least-privilege scope. Protected `develop` implements employment, position, and assignment creation through the executable People mutation handlers with those headers. Person, job-profile, and selection-decision remain published foundation API contracts until their server handlers are integrated; their OpenAPI presence is not runtime evidence. Confirmed-hire materialization instead binds the tenant in `/v1/tenants/{tenant_record_id}/candidate-worker-conversions`, the business purpose in its exact query parameter, and the actor through the authenticated principal. It does not accept weaker duplicate actor/tenant/purpose header authorities. All mutation families additionally require resource-scoped authorization and a versioned audit/provenance correlation reference. High-risk commands require an explicit human-confirmation boundary and immutable versioned evidence. Employment, position, and assignment commands carry confirmation/evidence on the command. Confirmed-hire materialization resolves the exact previously sealed `selection_decision` in the same tenant-bound transaction and rejects the mutation unless that decision records explicit human confirmation and sealed evidence provenance. diff --git a/docs/TEST_STRATEGY.md b/docs/TEST_STRATEGY.md index c20813b72..1fc227da7 100644 --- a/docs/TEST_STRATEGY.md +++ b/docs/TEST_STRATEGY.md @@ -72,43 +72,49 @@ Required negative and provenance tests include: ## External psychometric contracts -Orgmetra does not combine fast-mlsirm and TEPP into one dependency. +Orgmetra does not combine fast-mlsirm and TEPP into one dependency. Production integration is admitted only from an immutable supported owner release. A raw repository revision may remain in provenance evidence but cannot satisfy the consumer contract by itself. ### fast-mlsirm - Canonical repository: `ContextualWisdomLab/fast-mlsirm`. -- Reviewed immutable revision for this baseline: `fb67ced09d8ee00542c05d56374537a9a7239751`. -- Orgmetra contract identifier: `orgmetra.fast_mlsirm.v1`. -- Owner: `workforce_validation`; the normal online path consumes a Psychometrics Commons immutable result snapshot rather than calling the kernel from a role workspace. -- Backend: Rust production arithmetic with bounded CPU multithreading and GPU parity for material kernels. NumPy is a reference/parity path only. -- Request/result contract: versioned model identifier, response-snapshot reference, seed manifest, backend, precision, estimates, uncertainty, diagnostics, convergence, and provenance digest. -- Failure semantics: bounded timeout, typed unavailable/invalid/nonconverged result, no partial score publication, and no invented fallback estimate. +- Historical reviewed source revision: `fb67ced09d8ee00542c05d56374537a9a7239751`; this is provenance only, not the production dependency identity. +- Current authority classification: `contract_projection_missing`. Immutable fast-mlsirm releases exist, but the previously documented `orgmetra.fast_mlsirm.v1` identifier is not an owner-published contract. +- Required production boundary: a domain-neutral released scientific-result/provenance contract consumed through an Orgmetra Anti-Corruption Layer. The owner contract, not fast-mlsirm, must remain free of Orgmetra-specific HR/tenant/decision fields. +- Owner: `workforce_validation`; the normal online path consumes a Psychometrics Commons immutable result snapshot rather than calling a kernel from a role workspace. +- Backend: Rust production arithmetic with bounded CPU multithreading and GPU parity for material kernels. Python/NumPy reference calculations cannot become production fallbacks. +- Required conformance coordinates: released package/contract version, supported public result/schema identity, exact owner locator and artifact/package digest, model/estimator/scoring configuration fingerprint, immutable input/evidence reference, backend/precision, uncertainty/diagnostics, convergence/failure semantics, reproducibility manifest or seed identity where applicable, and CPU/GPU parity evidence where promoted. +- Failure semantics: unknown/incompatible schema, nonconvergence, invalid input, unavailable capability, missing owner locator, and unsupported release all fail closed; no partial score publication or invented fallback estimate. ### TEPP - Canonical repository: `ContextualWisdomLab/TEPP`. -- Reviewed immutable revision for this baseline: `40adac9a26a8af85147ffa2795fb548ea243e0e5`. -- Orgmetra contract identifier: `orgmetra.tepp.v1`. +- Historical reviewed source revision: `40adac9a26a8af85147ffa2795fb548ea243e0e5`; this is provenance only, not the production dependency identity. +- Current authority classification: `release_missing`; no immutable supported TEPP release is presently available to Orgmetra. +- Required production boundary: a released temporal-analysis owner contract with exact contract/version, artifact/package digest and owner locator. - Owner: `workforce_validation`. - Backend: Rust temporal/event/multilevel analysis services and immutable analytical artifacts. -- Request/result contract: tenant-scoped evidence references, event/effective/available times, knowledge cutoff, multiple-membership weights, model manifest, uncertainty, leakage audit, and provenance digest. -- Failure semantics: bounded timeout, typed invalid-temporal-order/insufficient-evidence/nonconverged/unavailable result, and no promotion of an analytical artifact to HRIS truth. +- Required conformance coordinates: evidence references, event/effective/available times, knowledge cutoff, multiple-membership weights, model manifest, uncertainty, leakage audit, provenance digest and owner result locator. +- Failure semantics: invalid temporal order, insufficient evidence, nonconvergence, unavailable capability, missing/incompatible release and provenance mismatch fail closed; an analytical artifact is never promoted to HRIS truth. ### Psychometrics Commons snapshot linkage - Canonical repository: `ContextualWisdomLab/psychometrics-commons`. -- Reviewed immutable revision for this baseline: `cc5850a0d1eacbbf16d03075534fce460a8286e6`. -- Orgmetra stores the immutable `snapshot_ref`, instrument/model version, scoring-contract version, event count, payload digest, result artifact reference, and provenance reference. -- A snapshot may be consumed only when tenant, session, instrument version, event prefix, digest, and result identity all match. +- Historical reviewed source revision: `cc5850a0d1eacbbf16d03075534fce460a8286e6`; this is provenance only, not the production dependency identity. +- Current authority classification: `release_missing`; no immutable supported Psychometrics Commons release is presently available to Orgmetra. +- Required production boundary: a released assessment execution/result-snapshot contract. Orgmetra stores purpose-minimized released owner references rather than copying foreign product persistence. +- A snapshot may be consumed only when the released owner contract/version, tenant, session, instrument/scoring coordinate, event prefix where applicable, digest, result identity and owner locator all agree. -Before production integration, each contract requires: +Before production integration, each specialist contract requires: -- schema compatibility tests against the immutable revision; -- fake-server timeout, malformed result, unavailable, and tenant-mismatch tests; +- an immutable supported owner release and exact contract/schema version; +- artifact or package digest plus owner locator; a digest alone or bare repository SHA is insufficient; +- installed-package/API/schema compatibility tests rather than checkout/PYTHONPATH-only acceptance; +- fake-server or equivalent timeout, malformed result, unavailable, tenant/purpose mismatch and unknown-version tests at the owning adapter boundary; - exact replay and provenance-link tests; -- fast-mlsirm Rust/NumPy and CPU/GPU parity evidence where supported; -- TEPP CPU/GPU parity for material kernels and leakage-safe temporal replay; -- upgrade tests proving a new revision cannot silently change a pinned result schema. +- fast-mlsirm Rust/reference and CPU/GPU parity evidence where the released result claims those paths; +- TEPP CPU/GPU parity for material kernels and leakage-safe temporal replay where applicable; +- negative tests proving `release_missing` and `contract_projection_missing` cannot fall back to a mutable branch, copied schema, floating `latest`, or unversioned result; and +- upgrade tests proving a new owner release cannot silently change the consumed result schema or scientific meaning. ## Psychometric and mathematical evidence @@ -132,4 +138,4 @@ A model that omits evidence for a structural feature it uses is not eligible for - Exact-value table for every chart. - Permission-denied and Keyverse-unavailable states. - High-risk review, confirmation, recording, and audit states. -- Narrow viewport, 200% zoom/reflow, reduced-motion, and high-contrast review. +- Narrow viewport, 200% zoom/reflow, reduced-motion, and high-contrast review. \ No newline at end of file diff --git a/docs/TRACEABILITY.md b/docs/TRACEABILITY.md index 22a4178fe..61fe6c0f2 100644 --- a/docs/TRACEABILITY.md +++ b/docs/TRACEABILITY.md @@ -1,40 +1,46 @@ # Traceability +`implemented_on_protected_main` is the repository's stable maturity enum for capability evidence integrated into the protected branch. In Orgmetra the protected branch is `develop`; the enum is intentionally retained for compatibility and must not be interpreted as a literal Git branch named `main`. `implemented_on_active_pr` means evidence exists only on an open, non-shipped PR. + ## 2. Product traceability matrix | Requirement | Architecture | Data object | Test family | ADR | Maturity | |---|---|---|---|---|---| -| Separate person/employment/organization/job/position/assignment | Core bounded contexts | `person_record`, `employment_record`, `employment_record_version`, `organization_unit`, `job_profile`, `position_record`, `position_record_version`, `assignment_record` | schema/domain and `orgmetra_hris_kernel` tests | ADR-0001, ADR-0004, ADR-0005 | implemented_on_active_pr | -| Exclusive employment and staffable seats | Core bounded contexts | `employment_concurrency_code`, staffable `position_status_code`, assignment allocation totals | Memorial Hospital exclusivity, freeze, and seat-capacity kernel tests plus OpenAPI employment/position/assignment commands | ADR-0005 | implemented_on_active_pr | -| Tenant-qualified HRIS integrity and fail-closed isolation | Core bounded contexts / Security architecture | `tenant_record`, tenant-qualified foreign keys, forced row-level security policies, tenant-scoped kernel query parameters | PostgreSQL cross-tenant FK/application-role RLS contracts plus kernel cross-tenant reconstruction, employment coverage, position coverage, seat-capacity, portfolio, exclusivity, and organization-hierarchy regressions | ADR-0001, ADR-0003 | implemented_on_active_pr | -| Reserved UUID sentinel exclusion | Persistence integrity boundary | every foundation UUID `*_id` column plus audit/outbox identifiers | PostgreSQL inventory proof plus Nil/Max foundation and audit/outbox persistence regressions | ADR-0001, RFC 9562 | implemented_on_active_pr | -| Normalized bitemporal organization/job/employment/position history | Core bounded contexts | `organization_unit_version`, `job_profile_version`, `employment_record_version`, `position_record_version` | PostgreSQL non-overlap, concurrent conflict, correction, rewrite-rejection, assignment-employment binding, and single-valued historical reconstruction | ADR-0001, ADR-0003, ADR-0004 | implemented_on_active_pr | +| Separate person/employment/organization/job/position/assignment | Core bounded contexts | `person_record`, `employment_record`, `employment_record_version`, `organization_unit`, `job_profile`, `position_record`, `position_record_version`, `assignment_record` | schema/domain and `orgmetra_hris_kernel` tests | ADR-0001, ADR-0004, ADR-0005 | implemented_on_protected_main | +| Exclusive employment and staffable seats | Core bounded contexts | `employment_concurrency_code`, staffable `position_status_code`, assignment allocation totals | Memorial Hospital exclusivity, freeze, and seat-capacity kernel tests plus OpenAPI employment/position/assignment commands | ADR-0005 | implemented_on_protected_main | +| Tenant-qualified HRIS integrity and fail-closed isolation | Core bounded contexts / Security architecture | `tenant_record`, tenant-qualified foreign keys, forced row-level security policies, tenant-scoped kernel query parameters | PostgreSQL cross-tenant FK/application-role RLS contracts plus kernel cross-tenant reconstruction, employment coverage, position coverage, seat-capacity, portfolio, exclusivity, and organization-hierarchy regressions | ADR-0001, ADR-0003 | implemented_on_protected_main | +| Reserved UUID sentinel exclusion | Persistence integrity boundary | every foundation UUID `*_id` column plus audit/outbox identifiers | PostgreSQL inventory proof plus Nil/Max foundation and audit/outbox persistence regressions | ADR-0001, RFC 9562 | implemented_on_protected_main | +| Normalized bitemporal organization/job/employment/position history | Core bounded contexts | `organization_unit_version`, `job_profile_version`, `employment_record_version`, `position_record_version` | PostgreSQL non-overlap, concurrent conflict, correction, rewrite-rejection, assignment-employment binding, and single-valued historical reconstruction | ADR-0001, ADR-0003, ADR-0004 | implemented_on_protected_main | | Acyclic organization hierarchy at historical coordinates | Organization core | `organization_unit_version.parent_organization_unit_id` | indirect A→B→C→A rejection plus future-recorded and foreign-tenant isolation in `orgmetra_hris_kernel` | ADR-0001, ADR-0003 | implemented_on_protected_main | -| Effective/system time | Bitemporal HRIS | `effective_from`, `recorded_from` | strict half-open interval and historical-coordinate tests | ADR-0003 | implemented_on_active_pr | -| Evidence-backed human selection decisions | Talent Acquisition | `decision_evidence_set`, `selection_decision_evidence`, `selection_decision` | database-owned SHA-256 sealing, non-empty evidence, drift/reuse rejection, OpenAPI human-confirmation tests | ADR-0001 | implemented_on_active_pr | +| Effective/system time | Bitemporal HRIS | `effective_from`, `recorded_from` | strict half-open interval and historical-coordinate tests | ADR-0003 | implemented_on_protected_main | +| Evidence-backed human selection decisions | Talent Acquisition | `decision_evidence_set`, `selection_decision_evidence`, `selection_decision` | database-owned SHA-256 sealing, non-empty evidence, drift/reuse rejection, OpenAPI human-confirmation tests | ADR-0001 | implemented_on_protected_main | | Governed candidate-to-worker conversion | Talent Acquisition / People core | `candidate_worker_conversion_record` with candidate, person, employment, selection decision, audit event and outbox evidence | PostgreSQL exact hire/evidence/audit-envelope binding, correction provenance, tenant RLS, legacy-write rejection and bitemporal history contract | ADR-0001, ADR-0003, ADR-0006 | implemented_on_protected_main | -| GET-only People API | People API / purpose-bound read boundary | `GET /v1/tenants/{tenant_record_id}/people/{person_record_id}`, `read_worker_people_record()`, `PostgresPeopleReadPort` | People API HTTP and PostgreSQL read contracts with exact 100% owned statement/branch coverage; current conversion lineage; no mutation writes | ADR-0002, ADR-0008 | implemented_on_protected_main | -| Governed People writes and confirmed-hire materialization | People API / purpose-bound mutation boundary | `POST /v1/employment-records`, `POST /v1/position-records`, `POST /v1/assignment-records`, `POST /v1/tenants/{tenant_record_id}/candidate-worker-conversions`, `people_mutation_idempotency_record` | People command/HTTP/PostgreSQL contracts with exact owned statement/branch coverage plus PostgreSQL tenant-RLS, atomic audit/outbox/idempotency, identical-retry replay, changed-command rejection, rollback, and concurrent-key regression | ADR-0002, ADR-0006, ADR-0008 | implemented_on_protected_main | -| Evidence-grounded Job analysis with governed Task/FJA/KSAO persistence | Job Analysis / Workforce Validation | `JobAnalysisSnapshot`, `TaskEvidence`, `KSAORequirement`, `FunctionalJobAnalysisProfile`, `TaskKSAOLink`, `EvidenceSource`, `job_analysis_snapshot`, `job_analysis_task_item`, `job_analysis_ksao_item`, `job_analysis_task_ksao_link`, `job_analysis_write_command`, `POST /v1/tenants/{tenant_record_id}/job-analysis-snapshots`, `GET /v1/tenants/{tenant_record_id}/job-analysis-snapshots/{analysis_record_id}` | domain tenant/Job isolation, source/version/digest provenance, task-KSAO completeness, deterministic canonicalization, accountable human-review and LLM-draft-only regressions; migration 0013 PostgreSQL parent-scope/RLS/append-only/idempotency/audit-outbox persistence; exact route/OpenAPI/error contracts and 100% owned service statement/branch coverage | ADR-0007, ADR-0014 | implemented_on_active_pr | +| Purpose-bound People read API | People API / purpose-bound read boundary | `GET /v1/tenants/{tenant_record_id}/people/{person_record_id}`, `read_worker_people_record()`, `PostgresPeopleReadPort` | People API HTTP and PostgreSQL read contracts with exact 100% owned statement/branch coverage, purpose-bound authorization, and current conversion lineage | ADR-0002, ADR-0008 | implemented_on_protected_main | +| Evidence-grounded Job analysis with Task/FJA/KSAO linkage | Job Analysis / Workforce Validation | `JobAnalysisSnapshot`, `TaskEvidence`, `KSAORequirement`, `FunctionalJobAnalysisProfile`, `TaskKSAOLink`, `EvidenceSource`, `job_analysis_snapshot`, `job_analysis_task_item`, `job_analysis_ksao_item`, `job_analysis_task_ksao_link`, `job_analysis_write_command`, `POST /v1/tenants/{tenant_record_id}/job-analysis-snapshots`, `GET /v1/tenants/{tenant_record_id}/job-analysis-snapshots/{analysis_record_id}` | domain tenant/Job isolation, source/version/digest provenance, task-KSAO completeness, deterministic canonicalization, accountable human-review and LLM-draft-only regressions; migration 0013 PostgreSQL parent-scope/RLS/append-only/idempotency/audit-outbox persistence; exact route/OpenAPI/error contracts and 100% owned service statement/branch coverage | ADR-0007, ADR-0014 | implemented_on_protected_main | | Job-, cycle-, and staffing-scoped performance criterion observations | Performance / Workforce Validation | `criterion_observation`, `criterion_blueprint`, `performance_cycle`, `assignment_record`, `employment_record_version`, `position_record`, `position_record_version` | PostgreSQL wrong-Job, pre-assignment, out-of-cycle, frozen-Position, terminated-employment, closed-recorded-time, and session-TimeZone/UTC-midnight rejection plus valid worker-Job/staffing acceptance | ADR-0009 | implemented_on_protected_main | -| Governed immutable audit and transactional outbox persistence | Audit Provenance / Integration Hub | `AuditOutboxEvent.canonical_json()`, `audit_event_record`, `outbox_delivery_record`, SHA-256 envelope digest | canonical-byte/digest regression plus PostgreSQL digest, allowlist/PII, high-impact confirmation, append-only, atomicity, lease-transition, terminal-state, and reserved-UUID tests | ADR-0006 | implemented_on_active_pr | -| Tenant-safe atomic outbox claiming and crash recovery | Integration Hub dispatcher boundary | `outbox_delivery_record` pending/expired-lease claim indexes plus `claim_outbox_delivery(...)` | PostgreSQL already-expired-new-lease rejection, due-order claim, live-lease exclusion, pre-exhaustion takeover with `lease_expired` evidence, retry-budget claim bound, tenant-context binding, opaque-worker validation, and bounded-lease contract | ADR-0006 | implemented_on_active_pr | -| Owner-bound outbox completion, retry, and terminal dead-letter escalation | Integration Hub dispatcher boundary | immutable `outbox_delivery_record.maximum_attempt_count`, `complete_outbox_delivery(...)`, `retry_outbox_delivery(...)`, `dead_letter_outbox_delivery(...)`, `outbox_delivery_escalation_record` | PostgreSQL foreign/stale-owner denial, dispatcher-budget-signature rejection, direct-terminal-DML rejection, stored-budget exhaustion, retry-attempt-N+1 denial, exhausted expired-lease non-reclaimability, recorded-owner terminalization, nonterminal-escalation rejection, terminal non-reclaimability, and append-only escalation evidence | ADR-0006 | implemented_on_active_pr | +| Governed immutable audit and transactional outbox persistence | Audit Provenance / Integration Hub | `AuditOutboxEvent.canonical_json()`, `audit_event_record`, `outbox_delivery_record`, SHA-256 envelope digest | canonical-byte/digest regression plus PostgreSQL digest, allowlist/PII, high-impact confirmation, append-only, atomicity, lease-transition, terminal-state, and reserved-UUID tests | ADR-0006 | implemented_on_protected_main | +| Tenant-safe atomic outbox claiming and crash recovery | Integration Hub dispatcher boundary | `outbox_delivery_record` pending/expired-lease claim indexes plus `claim_outbox_delivery(...)` | PostgreSQL already-expired-new-lease rejection, due-order claim, live-lease exclusion, pre-exhaustion takeover with `lease_expired` evidence, retry-budget claim bound, tenant-context binding, opaque-worker validation, and bounded-lease contract | ADR-0006 | implemented_on_protected_main | +| Owner-bound outbox completion, retry, and terminal dead-letter escalation | Integration Hub dispatcher boundary | immutable `outbox_delivery_record.maximum_attempt_count`, `complete_outbox_delivery(...)`, `retry_outbox_delivery(...)`, `dead_letter_outbox_delivery(...)`, `outbox_delivery_escalation_record` | PostgreSQL foreign/stale-owner denial, dispatcher-budget-signature rejection, direct-terminal-DML rejection, stored-budget exhaustion, retry-attempt-N+1 denial, exhausted expired-lease non-reclaimability, recorded-owner terminalization, nonterminal-escalation rejection, terminal non-reclaimability, and append-only escalation evidence | ADR-0006 | implemented_on_protected_main | +| Governed People writes and confirmed-hire materialization | People API / purpose-bound mutation boundary | `POST /v1/employment-records`, `POST /v1/position-records`, `POST /v1/assignment-records`, `POST /v1/tenants/{tenant_record_id}/candidate-worker-conversions`, `people_mutation_idempotency_record` | People command/HTTP/PostgreSQL contracts with exact owned statement/branch coverage plus PostgreSQL tenant-RLS, atomic audit/outbox/idempotency, identical-retry replay, changed-command rejection, rollback, and concurrent-key regression | ADR-0002, ADR-0006, ADR-0008 | implemented_on_protected_main | | Predictive-validity case integrity | Workforce Validation | `validity_study`, normalized `validity_study_case_record`, exact `selection_decision`, sealed `decision_evidence_set`, governed `candidate_worker_conversion_record`, `criterion_observation` | `test_validity_study_case_postgres.sh`: legacy loose-link write rejection; exact evidence-set ID, Job, criterion and worker mismatch rejection; study/observation system-recorded visibility boundaries; governed upstream decision/evidence/conversion lineage from the evidence-sealing and candidate-worker conversion contracts; UPDATE/DELETE/TRUNCATE protection; missing/foreign-tenant RLS denial. Statistical estimation remains subsequent work. | ADR-0001, SIOP Principles 5th ed., 29 C.F.R. Part 1607 | implemented_on_protected_main | -| Purpose-bound PII access | Security architecture / Keyverse adapter boundary | `PurposeBoundAccessPolicy`, `PurposeBoundAccessRequest.resource_reference`, `AuthorizationDecision.resource_reference` | exact tenant/actor/resource binding, exact opaque target correlation for allow/deny audit evidence, resource/purpose/operation matching, operation-specific scope, field-subset minimization, malformed-attribute rejection, reserved-UUID rejection, PII-minimized denial evidence, and exact 100% owned statement/branch coverage | ADR-0008 | implemented_on_protected_main | +| Purpose-bound PII access | Security architecture / Keyverse adapter boundary | `PurposeBoundAccessPolicy`, `PurposeBoundAccessRequest.resource_reference`, `AuthorizationDecision.resource_reference` | exact tenant/actor/resource agreement, exact opaque target correlation for allow/deny audit evidence, resource/purpose/operation matching, operation-specific scope, field-subset minimization, malformed-attribute rejection, reserved-UUID rejection, PII-minimized denial evidence, and exact 100% owned statement/branch coverage | ADR-0008 | implemented_on_protected_main | +| Bitemporal workforce-composition evidence | Workforce Intelligence | `WorkforceCompositionSnapshot` aggregate evidence | exact `(tenant_record_id, effective_on, known_at)` reconstruction, deterministic status ordering, aggregate-only payload, timezone-aware knowledge cutoff, exact 100% owned statement/branch coverage | ADR-0011 | implemented_on_protected_main | +| Governed requisition review evidence | Talent Acquisition | requisition-review packet with authoritative Job/optional Position, requirement, headcount, requester, and approver references | tenant-scoped actor re-resolution, distinct authoritative actors, versioned evidence, deterministic digest, value minimization, exact 100% owned statement/branch coverage | ADR-0013 | implemented_on_protected_main | +| Governed human selection review evidence | Talent Acquisition | `SelectionReviewPacket` | canonical opaque references, sealed-evidence binding, closed reason/version vocabulary, model draft/provenance digests, mandatory human authority, redacted representation, exact 100% owned statement/branch coverage | ADR-0001, ADR-0008 | implemented_on_protected_main | +| Executable PostgreSQL restore rehearsal evidence | Operability / Recovery | independent source and restore PostgreSQL clusters plus recovery manifest | cluster-identity binding, non-empty/listable dump, bitemporal/audit/outbox restore validation, least-privilege recovery ACLs, append-only/TRUNCATE rejection, deterministic recovery provenance | ADR-0006 | implemented_on_protected_main | | Least-privilege API capability | Keyverse gateway boundary | operation scope conceptual | structural per-operation scope and confused-deputy contract tests | ADR-0002 | implemented_on_active_pr | | Client-safe failure correlation | API error boundary | `support_reference` conceptual | error disclosure and support-lookup tests | ADR-0002 | implemented_on_active_pr | -| Foundation artifact integrity | Repository governance | deterministic `manifest.json` file inventory | SHA-256/byte/line validation plus Python/Node inventory-equivalence regression and explicit dispatcher/validity/criterion/job-analysis migration and execution-contract provenance regression | ADR-0001 | implemented_on_active_pr | +| Foundation artifact integrity | Repository governance | deterministic `manifest.json` file inventory | SHA-256/byte/line validation plus Python/Node inventory-equivalence regression and explicit dispatcher/validity/criterion/job-analysis migration and execution-contract provenance regression | ADR-0001 | implemented_on_protected_main | ## 4. CWL integration traceability | External contract | Orgmetra owner boundary | Integration style | Required evidence | ADR | Maturity | |---|---|---|---|---|---| | Keyverse identity and authorization | API Gateway / purpose-bound authorization | Published OIDC/API identity and scope contract plus Orgmetra-owned `orgmetra_keyverse_adapter` policy evaluation | tenant/actor/resource agreement, exact opaque target-resource reference, purpose, operation-specific scope, requested-field minimization, opaque subject, no stored credentials or protected values in authorization evidence | ADR-0002, ADR-0008 | implemented_on_protected_main | -| naruon communication and calendar | Integration Hub | Published API/event adapter | idempotency, delivery audit, no direct table access | ADR-0002 | planned | -| Psychometrics Commons @ `cc5850a0d1eacbbf16d03075534fce460a8286e6` | Workforce Validation | Immutable response/result snapshot contract | pinned revision, model/version/provenance snapshot, immutable result linkage, no direct application-table access | ADR-0002 | accepted_architecture | -| fast-mlsirm @ `fb67ced09d8ee00542c05d56374537a9a7239751` | Workforce Validation | Published `orgmetra.fast_mlsirm.v1` result contract; direct calls only from approved offline validation worker | pinned revision, contract identifier, backend/result provenance, CPU/GPU parity evidence where material, no duplicated kernel | ADR-0002 | accepted_architecture | -| TEPP temporal evidence | Workforce Validation | Published package/API contract | temporal provenance and version binding | ADR-0002 | planned | -| MHTML ETL Gateway / mightyETL | Governed Migration | Published ETL contract | lineage, idempotency, reconciliation, rollback | ADR-0002 | planned | +| naruon communication and calendar | Integration Hub | Published `/api/calendar/writeback-intent` adapter contract with `execute_provider=false` | tenant/actor/purpose/reason/evidence binding, idempotency intent, response provenance validation, no provider credential, no direct table access, provider execution remains foreign-owner responsibility | ADR-0010 | implemented_on_protected_main | +| Psychometrics Commons assessment/result handoff | Workforce Validation | Released owner contract required; current state `release_missing`. Historical reviewed source `cc5850a0d1eacbbf16d03075534fce460a8286e6` is provenance only | immutable owner release, exact contract/version, artifact/package digest, owner locator, model/version/provenance snapshot, immutable result linkage, consumer conformance, no direct application-table access | ADR-0002 | planned | +| fast-mlsirm scientific result/provenance | Workforce Validation | Domain-neutral released owner contract consumed through an Orgmetra ACL; current state `contract_projection_missing`. An immutable package release exists, but `orgmetra.fast_mlsirm.v1` is not an owner-published contract | exact supported result-contract/schema identity, immutable release/package digest and owner locator, backend/result provenance, convergence/failure semantics, CPU/GPU parity evidence where material, consumer conformance, no duplicated kernel | ADR-0002 | planned | +| TEPP temporal evidence | Workforce Validation | Released owner contract required; current state `release_missing`. Historical reviewed source `40adac9a26a8af85147ffa2795fb548ea243e0e5` is provenance only | immutable owner release, exact contract/version, artifact/package digest, owner locator, temporal provenance/version binding, leakage-safe consumer conformance | ADR-0002 | planned | +| MHTML ETL Gateway / mightyETL | Governed Migration | Published ETL contract consumed through the Orgmetra migration handoff | exact source/schema/mapping digests, tenant/actor/approval context, reviewed target families, immutable dependency revisions, bounded batch request, reconciliation/rollback evidence, no foreign application-table access | ADR-0012 | implemented_on_protected_main | | Semantic Data Portal / OriginWeave / LineageWeave | Evidence and lineage adapters | Published API/event contracts | provenance, tenant ACL, retention, export controls | ADR-0002 | planned | -| contextual-orchestrator | Draft-evidence orchestration adapter | Published API contract | model provenance, untrusted-output labeling, human confirmation | ADR-0002 | planned | +| contextual-orchestrator | Draft-evidence orchestration adapter | Published API contract | model provenance, untrusted-output labeling, human confirmation | ADR-0002 | planned | \ No newline at end of file diff --git a/docs/TRD.md b/docs/TRD.md index c6e5e5e2f..3ad4a0f51 100644 --- a/docs/TRD.md +++ b/docs/TRD.md @@ -84,18 +84,22 @@ These identifiers are canonical across deployment names, ACLs, metrics, generate |---|---|---| | `keyverse_adapter` | Keyverse OIDC/SCIM contract | `integration_hub` | | `naruon_adapter` | Naruon communication-intent contract | `integration_hub` | -| `psychometrics_commons_adapter` | immutable response/result snapshot contract pinned to `cc5850a0d1eacbbf16d03075534fce460a8286e6` | `workforce_validation` | -| `fast_mlsirm_adapter` | `orgmetra.fast_mlsirm.v1`, repository `ContextualWisdomLab/fast-mlsirm` pinned to `fb67ced09d8ee00542c05d56374537a9a7239751`; online role workspaces consume it through Psychometrics Commons, while direct calls are limited to an approved offline validation worker | `workforce_validation` | -| `tepp_adapter` | `orgmetra.tepp.v1`, repository `ContextualWisdomLab/TEPP` pinned to `40adac9a26a8af85147ffa2795fb548ea243e0e5` | `workforce_validation` | +| `psychometrics_commons_adapter` | released assessment execution/result-snapshot owner contract; production consumption is fail-closed while the owner has no immutable supported release. Historical reviewed source `cc5850a0d1eacbbf16d03075534fce460a8286e6` is provenance only, not consumer authority | `workforce_validation` | +| `fast_mlsirm_adapter` | domain-neutral released scientific-result/provenance contract consumed through an Orgmetra ACL. Immutable fast-mlsirm releases exist, but the previously named `orgmetra.fast_mlsirm.v1` contract is not owner-published; production consumption remains fail-closed until a supported owner projection is released. Direct role-workspace calls are prohibited | `workforce_validation` | +| `tepp_adapter` | released temporal-analysis owner contract; production consumption is fail-closed while the owner has no immutable supported release. Historical reviewed source `40adac9a26a8af85147ffa2795fb548ea243e0e5` is provenance only, not consumer authority | `workforce_validation` | | `semantic_data_portal_adapter` | versioned ontology and data-catalog contract | `job_architecture` | -| `contextual_orchestrator_adapter` | schema-bound draft and verification operations; no authoritative writes | `job_architecture` and `integration_hub` | +| `contextual_orchestrator_adapter` | released `contextual-orchestrator` schema-bound draft and verification operations; no authoritative writes or provider-routing authority in Orgmetra | `job_architecture` and `integration_hub` | | `clearfolio_adapter` | document preview artifact contract | `document_records` | | `newsdom_adapter` | canonical document-block and source-span contract | `document_records` | | `mhtml_etl_adapter` | governed schema-proposal and row-lineage contract | `integration_hub` | | `mightyetl_adapter` | bounded migration/CDC contract | `integration_hub` | +A repository commit SHA may be retained inside provenance or compatibility evidence, but it is never sufficient by itself as a production integration contract. A production specialist adapter requires a supported owner contract identity and version, immutable artifact or package digest, owner locator, and executable consumer-conformance evidence. A missing owner release is `release_missing`; an immutable release that does not expose the required supported projection is `contract_projection_missing`. Both states fail closed rather than falling back to a mutable branch, copied source/schema, digest-only pointer, or floating `latest`. + Adapters use bounded timeouts, typed error semantics, tenant validation, idempotency, and provenance. They fail closed, never log credentials, and never promote external data to authoritative HRIS truth without Orgmetra command validation. +Model-backed GitHub Actions consume only a released Contextual Orchestrator API/client/schema through `orchestrator/free` and the approved gateway token. Orgmetra does not hard-code a provider, model, provider group, or paid fallback and does not require provider API keys. Provider-key discovery, routing, capability availability, default model timeout, user cancellation, provider-end, and administrator-timeout semantics are owned by Contextual Orchestrator. If a required capability is unavailable at that boundary, the Orgmetra consumer fails closed and the owner contract is repaired rather than bypassed locally. + ## 7. Testing requirements -`docs/TEST_STRATEGY.md` is the canonical coverage and execution contract. Every service must satisfy its 100% statement/branch coverage requirement where the pinned toolchain exposes those metrics, document exact commands, and preserve migration, API, event, authorization, temporal, tenant-isolation, evidence-sealing, append-only, scientific, adapter-failure, and accessibility evidence. PostgreSQL contract tests use a `NOBYPASSRLS` application role and cover missing tenant context, cross-tenant references, concurrent bitemporal corrections, database-owned evidence digest computation, empty-evidence rejection, and post-decision evidence drift. This TRD does not define a weaker duplicate threshold. +`docs/TEST_STRATEGY.md` is the canonical coverage and execution contract. Every service must satisfy its 100% statement/branch coverage requirement where the pinned toolchain exposes those metrics, document exact commands, and preserve migration, API, event, authorization, temporal, tenant-isolation, evidence-sealing, append-only, scientific, adapter-failure, and accessibility evidence. PostgreSQL contract tests use a `NOBYPASSRLS` application role and cover missing tenant context, cross-tenant references, concurrent bitemporal corrections, database-owned evidence digest computation, empty-evidence rejection, and post-decision evidence drift. This TRD does not define a weaker duplicate threshold. \ No newline at end of file diff --git a/docs/adr/0006-governed-audit-outbox-envelope.md b/docs/adr/0006-governed-audit-outbox-envelope.md index bd86f2684..806b07e67 100644 --- a/docs/adr/0006-governed-audit-outbox-envelope.md +++ b/docs/adr/0006-governed-audit-outbox-envelope.md @@ -1,6 +1,6 @@ # ADR-0006: Governed audit/outbox envelope and durable persistence -- **Status:** Accepted for the stacked implementation branch; not protected-main truth until merged. +- Status: Accepted - **Decision date:** 2026-08-17 - **Scope:** Orgmetra-owned audit envelope, immutable audit persistence, guarded outbox delivery state, tenant-safe atomic dispatcher claiming, expired-lease takeover, owner-bound completion/retry, database-budget-governed terminal dead-letter escalation, review hardening, and privileged recovery of an expired exhausted lease when its recorded final worker identity is permanently unavailable. Exponential retry policy, retention/export workflows, and external delivery receipts remain subsequent work. diff --git a/docs/adr/0007-governed-job-analysis-evidence.md b/docs/adr/0007-governed-job-analysis-evidence.md index f9aeea835..060939382 100644 --- a/docs/adr/0007-governed-job-analysis-evidence.md +++ b/docs/adr/0007-governed-job-analysis-evidence.md @@ -1,6 +1,6 @@ # ADR 0007: Governed job-analysis evidence snapshots -- Status: Accepted on stacked implementation branch +- Status: Accepted - Date: 2026-08-17 - Owners: Orgmetra Job Analysis / Workforce Validation diff --git a/docs/adr/0010-naruon-calendar-intent-boundary.md b/docs/adr/0010-naruon-calendar-intent-boundary.md index 6bed4dd49..718dee8ef 100644 --- a/docs/adr/0010-naruon-calendar-intent-boundary.md +++ b/docs/adr/0010-naruon-calendar-intent-boundary.md @@ -2,7 +2,9 @@ ## Status -Accepted on active PR only. This document is not protected-`develop` product truth until its owning PR integrates. +Status: Accepted + +This ADR describes the intent-only adapter integrated on protected `develop`. Provider-executed create remains outside the Orgmetra-owned boundary until Naruon's owner contract supports and proves that path. ## Context diff --git a/docs/adr/0011-bitemporal-workforce-composition.md b/docs/adr/0011-bitemporal-workforce-composition.md index 11f137ee4..81161150a 100644 --- a/docs/adr/0011-bitemporal-workforce-composition.md +++ b/docs/adr/0011-bitemporal-workforce-composition.md @@ -2,7 +2,9 @@ ## Status -Accepted on active PR #33 only. This document is not protected-`develop` product truth until the owning PR integrates. +Status: Accepted + +Integrated on protected `develop` through PR #33. This ADR is shipped architecture truth; aggregate workforce evidence remains descriptive and does not authorize an employment decision. ## Context diff --git a/docs/adr/0012-governed-migration-handoff.md b/docs/adr/0012-governed-migration-handoff.md index 90f04d6bc..3dfde547e 100644 --- a/docs/adr/0012-governed-migration-handoff.md +++ b/docs/adr/0012-governed-migration-handoff.md @@ -2,7 +2,9 @@ ## Status -Accepted on this active PR only. This is not protected-`develop` product truth until the owning PR integrates. +Status: Accepted + +Integrated on protected `develop` through PR #31. This ADR is shipped architecture truth for the pre-write migration handoff; it does not claim that a migration batch completed. ## Context diff --git a/docs/adr/0013-governed-requisition-review-packet.md b/docs/adr/0013-governed-requisition-review-packet.md index 4f1e0b239..a0e501ff5 100644 --- a/docs/adr/0013-governed-requisition-review-packet.md +++ b/docs/adr/0013-governed-requisition-review-packet.md @@ -1,6 +1,6 @@ # ADR 0013: Governed requisition review packet -- Status: Accepted on active implementation branch +- Status: Accepted - Date: 2026-08-18 - Owners: Talent Acquisition / Job Architecture / People Governance @@ -39,7 +39,7 @@ The packet cannot claim approval, open a requisition, create a candidate, or per - Routine `repr()` output does not disclose trust-bearing references or digests. - Requisition approval requires authoritative resolved-actor separation; two different opaque references alone cannot satisfy the hiring-manager/approver separation requirement. - Downstream persistence must still enforce purpose-bound authorization, idempotency, human approval, and immutable audit/outbox evidence at the authoritative mutation boundary. -- This ADR describes active-PR truth only until the corresponding exact head integrates into protected `develop`. +- This ADR describes the requisition-review evidence contract integrated on protected `develop`; opening or mutating a requisition remains a separate authoritative mutation boundary. ## References diff --git a/docs/adr/0014-job-analysis-snapshot-persistence.md b/docs/adr/0014-job-analysis-snapshot-persistence.md index cef05e28f..e7fcc5da1 100644 --- a/docs/adr/0014-job-analysis-snapshot-persistence.md +++ b/docs/adr/0014-job-analysis-snapshot-persistence.md @@ -1,20 +1,21 @@ # ADR 0014: Persist governed job-analysis snapshots -- Status: Accepted on active implementation branch +- Status: Accepted +- Maturity: Integrated on protected `develop` via merged PR #38 - Date: 2026-08-20 - Owners: Orgmetra Job Analysis / Workforce Validation ## Context -ADR 0007 defines the canonical in-process `JobAnalysisSnapshot` evidence contract. Protected `develop` now also contains the governed People mutation/idempotency slice through migration 0012, so the next persistence migration is 0013. The previous draft persistence lane used historical migration/ADR numbers and overlapped a second proposed job-analysis store; that competing store has been closed rather than shipping two Task/KSAO authorities. +ADR 0007 defines the canonical in-process `JobAnalysisSnapshot` evidence contract. Protected `develop` contains the governed People mutation/idempotency slice through migration 0012 and governed Job Analysis snapshot persistence through migration 0013. The previous draft persistence lane used historical migration/ADR numbers and overlapped a second proposed job-analysis store; that competing store has been closed rather than shipping two Task/KSAO authorities. A snapshot that exists only in memory cannot be reread, audited, or bound to the Job, Position, or criterion identities already present in Orgmetra. Job analysis is a systematic examination of work tasks and the competencies required to perform them, with explicit task-to-competency linkage and evidence provenance. When later selection procedures depend on work behaviors or job knowledge, the analysis must remain reviewable evidence rather than an opaque model assertion. -This slice therefore persists one immutable snapshot without making a hiring, promotion, termination, compensation, or other high-impact employment decision. LLM-origin material remains untrusted draft evidence under ADR 0007 and cannot become validated occupational evidence without accountable human review. +The integrated slice persists one immutable snapshot without making a hiring, promotion, termination, compensation, or other high-impact employment decision. LLM-origin material remains untrusted draft evidence under ADR 0007 and cannot become validated occupational evidence without accountable human review. ## Decision -Orgmetra will persist the canonical `JobAnalysisSnapshot` in migration `0013_job_analysis_snapshot.sql` as tenant-scoped 3NF relations: +Orgmetra persists the canonical `JobAnalysisSnapshot` in migration `0013_job_analysis_snapshot.sql` as tenant-scoped 3NF relations: - `job_analysis_snapshot` stores the version header, optional Position and criterion scope, accountable review metadata, content digest, and the 1:1 Functional Job Analysis compatibility profile; - `job_analysis_task_item` stores observable duties and their versioned evidence source; @@ -42,7 +43,7 @@ The stronger provenance and sealing ideas from the superseded parallel case mode ## Verification -Tests must prove that the persisted snapshot document equals the posted payload, `Idempotency-Key` is bound at the write port and stored on `job_analysis_write_command`, missing parents fail closed for the expected foreign-key or same-Job scope reason, snapshot UPDATE and DELETE operations are rejected by the append-only guard, cross-tenant snapshot reads return no rows under a `NOSUPERUSER NOBYPASSRLS` role, and `record_audit_outbox_event(...)` is persisted in the same governed write path. The service boundary requires exact 100% owned production statement and branch coverage where the pinned toolchain exposes those metrics, plus a PostgreSQL integration test that applies protected migrations 0001 through 0012 before migration 0013. +Tests prove that the persisted snapshot document equals the posted payload, `Idempotency-Key` is bound at the write port and stored on `job_analysis_write_command`, missing parents fail closed for the expected foreign-key or same-Job scope reason, snapshot UPDATE and DELETE operations are rejected by the append-only guard, cross-tenant snapshot reads return no rows under a `NOSUPERUSER NOBYPASSRLS` role, and `record_audit_outbox_event(...)` is persisted in the same governed write path. The service boundary requires exact 100% owned production statement and branch coverage where the pinned toolchain exposes those metrics, plus a PostgreSQL integration test that applies protected migrations 0001 through 0012 before migration 0013. ## References diff --git a/docs/adr/0025-governed-candidate-evidence-intake.md b/docs/adr/0025-governed-candidate-evidence-intake.md index ab66b3088..e8b675d78 100644 --- a/docs/adr/0025-governed-candidate-evidence-intake.md +++ b/docs/adr/0025-governed-candidate-evidence-intake.md @@ -1,7 +1,7 @@ # ADR 0025: Govern candidate evidence intake as reference-only evidence -- **Status:** Proposed — active PR only -- **Date:** 2026-08-19 +- Status: Proposed — active PR only +- Date: 2026-08-19 ## Context diff --git a/docs/adr/README.md b/docs/adr/README.md index 099a21139..e33eaf095 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -7,12 +7,14 @@ | [0003](0003-bitemporal-hris-data-contract.md) | Bitemporal HRIS data contract | Accepted | | [0004](0004-employment-position-version-and-assignment-binding.md) | Employment and position versions bind assignments | Accepted | | [0005](0005-exclusive-employment-and-staffable-seats.md) | Exclusive employment and staffable seats | Accepted | -| [0006](0006-governed-audit-outbox-envelope.md) | Governed audit/outbox envelope and durable persistence | Accepted on stacked implementation branch | -| [0007](0007-governed-job-analysis-evidence.md) | Governed job-analysis evidence snapshots | Accepted on stacked implementation branch | -| [0008](0008-purpose-bound-pii-authorization.md) | Purpose-bound PII authorization | Accepted on protected `develop` | -| [0009](0009-performance-criterion-observation-scope.md) | Performance criterion observations require worker-job scope | Accepted on active implementation branch | -| [0010](0010-naruon-calendar-intent-boundary.md) | Naruon calendar intent boundary | Accepted on active implementation branch | -| [0011](0011-bitemporal-workforce-composition.md) | Bitemporal workforce composition | Accepted on active implementation branch | -| [0012](0012-governed-migration-handoff.md) | Governed migration handoff | Accepted on active implementation branch | -| [0013](0013-governed-requisition-review-packet.md) | Governed requisition review packet | Accepted on active implementation branch | -| [0014](0014-job-analysis-snapshot-persistence.md) | Persist governed job-analysis snapshots | Accepted on active implementation branch | +| [0006](0006-governed-audit-outbox-envelope.md) | Governed audit/outbox envelope and durable persistence | Accepted | +| [0007](0007-governed-job-analysis-evidence.md) | Governed job-analysis evidence snapshots | Accepted | +| [0008](0008-purpose-bound-pii-authorization.md) | Purpose-bound PII authorization | Accepted | +| [0009](0009-performance-criterion-observation-scope.md) | Performance criterion observations require worker-job scope | Accepted | +| [0010](0010-naruon-calendar-intent-boundary.md) | Naruon calendar integration uses a fail-closed intent adapter | Accepted | +| [0011](0011-bitemporal-workforce-composition.md) | Workforce composition is a bitemporal aggregate evidence boundary | Accepted | +| [0012](0012-governed-migration-handoff.md) | Governed HRIS migration uses a value-free handoff envelope | Accepted | +| [0013](0013-governed-requisition-review-packet.md) | Governed requisition review packet | Accepted | +| [0014](0014-job-analysis-snapshot-persistence.md) | Persist governed job-analysis snapshots | Accepted | +| [0017](0017-governed-offer-approval.md) | Governed offer approval evidence | Proposed | +| [0025](0025-governed-candidate-evidence-intake.md) | Govern candidate evidence intake as reference-only evidence | Proposed | diff --git a/docs/traceability/contextual-orchestrator-routing.md b/docs/traceability/contextual-orchestrator-routing.md new file mode 100644 index 000000000..6dbc49408 --- /dev/null +++ b/docs/traceability/contextual-orchestrator-routing.md @@ -0,0 +1,14 @@ +# Contextual Orchestrator model-routing traceability + +## Status + +Active PR #51 only. This evidence becomes protected-`develop` governance truth only after the unchanged exact head satisfies fresh gates and integrates through the ordinary protected path. + +| Requirement | Orgmetra consumer contract | Owner boundary | Executable evidence | +|---|---|---|---| +| Keep provider credentials out of Orgmetra model guidance | Model-backed paths authenticate through repository-scoped `GITHUB_TOKEN` and the approved gateway token; Orgmetra does not require provider API keys | released `contextual-orchestrator` | `tests/model-routing-governance.test.mjs` rejects direct provider credential names in `AGENTS.md` | +| Route model-backed GitHub Actions through the free orchestrator contract | GitHub Actions use `orchestrator/free` only | released `contextual-orchestrator` | `tests/model-routing-governance.test.mjs` requires the route in AGENTS/CLAUDE/TRD/security/traceability guidance | +| Prevent consumer-side provider/model/group or paid-fallback selection | Orgmetra does not choose provider, model, provider group, or paid fallback | released `contextual-orchestrator` owns routing/capability selection | AGENTS/TRD regression and review | +| Fail closed when the released owner lacks a capability | No local direct-provider escape hatch is permitted | Contextual Orchestrator owner is repaired before Orgmetra consumes the missing capability | AGENTS/CLAUDE/TRD/security guidance plus exact-head Foundation validation | +| Keep termination semantics in one owner | Default model timeout, user cancellation, provider-end, and administrator-timeout semantics are not reimplemented locally | released `contextual-orchestrator` | documentation contract review and absence of local routing implementation | +| Keep LLM output non-authoritative for employment decisions | Model output remains draft/verification evidence until accountable human action | Orgmetra high-impact command boundary | existing human-confirmation and audit/evidence contracts | diff --git a/docs/traceability/migration-handoff.md b/docs/traceability/migration-handoff.md index 27ec3f113..3df13c754 100644 --- a/docs/traceability/migration-handoff.md +++ b/docs/traceability/migration-handoff.md @@ -2,7 +2,7 @@ ## Status -Active-PR only. This evidence does not describe protected-`develop` product truth until the owning PR integrates. +Protected `develop` capability. This page describes the governed migration handoff contract shipped on protected `develop`; it remains value-free and does not grant Orgmetra direct access to another service's application database. | Requirement | Decision / owner contract | Production implementation | Executable evidence | |---|---|---|---| diff --git a/docs/traceability/naruon-calendar-intent.md b/docs/traceability/naruon-calendar-intent.md index 58fd889c3..1b8183f54 100644 --- a/docs/traceability/naruon-calendar-intent.md +++ b/docs/traceability/naruon-calendar-intent.md @@ -2,7 +2,7 @@ ## Status -Active-PR only. This evidence does not describe protected-`develop` product truth until the owning PR integrates. +Protected `develop` capability. This page describes the Orgmetra-owned intent adapter shipped on protected `develop`; provider-side calendar execution remains outside Orgmetra's ownership boundary. | Requirement | Decision / contract | Production implementation | Executable evidence | |---|---|---|---| diff --git a/docs/traceability/requisition-review.md b/docs/traceability/requisition-review.md index add4f20ba..8468cf99b 100644 --- a/docs/traceability/requisition-review.md +++ b/docs/traceability/requisition-review.md @@ -2,7 +2,7 @@ ## Maturity -**Active PR only.** Protected `develop` does not contain this capability until the candidate branch is integrated with fresh protected-head evidence. +**Protected `develop` capability.** The governed requisition review packet is present on protected `develop`; it remains evidence for accountable human review, not an autonomous employment decision. ## Requirement-to-evidence map @@ -20,7 +20,7 @@ | Bound opening cardinality | `requested_opening_count` | bool/non-integer/zero/>100 rejection and exact-position one-seat invariant | | Produce stable immutable correlation evidence | canonical JSON plus SHA-256 | deterministic serialization and independent SHA-256 recomputation regression | | Avoid host-time ambiguity | timezone-aware `generated_at`, canonical UTC rendering | naive/unknown-offset rejection, non-UTC-to-UTC canonicalization, and fractional-second preservation regressions | -| Meet owned production coverage gate | `orgmetra_requisition_review` | Foundation CI requires exact 100% statement and branch coverage | +| Meet owned production coverage gate | `orgmetra_requisition_review` | Foundation CI requires exact candidate SHA and exact 100% statement and branch coverage | ## Authority boundary diff --git a/docs/traceability/workforce-composition.md b/docs/traceability/workforce-composition.md index f02e4b8ef..78ded0d94 100644 --- a/docs/traceability/workforce-composition.md +++ b/docs/traceability/workforce-composition.md @@ -2,7 +2,7 @@ ## Status -Active-PR only. This evidence does not describe protected-`develop` product truth until PR #33 integrates. +Protected `develop` capability. This evidence describes the bitemporal workforce-composition snapshot shipped on protected `develop`; it is aggregate descriptive evidence, not a recommendation or employment decision. | Requirement | Decision / contract | Production implementation | Executable evidence | |---|---|---|---| diff --git a/manifest.json b/manifest.json index f7b6cf55e..15ce095e2 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "package": "orgmetra-foundation-pack", "version": "0.1.0", - "generated_for_branch": "feat/audit-outbox-envelope", + "canonical_target_branch": "develop", "files": [ { "path": ".github/workflows/foundation-ci.yml", @@ -17,27 +17,27 @@ }, { "path": "AGENTS.md", - "sha256": "28f7b7bc010a7739cfdc3e793fb5d39a0e74b842ea9c190e9a251e2d0cbc3a16", - "bytes": 2246, - "lines": 34 + "sha256": "a30f2ebb3d23b5ff6de2fac5ee23df1f386d8625c9a45e00b979a899d293b95d", + "bytes": 2925, + "lines": 35 }, { "path": "ARCHITECTURE.md", - "sha256": "52d68786f7359c1a50d804996021e4c70e90accd2fff6f1a27c91de1dd8df850", - "bytes": 7864, - "lines": 107 + "sha256": "930573f73d815a0f9a67fb98de75a0a9ba8112c3f26c31f67764e30a36e1d31d", + "bytes": 9172, + "lines": 109 }, { "path": "CHANGELOG.md", - "sha256": "f2d2e0b488c0440533effa821808f2f17e37d92f8fb586174c2fdb594f760ca5", - "bytes": 17539, - "lines": 77 + "sha256": "6f3278b774e76b65f077181b8e9323f8b88d4c3b5a5722d21b561d8650d84425", + "bytes": 17895, + "lines": 78 }, { "path": "CLAUDE.md", - "sha256": "add33884f466d324e20875388d103de41c6e062938a6e98727dc83a87ffe976f", - "bytes": 1229, - "lines": 20 + "sha256": "c26bbe63ea746ca1d73c18b5afe3f548d1c1acc43b4524ac49c028ad21e4a596", + "bytes": 1955, + "lines": 24 }, { "path": "LICENSE", @@ -53,9 +53,9 @@ }, { "path": "README.md", - "sha256": "1a9fc400d26d8137ae5911488794a6d3fa915957c95f27b36a48cef0fdf823c6", - "bytes": 3785, - "lines": 81 + "sha256": "c6d0fa3fd8490cbb73e270fc8a753518a667bf01c074bad7293a82dfc769b00c", + "bytes": 4536, + "lines": 85 }, { "path": "database/migrations/0001_foundation_schema.sql", @@ -155,9 +155,9 @@ }, { "path": "docs/OPERABILITY.md", - "sha256": "82b2d3e70cec371ef35e9e0f982ac40fef84351976bc04b863b81d27023d5a62", - "bytes": 11189, - "lines": 71 + "sha256": "821843e3ae6e5ff173e2ed45ab202341c50577568e67e3601b0cf9a6bc63c80c", + "bytes": 12816, + "lines": 77 }, { "path": "docs/PRD.md", @@ -167,9 +167,9 @@ }, { "path": "docs/SECURITY.md", - "sha256": "01918512d8882060e9cff0c4aa8206e0eccbdfb61cfd7f829331123c7a9fe6ac", - "bytes": 11185, - "lines": 64 + "sha256": "ccf708bc7a9acfe42a161485c04a117e69b4fa6a47ed4993d21c010b78478f4c", + "bytes": 12069, + "lines": 70 }, { "path": "docs/STORYBOARD.md", @@ -185,9 +185,9 @@ }, { "path": "docs/TEST_STRATEGY.md", - "sha256": "d0a0bc3b54ed0fc7973747987f1afb117d6144c390b51ed9370eb571972a33f8", - "bytes": 16534, - "lines": 135 + "sha256": "915478ea5819ded9c8c902d6df60ee7610f7d05dd8b011ae463c5be7fbc6d6eb", + "bytes": 18720, + "lines": 141 }, { "path": "docs/THREAT_MODEL.md", @@ -197,15 +197,15 @@ }, { "path": "docs/TRACEABILITY.md", - "sha256": "dbf6fd91375ea28e05456d2a0c9ba629506cbac6f52f5dfda61ae68db2395f7e", - "bytes": 11462, - "lines": 40 + "sha256": "0ac70fb7cb829b7057076bc2b79cf7fdef54a0f8ce3ae5e0839a3167cad8df3c", + "bytes": 14532, + "lines": 46 }, { "path": "docs/TRD.md", - "sha256": "23697d88a4882698e1a2782b7da3f2ccd0d3cd2d6d1bffe89b6597dc16851077", - "bytes": 9064, - "lines": 101 + "sha256": "289b3d5ffc1b133a4036bb53240e1ee272c792d997d62c476681a46446547259", + "bytes": 10794, + "lines": 105 }, { "path": "docs/UML.md", @@ -257,14 +257,14 @@ }, { "path": "docs/adr/0006-governed-audit-outbox-envelope.md", - "sha256": "827298ddd997b47f78a89e89911ad8ea72e517b7714303637f0329b8cb52cabd", - "bytes": 14100, + "sha256": "39a07687d24c8fa446c217b2b65cdf8b6e94a1326b4dd08e81e3911064a82a7c", + "bytes": 14018, "lines": 66 }, { "path": "docs/adr/0007-governed-job-analysis-evidence.md", - "sha256": "953c6d2b9864a78b461b576092ec3f198f0b76709eaaaf7d0ed0182f95182c52", - "bytes": 5653, + "sha256": "81821d7c959cf4752dd7ec4a38fcc88008d81fa4f41664748797255fef3f3e2e", + "bytes": 5620, "lines": 57 }, { @@ -281,39 +281,51 @@ }, { "path": "docs/adr/0010-naruon-calendar-intent-boundary.md", - "sha256": "3e1050a964cc4ed76a1a0cf1e699ae5080acf8c9336f0decdd6d5229359db3c9", - "bytes": 3917, - "lines": 35 + "sha256": "726730597a6e5df1a3efe67439d25ea1d1f2ea91c7c3f9e6f21d0603dc7d1d3b", + "bytes": 4028, + "lines": 37 }, { "path": "docs/adr/0011-bitemporal-workforce-composition.md", - "sha256": "dbe96dfd47066288cec835789de54cc4293f920d2ad4b0e0dba930191d7d249b", - "bytes": 5551, - "lines": 53 + "sha256": "7a575cd39f99b12d5e50dbfcbfd681d75a3dd49274369985944abe13ebf95391", + "bytes": 5636, + "lines": 55 }, { "path": "docs/adr/0012-governed-migration-handoff.md", - "sha256": "c7bfbda34996f717ed31f8307acc16a5d69ae464edb184ab5c8ec4b2d5763cbc", - "bytes": 5958, - "lines": 59 + "sha256": "d37b8168182f7ef7c7a6e8efd1a70544eae4184d9788f7bdff1674956b21e930", + "bytes": 6043, + "lines": 61 }, { "path": "docs/adr/0013-governed-requisition-review-packet.md", - "sha256": "70bf2cbdf903a8793d6d8bc116a08331931090118341f42010236e09c6cc1802", - "bytes": 4693, + "sha256": "4ef21c8cad467607e78a8f3094c1d613ee47f40b38a0f904cad0567a923f1fa2", + "bytes": 4730, "lines": 46 }, { "path": "docs/adr/0014-job-analysis-snapshot-persistence.md", - "sha256": "a7ab6fee50aaa63f7f407516a4cb39885faeb0fc6e5035ee8fc352ed73430105", - "bytes": 5365, - "lines": 49 + "sha256": "45f66efcedcdba001ca283167bb63419f25861b24b9a05c490523a93cbe14445", + "bytes": 5406, + "lines": 50 + }, + { + "path": "docs/adr/0017-governed-offer-approval.md", + "sha256": "1c0a3fb4d01fc3a42c95924ef4d6354fdea16a868282af6b87f15afd83c370f5", + "bytes": 5298, + "lines": 37 + }, + { + "path": "docs/adr/0025-governed-candidate-evidence-intake.md", + "sha256": "d39576a83608a40a03e0318145caf0d46aef2c6be24aabf3034868b31f6a8f6d", + "bytes": 5507, + "lines": 47 }, { "path": "docs/adr/README.md", - "sha256": "f3b3b5ed3b3b31a40a0a3696abf0065e3c25879b6be50077f38ffae742b9d002", - "bytes": 1838, - "lines": 18 + "sha256": "b00710176896385caa7293418c74f0d71bfaa6dd49661b638e8309925b3cff53", + "bytes": 1870, + "lines": 20 }, { "path": "docs/doctoring/REFERENCES.md", @@ -333,10 +345,16 @@ "bytes": 6237, "lines": 187 }, + { + "path": "docs/traceability/contextual-orchestrator-routing.md", + "sha256": "810cddbb3f50a2915c168dc85f8d4c973de2de5050caa8a5c866f06ba4fa7219", + "bytes": 2043, + "lines": 14 + }, { "path": "package.json", - "sha256": "59ae9e3e67c3fba9320cb18439692395cdfd16ae5c24e3c4cf30d77d63ebabb5", - "bytes": 388, + "sha256": "a8fa3ac9b1e15de4ad95648c2dd51927b4892b768a1c9cba0bcfdccdfbf257d6", + "bytes": 428, "lines": 9 }, { @@ -359,9 +377,9 @@ }, { "path": "scripts/foundation-contract-core.mjs", - "sha256": "9b03efbbdffa60a05f5924e8a61b1cbc3cd75c502df428a5920085e8d0bf3603", - "bytes": 28121, - "lines": 688 + "sha256": "fda9dcac94a5201f22a76981ea736b7d336d712a16b828c9cb0362b883c28016", + "bytes": 28607, + "lines": 698 }, { "path": "scripts/foundation-contract.mjs", @@ -371,9 +389,9 @@ }, { "path": "tests/dispatcher-inventory.test.mjs", - "sha256": "09f5e64410e6b7a26bf8d6ce61c50b737da2ea85d955f91eba63aa21f1537261", - "bytes": 1597, - "lines": 34 + "sha256": "26215a75fe4f721fa57bea9cab9dfd43b7fef0a9091d8bbe054c71e3458e9b3b", + "bytes": 7782, + "lines": 197 }, { "path": "tests/foundation-contract.test.mjs", @@ -381,11 +399,17 @@ "bytes": 14943, "lines": 387 }, + { + "path": "tests/model-routing-governance.test.mjs", + "sha256": "b7d04201669bbf359945b605eae9ef245070ec1217d452c2b5d49f55f3c9d31b", + "bytes": 1332, + "lines": 35 + }, { "path": "tests/openapi-contract.test.mjs", - "sha256": "80c1610ef1c189fa325e55389501e0e51531ddf61ee335bb94d9cb3aa55a9fdc", - "bytes": 6438, - "lines": 195 + "sha256": "09f0504e1bb517e6abde1bf6114337ab5d3e6a773215e858b1c2027cf5c70f83", + "bytes": 7981, + "lines": 236 }, { "path": "tests/test_audit_outbox_hardening_postgres.sh", @@ -467,9 +491,9 @@ }, { "path": "tests/validate_repository.py", - "sha256": "091836b2f68600a30b08f7da2cea8b3bef10201a123da720a7369bf10985eec2", - "bytes": 27237, - "lines": 637 + "sha256": "c87ff1c8939c97a7a62ec2ccc6ad3a3dd773214aafb49fd16a502f61995c5539", + "bytes": 27514, + "lines": 640 } ] } diff --git a/package.json b/package.json index ceb2fb8fc..7d7bc013a 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,6 @@ "private": true, "description": "Orgmetra evidence-centered HRIS foundation baseline.", "scripts": { - "validate": "python3 tests/validate_repository.py && node scripts/foundation-contract.mjs && node --test tests/foundation-contract.test.mjs tests/openapi-contract.test.mjs tests/dispatcher-inventory.test.mjs" + "validate": "python3 tests/validate_repository.py && node scripts/foundation-contract.mjs && node --test tests/foundation-contract.test.mjs tests/openapi-contract.test.mjs tests/dispatcher-inventory.test.mjs tests/model-routing-governance.test.mjs" } } diff --git a/packages/hris-kernel/tests/test_manifest_metadata_semantics.py b/packages/hris-kernel/tests/test_manifest_metadata_semantics.py new file mode 100644 index 000000000..824ebc6cf --- /dev/null +++ b/packages/hris-kernel/tests/test_manifest_metadata_semantics.py @@ -0,0 +1,17 @@ +"""Repository-manifest metadata must describe target truth without fake provenance.""" + +from __future__ import annotations + +import json +from pathlib import Path + + +REPOSITORY_ROOT = Path(__file__).resolve().parents[3] + + +def test_manifest_names_the_canonical_target_branch_without_fake_generation_provenance() -> None: + """Static integrity metadata must not claim the checked-out PR head was generated on another branch.""" + manifest = json.loads((REPOSITORY_ROOT / "manifest.json").read_text(encoding="utf-8")) + + assert manifest.get("canonical_target_branch") == "develop" + assert "generated_for_branch" not in manifest diff --git a/scripts/foundation-contract-core.mjs b/scripts/foundation-contract-core.mjs index 4aacefb3c..a73810015 100644 --- a/scripts/foundation-contract-core.mjs +++ b/scripts/foundation-contract-core.mjs @@ -51,7 +51,10 @@ export const REQUIRED_FILES = Object.freeze([ 'docs/adr/0012-governed-migration-handoff.md', 'docs/adr/0013-governed-requisition-review-packet.md', 'docs/adr/0014-job-analysis-snapshot-persistence.md', + 'docs/adr/0017-governed-offer-approval.md', + 'docs/adr/0025-governed-candidate-evidence-intake.md', 'docs/doctoring/REFERENCES.md', + 'docs/traceability/contextual-orchestrator-routing.md', 'docs/superpowers/specs/2026-08-15-orgmetra-foundation-design.md', 'docs/superpowers/plans/2026-08-15-orgmetra-foundation-implementation-plan.md', 'database/migrations/0001_foundation_schema.sql', @@ -74,6 +77,7 @@ export const REQUIRED_FILES = Object.freeze([ 'scripts/foundation-contract.mjs', 'tests/dispatcher-inventory.test.mjs', 'tests/foundation-contract.test.mjs', + 'tests/model-routing-governance.test.mjs', 'tests/openapi-contract.test.mjs', 'tests/test_bitemporal_postgres.sh', 'tests/test_tenant_isolation_postgres.sh', @@ -142,7 +146,8 @@ export const MIGRATION_BACKED_DATABASE_OBJECT_NAMES = Object.freeze([ ]); const UNFINISHED_MARKER_LINE_PATTERN = /^\s*(?:#{1,6}\s+|[-*+]\s+)?(?:\[(?:TODO|TBD|FIXME)\]|\{\{(?:TODO|TBD|FIXME)\}\}|<(?:TODO|TBD|FIXME)>|(?:TODO|TBD|FIXME)(?:\s*:\s*.*)?\s*)$/i; -const ADR_STATUS_PATTERN = /^\|\s*\[\d{4}\]\(([^)]+)\)\s*\|.*\|\s*(Proposed|Accepted|Superseded|Rejected)\s*\|$/; +const ADR_INDEX_ROW_PATTERN = /^\|\s*\[\d{4}\]\(([^)]+)\)\s*\|.*\|\s*([^|]+?)\s*\|$/; +const ADR_STATUS_VALUES = Object.freeze(new Set(['Proposed', 'Accepted', 'Superseded', 'Rejected'])); const LOCAL_LINK_PATTERN = /\[[^\]]+\]\((?!https?:\/\/|mailto:|#)([^)]+)\)/g; const CREATE_TABLE_PATTERN = /\bCREATE\s+TABLE(?:\s+IF\s+NOT\s+EXISTS)?\s+(?:[a-z_][a-z0-9_]*\.)?([a-z_][a-z0-9_]*)/gi; const DOLLAR_QUOTE_START_PATTERN = /^\$(?:[A-Za-z_][A-Za-z0-9_]*)?\$/; @@ -387,15 +392,20 @@ export function validateAdrIndex(rootPath) { const errors = []; const indexText = readFileSync(indexPath, 'utf8'); for (const line of indexText.split(/\r?\n/)) { - const match = line.match(ADR_STATUS_PATTERN); - if (!match) continue; - const adrPath = resolve(dirname(indexPath), match[1]); + const rowMatch = line.match(ADR_INDEX_ROW_PATTERN); + if (!rowMatch) continue; + const status = rowMatch[2].trim(); + if (!ADR_STATUS_VALUES.has(status)) { + errors.push(`${relative(rootPath, indexPath)}: non-canonical ADR status: ${status}`); + continue; + } + const adrPath = resolve(dirname(indexPath), rowMatch[1]); if (!existsSync(adrPath)) { - errors.push(`${relative(rootPath, indexPath)}: indexed ADR is missing: ${match[1]}`); + errors.push(`${relative(rootPath, indexPath)}: indexed ADR is missing: ${rowMatch[1]}`); continue; } - if (!readFileSync(adrPath, 'utf8').includes(`Status: ${match[2]}`)) { - errors.push(`${relative(rootPath, adrPath)}: status does not match ADR index (${match[2]})`); + if (!readFileSync(adrPath, 'utf8').includes(`Status: ${status}`)) { + errors.push(`${relative(rootPath, adrPath)}: status does not match ADR index (${status})`); } } return errors; diff --git a/services/people-api/tests/test_review_regressions.py b/services/people-api/tests/test_review_regressions.py index 82da96660..188f06bf5 100644 --- a/services/people-api/tests/test_review_regressions.py +++ b/services/people-api/tests/test_review_regressions.py @@ -162,7 +162,7 @@ def test_dispatch_rejects_commands_for_a_different_route(self) -> None: ) def test_security_contract_matches_published_openapi_header_scope(self) -> None: - """Keep published command scope distinct from currently executable handlers.""" + """Keep published command scope distinct from protected executable handlers.""" repository_root = Path(__file__).resolve().parents[3] security_contract = (repository_root / "docs/SECURITY.md").read_text(encoding="utf-8") api_contract = (repository_root / "docs/API_CONTRACT.md").read_text(encoding="utf-8") @@ -174,8 +174,8 @@ def test_security_contract_matches_published_openapi_header_scope(self) -> None: "`X-Actor-Reference`, and `X-Purpose-Code`" ) executable_scope = ( - "The executable People mutation handlers added on this branch currently implement " - "employment, position, and assignment creation with those headers." + "Protected `develop` implements employment, position, and assignment creation " + "through the executable People mutation handlers with those headers." ) self.assertIn(published_scope, security_contract) self.assertIn(executable_scope, security_contract) diff --git a/tests/dispatcher-inventory.test.mjs b/tests/dispatcher-inventory.test.mjs index 288a98eb4..abc679c72 100644 --- a/tests/dispatcher-inventory.test.mjs +++ b/tests/dispatcher-inventory.test.mjs @@ -22,6 +22,45 @@ function pythonRequiredFiles() { return new Set([...match[1].matchAll(/^\s+"([^"]+)",$/gm)].map((item) => item[1])); } +function validateInvokedNodeTests() { + const packageDocument = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')); + const validateScript = packageDocument.scripts?.validate; + assert.equal(typeof validateScript, 'string', 'package validate script is missing'); + return Object.freeze( + [...validateScript.matchAll(/(?:^|\s)(tests\/[a-z0-9_-]+\.test\.mjs)(?=\s|$)/g)] + .map((match) => match[1]) + .sort() + ); +} + +function manifestPaths() { + const manifest = JSON.parse(readFileSync(new URL('../manifest.json', import.meta.url), 'utf8')); + assert.ok(Array.isArray(manifest.files), 'manifest files array is missing'); + return new Set(manifest.files.map((entry) => entry.path)); +} + +function discoveredAdrFiles() { + return Object.freeze( + readdirSync(new URL('../docs/adr/', import.meta.url)) + .filter((name) => /^\d{4}-[a-z0-9-]+\.md$/.test(name)) + .sort() + ); +} + +function indexedAdrFiles() { + const index = readFileSync(new URL('../docs/adr/README.md', import.meta.url), 'utf8'); + return new Set( + [...index.matchAll(/\[\d{4}\]\((\d{4}-[a-z0-9-]+\.md)\)/g)] + .map((match) => match[1]) + ); +} + +function traceabilityRow(markdown, requirement) { + return markdown + .split('\n') + .find((line) => line.startsWith(`| ${requirement} |`)); +} + test('every migration and executable PostgreSQL contract is provenance-required', () => { const nodeRequired = new Set(REQUIRED_FILES); const pythonRequired = pythonRequiredFiles(); @@ -32,3 +71,127 @@ test('every migration and executable PostgreSQL contract is provenance-required' assert.equal(pythonRequired.has(filePath), true, `Python inventory omitted ${filePath}`); } }); + +test('every Node test invoked by validate is provenance-required and integrity-manifested', () => { + const nodeRequired = new Set(REQUIRED_FILES); + const pythonRequired = pythonRequiredFiles(); + const manifested = manifestPaths(); + const invokedTests = validateInvokedNodeTests(); + assert.ok(invokedTests.length > 0, 'validate script invokes no Node tests'); + for (const filePath of invokedTests) { + assert.equal(nodeRequired.has(filePath), true, `Node inventory omitted validate-invoked test ${filePath}`); + assert.equal(pythonRequired.has(filePath), true, `Python inventory omitted validate-invoked test ${filePath}`); + assert.equal(manifested.has(filePath), true, `manifest omitted validate-invoked test ${filePath}`); + } +}); + +test('every ADR document is represented in the canonical ADR index', () => { + const indexed = indexedAdrFiles(); + const discovered = discoveredAdrFiles(); + assert.ok(discovered.length > 0, 'ADR discovery returned no documents'); + for (const fileName of discovered) { + assert.equal(indexed.has(fileName), true, `ADR index omitted ${fileName}`); + } +}); + +test('protected buyer truth is positively pinned for recently integrated capabilities', () => { + const readme = readFileSync(new URL('../README.md', import.meta.url), 'utf8'); + const traceability = readFileSync(new URL('../docs/TRACEABILITY.md', import.meta.url), 'utf8'); + + assert.match( + readme, + /Protected `develop` is the sole shipped repository truth\./i, + 'README must positively identify protected develop as shipped truth' + ); + assert.match( + readme, + /implemented_on_protected_main[\s\S]{0,180}protected branch is `develop`/i, + 'README must map the stable protected-main maturity enum to protected develop' + ); + + for (const buyerVisibleCapability of [ + 'bitemporal workforce-composition snapshots', + 'governed migration handoff', + 'requisition review', + 'human selection-review evidence', + 'governed Job Analysis snapshot persistence' + ]) { + assert.match( + readme, + new RegExp(buyerVisibleCapability, 'i'), + `README is missing protected capability: ${buyerVisibleCapability}` + ); + } + + assert.doesNotMatch( + readme, + /(?:validity-study|workforce-composition|migration handoff|requisition review|selection-review|Job Analysis)[^\n]*(?:active[-_ ]PR|implemented_on_active_pr)/i, + 'README must not demote protected capabilities to active-PR truth' + ); + assert.doesNotMatch( + readme, + /GET-only People API/i, + 'README must not describe the protected People API as GET-only after governed mutations integrated' + ); + assert.match( + readme, + /purpose-bound People mutation/i, + 'README must positively describe the protected purpose-bound People mutation capability' + ); + + for (const requirement of [ + 'Bitemporal workforce-composition evidence', + 'Governed requisition review evidence', + 'Governed human selection review evidence', + 'Governed People writes and confirmed-hire materialization', + 'Evidence-grounded Job analysis with Task/FJA/KSAO linkage' + ]) { + const row = traceabilityRow(traceability, requirement); + assert.ok(row, `missing traceability row: ${requirement}`); + assert.match( + row, + /\| implemented_on_protected_main \|$/, + `protected capability is mislabeled: ${requirement}` + ); + } + + const migrationRow = traceabilityRow(traceability, 'MHTML ETL Gateway / mightyETL'); + assert.ok(migrationRow, 'missing migration integration traceability row'); + assert.match( + migrationRow, + /\| implemented_on_protected_main \|$/, + 'protected migration integration is mislabeled' + ); +}); + +test('integrated job-analysis persistence is protected buyer truth', () => { + const readme = readFileSync(new URL('../README.md', import.meta.url), 'utf8'); + const changelog = readFileSync(new URL('../CHANGELOG.md', import.meta.url), 'utf8'); + const traceability = readFileSync(new URL('../docs/TRACEABILITY.md', import.meta.url), 'utf8'); + + const jobAnalysisRow = traceabilityRow( + traceability, + 'Evidence-grounded Job analysis with Task/FJA/KSAO linkage' + ); + assert.ok(jobAnalysisRow, 'missing Job Analysis traceability row'); + assert.match( + jobAnalysisRow, + /\| implemented_on_protected_main \|$/, + 'merged Job Analysis persistence must be promoted to protected maturity' + ); + assert.match( + readme, + /governed Job Analysis snapshot persistence/i, + 'README must list integrated Job Analysis persistence as protected truth' + ); + assert.doesNotMatch( + readme, + /Job Analysis persistence remains active-PR truth/i, + 'README must not describe merged Job Analysis persistence as open-PR truth' + ); + assert.match( + changelog, + /Protected governed job-analysis evidence contract/i, + 'CHANGELOG must label the merged Job Analysis contract as protected truth' + ); +}); diff --git a/tests/model-routing-governance.test.mjs b/tests/model-routing-governance.test.mjs new file mode 100644 index 000000000..d375ee502 --- /dev/null +++ b/tests/model-routing-governance.test.mjs @@ -0,0 +1,35 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import test from 'node:test'; + +const REQUIRED_MODEL_BOUNDARY_DOCS = Object.freeze([ + 'AGENTS.md', + 'CLAUDE.md', + 'docs/TRD.md', + 'docs/SECURITY.md', + 'docs/traceability/contextual-orchestrator-routing.md' +]); + +function read(path) { + return readFileSync(path, 'utf8'); +} + +test('model-backed guidance routes through the released contextual-orchestrator contract', () => { + for (const path of REQUIRED_MODEL_BOUNDARY_DOCS) { + const content = read(path); + assert.match(content, /contextual[- ]orchestrator/i, `${path} must name the contextual-orchestrator owner boundary`); + assert.match(content, /orchestrator\/free/, `${path} must require the free orchestrator route`); + assert.match(content, /gateway token/i, `${path} must bind model-backed automation to gateway authentication`); + } +}); + +test('Orgmetra does not prescribe direct provider credentials or routing', () => { + const agents = read('AGENTS.md'); + assert.doesNotMatch( + agents, + /NVIDIA_NIM_API_KEY|NVIDIA_NIM_SUB_API_KEY|OPENROUTER_API_KEY|OPENAI_API_KEY|BYTEZ_API_KEY/, + 'AGENTS.md must not make a provider credential part of the Orgmetra consumer contract' + ); + assert.match(agents, /provider\/model\/group/i); + assert.match(agents, /fail closed/i); +}); diff --git a/tests/openapi-contract.test.mjs b/tests/openapi-contract.test.mjs index 8e98078da..0a310531d 100644 --- a/tests/openapi-contract.test.mjs +++ b/tests/openapi-contract.test.mjs @@ -193,3 +193,44 @@ test('structural OpenAPI gate rejects an empty-scope OIDC requirement', () => { const errors = validateOpenApiContract(`${canonical}\nkeyverse_oidc: []\n`); assert.ok(errors.some((error) => /empty-scope OIDC/.test(error)), errors.join('\n')); }); + +test('buyer-facing docs preserve protected People mutation truth', () => { + const readme = readFileSync(new URL('../README.md', import.meta.url), 'utf8'); + const changelog = readFileSync(new URL('../CHANGELOG.md', import.meta.url), 'utf8'); + const security = readFileSync(new URL('../docs/SECURITY.md', import.meta.url), 'utf8'); + const mutationLine = changelog + .split('\n') + .find((line) => line.includes('`POST /v1/employment-records`')); + + assert.ok(mutationLine, 'People mutation runtime changelog entry is missing'); + assert.doesNotMatch( + readme, + /GET-only People API/i, + 'README must not demote the integrated People API to GET-only' + ); + assert.match( + readme, + /purpose-bound People mutation/i, + 'README must describe the protected People mutation boundary' + ); + assert.match( + mutationLine, + /Protected governed People mutation/i, + 'integrated People mutations must be recorded as protected runtime' + ); + assert.doesNotMatch( + mutationLine, + /contract-only|non-shipped runtime/i, + 'protected People mutations must not be mislabeled as non-shipped' + ); + assert.doesNotMatch( + security, + /executable People mutation handlers added on this branch/i, + 'SECURITY must not describe already-integrated People mutation handlers as branch-only work' + ); + assert.match( + security, + /Protected `develop` implements employment, position, and assignment creation/i, + 'SECURITY must identify the integrated People mutation runtime as protected develop truth' + ); +}); diff --git a/tests/validate_repository.py b/tests/validate_repository.py index d9d4c15a3..2794a79d8 100644 --- a/tests/validate_repository.py +++ b/tests/validate_repository.py @@ -54,7 +54,10 @@ "docs/adr/0012-governed-migration-handoff.md", "docs/adr/0013-governed-requisition-review-packet.md", "docs/adr/0014-job-analysis-snapshot-persistence.md", + "docs/adr/0017-governed-offer-approval.md", + "docs/adr/0025-governed-candidate-evidence-intake.md", "docs/doctoring/REFERENCES.md", + "docs/traceability/contextual-orchestrator-routing.md", "docs/superpowers/specs/2026-08-15-orgmetra-foundation-design.md", "docs/superpowers/plans/2026-08-15-orgmetra-foundation-implementation-plan.md", "database/migrations/0001_foundation_schema.sql", @@ -77,6 +80,7 @@ "scripts/foundation-contract.mjs", "tests/dispatcher-inventory.test.mjs", "tests/foundation-contract.test.mjs", + "tests/model-routing-governance.test.mjs", "tests/openapi-contract.test.mjs", "tests/test_bitemporal_postgres.sh", "tests/test_tenant_isolation_postgres.sh", @@ -120,7 +124,7 @@ def _line_count(data: bytes) -> int: def _expected_manifest_document() -> dict[str, Any]: - """Build deterministic provenance for the exact active branch artifact set.""" + """Build deterministic integrity metadata for the canonical target branch artifact set.""" files = [] for relative_path in sorted(set(REQUIRED) - {"manifest.json"}): path = ROOT / relative_path @@ -138,7 +142,7 @@ def _expected_manifest_document() -> dict[str, Any]: return { "package": "orgmetra-foundation-pack", "version": "0.1.0", - "generated_for_branch": "feat/audit-outbox-envelope", + "canonical_target_branch": "develop", "files": files, } @@ -152,11 +156,10 @@ def _manifest_entries() -> dict[str, dict[str, Any]]: if not isinstance(manifest, dict) or not isinstance(manifest.get("files"), list): _fail("manifest.json must contain a files array") - if manifest.get("generated_for_branch") != "feat/audit-outbox-envelope": - _fail( - "manifest generated_for_branch must identify the active generation branch " - "feat/audit-outbox-envelope" - ) + if manifest.get("canonical_target_branch") != "develop": + _fail("manifest canonical_target_branch must identify protected target branch develop") + if "generated_for_branch" in manifest: + _fail("manifest must not claim generation-branch provenance from static target metadata") entries: dict[str, dict[str, Any]] = {} for raw_entry in manifest["files"]: