Skip to content

test(ontology): #204 OwlAdapter regression — 🔴 BUG FOUND: all readers return empty (RDFResource.Equals(Uri) type-mismatch) - #480

Merged
jsboige merged 1 commit into
masterfrom
test/204-ontology-owl-regression
Jun 15, 2026
Merged

test(ontology): #204 OwlAdapter regression — 🔴 BUG FOUND: all readers return empty (RDFResource.Equals(Uri) type-mismatch)#480
jsboige merged 1 commit into
masterfrom
test/204-ontology-owl-regression

Conversation

@jsboige

@jsboige jsboige commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

⚠️ This PR is also a [BUG] report. ai-01 — please read the BUG section before merging. The fix is a ~6-line change in OwlAdapter.cs (out of my scope); I've delivered the ready-to-go regression suite so the fix author flips the 8 [BUG]_* tests red→green.

What

NEW additive file Ontology/OwlAdapterRegressionTests.cs (+16 tests, 313 lines). Baseline 202 → 218 / 0 fail / 5 skip. The Ontology subsystem had zero xUnit coverage before this (the production-side Tests/OwlOntologyValidationTests.cs is a post-gen module, not a test suite).

🔴 BUG FOUND (not greenwashed)

Every self-retrieval reader in OwlAdapter is broken — they all silently return empty/false. Root cause: the comparison RDFResource.Equals(someUri) where someUri is a System.Uri (or string). RDFResource.Equals(object) requires the argument to be an RDFResource — so it returns false by type-mismatch on every call.

Confirmed empirically in Diag_RDFResource_Equals_String_Is_False_By_Type_Mismatch:

  • RDFResource.Equals(string)false (type mismatch) ← what the readers do
  • RDFResource.Equals(RDFResource with same URI) → true ← what they should do
  • RDFResource.ToString() == uriString → true ← the correct string basis

Affected readers (all return empty/false):

Reader Line Broken comparison
GetAnnotationSubjects 333-334 a.ValueIRI.Equals(typeResource.URI)
GetAnnotationObjects (GetTopConcepts) 342 — (returns ValueIRI but filter property.URI)
GetResourceAnnotations 351-352 a.SubjectIRI.Equals(subject.URI)
GetLiteralAnnotations 361-362 a.SubjectIRI.Equals(subject.URI)
HasAnnotation 389-391 a.ValueIRI.Equals(value.URI) + a.SubjectIRI.Equals(subject.URI)
CheckIsNarrowerConcept fallback 290-292 .Equals(...URI)
CheckHasClass 373 cls.GetIRI().Equals(resource.URI)

Production impact: Generation/Converters/Argumentum.AssetConverter/Tests/OwlOntologyValidationTests.cs is the post-generation OWL validation module and it calls these readers heavily:

  • ValidateMultilingualAnnotationsGetResourcesByType(Concept) returns empty → early-returns "no concepts → skip → PASS" (silent false-pass)
  • ValidateAIFMappings → same silent false-pass
  • ValidateOwlOntologyStructure → logs all 4 errors (no ConceptScheme, no Concept, no topConcepts, no narrower) → FAILs

So OWL validation is currently unreliable. #133 (OWL publication) ships a non-empty ontology because the write path + serialization work (verified in section C), but the validators can't actually inspect it.

Why no fix in this PR

OwlAdapter.cs is out of scope for this test-only dispatch (may intersect #444/#457 reserved files; fix is ai-01's call). Instead, this PR delivers the ready-to-go regression suite: the fix author changes the comparisons to a.ValueIRI.Equals(new RDFResource(value.URI.ToString())) (or .ToString()-based), and the 8 [BUG]_* tests flip red→green into proper round-trip assertions.

Test structure (16 tests)

Section A — [BUG] characterization (8 tests): pin the BROKEN behavior. Each .Should().BeEmpty() / .BeFalse() with a [BUG] reason. When fixed, these become .Should().HaveCount(...) / .BeTrue().

Section B — root-cause probe (1 test): pins the exact RDFSharp Equals semantics so the cause is undeniable and the fix is obvious.

Section C — write-path + serialization (7 tests): verify the WRITE side works (the graph IS correctly built in memory; ToFileAsync produces valid RDF/XML — that's why #133 ships non-empty despite broken readers). Verified by direct graph inspection (.ToString() comparison), NOT via the broken readers. So a fix can't accidentally regress the write side.

DoD

  • ✅ 202 → 218 pass / 0 fail / 5 skip
  • ✅ Additive only (1 new file, 0 existing file modified)
  • ✅ Build green
  • ✅ Real bug surfaced honestly (no greenwashing — the 8 [BUG] tests assert the broken behavior, not a flipped assertion)

Recommendation to ai-01

  1. This PR can merge as-is (pure additive test coverage + bug characterization).
  2. Open a separate [BUG] issue / fix PR for OwlAdapter.cs read methods — the fix is mechanical (6 comparison sites), and this PR's section-A tests become its regression suite.

🤖 Worker po-2024 on dispatch j1jfoi (primaire). Verdict QA visuelle = ai-01.

Co-Authored-By: Claude Opus 4.6 noreply@anthropic.com

…eturn empty (RDFResource.Equals(Uri) type-mismatch)

Dispatch 3a0d2l-continue primaire (j1jfoi). NEW additive file (+16 tests, 313 lines).
Baseline 202 -> 218 / 0 fail / 5 skip.

⚠️ BUG FOUND (not greenwashed): every self-retrieval reader in OwlAdapter compares
RDFResource.Equals(Uri) / RDFResource.Equals(string) — RDFResource.Equals(object) requires
the arg to BE an RDFResource, so it returns FALSE by type-mismatch on every call.
Affected readers ALL return empty/false:
  - GetConcepts, GetResourcesByType, GetTopConcepts
  - HasAnnotation, CheckIsNarrowerConcept
  - GetConceptPreferredLabels, GetConceptDocumentation
  - GetExactMatchConcepts/CloseMatch/RelatedMatch
  - CheckHasClass (cls.GetIRI().Equals(resource.URI) — same root cause, .URI is System.Uri)

Production impact: Tests/OwlOntologyValidationTests.cs (the post-gen validation module, NOT
an xUnit suite) relies on these readers. ValidateMultilingualAnnotations and ValidateAIFMappings
early-return "no concepts -> skip -> PASS" (silent false-pass). ValidateOwlOntologyStructure
logs all 4 errors and FAILs. So OWL validation is currently unreliable.

Root cause confirmed empirically (Diag_RDFResource_Equals_String_Is_False_By_Type_Mismatch):
  RDFResource.Equals(string) -> false (type mismatch)
  RDFResource.Equals(RDFResource with same URI) -> true  (what readers SHOULD use)
  RDFResource.ToString() == uriString -> true            (correct string basis)

Tests structured as:
  (A) [BUG] characterization — 8 tests pin the BROKEN behavior (.Should().BeEmpty() / .BeFalse()).
      When OwlAdapter is fixed, these flip red->green become proper round-trip assertions.
  (B) root-cause probe — pins RDFSharp Equals semantics so the cause is undeniable.
  (C) write-path + serialization — 7 tests verify the WRITE side works correctly (the ontology
      graph IS built in memory; ToFileAsync produces valid RDF/XML — that's why #133 ships
      a non-empty ontology despite the readers being broken). Verified by direct graph
      inspection (.ToString() comparison), NOT the broken readers.

No fix applied — OwlAdapter.cs is out of scope (test-only dispatch; fix is ai-01's call and
may intersect #444/#457 reserved files). The file gives the fix author a ready regression suite.

No existing file modified. Baseline additive (202->218). Deterministic, key-free, release-independent.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@clusterManager-Myia clusterManager-Myia left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[NanoClaw]

Solid regression suite. A few notes:

The bug characterization is excellent. Pinning broken behavior with explicit [BUG] tags and Should().BeEmpty() assertions (rather than greenwashing) is exactly the right approach. The root-cause probe (Diag_RDFResource_Equals_String_Is_False_By_Type_Mismatch) makes the fix obvious and undeniable.

Write-path tests (section C) are well-designed — verifying via direct graph inspection (.ToString() comparison) bypasses the broken readers, so these won't flip when the fix lands. Good defensive design.

Minor observations:

  • The class-level XML doc (~50 lines) is very thorough but could be trimmed — much of it duplicates what the individual test doc comments already say. Consider keeping the key context (BUG root cause, test structure overview) and moving the detailed reader-by-reader breakdown to the PR description where it already exists.
  • ToFileAsync(...).Wait() blocks the thread. Since this is a test it's acceptable, but await ... with an async test method would be cleaner and avoid potential deadlocks under certain sync contexts.
  • DocumentConcept_Unknown_Type_Throws sits in section C (write-path) but is really an edge-case/guard test. Consider a separate section or at least a comment grouping it with the BUG tests, since it validates a defensive code path rather than the write side.

Recommendation: LGTM — merge as-is. The test coverage is additive, well-structured, and the bug documentation is precise enough that the OwlAdapter fix author can land the ~6-line change with confidence using these as a regression suite.

@clusterManager-Myia clusterManager-Myia left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[NanoClaw]

Thorough regression test file. Read the full 313-line diff -- here are the specifics.

Section B -- Root cause probe (1 test)

Diag_RDFResource_Equals_String_Is_False_By_Type_Mismatch is clean and compelling. Three assertions in sequence: (1) Equals(string) is false -- the bug, (2) Equals(RDFResource) is true -- what readers should do, (3) ToString() == uriString is true -- the workaround basis. Assertions are NOT flipped. The test directly pins the RDFSharp semantics the PR body describes at lines 333-391 of OwlAdapter.cs. Good probe -- makes the fix obvious to whoever picks up the OwlAdapter work.

Section A -- BUG characterization (8 tests)

All 8 tests follow the same pattern: write data, read via the broken reader, assert empty/false. Cross-checked every assertion against the PR body claims:

  • BUG_GetConcepts_Returns_Empty: writes 3 concepts, asserts BeEmpty -- correct.
  • BUG_GetResourcesByType: asserts both Concept and ConceptScheme return empty -- correct.
  • BUG_GetTopConcepts: writes 2 top concepts, asserts empty -- correct.
  • BUG_HasAnnotation: writes ConceptScheme, asserts false -- correct.
  • BUG_CheckIsNarrowerConcept: writes narrower relationship, asserts false -- correct. Comment correctly notes the try/except fallback also suffers the same bug.
  • BUG_GetConceptPreferredLabels: writes prefLabel, asserts empty -- correct.
  • BUG_GetConceptDocumentation: writes definition, asserts empty -- correct.
  • BUG_GetExactMatchConcepts: writes exactMatch, asserts empty -- correct.

All assertions match the documented broken behavior. None are flipped. The naming convention [BUG]_Method_Result_Under_Condition is clear and consistent with the claimed failure mode.

One note: BUG_GetResourcesByType asserts two empty results in a single test. This is fine for characterization but will need splitting when flipped to green assertions, since a fix might resolve one reader path but not the other. Minor -- the fix author can address it.

Section C -- Write-path + serialization (7 tests)

Write-path tests correctly bypass the broken readers by using direct graph inspection: onto.AnnotationAxioms.OfType<OWLAnnotationAssertion>() with .ToString() string comparison. This is the right approach -- it proves the graph is populated independently of the broken read path.

  • Constructor_Produces_An_Adapter: basic sanity, fine.
  • DeclareConcept_Appends_AnnotationAxioms: verifies rdf:type=skos:Concept axiom in the graph. Checks property, subject, and value IRIs via ToString(). Solid.
  • DeclareNarrowerConcepts_Appends_Both_Directional_Axioms: verifies both skos:narrower and skos:broader. Good coverage of the reciprocal write.
  • AnnotateConceptPreferredLabel: verifies the prefLabel axiom exists with a non-null ValueLiteral. Correctly only asserts property+subject (not the literal value rendering, which is OWLSharp-internal).
  • BUG_CheckHasClass_Returns_False: hybrid test -- verifies both the write side (DeclarationAxioms non-empty) AND the broken read side (CheckHasClass returns false). Effective.
  • DocumentConcept_Unknown_Type_Throws: edge case for invalid enum. Should().Throw<ArgumentOutOfRangeException>(). Good defensive test.
  • ToFileAsync_Writes_A_Non_Empty_OWL2XML_File: end-to-end serialization with temp file, try/finally cleanup, asserts non-empty and contains RDF/XML markers. One note: uses .Wait() instead of await (sync-over-async). This is a known xUnit limitation with [Fact] returning void -- not a bug, but worth noting that [Fact] + .GetAwaiter().GetResult() or switching to [Fact] with async Task return type would be slightly safer against deadlocks.

Test structure and hygiene

  • xUnit [Fact] attributes, FluentAssertions throughout, consistent helper methods (NewAdapter, Res, Lit). Clean.
  • Test namespace (Argumentum.AssetConverter.Tests.Ontology) is correct for the project structure.
  • http://argumentum.test/onto# namespace -- clearly non-production. Good.
  • Temp file in ToFileAsync uses Guid for uniqueness and has try/finally cleanup. Proper.
  • No hardcoded secrets, credentials, or API keys. Clean.

Summary

This is well-crafted characterization work. The 8 BUG tests correctly pin the broken behavior (not flipped), the root-cause probe is undeniable, and the write-path tests genuinely verify graph population without depending on the broken readers. The PR delivers exactly what it claims: a regression suite ready for the fix author. Recommend merging as-is.

Nit: BUG_GetResourcesByType combines two assertion paths in one test -- consider splitting when flipping to green. And ToFileAsync could use async Task return instead of .Wait() to avoid potential sync-context deadlocks, though this is low-risk in a test runner.

@jsboige
jsboige merged commit 36c138b into master Jun 15, 2026
3 checks passed
@jsboige
jsboige deleted the test/204-ontology-owl-regression branch June 15, 2026 11:11
jsboige added a commit that referenced this pull request Jun 15, 2026
…SHelper silent-empty fallback (#481)

Fixes the bug surfaced by PR #480 (OwlAdapter readers returning empty). Root cause
was deeper than the .URI type-mismatch: RDFResource.Equals uses runtime-type
comparison (GetType()), so even RDFResource.Equals(fresh RDFResource) is false
when the stored IRI is a subtype — only GetIRI().Equals works. Switched all 14
reader comparison sites to .ToString() equality (the URI-as-string basis the
write-path tests already proved correct, agnostic to RDFResource subtype).

Also completes the "incomplete SKOSHelper bypass" flagged on the dashboard:
CheckIsNarrowerConcept / GetExactMatch/Close/RelatedMatch had try/catch fallbacks
that only triggered on exception, but SKOSHelper returns false/empty SILENTLY —
so the (now-correct) fallback scanner was never reached. Changed fallback to
trigger on empty/false result too, not just exception.

Tests: section-(A) [BUG] characterization suite from #480 flipped to proper
round-trip assertions (now the regression suite for this fix). Full suite
218 pass / 0 fail / 5 skip (baseline preserved).

Production impact: Tests/OwlOntologyValidationTests.cs (post-gen OWL validator,
not xUnit) was silently false-passing "no concepts → skip → PASS" on annotation
and AIF checks because GetResourcesByType(Concept) returned empty. Now resolves
correctly → validation becomes reliable (unblocks trustworthy #133 OWL publication).

Co-authored-by: Your <your.email@example.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
jsboige added a commit that referenced this pull request Jun 15, 2026
…ad (dispatch 4rkh1s secondaire) (#482)

* fix(ontology): #204 OwlAdapter readers — RDFResource.ToString() + SKOSHelper silent-empty fallback

Fixes the bug surfaced by PR #480 (OwlAdapter readers returning empty). Root cause
was deeper than the .URI type-mismatch: RDFResource.Equals uses runtime-type
comparison (GetType()), so even RDFResource.Equals(fresh RDFResource) is false
when the stored IRI is a subtype — only GetIRI().Equals works. Switched all 14
reader comparison sites to .ToString() equality (the URI-as-string basis the
write-path tests already proved correct, agnostic to RDFResource subtype).

Also completes the "incomplete SKOSHelper bypass" flagged on the dashboard:
CheckIsNarrowerConcept / GetExactMatch/Close/RelatedMatch had try/catch fallbacks
that only triggered on exception, but SKOSHelper returns false/empty SILENTLY —
so the (now-correct) fallback scanner was never reached. Changed fallback to
trigger on empty/false result too, not just exception.

Tests: section-(A) [BUG] characterization suite from #480 flipped to proper
round-trip assertions (now the regression suite for this fix). Full suite
218 pass / 0 fail / 5 skip (baseline preserved).

Production impact: Tests/OwlOntologyValidationTests.cs (post-gen OWL validator,
not xUnit) was silently false-passing "no concepts → skip → PASS" on annotation
and AIF checks because GetResourcesByType(Concept) returned empty. Now resolves
correctly → validation becomes reliable (unblocks trustworthy #133 OWL publication).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test(ontology): #204 OwlValidator live-path — silent false-pass is dead (dispatch 4rkh1s secondaire)

NEW additive file: OwlValidatorLivePathTests.cs (+5 tests). Dispatch `4rkh1s` secondaire —
prove the production OWL validation path is LIVE after the #481 reader fix.

The production validator `Tests/OwlOntologyValidationTests.cs` (runtime validator invoked by
`OwlValidatorConfig.Apply`, NOT an xUnit suite) had a silent false-pass: ValidateMultilingualAnnotations
and ValidateAIFMappings early-return `true` ("No concepts to validate — skipping") when
GetResourcesByType(Concept) was empty. Before #481 that reader ALWAYS returned empty, so the
validators reported PASS regardless of whether annotations/AIF mappings existed.

These tests drive the REAL production validator via reflection (its `_ontology` field is private;
the validation methods are public). They prove:
- (1) annotated concepts → validator inspects them and reports genuine PASS (not the skip-path);
- (2) UNannotated concepts → validator now FAILS (the annotation check actually ran and found the
  missing labels/definitions) — the dead silent false-pass is gone;
- (3) the GetResourcesByType(Concept) predicate the validators branch on resolves non-empty.

Tests: 223 pass / 0 fail / 5 skip (218 + 5). Deterministic, key-free, release-independent.
No existing file modified.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Your <your.email@example.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
jsboige added a commit that referenced this pull request Jun 15, 2026
…ch 4rkh1s tertiaire) (#483)

* fix(ontology): #204 OwlAdapter readers — RDFResource.ToString() + SKOSHelper silent-empty fallback

Fixes the bug surfaced by PR #480 (OwlAdapter readers returning empty). Root cause
was deeper than the .URI type-mismatch: RDFResource.Equals uses runtime-type
comparison (GetType()), so even RDFResource.Equals(fresh RDFResource) is false
when the stored IRI is a subtype — only GetIRI().Equals works. Switched all 14
reader comparison sites to .ToString() equality (the URI-as-string basis the
write-path tests already proved correct, agnostic to RDFResource subtype).

Also completes the "incomplete SKOSHelper bypass" flagged on the dashboard:
CheckIsNarrowerConcept / GetExactMatch/Close/RelatedMatch had try/catch fallbacks
that only triggered on exception, but SKOSHelper returns false/empty SILENTLY —
so the (now-correct) fallback scanner was never reached. Changed fallback to
trigger on empty/false result too, not just exception.

Tests: section-(A) [BUG] characterization suite from #480 flipped to proper
round-trip assertions (now the regression suite for this fix). Full suite
218 pass / 0 fail / 5 skip (baseline preserved).

Production impact: Tests/OwlOntologyValidationTests.cs (post-gen OWL validator,
not xUnit) was silently false-passing "no concepts → skip → PASS" on annotation
and AIF checks because GetResourcesByType(Concept) returned empty. Now resolves
correctly → validation becomes reliable (unblocks trustworthy #133 OWL publication).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test(ontology): #204 OwlValidator live-path — silent false-pass is dead (dispatch 4rkh1s secondaire)

NEW additive file: OwlValidatorLivePathTests.cs (+5 tests). Dispatch `4rkh1s` secondaire —
prove the production OWL validation path is LIVE after the #481 reader fix.

The production validator `Tests/OwlOntologyValidationTests.cs` (runtime validator invoked by
`OwlValidatorConfig.Apply`, NOT an xUnit suite) had a silent false-pass: ValidateMultilingualAnnotations
and ValidateAIFMappings early-return `true` ("No concepts to validate — skipping") when
GetResourcesByType(Concept) was empty. Before #481 that reader ALWAYS returned empty, so the
validators reported PASS regardless of whether annotations/AIF mappings existed.

These tests drive the REAL production validator via reflection (its `_ontology` field is private;
the validation methods are public). They prove:
- (1) annotated concepts → validator inspects them and reports genuine PASS (not the skip-path);
- (2) UNannotated concepts → validator now FAILS (the annotation check actually ran and found the
  missing labels/definitions) — the dead silent false-pass is gone;
- (3) the GetResourcesByType(Concept) predicate the validators branch on resolves non-empty.

Tests: 223 pass / 0 fail / 5 skip (218 + 5). Deterministic, key-free, release-independent.
No existing file modified.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test(utility): #204 UtilityExtensions layout math + path gate (dispatch 4rkh1s tertiaire)

NEW additive file: UtilityExtensionsLayoutTests.cs (+24 tests). Dispatch `4rkh1s` tertiaire —
cover a documented-fragile, deterministic, key-free area with ZERO existing coverage (grep
confirms no test references ToJaggedArray/UtilityExtensions/PathIsUrl).

(1) ToJaggedArray<T> — grid layout math. Pins rowLength = ceil(count/columns), the trailing
short row (remainder only, no padding — a padding regression would inject phantom blank cards
into final grid rows), row-major fill order (a transpose regression scrambles positions), and
the ToJaggedArray→Flatten inverse round-trip. This is the same class of geometry the coordinator
flagged ("count the geometry, not just the text").

(2) PathIsUrl — the asset-path gate. Pins that the relative paths CLAUDE.md documents as the
root cause of "white/empty cards" (../../Cards/..., ../, bare, Windows C:\, Unix /var/) are
NOT URLs (so the caller knows to rewrite them to absolute GitHub URLs), that http/https ARE
URLs, that null/empty/whitespace return false, and that whitespace-padded URLs still resolve.

Tests: 246 pass / 0 fail / 5 skip (223 + 24). Deterministic, key-free, release-independent.
No existing file modified. AssetConverterConfig.cs / DatasetUpdaterRootConfig.cs /
FallaciesLocalizationTests.cs untouched (reserved #444 β/γ po-2023).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Your <your.email@example.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
jsboige added a commit that referenced this pull request Jun 15, 2026
…lent-false-pass bug (#486)

Loads the committed generated ontology (docs/ontology/argumentum.owl, the real
OwlDocumentConfig.CreateOwlDocument output) and runs the production validation
path against it. This completes the #133 e2e proof that #482 (synthetic in-memory
adapters) started — and surfaces a SECOND silent-false-pass bug the #480#481#482
lane missed because it only exercised the in-memory path.

ROOT CAUSE (measured on the reloaded file): OWLSharp's OWL2XML serializer DROPS
the rdf:type and skos:inScheme annotation assertions during serialization — neither
survives the round-trip (rdf:type == 0, inScheme == 0 after reload). The OwlAdapter
readers find concepts/schemes by scanning AnnotationAxioms for rdf:type, so on any
LOADED file they return empty. OwlOntologyValidationTests.ValidateMultilingualAnnotations
and .ValidateAIFMappings then hit their `if (concepts.Count == 0) return true;` guard
and report PASS without inspecting anything. The real content IS present (2816
prefLabels, 10 AIF matches, 1510 class declarations) — the validator simply cannot
see it.

So #133's "confidence restored" premise does NOT hold for the production
load-and-validate path: the silent false-pass is still alive there, for a different
root cause than the #480 RDFResource type-mismatch.

4 characterization tests (all green, pinning current broken behavior):
1. rdf:type==0 and inScheme==0 after round-trip (prefLabel survives as contrast).
2. GetResourcesByType(Concept/ConceptScheme) returns empty on the loaded file.
3. The reloaded ontology DOES contain real content (prefLabel>1000, matches>0,
   classDecls>1000) — reader defect, not data defect.
4. Production validator returns TRUE for annotation + AIF checks on the loaded
   ontology — the silent false-pass, decisively pinned.

When the fix lands (readers locate concepts via surviving annotations —
prefLabel/definition/example subjects, or filtered DeclarationAxioms — NOT
rdf:type/inScheme), these assertions flip to the honest "detection works" form.
The fix is a prod behavior change with release-gate implications → coordinator scope;
this PR surfaces it rather than shipping a unilateral prod change.

Deterministic, key-free, release-independent. NEW additive file — nothing modified.

Co-authored-by: Your <your.email@example.com>
Co-authored-by: Claude <noreply@anthropic.com>
jsboige added a commit that referenced this pull request Jun 16, 2026
…nt-false-pass dead (#489)

The #481 reader fix only covered the IN-MEMORY path. On a LOADED ontology
(rdf:type + skos:inScheme dropped from the reloaded AnnotationAxioms by
OWLSharp's OWL2XML round-trip), GetResourcesByType(Concept)/GetConcepts
returned empty -> ValidateMultilingualAnnotations/ValidateAIFMappings hit
their `concepts.Count == 0 -> return true` guard -> PASS without inspecting
(the 2nd silent-false-pass, characterized by #486). Verified reloaded breakdown
(probed on the real generated ontology): prefLabel=2816, definition=2816,
example=2816, narrower/broader=1407, broadMatch=57, closeMatch=10,
narrowMatch=3, hasTopConcept=1; rdf:type=0, inScheme=0 among AnnotationAxioms.

Fix is READ-PATH ONLY (serializer untouched, per dispatch scope). When the
rdf:type scan is empty, locate entities via the surviving SKOS annotations:
  - skos:Concept       -> distinct subjects of skos:prefLabel (~1305 resolved)
  - skos:ConceptScheme -> subject of skos:hasTopConcept

In-memory path preserved (rdf:type present -> early-return, no fallback), so
the #482 in-memory live-path proofs still hold. Concepts deduped by URI string
(not RDFResource.Equals) to avoid the equality bug class of #480.

OwlE2EGenerationValidationTests (#486) flipped from bug-characterization to a
genuine-pass regression suite:
  (1) rdf:type/inScheme drop still real (now benign), prefLabel survives
  (2) readers now resolve concepts (>1000) + scheme (NotBeEmpty)
  (3) real content now resolvable (>1000 distinct concept subjects)
  (4) prod validator genuinely inspects + passes (skip guard unreachable)

Tests: Ontology namespace 25/25 green; full suite 259 passed / 0 failed / 5
skipped (no regression). Dispatch msg-...irkf5i primaire, base 4ac52e2.
Read-path only: no write/serialize, no CSV/template/config touched.

Co-authored-by: Your <your.email@example.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
jsboige added a commit that referenced this pull request Jun 16, 2026
/#133 (#495)

Unit-isolation of the OWL2XML round-trip SURVIVOR fallback in OwlAdapter.

The #489 read-path fix (e2e-pinned on the real 5MB ontology by
OwlE2EGenerationValidationTests) made the production validators stop
silent-false-passing when OWLSharp drops rdf:type on reload. But the
survivor fallback branch (OwlAdapter.cs ~424-441) was unit-uncovered:
OwlAdapterRegressionTests (#480/#481) builds ontologies WITH rdf:type
(DeclareConcept), so GetResourcesByType always early-returns on the type
scan and NEVER reaches the fallback.

7 additive tests on synthetic survivor-only ontologies (no DeclareConcept ->
no rdf:type; only prefLabel/hasTopConcept that survive the round-trip),
pinning what the e2e cannot:
- Concept dedup: 3 concepts x fr+en prefLabel (6 assertions) -> 3 distinct
  subjects (the GetAnnotationSubjectsByProperty .Distinct() contract)
- ConceptScheme via hasTopConcept SUBJECT (exact pin, not coarse NotBeEmpty)
- Unknown type -> empty (fallback does not over-resolve)
- rdf:type present -> type-scan governs, fallback SKIPPED. Decisive proof
  the fix did not change in-memory semantics; the e2e cannot test this
  because the real file has zero rdf:type
- GetConcepts() survivor tail (distinct path from GetResourcesByType)
- AIF exactMatch + closeMatch annotation-scan fallback

Verified: 7/7 new tests green; full suite 282 passed / 0 failed / 5 skipped.
Test-only, 0 prod change, 0 gate risk.

Co-authored-by: Your <your.email@example.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants