Skip to content

Viewer AI native evidence adapter register

Coverage belongs to #6833, within P01/P03 and the full implementation ledger. Only explicitly attached evidence is sent; opening a panel or the Assistant sends nothing. The register is code: apps/viewer/src/lib/assistant/adapters/registry.ts, with its completeness invariants in registry.test.ts (every source has exactly one adapter; every workspace panel is either mapped to a source or an explained boundary, never both and never neither).

Adapter contract

Each source has one adapter (adapters/types.ts):

Member Meaning
id, group Source id (sources.ts) and picker group: Checks, Coordination, Quantities, Model, Automation.
panelIds, panelSubject Panels whose header Discuss with AI attaches this source (the first is where Open goes). When one panel hosts several sources, panelSubject(state) decides the current one (Clash vs duplicate scan, IDS/rules vs manual checklist). A panel can also force a second source explicitly (Flow's run bar).
titleKey, descriptionKey, rowMeaningKey, unavailableKey, suggestionKeys Catalogued copy for the picker, evidence view and suggested questions.
readiness(state) Live picker status (TranslatableMessage), ready only when a native result exists. Cheap: sizes and references, never a population walk. subscribe exists only for state outside the viewer store (Linked records).
identity(state) The native result captured, compared by reference (element-wise for composite identities). Replacing the native result makes the snapshot not current.
reportStamp(state) Run-time analysis stamp (stampAnalysisReport) of stored results, so a result that predates an edit is stale even when captured after it. Live sources omit it.
capture(state, limit) { summary, rows ≤ limit, totalRows, availability }. Native totals live in summary and are never recomputed from the sample; totalRows is the exact native population; availability is available or unavailable (an available result with zero rows is empty).

The common capture path (evidence.ts) adds the envelope every source shares: E1…En citations, model pins and fingerprints, the context stamp (any mutation/geometry/placement change invalidates every snapshot), sourceAvailability, reportProvenance, sampled, and the bounded projection (100 rows, bounded strings/depth/work, 48,000-character JSON; values of credential-named fields such as apiKey, accessToken, password or Authorization are withheld). New adapters start each row with { kind, modelId?, globalId?, expressId?, unit?, status? }; unknown provenance stays null or absent, never guessed. The five original adapters keep their established row shapes, which saved conversations already contain. Credentials, endpoints, grants, binary data, images, script source text and artifact bytes are never captured.

Enabled adapters

Source (group) · panels Native owner Rows · summary Freshness Limits Acceptance tests (lib/assistant/adapters/ unless noted)
clash (Checks) · Clash clashResult/clashRawResult; @ifc-lite/clash Finding with both model-qualified references, rule, native status/severity, distance kind, discipline candidates · native summary, settings, truncation Identity clashResult; run stamp Candidates do not establish responsibility; human reviews not projected. Duplicate scans discuss as duplicates. ../evidence.test.ts, components/viewer/assistant/*.test.tsx
duplicates (Checks) · Clash (duplicate scan) Same result via duplicateSetSections / groupDuplicateSets One coincident set (members ≤10 with model/GlobalId/expressId/type) · set, element and pair counts, severity meaning, tolerance (m) [clashResult, clashGroups]; run stamp Panel touch/review filters are component state, so all non-excluded pairs are covered. duplicates.test.tsx (real duplicate scan at 1 and 2 models; >100 sets over three committed samples)
validation (Checks) · Data validation (IDS/rules side) idsValidationReport; native IDS and rules engines Specification summary, then entity/set results · native summary, source kind, model info Identity report; run stamp (IDS and now information rules) Manual checklist is its own source. ../evidence.test.ts, validation-rules-stamp.test.tsx
manualChecklist (Checks) · Data validation (manual side) manualLibrary/manualChecklist/manualAnswers; summarizeChecklist Item × loaded model with human verdict, comment, answer time · per-model status counts incl. unanswered, latest answer [library, checklist, answers] Verdicts are human decisions, not native results. The tab's own model picker is component state, so every loaded model is reported. manual-checklist.test.tsx
lens (Checks) · Lens lensRuleCounts/lensRuleEntityIds/lensAutoColorLegend via useLens Rule or legend entry with count and ≤5 resolved sample elements · matched, hidden and unmatched (null when not published) Live refs Unavailable while evaluation is pending. lens.test.tsx (real LensRuntimeHost over parsed sample, 1 and 2 models)
bcf (Checks) · BCF bcfProject Topic: status, priority, assignee, labels, dates, counts, IFC GUIDs ≤10 · counts by status Identity bcfProject No snapshots, comment text, server state or credentials. bcf.test.tsx (committed AC20-FZK-Haus_BIMcollabZoom.bcf)
compare (Coordination) · Compare compareResult Diff entry with base/head references · counts, scope, exclusions, geometry limits Identity; run stamp No AI promotion of ambiguous matches. ../evidence.test.ts
changes (Coordination) · Changes Undo/redo stacks, batch tags; changeOperations() Edit: model, GlobalId (null for created/model-level), path, old/new value, time · per model/type counts, undo/redo depth, hidden reverted edits Live refs Separate from model comparison. changes.test.tsx (120 real wall edits over two models)
changeSets (Coordination) · Change sets changeSets, changeSetSummaries Set metadata, edit/element counts, models, edit kinds · totals Live refs No edit values; no updated/exported time is recorded natively. change-sets.test.tsx
zones (Coordination) · Zones zoneTableRows and zone facts Element × zone table row (unit m³) · per-set revision digest, counts, refusals by reason [zoneSets, zoneAssignments, zoneApportionment] Mesh basis only; never runs the split; refusals are null until a split exists. zones.test.tsx
placement (Coordination) · Placement modelPlacement, getEffectiveGeoreference, detectDoubleGeoreference One model: local translation/rotation (m, rad), georeference present/absent/unknown, frozen ProjectedCRS/MapConversion fields, double-georeference flag [models, modelPlacement, georefMutations] Unknown georeference stays unknown. placement.test.tsx (real building-architecture.ifc EPSG:32760, hello-wall.ifc)
schedule (Coordination) · Schedule scheduleData; taskStartIso/taskFinishIso Task: dates (null when unavailable), milestone, parent, products ≤10, provenance ifc-file/session-authored · counts, date range, provenance Identity scheduleData, active work-schedule filter and schedule range Generated vs imported is not recorded natively and is reported as such; data exists only after the Gantt panel extracts it. schedule.test.tsx (real IfcTask extraction through the mounted panel)
semantic (Coordination) · Linked records useSemanticSession via semantic-access.ts Record resolution, then validation finding · resolution/severity counts, profile, completeness Session refs; picker subscribes to the session Unavailable until the lazy panel loads; source text, revision URIs, endpoints and grants never captured; record IRIs lose userinfo, query and fragment; an in-flight question is also cancelled when the session changes (the adapter's subscribe). semantic.test.tsx
review (Coordination) · Review workspace useReviewAssistantCard (the card pinned with Ask about this card) via lib/review/assistant.ts One row per finding in the pinned card: source, native status verbatim, run temporality and gaps, lifecycle · card identity/state, sources, BCF topics, the person's decision kept apart The pinned card object; the picker subscribes to the pin Unavailable until a card is pinned. Historical findings and not-evaluated or no-longer-observed lifecycles are labelled, never resolutions; the assistant never proposes changing native statuses or BCF topics. review.test.tsx
layerDiff (Coordination) · Layers layerStack, layerStackDiff Added/modified/deleted path with composition resolution · counts, layer provenance [diff, stack, pathToId] No signatures/keys/documents. layer-diff.test.tsx (real IFCX layer diff)
lists (Quantities) · Lists listResult (runListFederated) Row with model/GlobalId/values · columns with units per model, native summary/groups Identity; new run stamp (recordListRun, carryListRun) Values in source units; mixed-unit sums withheld. lists.test.tsx (mounted run over the real sample; 31-model federation)
charts (Quantities) · Charts Dashboards; aggregation moved from ChartCard to lib/charts/card-aggregation.ts (shared) Bucket with value, count, unit · per chart status, measure, unit, unbucketed/unmeasured/unsupported Dashboard, slice and dataset inputs Element-filtered charts report filter-unresolved; no totals across charts. charts.test.tsx
cost (Quantities) · Cost readCostModels (moved out of useCostModels), bim.cost evaluateItem IfcCostItem with Amount/Currency/Dimension/diagnostics · per model state (no-cost-source/no-cost-data/cost-data), exact decimal root totals per currency and dimension [models, ifcDataStore] Never sums across currencies; nested items are not double-counted. cost.test.tsx (real parser over the sample plus an appended cost schedule; no committed IFC carries IfcCostItem)
measurements (Quantities) · Measurements measurementSlice; panel readout maths Distance/polyline/angle/radius with its own unit, stale flag · counts per kind, current distance total only Live refs incl. stale set Never summed across kinds; workspace points carry no model anchor (modelId: null). measurements.test.tsx
drawingMeasurements (Quantities) · 2D drawing measure2DResults, polygonArea2DResults Distance (m) or area (m²) · current drawing plane Lists and drawing refs Markup is not tagged with its section; text/cloud only counted. drawing-measurements.test.tsx
deviation (Quantities) · Point clouds New pointCloudDeviationStatistics (moved from panel state; teardown-registered) Scan asset statistics (m), no histograms · pooled statistics, tolerance share, clip range Identity record; run stamp Distances are to all scene meshes; COPC covers loaded chunks only. deviation.test.tsx, store/teardown-registry.test.ts
loadReport (Model) · Load report buildLoadReports(models) One original-load report per model Identity models Missing diagnostics are unavailable, never clean. ../load-evidence.test.ts
selection (Model) · Properties, Hierarchy Selection channels; effectiveElementData (moved out of the selection summary) Element with effective attributes, psets and quantities with units (edits applied) · selection size, per model/class counts, bounds Selection refs Material assignments use the shared native panel reader, with bounded members, full counts, metre thicknesses and unverified source-free markers (#7119). Generic material property sets share the native reader and unit formatting, with bounded groups and live edits; source-free reads remain unverified. Inherited type definitions use the shared mutation-aware panel reader with model/type provenance and independent bounds (#7104). Classifications reuse the canonical effective parser reader and shared population availability (#7139/#7131), including occurrence/type edits, exact schema code names, bounded paths and unknown source-origin markers/null unavailable totals. Relationships use the native query facade and panel alias merge (#7179), with exact record IDs, directions, model-local endpoints and independent row bounds. Shared availability marks missing current membership unknown; native authoring suppresses superseded source edges while read-only panels explicitly retain original source-origin rows. Documents use the shared native mutation-aware reader, bounded metadata and explicit source-origin/unavailable membership markers (#7187). Hierarchy has no header row, so its Discuss button is not placed. selection.test.tsx (real wall #262 checked against STEP text; mounted edit), selection-type.test.tsx, selection-materials.test.tsx (native source/edit/export/federation/wire-data controls), selection-classifications.test.tsx (ArchiCAD/SketchUp/Revit native writer/export/schema/federation/source-empty controls), selection-relationships.test.tsx (native SketchUp writer/export/alias/federation/source-free/spatial-authoring controls), selection-documents.test.tsx, selection-document-reader.test.tsx (native writer/export/current membership/source-free controls)
flow (Automation) · Flow flowDoc Graph structure Identity flowDoc No parameters or run state. With no graph open the capture is available and empty (no-graph), so a new graph can be described (flow.create, #6919). ../flow-proposal.test.ts, assistant tests
flowRun (Automation) · Flow run bar flowLastRun, warnings, artifacts Failing node results first, then their inputs, warning, artifact metadata, output preview, other node results, log · status counts, verdict, failing node ids, duration Run refs; run-window stamp after the run's own writes; a debug flow.patch diagnosis cites this run (#6919) Never artifact bytes; missing node rows on error do not mean success. Review-paused runs remain review-required; all native statuses are counted, and execution totals count only reports with evaluation lanes, excluding restored outputs and paused nodes. Parameters only on the failing branch (error or lane errors, plus inputs), script source withheld, credential-like text redacted, all withheld without a loaded node registry. flow-run.test.tsx, flow-run-debug.test.ts
script (Automation) · Script scriptLastResult/Error/Diagnostics Return value (bounded), diagnostic, log entry · counts per level Result refs; stamp on publication (useSandbox) Script source and diagnostic snippets excluded; credential-named fields in the return value are withheld (projection). Log text is passed as printed. script.test.tsx
document (Automation) · Document documents/activeDocumentId Block: kind, excerpt/bindings, image/chart metadata only Identity active document No data URLs. document.test.tsx

Existing source actions

Each registered adapter has descriptors for the existing Open, Discuss and picker Run hosts (#7160). Open names its canonical workspace panel and the actual panel command ID when one is registered; null explicitly means no palette command, while the existing openInHome workspace host remains available. Discuss requires native evidence readiness. Recipes derive their source launch and evidence availability from the same descriptors.

The picker currently hosts only the native clash producer. Other sources declare that their preparation uses the source panel controls. Clash Run requires an idle producer and an IFC model with flat geometry or its own recorded IFNS handoff. The check reads model records and array sizes, including hashing-disabled instanced-only models after the upload queue drains. A handoff proves input delivery; it does not prove current GPU residency, eligible elements or successful detection. The existing native gathering preflight and error result remain authoritative.

Explicit boundaries

Panel Reason (shown in the source picker under Not discussable)
Appearance Display styling settings, not an analysis result.
Model Authoring tools; edits are discussed through Changes or Change sets. Native builder/command matrices remain P15A.
Extensions Installed extensions and their permissions; an extension's output is discussed in the panel that shows it.
Session (collab) Live roster and permissions; no analysis result.
Sources Cloud connections and retrieval; credentials and endpoint grants are never evidence.
Presentation Saved camera views; no analysis result.
Assistant Saved conversations are reopened, not attached as evidence.
Environment Sky, lighting and sun-time display settings. No solar analysis is recorded; display settings are not daylight performance.

Remaining limits

  • Freshness during an in-flight request is checked on viewer-store changes and on changes of sources that expose subscribe, including the Linked records session and the separate Data validation side-choice store. IDS/rules/manual side changes cancel an attached validation request immediately through that subscription (#7102); validation-choice-request.test.tsx covers native request cancellation, partial-output clearing and unaffected sources.
  • Population-wide clash classification uses bounded batches over the full native run, with root-budget checks and exact accounted/unclassified membership (clash-classify-run.ts, clash-classify-run.test.ts, #6906). Further cross-analysis Review coverage and per-source reviewed actions remain P04/P18 work; this implementation is not independent classification-quality evidence.
  • Acceptance tests use committed real models (apps/viewer/public/samples/*, the committed BCF archive) and real native engines; tests that need tests/models/* fixtures skip when they are absent. Rendered-browser screenshots for each new source have not been recorded.