Skip to content

fix(#810): refman coverage audit for Document/XDE assembly (Pass 3) - #977

Merged
gsdali merged 5 commits into
mainfrom
fix/810-refman-document-xde
Aug 20, 2026
Merged

fix(#810): refman coverage audit for Document/XDE assembly (Pass 3)#977
gsdali merged 5 commits into
mainfrom
fix/810-refman-document-xde

Conversation

@gsdali

@gsdali gsdali commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

What & why

Executes #810 (Pass 3 of the refman-audit epic #807): a re-runnable census comparing what OCCTSwift
wraps and documents against what OCCT's pinned kernel declares, for the OCAF/XDE document lane, in
both directions.

Artifact: Scripts/repro/810-refman-document-xde/refman_census.py, plus
selftest_removal_matrix.py and a README.md carrying the measurements. Verdicts: ok 118,
deliberate, recorded 160, under 0, over 36 fixed here plus 1 deferred to #971.
Runs from any cwd. Exits 1 on an over-coverage regression, a deferred finding that was quietly
fixed, a method attribution the pinned headers do not support, an unrecorded under, or lane drift
under --reverify-lane.

The lane is 278 classes, not 188, and the widening is measured

#810 names seven prefixes. Six more OCAF/XDE packages are named by no sub-issue of #807 at all,
established by grepping all twelve bodies (#808 to #818, #820) for every OCAF/XDE-shaped prefix in
the pinned headers:

package headers bridge constructs why claimed
TDataXtd_ 17 14 an OCAF standard-attribute package on TDF_Label, exactly like TDataStd_
TNaming_ 36 13 same, and the mechanism XCAFDoc_ShapeTool is built on
XCAFDimTolObjects_ 23 6 the payload types of XCAFDoc_Dimension/Datum/GeomTolerance
XCAFPrs_ 11 3 DocumentExplorer/DocumentNode/Style are traversal and style reading
XCAFView_ 2 2 the payload type of XCAFDoc_View
XCAFNoteObjects_ 1 1 the payload type of XCAFDoc_Note

All six are claimed. TDataXtd_ and TNaming_ are the 51 classes #810's own review notes
flagged as being in limbo; auditing XCAFDoc_Dimension while its only data-carrying type belonged
to nobody would have been the same failure #808 named when it widened BRep_Tool to the whole
BRep_* package.

Forty-four further OCAF-family packages, about 460 headers, are handed off by name in #973, with
their measured bridge usage and three candidate homes (a Pass 3b for TFunction_/TPrsStd_/TObj_,
Pass 4c for the persistence drivers, Pass 4d for StdPrs_/StdSelect_). They are the persistence,
function and presentation-driver layers below the document API, a different surface from the one
#810 describes, and folding them in would have made this table larger than #808 and #809 combined
plus half again without anyone deciding that.

Over-coverage: found by two detectors, not a hand read-through

#808 and #809 both established over-coverage by one unreproducible read-through and pinned only the
conclusions. That gap was #928. This pass ran #928's detector and built a second one for the
half it structurally cannot see.

source candidates true false rate
census-doc-occt-attribution.py --lane ... (#928) 34 18 16 47.1% false
check_method_attributions() (new, in the census) 25 23 2 8.0% false
reading 1 1 0

Five findings appear in both (a claim can name a class that is not reached and a member that is
not declared), so the union is 37: 36 fixed here, 1 deferred.

#928's 47.1% on this lane is close to its own measured 41.0% over a uniform 40-row sample, which
is the first independent check of that figure. Every one of its 16 false positives falls into a
category its own README already names; the split is in this PR's README.md.

The new check is what found 18 of the 36. #928 asks whether the class a claim names is
reached, so it cannot see that TNaming_Tool::SameShape names a member TNaming_Tool.hxx does not
declare, because TNaming_Tool is reached elsewhere. The new check resolves every Class::Member
attribution in the lane against that class's own pinned header and its ancestors. Six families:

what the docs said what OCCT 8.0.1 declares
TNaming_Tool::SameShape (twice) nothing of that name; the code walks TNaming_SameShapeIterator
XCAFDoc_AssemblyGraph::NbRoots GetRoots().Extent()
XCAFDoc_AssemblyItemId::GetPathLength GetPath().Size()
TDataXtd_Presentation::GetColor/GetTransparency/GetWidth/GetMode Color/Transparency/Width/Mode
TDataStd_Expression::SetExpressionString/GetExpressionString SetExpression/GetExpression
TDocStd_XLink::Set/GetDocumentEntry, Set/GetLabelEntry two overloaded DocumentEntry/LabelEntry
TNaming_Scope::Clear, TDataXtd_PatternStd::SetSignature/Find, XCAFDoc_AssemblyItemRef::RemoveExtraRef/GetPath ClearValid, Signature, TDF_Label::FindAttribute, ClearExtraRef, GetItem
XCAFDoc_ShapeMapTool::Map GetMap, and see "the detector was blind" below

The flagship divergence now reads as a decision

Four docs/reference/Document-Persistence-IO.md entries attributed saveOCAF, saveOCAFInPlace,
loadOCAF and Document.create(format:) to XCAFApp_Application, and three more attributed
documentCount/readingFormats/writingFormats to CDF_Application, which declares none of them.
All seven run on TDocStd_Application.

XCAFApp_Application.hxx's own comment calls GetApplication() "the only valid method to get
XCAFApp_Application object", and its constructor is protected, so the refman is telling the truth.
OCCTSwift deliberately does the other thing: since v1.15.17 (#371) OCCTDocument's constructor does
app = new TDocStd_Application(), because the shared instance is what made the #341 / #344 / #349 /
#353 race cluster reachable at all, and upstream maintainer gkv311's review of
OCCT#1396 reaches the same conclusion from
the other side. That divergence now has three places that say so and why:

  • the seven corrected entries;
  • a new "Why not XCAFApp_Application" section on that page, covering what is lost (nothing:
    the class adds only ResourcesName() and InitDocument(), and a ground-truth C++ test confirmed
    equivalence before the change landed) and what is not fixed (ocafStoreMutex() stays, because a
    private instance per document is what first makes Resource_Manager/Storage_Schema concurrent,
    Resource_Manager::Debug and Storage_Schema::ICurrentData() races surfaced by #371 (upstream OCCT#1398) #374);
  • a DELIBERATE_DIVERGENCE entry in the census and a full paragraph in
    docs/occtswift-wrapping-gaps.md.

A second instance of the same divergence, which neither detector can see: docs/thread-safety.md
still said, in the present tense, that every document-producing call goes through that singleton. Its
own #371 section, 130 lines below, says otherwise. Corrected to past tense with a forward pointer.

Under-coverage: 155 newly recorded, 0 unrecorded

All 155 gain a reason in docs/occtswift-wrapping-gaps.md. None needed a code fix:

  • 50 deprecated collection typedefs, each carrying Standard_HEADER_DEPRECATED at file scope.
    The file-scope test is what separates this list from a wrong one: grepping for
    Standard_DEPRECATED returns 56, and five of the extras (TDocStd_Application,
    TDF_LabelSequence, TDataStd_Real, TDataStd_Variable, XCAFDoc_VisMaterial) are live,
    wrapped classes carrying a per-method deprecation on one accessor. Filing those as deprecated
    aliases would have been wrong in the most misleading direction. Two of the 50's family
    (TDF_LabelSequence, TDF_LabelMap) are still genuinely called and are listed as an outstanding
    spelling migration, not a gap.
  • 34 internal helpers, six of them dead #includes in OCCTBridge_Document.mm. Three of those
    six reach the capability without naming the class, and the entries say so: TDF_Label::NewChild()
    is literally TDF_TagSource::NewChild(*this).
  • 21 enums nothing reads. Thirteen are GD&T qualifiers and modifiers, so a STEP file's ISO 286
    grade or datum modifiers survive a round trip but cannot be read; widening
    DimensionInfo/GeomToleranceInfo/DatumInfo is a public API change rather than a wrap.
  • 17 storage records and raw-pointer typedefs, 16 undo/redo delta records (reached as the
    wrapped TDF_Delta), 10 abstract bases, 7 package classes, 4 covered by a sibling
    (including TDocStd_PathParser, deliberately removed by OSDPath.fileExtension() and PathParser.fileExtension() disagree on dot-inclusion — two OCCT path-parsing classes wrapped as one duplicated public API #499 because Parse() is wrong for
    extension-less paths), 2 belonging to Pass 4d (XCAFPrs_AISObject, XCAFPrs_Texture).

Two real enumeration gaps are named rather than buried: TDocStd_XLinkIterator (links are readable
per label but not enumerable per document) and CDM_ReferenceIterator (cross-document reference
resolution is not exposed at all).

Filed rather than fixed, and why for each

Closes #810

CHANGELOG entry

Refman coverage audit, Pass 3: Document/XDE assembly (#810)

Scripts/repro/810-refman-document-xde/refman_census.py enumerates every OCCT class under
TDocStd_*, TDF_*, TDataStd_*, TDataXtd_*, TNaming_*, XCAFDoc_*, XCAFApp_*,
XCAFDimTolObjects_*, XCAFNoteObjects_*, XCAFView_*, XCAFPrs_*, CDF_* and CDM_*
(278 classes) and verdicts each against Sources/OCCTBridge and docs/.

Fixed 36 doc attributions across 6 files that named an OCCT class or member the implementation
does not use. Seven attributed OCAF save, load, create and session queries to
XCAFApp_Application or CDF_Application; all seven run on TDocStd_Application, and
XCAFApp_Application is deliberately not constructed anywhere in the bridge since #371 replaced
the process-wide singleton with a private application per document.
docs/reference/Document-Persistence-IO.md gains a "Why not XCAFApp_Application" section
recording that divergence, and docs/thread-safety.md no longer describes document creation, in
the present tense, as going through a singleton retired three releases ago. Eighteen more named a
member the pinned kernel does not declare: TNaming_Tool::SameShape and
XCAFDoc_AssemblyGraph::NbRoots do not exist at all, and TDataXtd_Presentation::GetColor,
TDataStd_Expression::SetExpressionString, TDocStd_XLink::GetLabelEntry,
TDataXtd_PatternStd::SetSignature, XCAFDoc_AssemblyItemRef::RemoveExtraRef and
XCAFDoc_ShapeMapTool::Map are near-miss spellings of Color, SetExpression, LabelEntry,
Signature, ClearExtraRef and GetMap. The rest
named a class nowhere in the call chain, several semantically different from the one that runs:
Document.selectShape uses TNaming_Selector::Select, which computes a name that survives later
modification, rather than TNaming_Builder::Select, which records a raw select pair.

Document.openNamedTransaction(_:) and Document.transactionNumber now document what they do:
the name argument is accepted and never recorded, and transactionNumber returns 1 or 0
rather than a transaction number. The underlying API defects are #970.

Recorded 155 previously-unrecorded unwrapped classes in docs/occtswift-wrapping-gaps.md:
deprecated NCollection typedefs, OCAF undo/redo delta records, abstract bases, framework storage
records, internal helpers, GD&T qualifier enums nothing reads, and capability covered by a wrapped
sibling. No public API change.

SemVer impact

NONE. Documentation corrections only. No public Swift API or bridge C++ symbol was added, removed,
renamed, or changed in behaviour. The one Sources/ edit is two /// doc comments on existing
declarations in Document.swift, correcting what they claim and adding a - Warning: and a
runnable snippet to each.

Checklist

  • New or changed behavior is covered by a unit test in the same PR (not just manual
    verification). N/A: no behaviour change of any kind. The census artifact is the coverage, and
    its four detectors were each injected against, below.

  • Every new test and every new --self-test case was run once with its subject broken, and the
    failure is reported here.

    1. The over-coverage regression check. Run against the tree before this PR's corrections it
    reports all 35 findings and exits 1, which is the whole battery failing on its real subject
    rather than a constructed case:

    Known over-coverage findings tracked: 36 (accessor spelling 14, application 7, ...)
    REGRESSION: the following fixed over-coverage findings have reappeared:
      docs/reference/Document-Persistence-IO.md: Document.saveOCAF(to:) -- '- **OCCT:** `XCAFApp_Application::SaveAs` / `PCDM_StoreStatus`.'
      ... 35 more, one per finding ...
    

    After the corrections, exit 0. Whitespace is collapsed on both sides, so re-wrapping a wrong
    sentence across a line break still counts.

    2. The deferred check, which is inverted. Applied OCCTDocumentIsLabelModified's header comment names TDocStd_Modified, which it does not use #971's own fix to
    OCCTBridge_Document.h: STALE: the following deferred findings appear to have been FIXED. Move each entry from DEFERRED_OVER_FINDINGS to KNOWN_OVER_FINDINGS, exit 1. Reverted (header
    confirmed byte-identical to main), exit 0.

    3. The under-coverage check. Removed the TNaming_UsedShapes entry from
    docs/occtswift-wrapping-gaps.md: UNRECORDED under-coverage findings ... TNaming* TNaming_UsedShapes, exit 1. Restored, exit 0.

    4. The new method-attribution detector. Fourteen --self-test cases in two halves, and
    selftest_removal_matrix.py covers both: it re-imposes each constraint the attribution pattern
    deliberately omits, and switches off each of declares_member's four accepting shapes. Every
    guard is load-bearing:

    parser baseline: 4/4 cases pass with the shipped pattern
    
    closing-backtick-anchor    imposed -> 2/4 cases fail  [load-bearing]
    no-leading-backtick        imposed -> 2/4 cases fail  [load-bearing]
    
    header baseline: 10/10 cases pass unmodified
    
    method-call        disabled -> 5/10 cases fail  [load-bearing]
    nested-type        disabled -> 1/10 cases fail  [load-bearing]
    data-member        disabled -> 1/10 cases fail  [load-bearing]
    base-class-walk    disabled -> 1/10 cases fail  [load-bearing]
    

    Each shape exists because omitting it produced a false report on this lane's real docs, and
    SELF_TEST_CASES names the doc line each one protects: XCAFDoc_AssemblyGraph::NodeType is a
    nested enum, CDF_Directory::myDocuments is a private field in thread-safety.md's prose about
    the Uncatchable SIGSEGV in parallel swift test run, right after concurrent OBJ imports — possibly related to #341, unconfirmed #344 race, and XCAFApp_Application::SaveAs is inherited (which also proves the flagship
    finding is the right kind of defect: the claim is wrong because the class is not constructed,
    not because the member is missing).

    5. The detector was blind, and the matrix is what found out. The first version of
    _ATTRIBUTION_RE was anchored on a closing backtick, so it matched `Class::Member` and
    silently skipped `Class::Member()`. docs/ writes attributions both ways. The difference
    contained a real finding: docs/reference/Document-XCAF-Notes.md attributed
    shapeMapToolExtent to XCAFDoc_ShapeMapTool::Map().Extent(), and the member is GetMap. That
    is a detector built to catch "the docs claim something the kernel does not support" doing exactly
    that itself. The pattern is now loose, the self-test has a case per spelling (plain,
    parenthesised, nested, and one with no backtick at all so the anchor cannot be dropped), and the
    matrix has a variant per constraint. 24 candidates became 25 and 35 findings became 36.

    6. The family counts are asserted, not typed. FAMILY_COUNTS repeats the docstring's six
    per-family totals as data and main() diffs them against the table. Two of the six were wrong
    when written by hand, in a prose block read three times, which is CLAUDE.md's own
    total-beside-a-list failure. Proved: setting application to 8 gives
    FAMILY COUNT DRIFT: ... table has 7, FAMILY_COUNTS says 8 and exit 1.

  • The CHANGELOG entry above is complete, and docs/CHANGELOG.md is not in this diff.

  • The SemVer impact above is stated, and docs/SEMVER.md is not in this diff.

Notes for the reviewer

Gates. All seven gates, both censuses and the merge-history audit, plus every --self-test,
run clean: check-bridge-index, check-null-handle-guards, check-docs-defaults,
check-docs-existence, check-borrowed-handles, derive-bridge-header-split --verify,
count-operations, check-style-manifest --base origin/main, census-unmeasured-values --self-test, census-doc-occt-attribution --self-test, check-changelog-transcription --self-test, comment-ratio-check --self-test. swift-format lint --strict and
swiftlint --strict are clean on Document.swift, which is off the manifest and therefore held
fully clean. No swift build or swift test was needed: no compiled code changed.

The census's own limitation, stated in its docstring rather than left to be found.
deliberate, recorded means the class name appears in docs/occtswift-wrapping-gaps.md, not
that the sentence around it is a reason. Five package classes (TDF, TDataStd, TDataXtd,
TNaming, XCAFDoc) matched that test before this pass wrote them an entry, because the file's
"What's Wrapped" table lists their toolkits by name. #808 and #809 have the same weakness and
neither says so. Every one of this lane's 160 recorded classes now sits in a bullet written by this
pass and carrying its own reason, so name and reason coincide today; the test still cannot tell the
difference tomorrow.

This PR's own corrections raise #928's count on the lane, from 16 residual false positives to
21
(22 reported, of which one is the deferred #971). Four of the five new ones are the NOISY shape #928's README already documents: a correction
that explains itself names the wrong class again in a contrastive sentence ("TNaming_Tool
declares no SameShape member in OCCT 8.0.1"), and the detector cannot see a contrast. The fifth
is the accessor-chain category. Keeping those sentences is deliberate, since a reader arriving at a
corrected entry needs to be told which class does not have the member; the count is recorded in
this PR's README.md so the next pass does not read 22 as 22 defects.

Deliberately left undone, each with its issue: #970 (two API defects), #971 (the one
over-coverage finding still in the tree), #973 (the 44 unclaimed packages).

On Libraries/. The two checks that read the pinned headers (--reverify-lane, the
method-attribution check, and the self-test) report SKIPPED rather than passing silently when
Libraries/OCCT.xcframework is absent, which is the normal case in CI. They were run here against
a symlinked xcframework, and --reverify-lane reports 278 classes, matching the pinned headers.

Census artifact at Scripts/repro/810-refman-document-xde/. 278 OCCT classes across
thirteen packages: ok 118, deliberate/recorded 160, under 0, over 35 fixed here plus
one deferred to #971.

The lane is wider than #810's own seven prefixes (188 headers). Six OCAF/XDE packages
are named by no sub-issue of #807 at all, measured by grepping all twelve bodies:
TDataXtd_, TNaming_, XCAFDimTolObjects_, XCAFView_, XCAFNoteObjects_ and XCAFPrs_.
All six are claimed. Forty-four further OCAF-family packages (~460 headers) are handed
off by name in #973 rather than absorbed.

Over-coverage was found by two detectors rather than a hand read-through. #928's
class-level census contributed 18 candidates at a 47.1% false-positive rate on this
lane, close to its own measured 41.0%. A new lane-scoped Class::Member check in the
census resolves every attribution against the pinned headers and their ancestors,
and found 17 more that #928 structurally cannot see: TNaming_Tool::SameShape and
XCAFDoc_AssemblyGraph::NbRoots do not exist, and TDataXtd_Presentation::GetColor,
TDataStd_Expression::SetExpressionString and TDocStd_XLink::GetLabelEntry are
near-miss spellings of Color, SetExpression and LabelEntry. One more came from
reading: docs/thread-safety.md described document creation, in the present tense, as
going through a singleton #371 retired.

The flagship divergence now reads as a decision. Four Document-Persistence-IO.md
entries attributed save, load and create to XCAFApp_Application, whose own header
calls GetApplication() "the only valid method" to obtain one. The bridge deliberately
does not: #371 replaced it with a private TDocStd_Application per document because the
shared instance is what made #341/#344/#349/#353 reachable. That page gains a "Why not
XCAFApp_Application" section and occtswift-wrapping-gaps.md carries the reasoning.

Two API defects found while checking the transaction entries are filed as #970 rather
than fixed here: openNamedTransaction drops its name, and transactionNumber returns a
flag. Both reference pages and both Swift doc comments now describe what the code does.

Closes #810

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@kilo-code-bot

kilo-code-bot Bot commented Aug 19, 2026

Copy link
Copy Markdown

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Overview

Severity Count
CRITICAL 0
WARNING 0
SUGGESTION 0
Issue Details (click to expand)

No issues found in the incremental changes.

Files Reviewed (8 files)
  • Scripts/repro/810-refman-document-xde/refman_census.py
  • Scripts/repro/971-islabelmodified-attribution/README.md
  • Scripts/repro/971-islabelmodified-attribution/probe.mm
  • Scripts/repro/971-islabelmodified-attribution/tokens-unchanged.py
  • Scripts/style-manifest-bridge.txt
  • Sources/OCCTBridge/include/OCCTBridge_Document.h
  • docs/CHANGELOG.md
  • docs/reference/Document.md
Previous Review Summaries (2 snapshots, latest commit e835948)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit e835948)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (4 files)
  • Scripts/repro/810-refman-document-xde/README.md
  • Scripts/repro/810-refman-document-xde/refman_census.py
  • Scripts/repro/810-refman-document-xde/selftest_removal_matrix.py
  • docs/reference/Document-XCAF-Notes.md

Previous review (commit f162bb4)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (11 files)
  • Scripts/repro/810-refman-document-xde/refman_census.py - New census script with 278-class lane, over/under coverage checks, method-attribution detector, self-tests
  • Scripts/repro/810-refman-document-xde/selftest_removal_matrix.py - Removal matrix proving all 4 detector shapes are load-bearing
  • Scripts/repro/810-refman-document-xde/README.md - Complete documentation of results, detector validation, and known limitations
  • Sources/OCCTSwift/Document.swift - Corrected doc comments for openNamedTransaction and transactionNumber with warnings about actual behavior
  • docs/occtswift-wrapping-gaps.md - Added 155 under-coverage entries + deliberate divergence entry for XCAFApp_Application
  • docs/reference/Document-Math-Bounds.md - 4 corrected OCCT attributions
  • docs/reference/Document-OCAF-Attributes.md - 12 corrected OCCT attributions (naming, presentation, transactions)
  • docs/reference/Document-Persistence-IO.md - 7 corrected OCCT attributions + "Why not XCAFApp_Application" section
  • docs/reference/Document-XCAF-Notes.md - 8 corrected OCCT attributions (assembly, expressions, XLink)
  • docs/reference/Document.md - 4 corrected OCCT attributions (tracing, selection, descendants)
  • docs/thread-safety.md - Tense correction for XCAFApp_Application singleton (present → past)

Reviewed by nemotron-3-ultra-550b-a55b:free · Input: 276.9K · Output: 6.3K · Cached: 2M

gsdali and others added 2 commits August 20, 2026 08:16
… blind to

The method-attribution check shipped in the previous commit anchored its pattern on a
closing backtick, so it matched `Class::Member` and silently skipped `Class::Member()`.
docs/ writes attributions both ways. The difference contained a real finding:
docs/reference/Document-XCAF-Notes.md attributed shapeMapToolExtent to
XCAFDoc_ShapeMapTool::Map().Extent(), and the member is GetMap. A detector written to
catch "the docs claim something the kernel does not support" was doing exactly that
itself.

The pattern is now loose. Four new parser self-test cases cover the spellings docs/
actually uses (plain, parenthesised, nested, and one with no backtick at all so the
leading anchor cannot be dropped either), and selftest_removal_matrix.py gains a
parser half that re-imposes each constraint the pattern deliberately omits: both are
load-bearing, 2 of 4 cases each.

Two of the docstring's six per-family finding counts were also wrong, written by hand
in a block that had been read three times. FAMILY_COUNTS now repeats them as data and
main() diffs it against the table, which is CLAUDE.md's own total-beside-a-list rule
applied to this file.

35 findings become 36; 24 method-check candidates become 25.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gsdali

gsdali commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator Author

Heads-up from #971, which this PR's census artifact carries as a deferred over-finding: the
premise is reversed, and three places in this diff assert it.

#971 (and this PR, following it) says OCCTDocumentIsLabelModified "reads
TDocStd_Document::GetModified() instead, which is a different mechanism" from the root-label
TDocStd_Modified attribute. It is the same mechanism. TDocStd_Document owns no modified-label
map; all three of its methods are forwarders (TDocStd_Document.cxx:151-175):

void TDocStd_Document::SetModified(const TDF_Label& L) { TDocStd_Modified::Add(L); }
void TDocStd_Document::PurgeModified()                 { TDocStd_Modified::Clear(Main()); }
const NCollection_Map<TDF_Label>& TDocStd_Document::GetModified() const
{ return TDocStd_Modified::Get(Main()); }

and TDocStd_Modified's statics all resolve through label.Root(). Measured from outside the
kernel as well as read from it (Scripts/repro/971-islabelmodified-attribution/probe.mm in
#971's PR): after doc->SetModified(child) the root gains a TDocStd_Modified attribute, and
&doc->GetModified() == &attr->Get() is true, the same map object by address. Marking through
either API is visible through the other.

The observation that made both of us conclude otherwise is correct but does not carry: the class
is never constructed in Sources/OCCTBridge because the kernel constructs it on the bridge's
behalf inside TDocStd_Modified::Add, not because the bridge reaches a different store.

Three sites in this diff need the correction:

  1. refman_census.py, the TDocStd_Modified gap rationale: "OCCTDocumentIsLabelModified reads
    TDocStd_Document::GetModified() instead, which is a different mechanism".
  2. refman_census.py's DEFERRED_OVER_FINDINGS entry for OCCTDocumentIsLabelModified. Its
    correct: text says the same, and its bad_phrase is
    "/// Check if a label is marked as modified (via TDocStd_Modified on root).", which is the
    line OCCTDocumentIsLabelModified's header comment names TDocStd_Modified, which it does not use #971's PR kept
    . The line that was deleted is the Note: on the next line. Since the
    entry is documented as failing when its phrase disappears without moving to
    KNOWN_OVER_FINDINGS, it needs re-pointing regardless of which PR lands first.
  3. docs/occtswift-wrapping-gaps.md, the paragraph beginning "Of the rest, TDocStd_Modified is
    the root-label attribute registering modified labels and is not what
    OCCTDocumentIsLabelModified reads".

Whether TDocStd_Modified still belongs in the deliberate-gap list is a separate call and probably
yes: the bridge does reach the capability, just through TDocStd_Document's forwarders rather than
by naming the class, which is the same shape as the TDF_TagSource entry two lines above.

One more, unrelated to the reversal but in the same neighbourhood: docs/reference/Document.md:1399
attributed isModified(_:) to TDocStd_Document::IsModified, a method that does not exist in
8.0.1 (commented out at TDocStd_Document.cxx:158-161). #971's PR corrects it to
TDocStd_Document::GetModified. This PR also touches docs/reference/Document.md, though not that
line, so expect a trivial or no conflict.

gsdali and others added 2 commits August 20, 2026 12:34
…ribe

#984 measured what #971 asserted and found the premise backwards.
TDocStd_Document::GetModified() is `return TDocStd_Modified::Get(Main());`
(TDocStd_Document.cxx:172), so the header line naming the attribute was the
correct one and the `Note:` denying it was the defect.

This census carried the reversed version twice:

  - TDocStd_Modified's curated reason said GetModified() is "a different
    mechanism". It is the same mechanism, reached through the document.
  - DEFERRED_OVER_FINDINGS pinned the line #984 KEPT rather than the one it
    deleted, so the check would have fired on a correct tree the moment #984
    landed.

The deferred list is emptied, not deleted: the mechanism is sound and the
comment records both the reversal and the mis-pinned phrase so nobody restores
the entry from this PR's history.

Also transcribes this PR's CHANGELOG entry.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gsdali
gsdali merged commit 91692f2 into main Aug 20, 2026
6 checks passed
gsdali added a commit that referenced this pull request Aug 20, 2026
Also resolves the docs/reference/Document-OCAF-Attributes.md conflict against
main. #977's audit documented openNamedTransaction's PRE-fix behaviour ("the
name is accepted for source compatibility and is not stored anywhere"), which
this PR makes false: the name is now held to commit and written to the
TDF_Delta. Kept this branch's description on both hunks.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gsdali added a commit that referenced this pull request Aug 20, 2026
…main

Resolves conflicts in docs/reference/Document-OCAF-Attributes.md (2 hunks) and
Sources/OCCTSwift/Document.swift (3 hunks) against main.

All five describe openNamedTransaction. #977's refman audit documented its
PRE-fix behaviour, stating the name "is accepted and not recorded" and that
TDocStd_Document has no named-transaction API. This PR makes the first half
false: the name is held to commit and written to the TDF_Delta via
TDF_Delta::SetName, which is what TDocStd_MultiTransactionManager does
internally. #977's second half stays true and this branch's text already says
it.

Kept this branch's side on every hunk. Verified after: zero conflict markers
tree-wide, swift build clean, swift-format clean on Document.swift, eight gate
scripts green, and 5655 tests / 1466 suites / 0 failures.

Worth recording: the first push of this commit carried conflict markers,
because `git add -A` stages a conflicted file and no gate script parses Swift
or Markdown for them. The build is what catches it.

Co-Authored-By: Claude Opus 5 (1M context) <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.

Refman coverage audit: Document/XDE assembly (Pass 3)

1 participant