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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@
**Status:** Accepted
**Date:** 2026-08-26
**Extends:** [ADR 0004](0004-knowledge-graph-ontology.md), [ADR 0145](0145-psychometric-channel-weight-estimation.md), [ADR 0207](0207-repository-case-ontology-namespace-canonical.md), [ADR 0232](0232-worker-function-taxonomy-in-the-published-ontology.md)
<<<<<<< HEAD
=======
**Superseded in part by:** [ADR 0252](0252-complete-2018-soc-hierarchy.md), which expands the major-group-only scheme into the complete 2018 SOC hierarchy.
>>>>>>> origin/feat/onet-rating-occupation-filter

## Context

Expand Down
87 changes: 15 additions & 72 deletions docs/product-requirements.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,20 @@ UI remain unavailable until their separate ADR acceptance. ADR 0253 adds
catalog-bound semantic-unit extraction through contextual-orchestrator's
multi-agent conduct path; exact offered IRIs and verbatim spans are required,
and a digest-bound run record distinguishes a supported empty result from an
unavailable provider. ADR 0254 adds the authorized Post-detail evidence review
surface and honest complete, processing, and unavailable states. ADR 0255
unavailable provider. The authorized Post-detail evidence review surface
(`frontend/src/components/OccupationalConstructEvidence.tsx`, covered by its
component test) reports honest complete, processing, and unavailable states.
ADR 0255
projects assertion-backed constructs into the existing ABAC-filtered ontology
neighborhood without duplicating graph storage or promoting truth. ADR 0257
neighborhood without duplicating graph storage or promoting truth. ADR 0265
adds authorized catalog-label search: reviewers type an official O*NET label
and open the earliest visible supporting Post. Constructs without visible
evidence stay undisclosed. Occupation ratings remain unavailable.
O*NET linkage relations from abilities, skills, and work styles to Work
Activities and Work Context remain explicitly unavailable: ADR 0250 point 4
defers them to their own provenance and decision records, and no accepted ADR
on this branch covers them. Relevance is therefore neither asserted as a
relation nor carried as a weight.

### PRD-FR-2C — FJA I/O-Psychology cognitive, affective & behavioral semantic layer

Expand Down Expand Up @@ -165,73 +172,10 @@ canonical namespace, and lookup round-trip isolation are enforced by
`tests/test_io_taxonomy.py`; `tests/test_ontology.py` continues to pass
unchanged.

### PRD-FR-2A — Worker-function taxonomy

- Publish the DOT/FJA Data/People/Things worker functions (24 concepts,
official definitions verbatim) in the canonical ontology namespace
(ADR 0232), each with its definitional ordinal rank. Do not infer a
DOT-to-O*NET or Fleishman crosswalk that the authorities do not publish.
- Expose the taxonomy through a deterministic application read model with
fail-closed lookups; an absent function is an honest unknown.
- Carry no numeric weight from the taxonomy: ranks are scale positions,
never calibrated weights.

Acceptance: completeness, full verbatim definitions, deterministic ordering,
and lookup round-trip isolation are enforced by
`tests/test_worker_function_taxonomy.py`; `tests/test_ontology.py`
continues to pass unchanged.

### PRD-FR-2B — Occupational classification and worker-characteristic taxonomy

- Publish all four levels of the 2018 Standard Occupational Classification:
23 major groups, 98 minor groups, 459 broad occupations, and 867 detailed
occupations with exact source parents, titles, and codes (ADR 0252), plus
the four O*NET 31.0 job-zone categories with
published names and source values 2 through 5 (ADR 0245).
- Publish the worker-characteristic families that work-related
cognition, affect, and behavior resolve into: Fleishman's four ability
domains, Holland's six RIASEC interest types with the published
hexagonal adjacency relation, the six explicitly legacy O*NET work-value
clusters, and
the seven higher-order dimensions of the revised O*NET Work Styles
structure.
- Publish all 3,006 O*NET 31.0 Content Model Reference elements with exact
identifiers, names, descriptions, and source-defined outline parents
(ADR 0264). Treat the six roots and 18 second-level branches as navigation
classes, never occupation ratings, person traits, scores, or weights.
- Declare typed derivation properties from classifications to
characteristics but assert no instance binding; binding requires a
versioned released source profile imported with provenance in its own
decision.
- Expose everything through a deterministic application read model with
fail-closed lookups; carry no numeric importance or level rating from
any occupational profile.

Acceptance: completeness counts, verbatim titles, closed RIASEC
vocabulary, exact published adjacency pairs, deterministic ordering,
canonical namespace, and lookup round-trip isolation are enforced by
`tests/test_io_taxonomy.py`, `tests/test_soc_2018_hierarchy.py`, and
`tests/test_onet_content_model.py`;
`tests/test_ontology.py` continues to pass unchanged.
### PRD-FR-2C — Evidence-bound occupational constructs

- Keep cognitive abilities, work styles, work activities, affective
reactions, and performance behaviors as non-equivalent construct classes
(ADR 0248). FJA worker functions remain separate.
- Reuse official external identifiers and source-published relationships;
never infer a DPT-to-psychology crosswalk or relabel work style as affect.
- Publish the eight O*NET 31.0 Ability, Essential Skill, Transferable Skill,
and Work Style link tables to Work Activities and Work Context as 1,417
directed, assertion-level provenance-bearing relations (ADR 0256). Treat
relevance as neither a causal effect nor a numeric weight.
- Bind a construct to record content only through a provenance-bearing,
evidence-cited assertion. Do not promote record evidence to a person trait,
score, causal effect, or job requirement.

Acceptance: SHACL rejects incomplete record assertions; ontology tests
prohibit FJA equivalence, require exact Post/evidence/PROV statement structure,
and reproduce every pinned O*NET linkage with its exact source table. Runtime
persistence and UI remain unavailable until their separate ADR acceptance.
The complete four-level SOC hierarchy and Content-Model-wide navigation
classes remain explicitly unavailable: no accepted ADR on this branch covers
them, and no implementation or test asserts them. They are not inferred from
labels and are not supplied by the catalog sync.

### PRD-FR-2D — Occupation-rating source observations

Expand Down Expand Up @@ -503,8 +447,7 @@ A release claim requires one exact protected-main head that proves:
- Product/data boundary: ADR 0001, ADR 0089.
- Asynchronous delivery and database-pool isolation: ADR 0204, ADR 0213.
- Knowledge Graph, ontology, and provenance: ADR 0004, ADR 0011, ADR 0065,
ADR 0184, ADR 0207, ADR 0222, ADR 0246, ADR 0256.
ADR 0184, ADR 0207, ADR 0222, ADR 0246.
ADR 0184, ADR 0207, ADR 0222, ADR 0246, ADR 0256.
- Semantic units and retrieval: ADR 0047, ADR 0062, ADR 0102, ADR 0217.
- LLM/model boundary: ADR 0070, ADR 0072, ADR 0076, ADR 0079.
- Measurement: ADR 0003, ADR 0145, ADR 0200, ADR 0205.
Expand Down
47 changes: 47 additions & 0 deletions tests/test_prd_requirement_traceability.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""PRD requirement identifier and reference regression contract (issue #807)."""

import re
from pathlib import Path


_ROOT = Path(__file__).resolve().parents[1]
_PRD = _ROOT / "docs" / "product-requirements.md"
_ADR_DIR = _ROOT / "docs" / "adr"
_TESTS_DIR = _ROOT / "tests"

_HEADING_RE = re.compile(r"^###\s+(PRD-[A-Z0-9]+(?:-[A-Z0-9]+)*)\s", re.MULTILINE)
_ADR_RE = re.compile(r"ADR (\d{4})(?![A-Za-z0-9_])")
_TEST_RE = re.compile(r"tests/(test_[A-Za-z0-9_]+\.py)(?![A-Za-z0-9_./-])")


def test_reference_patterns_reject_longer_token_prefixes() -> None:
"""Near-miss ADR numbers and backup filenames must not satisfy exact references."""
assert _ADR_RE.findall("ADR 0256") == ["0256"]
assert _ADR_RE.findall("ADR 02560") == []
assert _TEST_RE.findall("tests/test_example.py") == ["test_example.py"]
assert _TEST_RE.findall("tests/test_example.py.bak") == []


def test_prd_requirement_identifiers_are_unique() -> None:
"""Keep each PRD-FR-* identifier stable and singular (issue #807)."""
counts: dict[str, int] = {}
for ident in _HEADING_RE.findall(_PRD.read_text(encoding="utf-8")):
counts[ident] = counts.get(ident, 0) + 1
duplicated = sorted(name for name, count in counts.items() if count > 1)
assert not duplicated, f"duplicated PRD identifiers: {duplicated}"


def test_prd_cited_adrs_exist() -> None:
"""Pin every ADR number the PRD cites to a file on this branch (issue #807)."""
cited = sorted(set(_ADR_RE.findall(_PRD.read_text(encoding="utf-8"))))
missing = [
number for number in cited if not list(_ADR_DIR.glob(f"{number}-*.md"))
]
assert not missing, f"PRD cites ADRs with no file: {missing}"


def test_prd_cited_tests_exist() -> None:
"""Pin every test file the PRD acceptance cites to tests/ (issue #807)."""
cited = sorted(set(_TEST_RE.findall(_PRD.read_text(encoding="utf-8"))))
missing = [name for name in cited if not (_TESTS_DIR / name).exists()]
assert not missing, f"PRD cites missing tests: {missing}"
Loading