From 3acf4c6f9ad90b1af077f4a00c5fa1254b51a521 Mon Sep 17 00:00:00 2001 From: Codex Date: Mon, 7 Sep 2026 12:29:32 +0900 Subject: [PATCH 1/4] fix(voice): validate admitted Post endpoints in both exports --- lineageweave/ontology_neighborhood.py | 5 ++++ tests/test_ontology_neighborhood.py | 33 +++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/lineageweave/ontology_neighborhood.py b/lineageweave/ontology_neighborhood.py index e67269343..48c2809be 100644 --- a/lineageweave/ontology_neighborhood.py +++ b/lineageweave/ontology_neighborhood.py @@ -322,6 +322,8 @@ def exact_value_rows(self) -> tuple[dict[str, str], ...]: raise OntologyNeighborhoodError( "dangling_endpoint", "voice assignment references a missing post" ) + if assignment.evidence_post_id is not None: + _node_type_for(self.nodes, NODE_POST, assignment.evidence_post_id) rows.append( { "edge_id": _voice_assignment_id(assignment), @@ -400,6 +402,9 @@ def jsonld_document(self) -> dict[str, object]: graph.append(item) assignments_by_post: dict[str, list[OntologyVoiceAssignment]] = {} for assignment in self.voice_assignments: + _node_type_for(self.nodes, NODE_POST, assignment.post_id) + if assignment.evidence_post_id is not None: + _node_type_for(self.nodes, NODE_POST, assignment.evidence_post_id) assignments_by_post.setdefault(assignment.post_id, []).append(assignment) for post_id, assignments in assignments_by_post.items(): graph.append( diff --git a/tests/test_ontology_neighborhood.py b/tests/test_ontology_neighborhood.py index dce3add0a..6be3937d4 100644 --- a/tests/test_ontology_neighborhood.py +++ b/tests/test_ontology_neighborhood.py @@ -1140,3 +1140,36 @@ def test_unlabeled_source_is_skipped_and_unknown_fact_node_type_fails_closed() - labels=_labels(), ) assert node_type.value.code == "unknown_node_type" + + +@pytest.mark.parametrize("projection", ["exact_value_rows", "jsonld_document"]) +@pytest.mark.parametrize("missing_endpoint", ["carrying", "evidence"]) +def test_voice_exports_reject_posts_outside_admitted_neighborhood( + projection: str, + missing_endpoint: str, +) -> None: + """Neither export may disclose a Voice endpoint absent from admitted Posts.""" + neighborhood = assemble_ontology_neighborhood( + focus_node_type_code=NODE_POST, + focus_node_id=POST_ID, + facts=_mention_affiliation(), + labels=_labels(), + maximum_depth=2, + ) + # This identifier is admitted as a Person, never as a Post. + assignment = OntologyVoiceAssignment( + post_id=PERSON_ID if missing_endpoint == "carrying" else POST_ID, + voice_type_code="vops", + voice_type_iri=str(LW.voiceOfProcessType), + voice_type_label="Voice of Process", + is_primary=False, + truth_status_code=TRUTH_OBSERVED, + recorded_at=T0, + effective_from=T0, + provenance_reference="Evidence-backed additional voice", + evidence_post_id=PERSON_ID if missing_endpoint == "evidence" else POST_ID, + ) + neighborhood = replace(neighborhood, voice_assignments=(assignment,)) + with pytest.raises(OntologyNeighborhoodError) as error: + getattr(neighborhood, projection)() + assert error.value.code == "dangling_endpoint" From 8eccd9adb384dbb87d6d2087880a0ef0fe405108 Mon Sep 17 00:00:00 2001 From: Codex Date: Mon, 7 Sep 2026 12:30:54 +0900 Subject: [PATCH 2/4] docs(gaps): record current Voice export boundary evidence --- docs/product-technical-gap-baseline.md | 79 ++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 239e03da1..3b618fa97 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,5 +1,84 @@ # Product & Technical Gap Baseline +## Current bounded review — 2026-09-07T03:30:53+00:00 + +This section supersedes the queue/runtime claims in the historical observations +below. It records separately fetched observations, not a transactional snapshot +of GitHub and the running stack. The inspected protected-main commit is +`83eba56149eb802cd63642c507c324c9976ec78e`. The implementation parent is open +PR #780 at `1d8fa267b059289e77301a09985dfac70a439814`. + +### Authority, implementation, and acceptance + +| Evidence class | Current observation and limit | +| --- | --- | +| Product authority | Read this tree's `docs/product-requirements.md` FR-2/FR-3 and release requirements. Read remote contextual-orchestrator `docs/product_planning.md` and `docs/architecture.md`; inference remains upstream-owned. | +| Normative authority | ADR 0246 governs 12 atomic Voices; ADR 0256 governs extensible evidence-bearing composition and authorized projections. ADR 0251 is the I/O-Psychology layer in this tree. No compound codes or new inference policy were introduced. | +| Research | No new empirical or theoretical claim. Existing ADR references remain supporting research; they do not prove implementation, authorization, capacity, or release acceptance. DeepWiki has no index for this repository. | +| Reproduced defect | Direct Voice projection admitted an evidence identifier absent from the bounded Post node set; JSON-LD also admitted an absent carrying Post. A Person sharing the supplied identifier did not establish Post authorization. Three of four synthetic regression cases failed before repair. | +| Candidate implementation | `3acf4c6f9ad90b1af077f4a00c5fa1254b51a521` reuses the existing typed endpoint validator in both exports. Missing admitted endpoints fail closed. Optional absent evidence stays absent; carrying Post is never substituted. No API shape, migration, ADR number, package pin, or release number changes. | +| Local verification | 78 tests passed across ontology neighborhood, ingestion, Voice authority, and SHACL suites. The four new cases cover carrying/evidence endpoints in exact-value and JSON-LD exports. No warning suppression was added. | +| Running stack | Existing `lineageweave` Compose services were running. A synthetic account authenticated through OIDC; existing Posts and Lineage APIs returned 200. Response bodies and credentials were not retained. These observations do not establish that the candidate is deployed. | +| Required acceptance | Candidate authenticated PostgreSQL/API proof, desktop/mobile rendered Voice evidence, and synthetic authenticated k6 end-to-end saturation measurements remain unverified. No production population inference, latency target, capacity threshold, or measured-largest-gap claim is made. | + +The selected increment protects evidence export fidelity. Its priority follows +the explicit authorized-evidence requirement; no invented score ranks the gaps. +The existing loader already filters Posts; this change independently enforces +the same typed endpoint invariant at the reusable export boundary. It adds no +UI layout or copy. Existing #937 owns Post read reauthorization, #936 owns +assignment correction history, and #934/#968 own overlapping page accumulation +changes. Those implementations were not copied or overwritten. + +### Protected delivery observation + +The complete PR inventory contained 129 open PRs, 121 Drafts, +and 99 stacked children. A separate full issue inventory +contained 20 open issues. All eight inspected ready PRs required independent +review; their first-100 thread connections had no unresolved threads and no +additional page. A bot COMMENT is not approval. + +| PR | Exact inspected head | Checks rollup | +| --- | --- | --- | +| #969 | `583157c5d007d4903a78b2e30c0caac224f6460e` | PENDING | +| #964 | `1cced397600b15258b36e221a33beb62c4cca4cd` | FAILURE | +| #961 | `3bdec0504a65e63f44bd49ba15de37182a1672cc` | FAILURE | +| #929 | `2a8ed5d02f4a3082b346d923d754c1ff37ebff52` | FAILURE | +| #914 | `61ed3a3712d252e3c179a71d297c52f05e1bac20` | FAILURE | +| #911 | `5d40eed35a0b6e0d182397f8d02b29c38e9bdd17` | FAILURE | +| #802 | `32f1cda10a2a1a6cabd64a3ae6f59bd6f0b20fd6` | FAILURE | +| #780 | `1d8fa267b059289e77301a09985dfac70a439814` | FAILURE | + +The active organization ruleset requires one approval, resolved review threads, +and seven central workflows; stale approvals are dismissed on push. Last-push +approval is false in the observed rule. Organization and repository rules both +prohibit force pushes. #780 retains normal squash auto-merge, remains open, and +has no qualifying independent approval. No merge or merge SHA is claimed. +No in-progress Actions run was returned by the current query; none was cancelled. +Pending Checks were not used to stop this independent regression repair. + +This candidate stays stacked on #780. Merge the parent under protection before +retargeting the child to main, then collect fresh head/base/check/review evidence. +Draft PRs have not all received full code review in this bounded observation. + +### Cross-PR conflicts and canonical names + +Release titles collide at 2.61.0 (#841/#842), 2.62.0 (#843/#844), and 2.92.0 +(#876/#877); title overlap is a review signal, not proof of conflicting release +files. #934 and #968 both edit page accumulation in `ontologyLayout.ts` and need +owner reconciliation before protected delivery. This candidate changes only the +Python export boundary and its regression tests plus this evidence document; +it introduces no schema/API/version identity. Complete cross-PR ADR, migration, +API, and release-file reconciliation remains outstanding. + +Live remote repository metadata confirms `ContextualWisdomLab/LineageWeave`, +`ContextualWisdomLab/RankWeave`, `ContextualWisdomLab/ThreadWeave`, and +`ContextualWisdomLab/TEPP`. The canonical storage repository is +`ContextualWisdomLab/disksage`. Earlier `DiskSage` spelling is not canonical. +The primary worktree's existing translation-ledger and baseline edits were +preserved; this candidate uses a separate checkout of the exact parent head. + +## Historical observations — not current acceptance + > Exact-head development-loop snapshot: 2026-09-02 KST. Protected `main` is > `3f61c8242b9c02dec307a7396e83e28f7cdd9f3d`; the fresh inventory contains > 107 open PRs and 15 open non-PR issues. PR #780's remotely observed evidence From 52cd655196a20907f4c8e9e678cebb360cb8d3fb Mon Sep 17 00:00:00 2001 From: Codex Date: Mon, 7 Sep 2026 12:31:45 +0900 Subject: [PATCH 3/4] docs(gaps): record non-identifying current Voice counts --- docs/product-technical-gap-baseline.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 3b618fa97..2e707a567 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -18,7 +18,7 @@ PR #780 at `1d8fa267b059289e77301a09985dfac70a439814`. | Reproduced defect | Direct Voice projection admitted an evidence identifier absent from the bounded Post node set; JSON-LD also admitted an absent carrying Post. A Person sharing the supplied identifier did not establish Post authorization. Three of four synthetic regression cases failed before repair. | | Candidate implementation | `3acf4c6f9ad90b1af077f4a00c5fa1254b51a521` reuses the existing typed endpoint validator in both exports. Missing admitted endpoints fail closed. Optional absent evidence stays absent; carrying Post is never substituted. No API shape, migration, ADR number, package pin, or release number changes. | | Local verification | 78 tests passed across ontology neighborhood, ingestion, Voice authority, and SHACL suites. The four new cases cover carrying/evidence endpoints in exact-value and JSON-LD exports. No warning suppression was added. | -| Running stack | Existing `lineageweave` Compose services were running. A synthetic account authenticated through OIDC; existing Posts and Lineage APIs returned 200. Response bodies and credentials were not retained. These observations do not establish that the candidate is deployed. | +| Running stack | Existing `lineageweave` Compose services were running. A synthetic account authenticated through OIDC; existing Posts and Lineage APIs returned 200. Response bodies and credentials were not retained. A direct PostgreSQL aggregate found 43,189 Voice assignments, all primary, and zero additional assignments; it does not prove an additional-Voice workflow. These observations do not establish that the candidate is deployed. | | Required acceptance | Candidate authenticated PostgreSQL/API proof, desktop/mobile rendered Voice evidence, and synthetic authenticated k6 end-to-end saturation measurements remain unverified. No production population inference, latency target, capacity threshold, or measured-largest-gap claim is made. | The selected increment protects evidence export fidelity. Its priority follows From b6046c9c23f647abfd7b2436419c5b5b0db91bc5 Mon Sep 17 00:00:00 2001 From: Codex Date: Mon, 7 Sep 2026 13:44:55 +0900 Subject: [PATCH 4/4] fix(voice): omit unsupported additional assignments from exports --- docs/product-technical-gap-baseline.md | 42 +++++++++++++++++++++++++- lineageweave/ontology_neighborhood.py | 6 ++++ tests/test_ontology_neighborhood.py | 19 ++++-------- 3 files changed, 53 insertions(+), 14 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 2e707a567..71aa30438 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,6 +1,46 @@ # Product & Technical Gap Baseline -## Current bounded review — 2026-09-07T03:30:53+00:00 +## Current export-integrity review — 2026-09-07T04:44:55+00:00 + +This observation supersedes older current-state claims below. GitHub and runtime +observations are separate reads, not one atomic snapshot. Protected main was +`83eba56149eb802cd63642c507c324c9976ec78e`; inspected PR #971 head was +`52cd655196a20907f4c8e9e678cebb360cb8d3fb`, stacked on PR #780 at +`1d8fa267b059289e77301a09985dfac70a439814`. The implementation accompanying +this section extends that exact inspected head; hosted evidence does not transfer. + +| Evidence class | Observation and acceptance boundary | +| --- | --- | +| Product authority | Read LineageWeave FR-2/FR-3 and release gates, contextual-orchestrator `conductor/product.md`, and TEPP `docs/product/prd-v0.4-approved.md`. This repair invokes no inference or arithmetic and changes no owner contract. | +| Normative authority | ADR 0246 retains twelve atomic Voices. ADR 0256 requires omission of additional assignments without admitted evidence; ADR 0252 preserves cutoff history. ADR 0251 in this tree concerns I/O psychology, not Voice composition. | +| Research | No new research claim or priority score. Existing cited research does not establish runtime completion. DeepWiki structure, contents, and question requests returned repository-not-found; local ADRs remain the authority. | +| Reproduced defect | A direct export with an additional Voice lacking evidence still emitted a CSV row and a qualified JSON-LD assignment, violating the existing evidence minimum. The synthetic regression failed before repair. | +| Minimal implementation | Both export projections now omit the unsupported additional assignment, its relationship, and its otherwise unused concept. Imported primary and evidence-bearing assignments keep their existing contract. No carrying Post is substituted for hidden derivation evidence. | +| Local verification | 78 ontology neighborhood, ingestion, Voice authority, and SHACL tests passed after repair. The regression checks absence of the CSV row, assignment subject, carrying relation, and concept. Existing admitted-endpoint rejection remains covered. | +| Current runtime aggregate | Read-only official `lineageweave` PostgreSQL count: 43,189 assignments, 43,189 primary, zero additional. This is an exact table count, not a population inference or additional-Voice acceptance. No identifying values were collected. | +| Outstanding acceptance | Candidate authenticated PostgreSQL API, rendered desktop/mobile evidence, paged UI accumulation, and authenticated synthetic k6 concurrency/latency/error/throughput plus service saturation remain unverified for this head. No completion or deployed fix is claimed. | + +The complete inventory returned 131 open PRs (120 Draft), 100 stacked children, +31 `REVIEW_REQUIRED`, 100 without a review decision, and no `APPROVED` decision. +The separate paginated issue query returned 20 non-PR issues. Six PRs retained +auto-merge. #780 still has normal squash auto-merge and requires independent +approval. #971 is Draft with zero review threads at its inspected head. Parent +protection must complete before retargeting; no stack has been retargeted here. +The recent 100-run query showed active runs for open PRs #972, #966, and #959 +at their inventoried heads; none was cancelled. This is not a full runner audit. +Required central workflow failures on #929/#964 remain failures, not pending +Checks or permission to bypass. No merge SHA is claimed. + +Remote metadata reconfirmed canonical `ContextualWisdomLab/LineageWeave`, +`RankWeave`, `ThreadWeave`, `TEPP`, `contextual-orchestrator`, and lowercase +`disksage`. The PRD still contains duplicate occupational requirement identifiers; +#847 owns that reconciliation. The #971 delta adds no API shape, schema, ADR +number, or release identity. Earlier cross-PR collisions listed below remain +unresolved; #934/#968 page-merge overlap and #936/#937 history/read authorization +remain with their owners. No claim of complete queue-wide conflict resolution. +The primary checkout's three existing edits were preserved. + +## Earlier bounded review — 2026-09-07T03:30:53+00:00 This section supersedes the queue/runtime claims in the historical observations below. It records separately fetched observations, not a transactional snapshot diff --git a/lineageweave/ontology_neighborhood.py b/lineageweave/ontology_neighborhood.py index 48c2809be..22f1a24a9 100644 --- a/lineageweave/ontology_neighborhood.py +++ b/lineageweave/ontology_neighborhood.py @@ -317,6 +317,8 @@ def exact_value_rows(self) -> tuple[dict[str, str], ...]: if node.node_type_code == NODE_POST } for assignment in self.voice_assignments: + if not assignment.is_primary and assignment.evidence_post_id is None: + continue source_label = post_labels.get(assignment.post_id) if source_label is None: raise OntologyNeighborhoodError( @@ -402,6 +404,8 @@ def jsonld_document(self) -> dict[str, object]: graph.append(item) assignments_by_post: dict[str, list[OntologyVoiceAssignment]] = {} for assignment in self.voice_assignments: + if not assignment.is_primary and assignment.evidence_post_id is None: + continue _node_type_for(self.nodes, NODE_POST, assignment.post_id) if assignment.evidence_post_id is not None: _node_type_for(self.nodes, NODE_POST, assignment.evidence_post_id) @@ -417,6 +421,8 @@ def jsonld_document(self) -> dict[str, object]: } ) for assignment in self.voice_assignments: + if not assignment.is_primary and assignment.evidence_post_id is None: + continue assignment_iri = _voice_assignment_iri(assignment) evidence_post_id = assignment.evidence_post_id evidence_iri = ( diff --git a/tests/test_ontology_neighborhood.py b/tests/test_ontology_neighborhood.py index 6be3937d4..1283ff2a2 100644 --- a/tests/test_ontology_neighborhood.py +++ b/tests/test_ontology_neighborhood.py @@ -945,19 +945,12 @@ def test_voice_assignments_join_exact_csv_rows_and_jsonld() -> None: } hidden_evidence = replace(assignment, evidence_post_id=None) - hidden_row = replace( - neighborhood, voice_assignments=(hidden_evidence,) - ).exact_value_rows()[0] - assert hidden_row["evidence_post_id"] == "" - assert hidden_row["evidence_count"] == "0" - hidden_projection = next( - item - for item in replace(neighborhood, voice_assignments=(hidden_evidence,)) - .jsonld_document()["@graph"] - if item.get("@id") == assignment_iri - ) - assert str(LW.voiceAssignmentEvidence) not in hidden_projection - assert "prov:wasDerivedFrom" not in hidden_projection + hidden_neighborhood = replace(neighborhood, voice_assignments=(hidden_evidence,)) + assert hidden_neighborhood.exact_value_rows() == () + hidden_graph = hidden_neighborhood.jsonld_document()["@graph"] + assert all(item.get("@id") != assignment_iri for item in hidden_graph) + assert all(str(LW.hasVoiceAssignment) not in item for item in hidden_graph) + assert all(item.get("@id") != assignment.voice_type_iri for item in hidden_graph) imported_primary = replace(assignment, is_primary=True, evidence_post_id=None) primary_projection = next(