Skip to content

read-model: publish the selected filter receipt on the progress channel, so a filtered read can be drawn progressively #407

Description

@pawellisowski

What

ifc-reference-reader.read-model publishes parse / tessellate / batch / complete on the progress channel (#405). None of them carries the filter receipt (selected), which appears only in the complete node output.

Why it matters

A consumer that draws segments as they arrive cannot, while drawing, tell these two runs apart:

  • a bridge that honoured storeys: [L2] and is streaming one floor, and
  • a pre-1.2.0 bridge that ignored the filter entirely, exits zero, and is streaming the whole building.

read-model.md is explicit that this is the failure the receipt exists to catch, and that absence-means-cannot-answer applies to the input as well as the output. So a progressive consumer has no honest option but to refuse to draw filtered reads at all.

No count cap substitutes for it. floless's own pre-read estimate documents itself as not an upper bound (a type filter resolves with includeInherited: true while the probe's rows are exact leaf names), and the harm is correctness rather than size anyway — a legitimately large floor and a silently unfiltered building are the same number of objects. Inferring capability from capability ("segments arrived, so the bridge must be new enough to filter") reasons across two independently installed binaries, which is the move frame, selected, colorsAvailable and budget all exist to make unnecessary.

Repro (measured 2026-08-12, CLI 0.121.0, agent 1.4.0, bridge current)

2023-05-09 30 Daldy Street Model.ifc, 65.8 MB, 17,460 objects, batch-size: 100:

  • 237 node-progress records — 1 parse, 1 tessellate, 235 batch. Every batch record carries seq, done and an artifact descriptor.
  • No record carries selected, at any phase, including complete (which repeats the whole artifact's descriptor only).
  • The same run filtered to one storey behaves identically on the channel: nothing distinguishes it.

Suggested shape

Carry the receipt on the tessellate record — it is published once, after the filter has resolved to expressIDs and before the first segment, which is exactly the point at which a consumer must decide whether it may draw:

{ "kind": "node-progress", "node": "read",
  "data": { "phase": "tessellate",
            "selected": { "storeys": ["L2"], "candidates": 3767, "unmatched": [] } } }

A consumer then draws only when the receipt confirms the axes it asked for, and falls back to today's wait-for-complete otherwise. Absent selected on tessellate keeps its current meaning (this bridge cannot answer), so nothing existing changes.

Impact

floless.app ships progressive reference-model import today for unfiltered reads only, for exactly this reason — first geometry drops from ~64 s to ~6 s there. Filtered reads are the case where the wait is most often deliberate (a user narrows precisely because the building is too big), so they are the ones currently left out.

Metadata

Metadata

Assignees

No one assigned

    Labels

    qa-readyFixed and merged — awaiting QA verification

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions