Repository navigation
feat: deliver the fork delta since the 1108c sync wave - #853
Merged
Blogbotana merged 537 commits intoNov 9, 2026
Merged
Conversation
A cumulative fork branch once rolled back other people's upstream commits on its way to a mirror PR. The gate makes that failure mode impossible to repeat silently: it refuses a branch whose base is behind upstream/master (printing how many upstream commits are missed), refuses deletions of files that exist in upstream/master unless each path is passed to --allow-delete, and prints a changed-files and +/- lines summary otherwise. The script is read-only bash + git; CONTRIBUTING.md gains the matching step 8. Co-Authored-By: Claude Code <[email protected]>
…from Apibim-com/bug/r01-, Display foreign references instead of validating, bug: admit references under model-sized USD budg
git detects renames by default, so an upstream file moved to a new path showed as R and slipped past the deletion check of upstream-pr-gate.sh; the old path vanished from upstream without hitting --allow-delete. Pass --no-renames so the moved-from path lands in the deleted list. Co-Authored-By: Claude Code <[email protected]>
…er interface (Apibim-com#733), Install the software Vulkan prerequisite for Lin, Show axis labels and readable actions in the grid editor, Complete T01.6 local grid line tools and interactiv The workbench conflict was resolved by the owner's decision to adopt the upstream Inter interface wholesale (apps/beamcraft-ui/src/app/workbench.rs taken from upstream); every other file follows the fork-sync contract.
…ivery (#263) * docs: accept MVP amendments and map the M5 CLI delivery dependencies * docs: record published CLI slices and avoid duplicate prerequisite work * docs: consolidate the master CI repair reference * docs: record merged P14 and current-master CI repair
…eshes (P13) (#270) * feat: persist circular member paths with true arc quantities (P13) * fix: retain sweep deviation admission before arc length capacity * docs: state the P14 placement boundary for circular members * fix: carry the curved flag through the fabrication member adapter --------- Co-authored-by: axisrow <[email protected]>
chore: add an upstream pull request gate script
…requisite) (#281) * fix: use the shared fixture in D07 drafting tests * feat: replace and clear plate corners in one linked-group edit * fix: return a public typed CLI capacity error for corner lists * fix: qualify the D07 JSON limit across parent fixture updates --------- Co-authored-by: axisrow <[email protected]>
* chore: run the local test gate with nextest The local gate (CLAUDE.md, CONTRIBUTING.md, the PR template and fork-sync.sh gate 3/3) still ran `cargo test --workspace`, which executes the 151 test suites serially: 382 s warm. nextest, already the CI runner and documented in docs/development.md, runs the same 1827 tests with process-level parallelism in 132 s (measured locally, #285). Doctests stay a separate gate line because nextest never runs them, exactly like CI. Part of #285. Co-Authored-By: Claude Code <[email protected]> * chore: describe the nextest plus doctest gate in fork-sync usage Same stale-gate class as the main change: the usage block still named bare 'test --workspace' as the gate step. Co-Authored-By: Claude Code <[email protected]> --------- Co-authored-by: axisrow <[email protected]> Co-authored-by: Claude Code <[email protected]>
* test: build the CLI integration suites into one test binary The 76 integration suites of beamcraft-cli each linked their own ~200 MB test binary, and `cargo test` runs test binaries one after another, so a run waited for the slowest case of every suite in turn while the other threads sat idle. One `cli` binary (tests/cli.rs, one module per suite file) links once and lets libtest schedule all 454 cases on one pool. Every suite file stays where it is and keeps its cases; only the shared `support` module moves to the crate root. The two suites that re-run their own binary as a crash child now name the child by its module path. The nextest `fast` profile filters the same suites by module, and documented `--test <suite>` commands become `--test cli -- <suite>::`. `macos_icon` checks the desktop app's icon and stays its own target. Claude-Session: https://claude.ai/code/session_01HF6nmZMJd1rwsnpfakAu3Z * test: run the independent offline-client cases side by side The C05-01 suite-scale case authored 32 plates in workspace A and then 32 in workspace B one process at a time; with every commit re-verifying the draft history this was the longest CLI test by far. The two workspaces are separate stores, as two offline machines would be, so they are now authored on two threads; publication, rebase and every assertion stay sequential and unchanged. The crash-window case looped over seven commit points with a fresh fixture each; each point is now its own test so they run in parallel and a failure names its window. Claude-Session: https://claude.ai/code/session_01HF6nmZMJd1rwsnpfakAu3Z * test: fail when a CLI suite file is not part of the cli binary With `autotests = false`, a new file under apps/beamcraft-cli/tests that is not declared in tests/cli.rs would never build or run, silently. A guard test now reads the directory and requires every suite file to be a module of the binary. docs/development.md says how to run one suite. Claude-Session: https://claude.ai/code/session_01HF6nmZMJd1rwsnpfakAu3Z --------- Co-authored-by: Claude <[email protected]>
… work (A13, A03, A04, A12.3, P13, CLI test speed-ups) (Apibim-com#734) Conflicting files keep the upstream version: the merged delivery is the new superset and carries the review follow-ups (A13 persistent ordinals and retired identities, fresh instance bodies, the A04 kind guard, the edit-drafting replay fingerprint and the restored strict drafting test). Fork-only infrastructure keeps its fork version. Co-Authored-By: Claude Code <[email protected]>
…C06) (#296) * feat: compensate a published operation as a forward draft operation (C06) A compensation appends one ordinary evidence-bearing draft operation that restores the target's semantic write groups to the accepted state before it, materialized against the current published head with the rebase materializer. The C04 planner runs first and refuses with the bounded report naming every accepted operation after the target that intersects the target's footprint, so a later edit by another actor is never rolled back or silently overwritten. The identity replays exactly once across processes, entry points and crash windows; the compensated draft publishes through the ordinary path. The wire operation compensate and the coordinator-compensate client run the same local semantics with the token actor, who must own the workspace. Acceptance C06-01..C06-07 is executable in tests/compensation.rs. Refs #293, refs #12, refs #160. * fix: refuse a compensation on a dirty draft so unsent work is never dropped The compensation candidate replaces the whole draft content, so a draft with unsent operations would silently lose them. The precondition now requires a clean draft (draft head at the synced sequence) with a typed remedy, like the C03/C04 discipline of retaining or explicitly renouncing unsent work; the disjoint-edit acceptance now publishes its extra plate before compensating and asserts it survives. --------- Co-authored-by: axisrow <[email protected]>
…03) (#294) The coordinator wire only spoke head and publish, so a client had to run rebase-workspace as a separate local process between publications. The new rebase operation runs the same guarded local rebase with the token-derived actor as the only trusted actor, answers the same typed result plus the current head, never moves the published head, and replays one request identity across both entry points and crash windows. Acceptance C03-R01..C03-R08 runs against a real serve-coordinator process in tests/coordinator_rebase.rs. Refs #290, refs #12, refs #160. Co-authored-by: axisrow <[email protected]>
…ead refusal branch (#297) The coordinator's rebase (C03, #294) and compensation (C06, #296) both derived the trusted actor by re-parsing the authenticated id's canonical text, so every request carried a refusal branch that validation had already made unreachable. Uuid7::from_bytes builds the typed host id from the model id's validated big-endian bytes instead; the canonical text is derived, so the construction is infallible and the dead INVALID_ARGUMENT branch is gone from both wire operations. A host unit test pins the canonical formatting and its round trip through parse. The acceptance specification's header still listed the coordinator rebase (C03) and compensation (C06) as specified only; both run executable as of 2026-10-30 (tests/coordinator_rebase.rs, tests/compensation.rs), so the header now points at the suites and names the semantic-conflict workflow (C04) as the part that remains specified only. Refs #294, refs #296, refs #12, refs #160. Co-authored-by: axisrow <[email protected]>
PR #288 moved gate 3/3 of tools/fork-sync.sh to cargo nextest, but the cron runner never installed it, so every pending sync died with "no such command: nextest", rolled the merge back and exited 3, leaving the fork behind upstream. Reuse the pinned taiki-e/install-action step from ci.yml with the same pinned nextest version. Co-authored-by: axisrow <[email protected]> Co-authored-by: Claude Code <[email protected]>
The first sync after the nextest fix reached the full test gate and died in beamcraft-ui: a UI test panics with "a native or software wgpu adapter is required" on the adapter-less ubuntu runner. Upstream CI installs mesa-vulkan-drivers for the same tests; give the sync runner the same package so its gate runs the same code in the same environment. Co-authored-by: axisrow <[email protected]> Co-authored-by: Claude Code <[email protected]>
…ontext parser an, feat: simplify properties and create parts inter
…uthored-By trailer (#301) * feat: fail CI when a PR commit or description carries the Claude Code attribution trailer * fix: take the PR description from the event payload so the scan cannot fail silently --------- Co-authored-by: axisrow <[email protected]>
#309) The K4 row and the deferred paragraph still said C03-C06 were deferred, but master has moved past that: C03 (#294) and C06 (#296) are merged, C04 is delivered (upstream #503 closed completed) and C05 is delivered at suite scale (32 + 32) with its 1000 + 1000 acceptance open (#292, upstream #504). The row now states the per-package facts in the K6 style, the deferred paragraph lists the remaining post-MVP collaboration work instead, and the later-work paragraph names the M6 cards C07 and C08 (upstream #506, #507) that the roadmap did not mention. Refs Apibim-com#738, Apibim-com#739. Co-authored-by: axisrow <[email protected]>
…319) The C04 rows have been executable since PRs #171 (mechanics) and #180 (C04-01..C04-10), but the status line still said "remains specified only". The implemented, tested conflict-report budget is MAX_REBASE_CONFLICTS = 256 (crates/engine/src/rebase.rs), not the sketched 4096. Fork issue #291. Co-authored-by: axisrow <[email protected]>
The original Q01 scenario ends at numbering, publication and a drawing; the expanded acceptance (fork #318, upstream #334) asks the story to carry the model tools, views/filters, storey model data, invalid-input and cancellation regressions, and exact stored outputs, with a record of what actually executed. The new suite adds those steps as one fresh-binary story next to the delivered one, and docs/design/q01-alpha-matrix.md separates the executed cells (macOS/Apple silicon, CLI plus the existing run_ui suites) from the cells that stay open, with the open dependency issues named as reasons. The record is evidence, not a gate pass. Co-authored-by: axisrow <[email protected]>
* docs: add the I04 user-attributes design note The storage, engine and CLI design for defined user attributes (text, number, integer, boolean, choice, with units) on any element, their attribute sets, and the unknown-attribute rule: values shown, never dropped, definitions mutable in a dedicated schema scope. * feat: add typed user attributes on any element (I04) Defined attributes (text, number, integer, boolean, choice, with units and named sets) live as mutable schema metadata under /World/Definitions/Attributes; values are bim:attr:<name> properties of any element, written through the existing edit publication path. A value may outlive its definition: such an unknown attribute is shown by attribute-get and never dropped, because every edit is a targeted property write. Commands: attribute-define, attribute-undefine, attribute-set, attribute-clear, attribute-get, attributes. A schema change conflicts as one AttrSchema target; a value change writes only the element's attributes group. The changeset dependency encoding gains a v3 magic without retagging v2, and the conservative changeset reads cover the new group. * docs: fix the broken intra-doc link of the attribute module * fix: align the attribute view, note and unit admission with review values_of no longer presents a leftover value as a defined one when the attribute was re-defined with another type (it stays in the unknown list alone); the design note names NOT_FOUND for setting an undefined attribute; a unit label refuses control characters, as its comment promised, since it is stored verbatim in USD and JSON. --------- Co-authored-by: axisrow <[email protected]>
windows-latest currently resolves to the windows-2025-vs2026 image, whose hosts fail the install-action step with the bash startup failure (actions/partner-runner-images#169) before any test starts; reruns of the failed master shards landed on the same image twice. windows-2022 is the previous stable pool and avoids the affected image, mirroring the macos-15 pin for the same class of outage. Co-authored-by: axisrow <[email protected]>
The expanded Q01 story walked every delivered modelling surface except the P14 section placement. Fold it in as its own published store, so the numbered frame keeps the counts the manual runbook records: a plane/depth placement with offsets is a pure shift with the exact moved world box, the end offsets shorten the solid while the authored axis stays put, the flagless default stays centred (no placement record), refusing placements write nothing, and the publication round trip preserves the exact placements, bounds and meshes. Covers fork issue #318 (Q01 expanded alpha, P14 cell). Co-authored-by: axisrow <[email protected]>
…om#769 follow-up (#523) * docs: record the owner decisions on items 4 and 6a-6d of the Apibim-com#769 follow-up The mirrored follow-up (#500, upstream Apibim-com#769) closed its test items with #488, #493, #502, #503 and #504; the owner recorded the remaining decisions on 2026-11-06 so the open questions resolve in the plan document: Windows coverage stays out of the pull-request route with the platform track pinned to the windows-2022 pool (#521), bent-plate features follow the developed-contour path of the A10 design (6a), the faceted IFC export stays (6b), snapping and welding keep facets with the carried analytic metadata (6c), and a B-Rep kernel stays out of scope, tracked as #522 (6d). * docs: mark the 2026-11-06 entries as fork-owner decisions For the upstream mirror the decision-maker is the upstream maintainer (Blogbotana), and Apibim-com#769 has no answer from them on items 4 and 6. The recorded decisions are the fork owner's, so the entries name that subject explicitly and the upstream mirror is left open instead of reading as settled. --------- Co-authored-by: axisrow <[email protected]>
…#525) * fix: decide the bolt grip from the actual faces, not the parts' boxes A rotated part inflates its conservative box along the shank, so a knee-brace group's length requirement exceeded every real library length and #514 had to add a 160 mm entry to unblock the demo commit (issue 519, defect B). The crossing admission keeps the A05 box rule unchanged; the grip itself now pairs the shank's crossings with the world triangles of each part's stored scene mesh: exact under any placement rotation, a bearing inside a part grips its remaining material, and a bearing over a pre-drilled hole grips nothing there. A part without a usable stored mesh falls back to its conservative box, which errs long and never under. * docs: link the face-interval rule without naming the private helper * fix: heal a bolt group's own holes and merge the shared-edge double hit A generate group's re-place ran over the meshes it rewrote itself: its own clearance holes are coaxial with the shanks, so the grip collapsed and a plain rename stored a shorter length while a retry of the accepted create mismatched into OP_ID_REUSE. The parts whose hole records the group owns now grip per their conservative box wherever the axis crosses no face. A ray through a shared triangle edge hit both triangles a few ulps apart and paired into zero-length intervals, collapsing the grip to nothing; hits that land on one boundary now merge into one crossing (review of PR #525, issue 519 defect B). --------- Co-authored-by: axisrow <[email protected]>
Reverts the data change of #514 (b633c22). That entry existed only to absorb the engine's conservative-box grip for the knee-brace joint; since #525 the joint resolves its real ~60 mm grip from the actual faces, so no shipped bolt needs the 160 mm length any more and the sample list returns to its previous stock lengths. Co-authored-by: axisrow <[email protected]>
…eavy R01 test (#530) * docs: pair nextest with doctests in full-suite claims and bound the heavy R01 test nextest does not run doctests, and the development docs placed standalone nextest lines beside CI's component checks without saying so: a reader following them could believe they ran the full gate. State the pairing rule (nextest plus cargo test --workspace --doc, or the recorded gate that runs both), recommend reading a sweep's verdict from redirected output rather than a pipe, and note the omission in CLAUDE.md. Give the load-sensitive R01 bounding test its own 240-second budget through a versioned nextest override instead of weakening it: its 9,500-prim source is what proves the bounded reply, and under concurrent heavy local builds it outgrows the default 120 seconds and dies on the deadline like a regression. Fork issue #529 (mirror of upstream Apibim-com#767). * fix: name the cli test binary in the timeout override filter The R01 suites are modules of the one `cli` integration binary, so the override's `binary(reference)` matched no binary and nextest refused the config at parse time, failing the gate's prepare stage. Filter by the real binary and the test's full module path; validated with `cargo nextest show-config test-groups`. * fix: match the timeout override by exact test name only --------- Co-authored-by: axisrow <[email protected]>
…ce 3) (#531) * feat: preview the bolt row and its holes from the bench form (V19 slice 3) The Bolt bench could place and edit a group, but the viewport showed nothing until the command committed: a wrong offset or spacing became visible only after publishing. This adds the display-only preview the owner chose for V19 (the projected 2D markers of the slice plan): the row line, a marker at every bearing and the outline of every generated hole, drawn over the active view while the form fills. The engine decides the preview, as it decides the commit: preview_row derives the frame, the bearings and the expanded spacings from the group's inputs alone (the parts' reachability and the length stay the commit's decision), and generate_holes now takes that row, so the one hole decision serves both the commit and the preview. The UI reads the parts' bounds, placements and member identities from the snapshot it already shows, and fetches the form's definition by the read-only show-library a user types, once per library-and-designation pair of the loaded listing. A refusal draws nothing; Cancel still publishes nothing and the saved result stays the CLI's. * fix: lift the preview's hole rings into world space by the part translation The engine's generated hole polygons are plate-local XY; the preview lifted only the mid-plane z, so a translated plate drew its rings off the bearings the commit cuts (review finding on PR #531). The world lift is the part's own translation - identity rotation is the only way a plate reaches the hole decision - extracted into hole_world_rings with its own translated-plate test. --------- Co-authored-by: axisrow <[email protected]>
#528) * feat: ride a built-in catalogue set as the default viewport colouring (issue 526) * feat: pin the owner-approved catalogue hues (issue 526) * fix: keep the automatic catalogue evaluation off the command lane (issue 526) * docs: state where the catalogue hues are recorded (issue 526) * fix: keep the automatic catalogue default quiet and out of perf runs (issue 526) * docs: cite the recorded colour decision in issue 526 --------- Co-authored-by: axisrow <[email protected]>
… rehearsal) (#533) * fix: ship the fastener and section libraries in release packages A clean install could not place a bolt group: the UI bolt panel asks for a fastener library path and the shipped files were not in the archive (rehearsal round 1, fork issue #532). * fix: flatten branch separators in the release dispatch package tag A workflow_dispatch on a branch ref put the raw ref name into the archive name, so the smoke test could not find the binaries (rehearsal round 3, fork issue #532). * chore: restart CI checks after a wedged hosted runner --------- Co-authored-by: axisrow <[email protected]>
* feat: add screenshot-view, a fitted PNG render of a store head Visual acceptance needs screenshots without anyone's hands: the window's default camera sits inside the model and driving the live window loses the focus war to other apps. The new command renders the verified head through the native viewport renderer, the same Renderer the window draws with, now exposed by beamcraft-ui --screenshot with the camera fitted over the whole scene; the CLI relays it by the same neighbourhood rule the window uses to find the CLI, so no crate depends on another app. * test: list the screenshot suite as a module of the ui test binary autotests is off, and the meta-test requires every tests/*.rs file to be a module of tests/ui.rs; a separate [[test]] target never built and failed the gate. * feat: point the screenshot camera with --yaw and --pitch Side views like a detail drawing need a direction other than the fitted default: the angles are radians, pitch above the horizon, refused outside the orbit bounds, and None keeps the fitted frame byte-compatible with the previous behaviour. The CLI relays the options verbatim; the ui validates them where the camera lives. * ci: retrigger checks after a cancelled run left a tombstone * fix: refuse screenshot-view inside a session with the typed word Route::ScreenshotView was missing from the session refusal list, so inside a session the word fell through dispatch into run_store_command and was refused with a generic INVALID_ARGUMENT over its unknown --out instead of the typed cannot-run-inside-a-session refusal export-view gets. Add it to the matches! and cover the refusal with a session test. --------- Co-authored-by: axisrow <[email protected]>
…ls (#536) * feat: give screenshot-view the camera controls of a detail view Matching a reference picture needs the orthographic projection, a zoom and a screen-plane pan, not only the orbit direction: a perspective frame of the whole store never lines up with a drawing-style view of the joint. --projection ortho, --zoom and --pan X,Y ride on the fitted camera like the window's own navigation; absent keys keep the fitted perspective frame byte-compatible. * feat: colour the screenshot with the default catalogue set A screenshot-view render drew every element in the neutral shaded colour while the window colours a freshly opened model by the built-in Catalogue set (526): plates yellow, members blue-grey. Evaluate the same set by the window's own query-elements path and build the scene with the overlay, so a screenshot looks like what the viewport shows (issue 535). Only the built-in set: a headless screenshot reads no colour-sets file. * fix: admit a fully specified screenshot-view invocation The camera options grew the KEY VALUE-pairs bound to 18 argv entries, but the command now documents ten options, and a call naming every one of them is twenty entries long and was refused as malformed. Raise the bound to cover the documented surface and pin it with a fully specified invocation in the end-to-end test. --------- Co-authored-by: axisrow <[email protected]>
…#538) Matching the base-joint demo against its drawing-style reference picture showed the palette, not the geometry, off (issue 537): concrete took the member hue because the Catalogue rules match the element type only, and the renderer's dark clear colour had no light alternative. screenshot-view gains `--colour-set (Catalogue | "Part classes" | FILE)`, default Catalogue, keeping today's output byte-for-byte when absent. A builtin preset name picks that preset; anything else is read as a colour-sets file and decoded by the existing `colour_sets::Sets::decode`, refused unless it holds exactly one set of its own; the chosen set is evaluated by the same `colour_sets::evaluate` path the window uses. `--background light|dark`, default dark, sets the renderer's public `background` field to a paper tone near `rgb(245, 246, 248)` after construction, so the screenshot's own lit-pixel accounting follows it. The flags ride the CLI adapter verbatim into `beamcraft-ui --screenshot` like the camera options; the ui's argv caps rise by the two new pairs. The registry entry and the help section name the new keys, COMMANDS.md is regenerated, and the end-to-end suite asserts the light background bands, the file set's hue by channel dominance, the built-in preset path and the three refusals. Co-authored-by: axisrow <[email protected]>
…pibim-com#835 closing-reference policy BeamCraft-Test-Gate: {"version":1,"commit":"025c17c88a475171dd6a2f8171436bdedfc637e7","tree":"2a6318ef7251f92e952df1cf7ad515e7e89b5b45","base":"025c17c88a475171dd6a2f8171436bdedfc637e7","merge_parent":"1cd0aafb9814e524c3cdd7a023303cb7aaba755a","os":"macos","arch":"aarch64","scope":"full","ui_independent_reason":null,"ui_tested":true,"rustc":"rustc 1.99.1 (58cf8f9c3 2026-10-13)","cargo":"cargo 1.99.1 (5f94df478 2026-08-27)","nextest":"cargo-nextest 0.9.149 (3fe4ef319 2026-10-20)\nrelease: 0.9.149\ncommit-hash: 3fe4ef31972f24e0c94cfe291718eab0fe678260\ncommit-date: 2026-10-20\nhost: aarch64-apple-darwin","expected_tests":2665,"executed_tests":2665,"ignored_tests":["beamcraft-test-gate::process::process_fixture"],"source_unchanged":true,"stages":[{"name":"format","exit_code":0,"elapsed_ms":2863,"timed_out":false},{"name":"clippy","exit_code":0,"elapsed_ms":33237,"timed_out":false},{"name":"prepare","exit_code":0,"elapsed_ms":90681,"timed_out":false},{"name":"tests","exit_code":0,"elapsed_ms":232292,"timed_out":false},{"name":"doctests","exit_code":0,"elapsed_ms":2917,"timed_out":false},{"name":"docs","exit_code":0,"elapsed_ms":7123,"timed_out":false}]}
) The contract row promised a refusal for a grid "named by a saved view", but saved views carry no grid references and live outside the element store, so that precondition cannot arise. The honest evidence is the chain that does exist: an element relationship targeting the grid prim makes every axis referenced, and the engine guard refuses the removal. Extract the referenced-axes decision out of mutate_grid and cover it with a commands-level test over the real bounded reader; record the delivered limits in the T01 contract. Co-authored-by: axisrow <[email protected]>
* docs: answer O-G5 and specify the magnetic grid mode T01.8 was blocked on the owner decision O-G5; the owner delegated the resolution on 2026-11-08. The magnetic switch becomes the element's own explicit grid binding: bind-grid/unbind-grid, grid-frame following, read-time derivation so a shared-grid edit writes only the grid, GRID_IN_USE for a grid with followers, atomic detach on hand edits, and FOREIGN_READ_ONLY for pinned foreign grids. The contract section 7.5 is specified, the acceptance cases GR-P17 and GR-N20 to GR-N23 are written, and every O-G5 deferral note is updated. The delivery itself is T01.8; the card stays open until the feature lands. * docs: reconcile the GR-N14 guard with the magnetic binding The line-removal guard marks every axis referenced whenever any relationship targets the grid, so a binding relationship would refuse every line edit and contradict the frame-following semantics. Specify the blocker-kind distinction: referenced_axes ignores frame-following bindings (bim:followsGrid) by kind, any other relationship still pins every axis, and grid deletion answers to every relationship. Mark the O-G5 row of the open questions answered. --------- Co-authored-by: axisrow <[email protected]>
* feat: magnetic grid bindings for members (T01.8) A placed member can now follow a grid frame: bind-grid stores its axis in the grid's local frame, and the world geometry is derived at read time, so a shared-grid edit writes only the grid and never rewrites a section element outside its scope. unbind-grid re-materializes the world axis and refreshes the derived mesh and quantities. Guards: a grid with followers refuses deletion (GRID_IN_USE) — the first real producer behind the delete-side check; line edits stay free because referenced_axes ignores frame-following relationships by kind (the GR-N14 reconciliation); any shape rewrite of a bound element refuses until the binding is released (GR-N22), so the local record and the world snapshot never diverge silently; a pinned coordination grid is never followed (FOREIGN_READ_ONLY). The stored world axis of a bound member is the frozen snapshot of its last binding event; the layer schema requires it, and the release overwrites it with the current world. The stored mesh and quantities lag the frame while bound and are exempt from the strict derived checks until the release re-materializes them. CLI: bind-grid and unbind-grid on the grid route; COMMANDS.md regenerated. Design note: docs/design/t018-magnetic-mode.md. * fix: address the T01.8 review findings The pinned-grid refusal now uses pinned_owns_element over the store (the colon-form selector never matches a bare grid id, so the check was unreachable and a pinned bind answered NotFound). A shape rewrite of a bound member is covered end to end: the refused edit leaves the geometry unchanged and the same edit passes after the release (GR-N22). The storage docs and the design note describe the delivered semantics: binding keeps the stored world axis as the frozen snapshot of the binding event, and a rebind replaces the record while the member stays bound, so only a release re-materializes the mesh and quantities. --------- Co-authored-by: axisrow <[email protected]>
…pibim-com#828 view-manager wave and the Apibim-com#837 test fix BeamCraft-Test-Gate: {"version":1,"commit":"ed0ad4b0af0f50e3466e7dd0668de9c876bde98f","tree":"649dab7ccb8147bb2f0d1f5c23bdc86ea04aa3e2","base":"ed0ad4b0af0f50e3466e7dd0668de9c876bde98f","merge_parent":"b277ffd552033b00989bc2a74505fab4c620d2e5","os":"macos","arch":"aarch64","scope":"full","ui_independent_reason":null,"ui_tested":true,"rustc":"rustc 1.99.1 (58cf8f9c3 2026-10-13)","cargo":"cargo 1.99.1 (5f94df478 2026-08-27)","nextest":"cargo-nextest 0.9.149 (3fe4ef319 2026-10-20)\nrelease: 0.9.149\ncommit-hash: 3fe4ef31972f24e0c94cfe291718eab0fe678260\ncommit-date: 2026-10-20\nhost: aarch64-apple-darwin","expected_tests":2692,"executed_tests":2692,"ignored_tests":["beamcraft-test-gate::process::process_fixture"],"source_unchanged":true,"stages":[{"name":"format","exit_code":0,"elapsed_ms":1696,"timed_out":false},{"name":"clippy","exit_code":0,"elapsed_ms":12294,"timed_out":false},{"name":"prepare","exit_code":0,"elapsed_ms":36694,"timed_out":false},{"name":"tests","exit_code":0,"elapsed_ms":205192,"timed_out":false},{"name":"doctests","exit_code":0,"elapsed_ms":1716,"timed_out":false},{"name":"docs","exit_code":0,"elapsed_ms":4882,"timed_out":false}]}
The M5 delivery decision requires schedule templates to be shared, owned model USD entities with revisions, footprints, commit and undo; the delivered export took the template only as a file, so the decision's storage form was missing. A template now saves as a definition under /World/Definitions/Schedules and exports by name through the same decode as its file, so the two forms render byte-identically. The definitions share the attribute schema's conflict domain and its shared-data rule, and keep the file form's honesty when the attribute state moves: a displaced column stays, renders empty and is named. Co-authored-by: axisrow <[email protected]>
) * Build an arc sweep on its authored circle, not on its mirror image chord_arc measured the start, on and end angles as atan2(e1 part, e2 part) while it rebuilds the points as centre + R(cos e1 + sin e2). The faceted arc was therefore reflected about the diagonal through the centre: a curved beam stored the right axis and quantities but drew its solid metres away, with the chord perpendicular to the authored one. The existing quarter-arc test only checked the volume, which a reflection preserves, so the new test checks every vertex against the circle through the three authored points and that the authored ends lie on the mesh. Fixes #542 Claude-Session: https://claude.ai/code/session_01HF6nmYPqtjLF8X4P7BggmV * Apply a bound member's placement exactly once in magnetic grid follows bind-grid mapped the member's element-local axis into the grid frame as if it were world, and the read-time decode wrote the derived world axis back into the element-local field, so every consumer that applies the placement (scene, snap) moved a placed member twice while inspect did not. A member with a placement offset split away from its magnetic position after a grid rotation, and consumers disagreed about where it was. The grid-local record now holds the placed world axis: bind applies the placement first, decode and unbind map back through the inverse placement, so the derived axis stays element-local. The GR-N22 hand-edit guard now also covers placement rewrites of a bound member, which would otherwise split the record from the member again. Fixes #549 Claude-Session: https://claude.ai/code/session_01HF6nmYPqtjLF8X4P7BggmV * Refuse sheet content that overlaps the title block The whole-sheet fit check only kept strokes inside the frame, so a placed detail or its annotation could be drawn straight over the title block on both the SVG and the PDF surface. Every content stroke is now clipped against the block rectangle (Liang-Barsky, since a glyph or edge can cross the block with both ends outside) and a crossing of the block's interior refuses LIMIT_EXCEEDED like content beyond the frame; touching the border is allowed. The sheet unit fixtures and two CLI stories sat inside the A4/A3 block and are lifted clear of it. Fixes #546 Claude-Session: https://claude.ai/code/session_01HF6nmYPqtjLF8X4P7BggmV * Keep a revision viewable when it holds a plate without geometry D-7 retains a wrongly built plate as a degenerate draft, but export-view then refused the whole revision with DEPENDENCY_UNAVAILABLE, so one bad contour made the store unviewable in screenshot-view and the window, and nothing said so at create time. The create-plate help still promised an INVALID_ARGUMENT refusal that the code no longer gives. The view bundle already leaves bodiless plates out of its snapshot; export -view now ships it and names the skipped plates in skipped_plates instead of refusing. create-plate answers a kept draft with a warning, and its help describes the retention. Numbering, BOM and IFC keep refusing such a revision. The F04 on_invalid_shape reject default stays unimplemented; the K1 note records that the owner decides whether to restate it. Fixes #545 Claude-Session: https://claude.ai/code/session_01HF6nmYPqtjLF8X4P7BggmV * Draw and fit project grids in the headless screenshot screenshot-view rendered elements only and fitted the camera over them, while the window draws the project grids with their labels and fits the union of model and grids, so the PNG and the live viewport showed different scenes for the same store. The screenshot now loads the same framed export-view --with-grids reply the window refreshes with, fits GridScene::framing over the scene, and paints the lines and labels with the window's own GridScene::paint through one headless egui pass drawn by egui_wgpu over the resolved render. The reply counts grid_lines; --grids false keeps the model-only picture and fit. Fixes #543 Claude-Session: https://claude.ai/code/session_01HF6nmYPqtjLF8X4P7BggmV * Carry a bolt group with the part an update-element moves Moving a bolted part with update-element wrote only its placement: the generated holes travelled with the plate while the fasteners stayed at their absolute points, so the node visibly fell apart and nothing warned. A bolt group now belongs to its main part. When update-element moves, rotates or re-orients a connected part, the same transaction carries the part's world geometry by the rigid delta new * old^-1, moves the row of a group whose main part moved, re-places every group over the part and regenerates the generated holes of all of them in one pass. A part that no longer crosses the row, or a hole the engine cannot generate, refuses the whole edit with nothing written. A mirror (not rigid) and a move combined with a shape or material change of a bolted part refuse. Fixes #544 Claude-Session: https://claude.ai/code/session_01HF6nmYPqtjLF8X4P7BggmV --------- Co-authored-by: Claude <[email protected]>
BeamCraft-Test-Gate: {"version":1,"commit":"12e8a5bb96e3ac35f55a60a5ce53bb780c6d9d91","tree":"fbc2eba7cfce752f47ea181d2cb232d3ad59d8e1","base":"12e8a5bb96e3ac35f55a60a5ce53bb780c6d9d91","merge_parent":"3ba696a78c79d90fed744868701b2a3f6d8f42f2","os":"macos","arch":"aarch64","scope":"full","ui_independent_reason":null,"ui_tested":true,"rustc":"rustc 1.99.1 (58cf8f9c3 2026-10-13)","cargo":"cargo 1.99.1 (5f94df478 2026-08-27)","nextest":"cargo-nextest 0.9.149 (3fe4ef319 2026-10-20)\nrelease: 0.9.149\ncommit-hash: 3fe4ef31972f24e0c94cfe291718eab0fe678260\ncommit-date: 2026-10-20\nhost: aarch64-apple-darwin","expected_tests":2707,"executed_tests":2707,"ignored_tests":["beamcraft-test-gate::process::process_fixture"],"source_unchanged":true,"stages":[{"name":"format","exit_code":0,"elapsed_ms":1610,"timed_out":false},{"name":"clippy","exit_code":0,"elapsed_ms":20676,"timed_out":false},{"name":"prepare","exit_code":0,"elapsed_ms":60564,"timed_out":false},{"name":"tests","exit_code":0,"elapsed_ms":167103,"timed_out":false},{"name":"doctests","exit_code":0,"elapsed_ms":1715,"timed_out":false},{"name":"docs","exit_code":0,"elapsed_ms":4340,"timed_out":false}]}
One batch commit carrying the fork delta accumulated since the 1108b delivery (Apibim-com#852): schedule templates stored as model definitions (I05) - the model-level template records, the schedule command family that authors, applies and lists them, the layer-engine validation and edit paths, and the I05 design note - and the six bug-hunt fixes with their regression tests: - Build an arc sweep on its authored circle, not on its mirror image: the chord angles were measured against the rebuilt basis, so a curved beam stored the right axis and quantities but drew its solid metres away; the new test checks every vertex against the circle through the three authored points. - Apply a bound member's placement exactly once in magnetic grid follows: the grid-local record holds the placed world axis, decode and unbind map back through the inverse placement, and the GR-N22 hand-edit guard covers placement rewrites of a bound member. - Refuse sheet content that overlaps the title block: every content stroke is clipped against the block rectangle (Liang-Barsky, since a glyph or edge can cross with both ends outside) and a crossing refuses LIMIT_EXCEEDED; touching the border is allowed. - Keep a revision viewable when it holds a plate without geometry: export-view names the skipped plates in skipped_plates instead of refusing, create-plate warns on a kept draft and its help describes the retention. - Draw and fit project grids in the headless screenshot from the same framed export-view --with-grids reply the window refreshes with, painted through one headless egui pass. - Carry a bolt group with the part an update-element moves: the rigid delta re-places the group's row and regenerates the generated holes of all its groups in one transaction, refusing the whole edit when a hole cannot be regenerated. Fork-only policy paths are not part of the delivery.
axisrow
commented
Nov 8, 2026
axisrow
left a comment
Collaborator
Author
There was a problem hiding this comment.
Approved
Reviewed the full delta against upstream master (46 files, +2557/−152): the I05 stored schedule templates and the six bug-hunt fixes with their regression tests and design-note updates. The diff is clean over the merge-base and matches the delivery message.
Checked in depth:
- Arc sweep (#542): the chord angles now use the same
atan2(e2, e1)convention the rebuild below uses (centre + e1·radius·cos + e2·radius·sin), so the mirror-image bug is gone. The new test checks every vertex against the independently solved circumcircle for four cases, including both bulge directions and a three-quarter arc. - Magnetic binding (#549):
grid_local_axis/grid_world_axisthread the placement through; all three callers (bind, unbind, plate decode) are updated consistently, and the new GR-N22 placement guard closes the drift the old decode allowed. Bindings recorded under the old semantics are covered by the standing retire-no-migrate rule documented int018-magnetic-mode.md. - Bolt follow (#544):
follow_moved_partrefuses mirror and move+shape/material combos before anything is written, carries faces and bounds conservatively, re-places every group over the moved part, andregenerated_holesdrops and rewrites shared-plate record sets once with continued ordinals. Refusal paths and the single-undo-unit property are covered by the new test. - Title block clip (#546): the Liang–Barsky check matches the drawn block rectangle exactly, border touching stays allowed, and the existing drawing fixtures that sat over the block were moved clear instead of weakening the check.
- Stored schedule templates (I05): definition prim, conflict domain and shared-data rule mirror the I04 attribute pattern; the publish pipeline is reused via
publish_modelwith identical replay semantics; define-time admission equals the file form and byte-identical export of both forms is asserted, including the unknown-and-stale behaviour after an attribute is undefined. - export-view (#545):
skipped_platesreplaces the refusal for a revision holding a bodiless plate,create-platewarns at create time, and help, registry and COMMANDS.md all describe the same surface. - Headless screenshot grids (#543): empty grids fall back to the scene framing, the egui pass renders into the same Rgba8Unorm target with
LoadOp::Load, and a missing font degrades instead of failing. The CLI relays--gridsand validates it before any render.
Two non-blocking observations for the record, neither introduced by this delivery: a shape-only edit of a bolted part still leaves its generated holes untouched (the new guard covers only a move combined with shape or material change), and the behaviour flip of export-view on bodiless plates intentionally changes two existing test expectations, which are updated alongside.
Requesting no changes; ready to merge from my side.
Blogbotana
approved these changes
Nov 9, 2026
This was referenced Nov 9, 2026
axisrow
added a commit
to axisrow/BeamCraft
that referenced
this pull request
Nov 9, 2026
…elivery squashes
BeamCraft-Test-Gate: {"version":1,"commit":"978895022f0e95d87c1cf933d2944144d3ffb6a6","tree":"4726355e8bef11ef0082b824034e86156e571003","base":"978895022f0e95d87c1cf933d2944144d3ffb6a6","merge_parent":"7c21d0248c24ce7830d9841b6bbe9a567e30a5d9","os":"macos","arch":"aarch64","scope":"full","ui_independent_reason":null,"ui_tested":true,"rustc":"rustc 1.99.1 (58cf8f9c3 2026-10-13)","cargo":"cargo 1.99.1 (5f94df478 2026-08-27)","nextest":"cargo-nextest 0.9.149 (3fe4ef319 2026-10-20)\nrelease: 0.9.149\ncommit-hash: 3fe4ef31972f24e0c94cfe291718eab0fe678260\ncommit-date: 2026-10-20\nhost: aarch64-apple-darwin","expected_tests":2709,"executed_tests":2709,"ignored_tests":["beamcraft-test-gate::process::process_fixture"],"source_unchanged":true,"stages":[{"name":"format","exit_code":0,"elapsed_ms":1797,"timed_out":false},{"name":"clippy","exit_code":0,"elapsed_ms":27432,"timed_out":false},{"name":"prepare","exit_code":0,"elapsed_ms":80354,"timed_out":false},{"name":"tests","exit_code":0,"elapsed_ms":183280,"timed_out":false},{"name":"doctests","exit_code":0,"elapsed_ms":1620,"timed_out":false},{"name":"docs","exit_code":0,"elapsed_ms":4542,"timed_out":false}]}
This was referenced Nov 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
Delivers the fork delta accumulated since the 1108b sync wave's delivery (#852) as one batch
commit on top of
master(the single-batch delivery the fork sync policy prescribes). Twofeature lines, delivered whole:
(
crates/model/src/schedule.rs); the schedule command family authors, applies and liststhem (
crates/commands/src/schedules.rs,apps/beamcraft-cli/src/schedule_cmd.rs), userattribute templates and element attribute admission follow the same shapes
(
crates/commands/src/attribute.rs), the layer engine validates and edits the records(
crates/layer-engine/src/authored.rsand friends), and the I05 design note documents themodel.
its authored circle instead of its mirror image (vertex-level test against the circle
through the three authored points); a bound member's placement is applied exactly once in
magnetic grid follows and the GR-N22 guard covers placement rewrites; sheet content that
overlaps the title block refuses
LIMIT_EXCEEDED(Liang-Barsky stroke clipping, touchingthe border allowed); a revision with a plate without geometry stays viewable — export-view
names the skipped plates and
create-platewarns on a kept draft; the headless screenshotdraws and fits the project grids from the same framed
export-view --with-gridsreply thewindow refreshes with; a bolt group is carried with the part an
update-elementmoves andits generated holes regenerate in the same transaction.
The fork-only policy (its workflow forms,
docs/plan/, visual evidence, fork tooling) is notpart of this delivery; the upstream-owned Python CI tools are untouched.
How you verified it
cargo fmt --all -- --check(recorded gate stage, exit 0)cargo clippy --workspace --all-targets -- -D warnings(recorded gate stage, exit 0)cargo test --workspace(recorded gate: 2707/2707 runnable tests executed with nextest0.9.149 on macOS aarch64, plus mandatory doctests and
cargo doc -D warnings, all exit 0)is tested against current
master, not against a pre-squash base.Never-crash
Every model file, IFC/DSTV import and keystroke is untrusted input (
AGENTS.md§4).unwrap/expect/panic!/todo!outside testsunsafeProvenance
Read
AGENTS.md§1 and §2 before adding any asset.Anything a reviewer should look at first
on top of it (T01.8 storage section).
that previously drew over the block now refuse at placement time, and
export-viewskipsbodiless plates instead of refusing the whole revision.
🤖 Generated with Claude Code