Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -1185,6 +1185,52 @@ Reader and unwired writer on one panel — still the reason not to separate them

Pin 731 → 727. **80 above the banner, still no map.**

Thirty-ninth follow-on on the same version: **SCALE-SEAM (100)** — *the element-connection pair, and
a destination named at the strength the evidence supports*.

Two methods out of `client.ts` (`648 → 642`) into the existing `apps/web/src/api/model.ts`:
`elementConnections` and `connectElements`. No new mixin. **What they answer: what is physically
joined to what, and record a joint.**

### The backend names its own writer

The `/element-connections` route docstring reads: *"Author edges with the `connect_elements` recipe
(`POST /edit` with `{guid_a, guid_b}`)."* Reader and writer, one relationship type
(`IfcRelConnectsElements`), both marked B5. That is the (96) shape and it is what carries the pair.

### The destination argument is weaker, and is labelled as such

`model.ts` owns `modelGraphStats` — whose `by_rel` counts the IFC relationship graph **by relation**,
and `IfcRelConnectsElements` is one of those relations — plus `graphNeighbors`, which walks it. So
this pair is one relation of a graph the file already reads, plus its authoring verb.

**That is a specialisation, not an identity.** `modelGraphStats`/`graphNeighbors` are generic
traversal over every `IfcRel*`; these two are one relation with a verb attached. Recorded as the best
available home rather than a derived one — *the pairing is evidenced, the placement is a judgement,
and collapsing the two would be the overstatement this sequence keeps catching.*

### Two candidates rejected on checkable grounds

**`connections.ts` is the trap.** It is *data-source* connections — SQL, ACC, Procore — and shares
nothing with this but the English word. (97) found two version stacks behind one word; this is the
same collision in a **destination** rather than a source, and it is the file a name-based search
would have landed on first.

**`elements.ts`** holds element *attributes* and views — properties, 5D, colouring, QA, costs. A
relationship between two elements is not an attribute of either.

`addBasePlate` and `addShearTab` did **not** come despite sharing `services/data/src/aec_data/connections.py`
with these: a backend module is a HOW, the grouping (89) had to reject, and those two author
*physical* assemblies (plates, bolts) rather than `IfcRelConnectsElements` edges.

### Found while deriving

`add_connection_assembly` (B5, `IfcRelConnectsWithRealizingElements`) has **no client method
anywhere** in `apps/web/src` — a backend recipe with no web exposure, the same class (93) recorded
for three MEP recipes. Noted, not fixed.

`client.ts` is 60 methods above the STAYING banner and 4 below.

Thirty-eighth follow-on on the same version: **SCALE-SEAM (99)** — *the content half of a shelf the
destination's own first line already claimed*.

Expand Down
16 changes: 5 additions & 11 deletions apps/web/src/api/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,16 +178,6 @@ export class ApiClient extends withDetailing(withAnnotate(withCreDeal(withClient
ahead: number; on_track: number; behind: number; worst: string | null; note: string;
}>(`/projects/${pid}/progress/actuals`, { method: "POST", body: JSON.stringify({ actuals, planned }) });
}
/** B5: record a physical connection between two elements (IfcRelConnectsElements, LOD-350 coordination). */
connectElements(pid: string, guidA: string, guidB: string, description?: string, publish = true) {
return this.editIfc(pid, "connect_elements", { guid_a: guidA, guid_b: guidB, ...(description ? { description } : {}) }, publish);
}
/** B5: the element-to-element connection graph (IfcRelConnectsElements) — pairs + per-element degree. */
elementConnections(pid: string) {
return this.json<{ count: number; elements_connected: number; max_degree: number;
connections: { a: string; a_class: string; b: string; b_class: string; description: string | null }[] }>(
`/projects/${pid}/element-connections`);
}
/** W11 F0: establish the view-keyed representation contexts (Model+Plan; Body/Axis/Box/Annotation/
* FootPrint) the drawing pipeline needs. Idempotent. */
ensureContexts(pid: string, publish = false) {
Expand Down Expand Up @@ -545,7 +535,7 @@ export class ApiClient extends withDetailing(withAnnotate(withCreDeal(withClient
// through (87) worked through, and they are recorded here as DECIDED rather than pending.
//
// **THIS IS NOT THE END OF SCALE-SEAM, and a previous version of this banner implied it was.**
// 62 methods still sit ABOVE this line — `disciplineTree`, `classify`, `specManual`, `editUndo`,
// 60 methods still sit ABOVE this line — `disciplineTree`, `classify`, `specManual`, `editUndo`,
// `energyModel`, `propmapPlan`, `camReconciliation` and the rest. They were never inside the
// CX-1 banner, so no map has ever covered them. The UNFILED map described the TAIL of this file,
// not the file.
Expand Down Expand Up @@ -620,6 +610,10 @@ export class ApiClient extends withDetailing(withAnnotate(withCreDeal(withClient
// `authoring.ts`, leaving 62. Role-for-role parallel with the family shelf already there; that
// file's first line had claimed "family/content shelf" while holding no content method.
//
// (100) took the ELEMENT-CONNECTION pair — `elementConnections`/`connectElements` — to
// `model.ts`, leaving 60. The route docstring names its own writer. `connections.ts` is the trap:
// that file is DATA-SOURCE connections and shares only the word. Reasoning in `model.ts`.
//
// the four that stay enumOptions, searchAll, attachmentUrl, templates
enumOptions(pid: string) {
return this.json<Record<string, Record<string, string[]>>>(`/projects/${pid}/enum-options`);
Expand Down
42 changes: 42 additions & 0 deletions apps/web/src/api/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,38 @@
*
* SCALE-SEAM ⓭ adds E57 scan ingest — *can we bring this scan in?* Status plus convert.
* Admin audit/error stayed.

* **SCALE-SEAM (100) adds the ELEMENT-CONNECTION pair** — `elementConnections` (the
* `IfcRelConnectsElements` graph: pairs, per-element degree) and `connectElements` (the verb that
* adds an edge). *What is physically joined to what, and record a joint.*
*
* **The pair is bound by the backend naming its own writer**, the (96) shape: the
* `/element-connections` route docstring reads *"Author edges with the `connect_elements` recipe
* (`POST /edit` with `{guid_a, guid_b}`)."* Reader and writer, one relationship type, both marked
* B5. That link is strong and is what carries the pair.
*
* **The DESTINATION argument is weaker than the pairing argument, and is stated at that strength.**
* This file owns `modelGraphStats`, whose `by_rel` counts the IFC relationship graph *by relation* —
* and `IfcRelConnectsElements` is one of those relations — plus `graphNeighbors`, which walks it.
* So this pair is one relation of the graph this file already reads, plus its authoring verb. *That
* is a SPECIALISATION, not an identity: `modelGraphStats`/`graphNeighbors` are generic traversal
* over every `IfcRel*`, while these two are one relation with a verb attached.* Recorded as the
* best available home rather than a derived one.
*
* **Two candidates were rejected on checkable grounds.** `connections.ts` is the trap: it is
* DATA-SOURCE connections — SQL, ACC, Procore — and shares nothing with this but the English word.
* *(97) found two stacks behind one word; this is the same collision in a destination rather than a
* source.* And `elements.ts` holds element ATTRIBUTES and views (properties, 5D, colouring, QA,
* costs); a relationship between two elements is not an attribute of either.
*
* *`addBasePlate` and `addShearTab` did NOT come, though they share `connections.py` with these.*
* A backend module is a HOW — the grouping (89) had to reject — and those two are W11 B6 authoring
* PHYSICAL assemblies (plates, bolts), not `IfcRelConnectsElements` edges. Different output,
* different question, same file on the server.
*
* *Recorded while deriving this: `add_connection_assembly` (B5,
* `IfcRelConnectsWithRealizingElements`) has NO client method anywhere in `apps/web/src` — a
* backend recipe with no web exposure, the same class (93) recorded for three MEP recipes.*
*
* SCALE-SEAM ⓳ adds publish history — *what changed between publishes?* Version list,
* element diff, cost delta, and the submit/approve/reject review gate. They were **not**
Expand Down Expand Up @@ -871,5 +903,15 @@ export function withModel<TBase extends Ctor<NeedsEditIfc>>(Base: TBase) {
setManufacturerInfo(pid: string, guids: string[], opts: { manufacturer?: string; model_label?: string; production_year?: string; serial?: string; barcode?: string } = {}, publish = true) {
return this.editIfc(pid, "set_manufacturer_info", { guids, ...opts }, publish);
}
/** B5: record a physical connection between two elements (IfcRelConnectsElements, LOD-350 coordination). */
connectElements(pid: string, guidA: string, guidB: string, description?: string, publish = true) {
return this.editIfc(pid, "connect_elements", { guid_a: guidA, guid_b: guidB, ...(description ? { description } : {}) }, publish);
}
/** B5: the element-to-element connection graph (IfcRelConnectsElements) — pairs + per-element degree. */
elementConnections(pid: string) {
return this.json<{ count: number; elements_connected: number; max_degree: number;
connections: { a: string; a_class: string; b: string; b_class: string; description: string | null }[] }>(
`/projects/${pid}/element-connections`);
}
};
}
2 changes: 2 additions & 0 deletions apps/web/src/api/surface.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,8 @@ describe("the API client's public surface", () => {
"elementDetailing", "classify", "applyDetailingRules", "validateDetailing", "attachDocument",
// (99) the content shelf -> authoring.ts, joining the family triple it parallels.
"contentCatalog", "placeContent", "importContent",
// (100) the IfcRelConnectsElements reader + its writer -> model.ts.
"elementConnections", "connectElements",
]) {
expect(surface.has(k), `${k}() vanished — a call site is now broken`).toBe(true);
}
Expand Down
26 changes: 25 additions & 1 deletion docs/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -3135,7 +3135,7 @@ verbs, with a command bar as the escape hatch to everything); and **role-shaped
banner is renamed UNFILED → STAYING and now says exactly that; the next slices work the 126,
and there is no map for them yet.

**(88)–(99) took sixty-four of those 126 — 62 remain, and there is STILL no map.** A new
**(88)–(100) took sixty-six of those 126 — 60 remain, and there is STILL no map.** A new
`apps/web/src/api/operations.ts` holds the operate-phase cluster: *the building is built and
running.* Maintenance (`cmmsGeneratePm`, `cmmsKpis`), consumption (`energyActual`,
`energyBenchmarkStatus`, `esgSummary`), condition and capital (`fcaIndex`, `fcaPortfolio`,
Expand Down Expand Up @@ -3390,6 +3390,30 @@ verbs, with a command bar as the escape hatch to everything); and **role-shaped
true, and this one had been wrong for as long as it had existed.* It is the smallest possible
instance of the drift these instructions keep warning about.

**(100) took the ELEMENT-CONNECTION pair to `apps/web/src/api/model.ts`** —
`elementConnections` (the `IfcRelConnectsElements` graph) and `connectElements` (the verb that adds
an edge). **The pair is bound by the backend naming its own writer**, the (96) shape: the
`/element-connections` route docstring says *"Author edges with the `connect_elements` recipe."*

**The DESTINATION argument is weaker than the pairing argument, and is recorded at that strength.**
`model.ts` owns `modelGraphStats`, which counts the IFC relationship graph BY RELATION —
`IfcRelConnectsElements` being one — and `graphNeighbors`, which walks it. So this is one relation
of a graph the file already reads, plus its verb: **a specialisation, not an identity.** *The
pairing is evidenced; the placement is a judgement. Collapsing the two into one confident sentence
is the overstatement this sequence keeps catching, so they are stated separately.*

*Two candidates rejected on checkable grounds.* **`connections.ts` is the trap** — it is
DATA-SOURCE connections (SQL, ACC, Procore) and shares only the English word; **(97) found two
version stacks behind one word, and this is the same collision in a destination rather than a
source**, on the very file a name-based search lands on first. And `elements.ts` holds element
ATTRIBUTES and views, whereas a relationship between two elements is not an attribute of either.
`addBasePlate`/`addShearTab` also did not come despite sharing `connections.py`: a backend module is
a HOW, and those author PHYSICAL assemblies rather than relationship edges.

*Found while deriving, recorded not fixed:* `add_connection_assembly` (B5,
`IfcRelConnectsWithRealizingElements`) has **no client method anywhere** in `apps/web/src` — a
backend recipe with no web exposure, the class (93) recorded for three MEP recipes.

**(93) finished SCALE-SEAM ⑲.** Two methods to the existing `apps/web/src/api/mep.ts` —
`connectMep` and `addMepFitting` — which that file has claimed by name since ⑲ under the note
*"call `editIfc` (`/edit`) and stay"*. **That note recorded the symptom without diagnosing the
Expand Down
2 changes: 1 addition & 1 deletion services/api/test_file_sizes.py

Large diffs are not rendered by default.