feat(ontology): preserve temporal imported primary Voice intervals (ADR 0252) - #752
feat(ontology): preserve temporal imported primary Voice intervals (ADR 0252)#752seonghobae wants to merge 61 commits into
Conversation
Expand voc_type from five to twelve post types (Supplier, Employee, Business, Regulator, Investor, Society, Process added) grounded in stakeholder identification theory and quality-engineering practice, and mirror six new counterparty relationship codes so any post class can type each named organization. Ontology SKOS concepts/object properties, idempotent migration 0222, classifier vocabulary + prompt, round-trip and parser tests stay in sync.
…y' into feat/voice-of-x-combinations
|
Warning Review limit reachedNext included review available in 50 minutes. View limit detailsLimit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (20)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
# Conflicts: # backend/tests/test_api.py
| create or replace function synchronize_source_post_primary_voice() | ||
| returns trigger | ||
| language plpgsql | ||
| as $$ | ||
| declare | ||
| change_at timestamptz := clock_timestamp(); | ||
| begin | ||
| update source_post_voice | ||
| set effective_to = change_at | ||
| where post_id = new.post_id | ||
| and effective_to is null | ||
| and (is_primary or voice_type_code = new.voc_type_code); | ||
|
|
||
| insert into source_post_voice | ||
| (post_id, voice_type_code, is_primary, truth_status_code, | ||
| effective_from, recorded_at) | ||
| values ( | ||
| new.post_id, | ||
| new.voc_type_code, | ||
| true, | ||
| 'truth_observed', | ||
| case when tg_op = 'INSERT' then least(new.created_at, change_at) else change_at end, | ||
| change_at | ||
| ); | ||
| return new; | ||
| end; | ||
| $$; |
There was a problem hiding this comment.
📝 Info: Primary-voice trigger relies on the source row lock for serialization
The rewritten synchronize_source_post_primary_voice drops the explicit for update and on conflict, closing the current primary and any current row for the incoming voice type before a plain insert. Non-overlapping intervals under concurrent A→B→A updates depend on the AFTER UPDATE trigger running while the source_post row is already locked, so clock_timestamp() reads distinct instants per serialized transaction.
Was this helpful? React with 👍 or 👎 to provide feedback.
| - 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 |
There was a problem hiding this comment.
🟡 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.
Was this helpful? React with 👍 or 👎 to provide feedback.
| | [`product-technical-gap-baseline.md`](../product-technical-gap-baseline.md) | Product/technical traceability projection across the ADR set; ADRs remain normative | | ||
| | [`lineage-bi-research-notes.md`](../lineage-bi-research-notes.md) | [0084](0084-lineage-research-grounding.md), [0062](0062-semantic-unit-embedding.md), [0064](0064-lineage-evidence-and-tree-assembly.md), [0024](0024-rankweave-fusion-fail-closed.md), [0165](0165-quantity-script-display.md), [0167](0167-rankweave-ranking-channel-evidence.md), [0169](0169-ask-batched-lineage-graph.md), [0172](0172-event-lineage-channel-evidence.md), [0202](0202-ask-event-time-filter.md), [0223](0223-explicit-semantic-content-unit-kinds.md), [0238](0238-source-conversation-turn-import-contract.md) | | ||
| | [`voice-combination-technical-requirements.md`](../voice-combination-technical-requirements.md) | [0246](0246-expanded-voice-of-x-post-taxonomy.md), [0251](0251-evidence-bearing-voice-combinations.md), [0252](0252-temporal-primary-voice-history.md) | | ||
| | [`lineage-bi-research-notes.md`](../lineage-bi-research-notes.md) | [0084](0084-lineage-research-grounding.md), [0062](0062-semantic-unit-embedding.md), [0064](0064-lineage-evidence-and-tree-assembly.md), [0024](0024-rankweave-fusion-fail-closed.md), [0165](0165-quantity-script-display.md), [0167](0167-rankweave-ranking-channel-evidence.md), [0169](0169-ask-batched-lineage-graph.md), [0172](0172-event-lineage-channel-evidence.md), [0202](0202-ask-event-time-filter.md), [0223](0223-explicit-semantic-content-unit-kinds.md) | |
There was a problem hiding this comment.
🟡 Duplicate supporting-document row in ADR map
A second lineage-bi-research-notes.md row is added to the supporting-document table, duplicating the existing one. The two rows also disagree: one lists ADR 0238 and the other omits it.
| | [`lineage-bi-research-notes.md`](../lineage-bi-research-notes.md) | [0084](0084-lineage-research-grounding.md), [0062](0062-semantic-unit-embedding.md), [0064](0064-lineage-evidence-and-tree-assembly.md), [0024](0024-rankweave-fusion-fail-closed.md), [0165](0165-quantity-script-display.md), [0167](0167-rankweave-ranking-channel-evidence.md), [0169](0169-ask-batched-lineage-graph.md), [0172](0172-event-lineage-channel-evidence.md), [0202](0202-ask-event-time-filter.md), [0223](0223-explicit-semantic-content-unit-kinds.md) | | |
| | [`lineage-bi-research-notes.md`](../lineage-bi-research-notes.md) | [0084](0084-lineage-research-grounding.md), [0062](0062-semantic-unit-embedding.md), [0064](0064-lineage-evidence-and-tree-assembly.md), [0024](0024-rankweave-fusion-fail-closed.md), [0165](0165-quantity-script-display.md), [0167](0167-rankweave-ranking-channel-evidence.md), [0169](0169-ask-batched-lineage-graph.md), [0172](0172-event-lineage-channel-evidence.md), [0202](0202-ask-event-time-filter.md), [0223](0223-explicit-semantic-content-unit-kinds.md), [0238](0238-source-conversation-turn-import-contract.md) | |
Was this helpful? React with 👍 or 👎 to provide feedback.
| and voice.effective_from <= coalesce($2::timestamptz, $3::timestamptz) | ||
| and ( | ||
| voice.effective_to is null | ||
| or coalesce($2::timestamptz, $3::timestamptz) < voice.effective_to | ||
| ) | ||
| and voice.recorded_at <= $3::timestamptz |
There was a problem hiding this comment.
📝 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).
Was this helpful? React with 👍 or 👎 to provide feedback.
| create unique index if not exists source_post_voice_current_pair_idx | ||
| on source_post_voice (post_id, voice_type_code) | ||
| where effective_to is null; | ||
|
|
||
| alter table source_post_voice | ||
| drop constraint if exists source_post_voice_primary_period_excl; | ||
| alter table source_post_voice | ||
| add constraint source_post_voice_primary_period_excl | ||
| exclude using gist ( | ||
| post_id with =, | ||
| tstzrange(effective_from, effective_to, '[)') with && | ||
| ) where (is_primary); |
There was a problem hiding this comment.
📝 Info: Redundant current-pair index and double overlap enforcement
source_post_voice_current_pair_idx duplicates the existing source_post_voice_current_type_idx (identical unique predicate), and primary-interval overlap is now enforced both by the 0237 validate trigger and the new GiST exclusion constraint. Harmless, but worth consolidating.
Was this helpful? React with 👍 or 👎 to provide feedback.
|
Closing as superseded by #761. PR #752's net contribution (temporal Imported-primary-Voice history, ADR 0252) was promoted onto current main via a three-way merge that keeps main's newer shared files while grafting the missing migration 0243, the effective_from/effective_to dataclass fields, the neighborhood payload/JSON-LD exports, and the coalesce cutoff predicate. #752's own branch was built on an older Voi-combination base and cannot rebase cleanly; #761 carries the same feature, 1597 tests green. |
Pull request was closed
Summary
effective_from~effective_to) insource_post_voiceunder ADR 0252.effective_to is null), knowledge-cutoff reads (effective_from <= cutoff < effective_to), and ontology-snapshot reads with TRD and PRD contracts.docs/voice-combination-technical-requirements.md), UML models, ADR 0252, and product gap baseline.Verification
pytest tests/test_source_post_voice* tests/test_ontology*: 142 passed.test_public_docstrings.py: 100% passed.backend/tests/test_api.pyschema integration tests passed.pnpm run lint && pnpm run test && pnpm run build: all passed.Stack
Depends on #717 (feat/voice-of-x-combinations). Retarget after parent merges.