Skip to content

SCALE-SEAM (96) — the as-built question's aggregate reader, and a witness that actually bounds - #413

Merged
ibuilder merged 3 commits into
mainfrom
claude/codebase-audit-roadmap-45656d
Sep 4, 2026
Merged

SCALE-SEAM (96) — the as-built question's aggregate reader, and a witness that actually bounds#413
ibuilder merged 3 commits into
mainfrom
claude/codebase-audit-roadmap-45656d

Conversation

@ibuilder

@ibuilderibuilder commented Sep 4, 2026

Copy link
Copy Markdown
Owner

What & why

apps/web/src/api/client.ts goes 711 → 698 (73 methods above the STAYING banner, 4 below).
Three methods move to apps/web/src/api/model.tslod500, setManufacturerInfo,
attachOmDocument — rejoining verifyAsbuilt and recordAsbuiltDimension, which (94) moved and
could only claim as "two known members, not necessarily all". This slice can say more than that,
and the reason matters more than the extraction.
Continues SCALE-SEAM in docs/roadmap.md.

Two bounding witnesses, derived independently, agreeing

openAsBuiltPanel in apps/web/src/viewer/tools/modelStatePanels.ts calls exactly five API
methods — read off that function's brace closure rather than grepped for, so it is the closure of a
scope and not a sample. Two of the five were already in model.ts.

Separately, the reader's own response type names its writer set field by field:

response fieldwriter
verified, by_method, readiness_pctverify_asbuilt — moved in (94)
with_dimensions, dimensions_out_of_tolerancerecord_asbuilt_dimension — moved in (94)
with_manufacturer, with_serialset_manufacturer_infomoves here
with_om_docs, om_documentsattach_om_documentmoves here

The backend route states it in prose: "Stamp elements with the verify_asbuilt recipe."

A reader whose response type enumerates its writers is a derived population. After eight slices
of sampling, that is the first grouping witness in this sequence that bounds a set rather than
illustrating one.

What corroborates is not what bounds

services/api/test_lod500.py reaches exactly three recipes — attach_om_document,
set_manufacturer_info, verify_asbuilt — and omits record_asbuilt_dimension, which is
unambiguously in this family. It agrees with the answer without being able to establish it. A
witness that misses a known member cannot bound anything, however exactly its members match.
Three slices claimed "and no others" off a test file and were wrong all three times; the fix is not
to read the test harder, it is to ask which question the test is able to answer at all.

What is NOT claimed

attachDocument stays in client.ts, takes a purpose parameter, and asbuilt_summary counts
any purpose-tagged document reference — so "every writer of with_om_docs moves here" is
false. The field map above is of the recipes each field was designed around, not of everything
that can set it. The claim that survives is the bounded one: the five methods openAsBuiltPanel
calls. This caveat is in the header, the size pin, the changelog and the roadmap — not only here.
(94) hedged in its PR while its artifact overstated; that is what this is avoiding.

Two sources disagree, and lose for the same reason

attach_om_document is implemented as a purpose-tagged wrapper of detailing.attach_document, and
authoring_matrix.py files it and set_manufacturer_info under data. The first is a shared
helper, the second a storage bucket — the two groupings (89) and (90) each had to reject.
The matrix is now the losing vote twice running after being right three times; a corroborating
source that keeps winning is the one that quietly stops getting checked.

Also fixed

The extraction helper terminated its brace count on the method signature line, so a signature that
wraps across two lines with no opening brace on the first read as a 3-line method.
attachOmDocument is 6.

Note on this branch's history

#412 was squash-merged, so origin/main carries (95) as b0e8281d while this branch still pointed
at the pre-squash 44a6ed44. The content diff between the remote branch and origin/main was
empty, so the branch held no unmerged work; the histories were reconciled with a -s ours merge
rather than a force-push, leaving the remote branch's commits intact.

Checklist (mirrors CONTRIBUTING.md)

  • Backend: cd services/api && python -m ruff check ../.. clean
  • Backend: test_file_sizes.py, test_claude_md_gates.py, test_roadmap_status.py,
    test_ruff_scope.py, test_reachable.py all exit 0; full suite running as a cross-check
  • Web: npx tsc --noEmit 0, npm run lint 0, npm run build 0;
    npx vitest run src/api 27 files / 119 tests
  • No import cycles introduced
  • CHANGELOG.md entry added (newest at top); docs/roadmap.md updated
  • Version bump — n/a, not a release PR
  • No secrets, no competitor names in shipped docs

🤖 Generated with Claude Code

https://claude.ai/code/session_01Tt2XKB83wwNt2nrMbK6eEA


Generated by Claude Code

Summary by CodeRabbit

  • New Features

    • Added model API support for:
      • Checking LOD 500 readiness.
      • Attaching O&M and warranty document references.
      • Recording manufacturer and product information.
    • These capabilities remain available through the API after being reorganized under model operations.
  • Documentation

    • Updated the changelog and roadmap to reflect the API organization changes and current client method count.

…trix loses
Moves `lodSummary`/`setLod` and `phasing`/`setPhase` out of `client.ts` into
`api/model.ts`. They answer one question — *what state are the model's elements
in, and set it?* — and `client.ts` goes 727 -> 711, 76 methods above the STAYING
banner.
The grouping is derived, not asserted:
- identical return shape `{ total, <x>ed, prop, counts: Record<...> }`;
- both writers are `(pid, guids, <enum>, publish) -> editIfc`;
- both readers are consumed by `viewer/tools/modelStatePanels.ts` (251, 316);
- both writers sit unwired and *adjacent* on `clientCallers.test.ts`'s UNCALLED
allowlist;
- `model.ts` already owned `/model/lod/census`, `/lod/handover-readiness` and
`/lod/assessment`, while the base distribution `/projects/{pid}/lod` was left
behind in `client.ts` — `lodSummary` was a sibling separated from its family.
`authoring_matrix.py` DISAGREES and is recorded as the losing vote rather than
elided. It files `set_lod` under `data` and `set_phase` under `lifecycle`,
because it categorises by the IFC output each recipe writes — an LOD stage tag
against `Massing_Phasing.Status`. Different property sets, same question, which
is (89)'s "storage is a HOW" trap. This is the first slice where the matrix has
been wrong after being right three running.
It also MEETS (94)'s objection rather than overriding it: that slice declined
`setPhase` because taking the writer alone would have stranded `phasing()`, the
reader/writer split (87) had to undo. Both halves move together here.
The four names are added to `surface.test.ts` because its floor is a slack
ratchet (788 actual vs 751 floor) — the count alone would not notice a loss —
and because the UNCALLED allowlist is about call sites, not the surface.
Verified: tsc 0, lint 0, `vitest run src/api` 27 files / 119 tests, build 0,
`test_file_sizes.py` / `test_claude_md_gates.py` / `test_roadmap_status.py` /
ruff all 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tt2XKB83wwNt2nrMbK6eEA
…ness that actually bounds
Moves `lod500`, `setManufacturerInfo` and `attachOmDocument` out of `client.ts`
into `api/model.ts`, rejoining `verifyAsbuilt` and `recordAsbuiltDimension`
which (94) moved. `client.ts` goes 711 -> 698, 73 methods above the STAYING
banner.
TWO BOUNDING WITNESSES, derived independently, agreeing:
- `openAsBuiltPanel` in `viewer/tools/modelStatePanels.ts` calls exactly five
API methods — read off that function's brace closure rather than grepped for,
so it is the closure of a scope and not a sample. Two of the five were
already in `model.ts`.
- The reader's own response type names its writer set field by field:
`verified`/`by_method` from `verify_asbuilt`;
`with_dimensions`/`dimensions_out_of_tolerance` from
`record_asbuilt_dimension`; `with_manufacturer`/`with_serial` from
`set_manufacturer_info`; `with_om_docs`/`om_documents` from
`attach_om_document`. The backend route says it in prose: "Stamp elements
with the `verify_asbuilt` recipe."
A reader whose response type enumerates its writers is a DERIVED population.
After eight slices of sampling, that is the first grouping witness here that
bounds a set instead of illustrating one.
WHAT CORROBORATES IS NOT WHAT BOUNDS. `test_lod500.py` reaches exactly three
recipes — `attach_om_document`, `set_manufacturer_info`, `verify_asbuilt` — and
OMITS `record_asbuilt_dimension`, which is unambiguously in this family. It
agrees with the answer without being able to establish it. Three slices claimed
"and no others" off a test file and were wrong all three times.
NOT CLAIMED, and said in the header, the pin, the changelog and the roadmap
rather than only in review: `attachDocument` stays in `client.ts`, takes a
`purpose` parameter, and `asbuilt_summary` counts ANY purpose-tagged document
reference — so "every writer of `with_om_docs` moves here" is false. The field
map is of the recipes each field was designed around, not of everything that
can set it.
Two sources disagree and lose for the same reason: `attach_om_document` is a
purpose-tagged wrapper of `detailing.attach_document`, and
`authoring_matrix.py` files it and `set_manufacturer_info` under `data`. The
first is a shared HELPER, the second a STORAGE bucket — the groupings (89) and
(90) each had to reject. The matrix is the losing vote twice running after
being right three times.
Also fixes the extraction helper: it terminated its brace count on the method
signature line, so a signature wrapping across two lines with no opening brace
on the first read as a 3-line method. `attachOmDocument` is 6.
Verified: tsc 0, lint 0, `vitest run src/api` 27 files / 119 tests, build 0,
ruff (the CI command, from `services/api`) 0, and `test_file_sizes.py`,
`test_claude_md_gates.py`, `test_roadmap_status.py`, `test_ruff_scope.py`,
`test_reachable.py` all 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tt2XKB83wwNt2nrMbK6eEA
PR #412 was squash-merged, so origin/main carries (95) as b0e8281 while this
branch still pointed at the pre-squash 44a6ed4. The content diff between the
remote branch and origin/main was empty before this merge, so the branch held
no unmerged work; -s ours keeps this branch's tree (origin/main plus (96)) and
reconciles the histories without rewriting the remote branch.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tt2XKB83wwNt2nrMbK6eEA
@coderabbitai

coderabbitaiBot commented Sep 4, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Team

Run ID: ac233318-cea2-4c3c-b79c-800db6acfc0f

📥 Commits

Reviewing files that changed from the base of the PR and between b0e8281 and 2f09a5c.

📒 Files selected for processing (6)
  • CHANGELOG.md
  • apps/web/src/api/client.ts
  • apps/web/src/api/model.ts
  • apps/web/src/api/surface.test.ts
  • docs/roadmap.md
  • services/api/test_file_sizes.py

Included review availability: Your plan provides up to 2 included reviews per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

Three API methods moved from ApiClient to the withModel mixin. The methods retain their API behavior and remain exposed through the client surface. Tests and SCALE-SEAM documentation now record the extraction.

Changes

Model API extraction

Layer / File(s)Summary
Move model methods into the mixin
apps/web/src/api/model.ts, apps/web/src/api/client.ts
attachOmDocument, lod500, and setManufacturerInfo now belong to the model mixin. The client-level definitions and method count were updated.
Preserve coverage and update slice records
apps/web/src/api/surface.test.ts, CHANGELOG.md, docs/roadmap.md, services/api/test_file_sizes.py
Surface tests retain coverage for the three methods. Changelog, roadmap, and file-size records describe slice (96) and the reduced client size.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk:⚪ Minimal · up to 2f09a

This change relocates three as-built API methods while retaining their client-facing availability and associated behavior. No concrete merge-blocking risk remains.

Suggested reviewers:cursoragent

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 4 files. (2 skipped: 2 …Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
Title check✅ PassedThe title clearly identifies SCALE-SEAM slice 96 and its primary as-built API grouping and bounding-witness rationale. It is somewhat long but remains specific and relevant.
Description check✅ PassedThe description explains the changes, rationale, scope boundaries, supporting evidence, exclusions, testing, documentation updates, and checklist status. It satisfies the repository template and provi…
Full details: Docstring Coverage

Explanation

Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 4 files. (2 skipped: 2 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/codebase-audit-roadmap-45656d

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ibuilderClaude

Copy link
Copy Markdown
OwnerAuthor

@coderabbitai review


Generated by Claude Code

@coderabbitai

coderabbitaiBot commented Sep 4, 2026

Copy link
Copy Markdown

@ibuilder I will review pull request #413.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@ibuilder
ibuilder marked this pull request as ready for review September 4, 2026 05:02
@strix-security

Copy link
Copy Markdown

Strix is installed on this repository, but we couldn't run this PR security review because this workspace's trial has ended. Add a card to resume code reviews here.

So far, Strix has reviewed 28 pull requests, surfaced 3 security issues (1 critical/high) and blocked 2 risky merges across this workspace.

@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because your trial has ended. Ask your workspace admin to add credits to resume reviews. Manage billing

@ibuilder
ibuilder merged commit ffb7b9f into mainSep 4, 2026
12 checks passed
ibuilder pushed a commit that referenced this pull request Sep 4, 2026
PR #413 was squash-merged, so origin/main carries (96) as ffb7b9f while this
branch still held the pre-squash commits. The content diff between the remote
branch and origin/main was empty before this merge, so the branch held no
unmerged work; -s ours keeps this branch's tree (origin/main plus (97)) and
reconciles the histories without rewriting the remote branch.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tt2XKB83wwNt2nrMbK6eEA
ibuilder pushed a commit that referenced this pull request Sep 4, 2026
PRs #412, #413, #414, #431, #432 and #433 were all squash-merged, so origin/main
carries their work as new commits while this branch still held the pre-squash
originals. Verified before merging: the content diff between the remote branch
and origin/main is empty, and so is the diff between this branch and
origin/main — every slice is already on main and nothing is unmerged on either
side.
-s ours keeps this branch's tree (identical to origin/main) and reconciles the
histories so the branch can fast-forward push, without rewriting the remote
branch's commits.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tt2XKB83wwNt2nrMbK6eEA
Sign up for freeto 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

@ibuilder@claude