Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
17b25b3
feat(ontology): govern complete Voice-of-X taxonomy (ADR 0232)
seonghobae Aug 26, 2026
09838e1
fix(ontology): separate post voices from organization relations
Aug 26, 2026
fea73e1
docs: align Voice-of-X changelog vocabulary
Aug 26, 2026
cc3dfc1
docs(ontology): record Voice-of-X composition gap
seonghobae Aug 26, 2026
dce623a
feat(ontology): persist evidence-bearing voice combinations
seonghobae Aug 26, 2026
8b8a9be
docs(gap): track stacked voice-combination delivery
seonghobae Aug 26, 2026
461a4d1
fix(db): enforce Voice-of-X lookup category
seonghobae Aug 26, 2026
118cc38
feat(api): expose authorized Voice-of-X combinations
seonghobae Aug 26, 2026
771a8ed
fix(db): validate Voice assignment truth state
seonghobae Aug 26, 2026
182f5b8
feat: publish qualified voice evidence
seonghobae Aug 26, 2026
0a8ce31
docs: audit combined voice evidence scene
seonghobae Aug 26, 2026
b0f6ca4
fix: preserve combined voice behavior
Aug 26, 2026
684df3d
fix: preserve combined voice cutoff semantics
seonghobae Aug 26, 2026
e7816ce
feat(ui): localize all Voice labels
seonghobae Aug 26, 2026
90b3999
fix(ontology): retain visible post voices
seonghobae Aug 26, 2026
52bb01b
docs(adr): reserve Voice combinations as 0251
seonghobae Aug 26, 2026
e3ecb3b
feat(voice): add governed evidence assignments
seonghobae Aug 26, 2026
edc0ab9
feat(ui): show recorded Voice perspectives
seonghobae Aug 26, 2026
991753d
fix: preserve Voice assignment evidence states
Aug 26, 2026
d206fd8
fix: preserve Voice evidence provenance
seonghobae Aug 26, 2026
9db158c
docs: refresh Voice delivery evidence
seonghobae Aug 26, 2026
9c0a3e1
feat(ui): author evidence-backed Voice perspectives
seonghobae Aug 26, 2026
850494c
fix(frontend): localize expanded voice filters
Aug 26, 2026
021cc75
Merge remote-tracking branch 'origin/feat/voice-of-x-complete-taxonom…
seonghobae Aug 26, 2026
f0d072a
docs: refresh Voice delivery evidence
seonghobae Aug 26, 2026
e4d72e4
fix: expose full Voice catalog for authoring
seonghobae Aug 26, 2026
48af574
docs: record Voice authoring catalog gap closure
seonghobae Aug 26, 2026
2644fbb
fix(frontend): align Regulator Voice fixtures
seonghobae Aug 26, 2026
3ad9d74
docs: align Voice evidence terminology
seonghobae Aug 26, 2026
c6a4c26
test: prove authenticated Voice persistence
seonghobae Aug 26, 2026
34f8d10
docs: record authenticated Voice evidence
seonghobae Aug 26, 2026
55a5b27
fix(frontend): filter exact ontology IRIs
seonghobae Aug 26, 2026
bf35587
fix(frontend): retain canonical Voice assignment IRIs
seonghobae Aug 26, 2026
11b7fff
docs: record exact JSON-LD filtering evidence
seonghobae Aug 26, 2026
4aab6e5
fix(frontend): match canonical ontology encoding
seonghobae Aug 26, 2026
bb2eec1
docs: align Voice implementation head
seonghobae Aug 26, 2026
d738bd0
docs: reconcile downstream Voice stack
seonghobae Aug 26, 2026
dde0a83
fix: label Voice source navigation accurately
seonghobae Aug 26, 2026
3e18e7c
docs: refresh Voice exact-head evidence
seonghobae Aug 26, 2026
c731706
feat: expose authorized Voice derivation evidence
seonghobae Aug 26, 2026
3db9c44
fix: preserve paged Voice JSON-LD evidence
seonghobae Aug 26, 2026
ebb4ef1
docs: record Voice evidence paging head
seonghobae Aug 26, 2026
d5fe482
test: reuse migrated Voice vocabulary
seonghobae Aug 26, 2026
b2e0c96
docs: refresh Voice gate evidence
seonghobae Aug 26, 2026
3e332fd
docs: distinguish Voice cutoff from history
seonghobae Aug 26, 2026
201ac4e
fix: retain primary Voice assignment history
Aug 26, 2026
7a259a4
fix: keep Voice migration replay conflict-free
Aug 26, 2026
c293323
feat(ontology): preserve temporal imported primary Voice intervals (A…
seonghobae Aug 27, 2026
11fc2fa
docs(adr): renumber Voice combinations after collision
Aug 27, 2026
ad6dc5d
Merge protected main into Voice combinations stack
Aug 27, 2026
474dfdf
feat(ontology): preserve temporal imported primary Voice intervals (A…
seonghobae Aug 27, 2026
4b48c55
test(db): restore Voice migration fixture syntax
Aug 27, 2026
0ff51f8
fix(db): keep Voice history replay-safe
Aug 27, 2026
f778a01
Merge commit '4b48c5594' into codex/pr752-repair
Aug 27, 2026
b0eedab
test(db): prove replay after Voice history change
Aug 27, 2026
d0f6e7e
Merge commit 'c293323e79069ee6a7969533c4daf22b6ae0a8c5' into codex/pr…
Aug 27, 2026
123fdb7
fix(db): assign Voice history a unique migration number
Aug 27, 2026
9acd920
codex: address PR review feedback (#752)
Aug 27, 2026
5c2dfed
Merge origin/main into feat/voice-primary-history
Aug 27, 2026
8949f80
docs(gaps): refresh exact-head Voice delivery baseline
Aug 27, 2026
564f9df
docs(gaps): record rendered Voice evidence boundary
Aug 27, 2026
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
29 changes: 8 additions & 21 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,8 @@ flowchart LR
| `commitment_extraction.py` | Pluggable LLM derivation of a customer commitment (promise + deadline) from a post; `Null` default, `ContextualOrchestrator` real impl |
| `temporal_expressions.py` | Pure Korean relative-time resolver for Global Ask (ADR 0150) |
| `ask_time_axis.py` | Event-time vs ingestion-time clock choice for that window (ADR 0202) |
| `ontology.py` | Loads the governed Turtle source tree (`lineageweave-kg.ttl` plus generated fragments), the formal OWL 2/RDFS/SKOS vocabulary for the Knowledge Graph's node/edge types, source taxonomies, and published O*NET linkages (ADR 0004, ADR 0252, ADR 0255, ADR 0256) |
| `backend/app/occupation_rating_ingestion.py` | Projects authenticated occupation-rating evidence plus persisted source and represented-occupation catalogs (ADR 0258, ADR 0260, ADR 0261) |
| `frontend/src/components/OccupationRatingProfile.tsx` | Selects an imported source, filters stored occupation titles without ranking, and reads exact Dashboard evidence while preserving absence, uncertainty, and warning semantics (ADR 0259–0262) |
| `ontology.py` | Loads `docs/ontology/lineageweave-kg.ttl`, the formal OWL 2/RDFS/SKOS vocabulary for the Knowledge Graph's node/edge types (ADR 0004) |
| `ontology_neighborhood.py` | Bounded typed ontology/provenance neighborhood (ADR 0184); PostgreSQL stays authoritative, OWL subclass is not an instance edge |
| `occupational_construct_catalog.py` | Official O*NET 31.0 construct catalog sync (ADR 0250); no ratings or invented IRIs |
| `backend/app/occupational_construct_search.py` | Authorized catalog-label search over assertion-backed constructs (ADR 0257); hidden Posts never mint a hit |
| `ontology_source_cursor.py` | Opaque HMAC source-window continuation (ADR 0124); keyset pagination, never OFFSET |
| `period_report.py` | Fit GRM/GPCM on persisted IRT rows, FIPC-select, EAP-score a period (ADR 0003 slice 3; Bock & Mislevy, 1982) |
| `fixtures.py` | Synthetic demo dataset -- no real data ships in this repo |
Expand Down Expand Up @@ -379,6 +375,11 @@ governed atomic Voice with an explicit truth state and an ABAC-visible evidence
Post. The server creates the normalized PROV-O derivation and assignment in one
transaction; clients never submit an internal assertion id, and this route
cannot replace the imported primary Voice.
Imported-primary changes are retained in `source_post_voice` as non-overlapping
half-open effective intervals (ADR 0252). The database closes the current row
and opens the new observed primary at one statement instant; live reads select
the open interval, cutoff reads select the containing interval, and an ontology
continuation without an explicit cutoff uses its frozen snapshot instant.
The bounded ontology response carries a visible Voice assignment's evidence
Post id alongside its exact-value row. The exact-value table therefore offers
separate carrying-Post and derivation-evidence actions; hidden evidence removes
Expand Down Expand Up @@ -683,8 +684,7 @@ vocabulary (`node_type`, `edge_type`, `entity_relationship_type`,
`person_side`, `corporate_entity_level`) actually matches what the
Ontology/Semantic-Layer claim implies.

`docs/ontology/lineageweave-kg.ttl` and its deterministic governed fragments
are a real OWL 2 / RDFS / SKOS
`docs/ontology/lineageweave-kg.ttl` is a real OWL 2 / RDFS / SKOS
ontology in Turtle syntax: classes for `Post`/`Person`/`CorporateEntity`
(with `OurSidePerson`/`CounterpartyPerson` subclasses), object
properties for each `edge_type_code` and `entity_relationship_type`
Expand All @@ -698,7 +698,7 @@ specification over it, in the same sense W3C's own stack uses "semantic
layer" (RDFS/OWL as the governed conceptual layer over raw data), not a
separate BI-metrics product and not a parallel triple store.

`lineageweave/ontology.py` parses the Turtle source tree once with `rdflib`
`lineageweave/ontology.py` parses the Turtle file once with `rdflib`
(pure Python, no Rust toolchain, unlike `fast-mlsirm`) and exposes the
vocabulary as importable IRI constants, so application code has one
canonical name per class/property instead of re-typing lookup codes as
Expand All @@ -715,19 +715,6 @@ enforcement mechanism: a future PR that adds a new `edge_type` or
`entity_relationship_type` code without updating the ontology fails
this test, not just a docstring's word.

### Authorized job architecture snapshots

The public SOC/O*NET vocabulary and an employer's job architecture remain
different graphs. ADR 0263 adds an organization-scoped PostgreSQL source
boundary for private job-family/job-series snapshots: immutable source
metadata owns normalized nodes, source-declared broader/narrower edges, and
optional explicit bindings to a versioned external occupation scheme. An edge
table preserves multiple-family membership; the importer rejects cycles and
never derives a parent or binding from a label or code pattern. The snapshot
is source evidence only. It does not create a person, post, organizational
unit, competency, score, weight, or ontology assertion, and runtime rows never
enter repository artifacts.

## Phase 6c: post content normalization before any LLM/embedding call

The brief's latest revision calls out, explicitly, that a post body mixing
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ All notable changes to this project are documented here. Format follows
### Added

- Normalized Voice-of-X composition persistence (ADR 0256): every imported
- Imported primary Voice changes now retain non-overlapping effective intervals
(ADR 0252), including recurring A → B → A values. Live, knowledge-cutoff,
and ontology-snapshot reads select the same period contract; PostgreSQL
rejects overlapping primary intervals instead of relying on application
ordering.
- Normalized Voice-of-X composition persistence (ADR 0251): every imported
Comment on lines +12 to +17

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changelog has a truncated, wrong-ADR duplicate entry

Inserting the new bullet leaves the existing ADR 0256 line truncated at "every imported", and its continuation is reattached to a duplicate bullet now citing ADR 0251. The changelog ends up with two composition-persistence entries carrying conflicting ADR numbers.

Prompt for agents
In CHANGELOG.md the Unreleased/Added section now contains a broken entry. The original single bullet was 'Normalized Voice-of-X composition persistence (ADR 0256): every imported primary voice is mirrored into source_post_voice; ...'. This PR inserted a new ADR 0252 bullet between the first line ('...(ADR 0256): every imported') and its continuation ('primary voice is mirrored...'), and also duplicated the composition-persistence bullet with a different ADR number (0251). This leaves a truncated dangling line ending at 'every imported' plus two contradictory entries. Fix by removing the orphaned/truncated ADR 0256 line so the composition-persistence bullet appears once with the correct ADR number, and keep the new ADR 0252 bullet as its own separate entry.
Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

primary voice is mirrored into `source_post_voice`; each additional voice
requires its own PROV-O assertion and truth status. Compound lookup codes,
keyword inference, confidence thresholds, and invented weights remain out of
Expand Down
16 changes: 12 additions & 4 deletions backend/app/ontology_neighborhood_ingestion.py
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,10 @@ def neighborhood_to_payload(neighborhood: OntologyNeighborhood) -> dict[str, Any
"is_primary": assignment.is_primary,
"truth_status_code": assignment.truth_status_code,
"recorded_at": assignment.recorded_at.isoformat(),
"effective_from": assignment.effective_from.isoformat(),
"effective_to": assignment.effective_to.isoformat()
if assignment.effective_to
else None,
"provenance_reference": assignment.provenance_reference,
"evidence_post_id": assignment.evidence_post_id,
}
Expand All @@ -890,6 +894,7 @@ async def _load_voice_assignments(
"""
select voice.post_id, voice.voice_type_code, lookup.lookup_label, voice.is_primary,
voice.truth_status_code, voice.recorded_at,
voice.effective_from, voice.effective_to,
case when evidence.node_id = any($1::uuid[]) then evidence.node_id end
as evidence_post_id
from source_post_voice voice
Expand All @@ -903,10 +908,11 @@ async def _load_voice_assignments(
and evidence.node_type_code = 'node_post'
where voice.post_id = any($1::uuid[])
and (voice.is_primary or evidence.node_id = any($1::uuid[]))
and (($2::timestamptz is null and voice.effective_to is null)
or ($2::timestamptz is not null
and voice.effective_from <= $2
and (voice.effective_to is null or $2 < voice.effective_to)))
and voice.effective_from <= coalesce($2::timestamptz, $3::timestamptz)
and (
voice.effective_to is null
or coalesce($2::timestamptz, $3::timestamptz) < voice.effective_to
)
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.
and voice.recorded_at <= $3::timestamptz
Comment on lines +911 to 916

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Cutoff-null neighborhood read now keyed to snapshot instant

The rewritten query in _load_voice_assignments replaces the old cutoff-null branch with coalesce(knowledge_cutoff, snapshot_at). This matches ADR 0252: a frozen-snapshot continuation selects the interval containing that snapshot rather than the current open row, while a live read (snapshot=now) still returns the current row. Non-overlapping primary intervals guarantee one row per (post, voice).

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

order by voice.post_id, voice.is_primary desc,
lookup.display_order, voice.voice_type_code
Expand All @@ -931,6 +937,8 @@ async def _load_voice_assignments(
is_primary=row["is_primary"],
truth_status_code=row["truth_status_code"],
recorded_at=row["recorded_at"],
effective_from=row["effective_from"],
effective_to=row["effective_to"],
provenance_reference=(
"Evidence-backed additional voice"
if not row["is_primary"]
Expand Down
Loading
Loading