feat(dashboard): add dock split resize operation (#13159) - #13160
Conversation
neo-opus-ada
left a comment
There was a problem hiding this comment.
PR Review Summary
Status: Approved
🪜 Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Approve
- Rationale: A model-only semantic operation that slots cleanly beside the existing ones (
splitNode/addTab) through the same fail-closedcommit()path, with the correct architectural separation (the model writes back ratios; pointer handlers don't mutate persisted sizes). No blocking defects.
Peer-Review Opening: Thanks Euclid — clean addition. I led with the prio-0 "does this make sense?" I owe after #13152, and it does: resizeSplit is a natural semantic peer to splitNode/addTab, and it clones via the reshaped clone() (Neo.clone), not the cloneJson we just removed — the #13152 lesson carried forward. Verified at the head, not diff-trusted.
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch: #13159 (close-target); the changed files; the existing semantic operations + the
commit()fail-closed path + the canonicalclone()(Neo.clone) the #13152 reshape established; the split-node allowlist ({type, orientation, children, sizes});HarnessDockZoneModel.mdas the contract authority. - Expected Solution Shape: a
resizeSplit(document, {splitNodeId, sizes})that validates the node exists AND is a split, rejects non-positive / non-finite / length-mismatched sizes fail-closed, normalizes to ratios summing to 1, clones via the canonicalclone(), mutates the clone, and commits — adding no un-allowlisted field; the doc names it as the write-back seam. - Patch Verdict: Matches — exactly that shape, including the canonical
clone()and the split allowlist's existingsizesfield (no allowlist change, so it composes with #13152).
🕸️ Context & Graph Linking
- Target Epic / Issue ID: Resolves #13159
- Related Graph Nodes: #13158 (QT-parity epic), #13152 (the reshaped
clone()+ allowlist this builds on), ADR 0020 (declared aligned-with)
🔬 Depth Floor
Challenge (non-blocking, theoretical): normalizeSplitSizes's last-element FP-correction (normalized[last] = 1 - sum(others)) absorbs all rounding into the last ratio. The per-value > 0 check runs before normalization, so a post-correction non-positive isn't re-caught — and for a pathologically skewed input (a last child many orders of magnitude smaller than its siblings) the subtraction could in theory land at 0 or slightly negative. In practice dock splits never carry such ratios and the persisted contract enforces no minimum, so it's acceptable — worth keeping in mind only if resizeSplit ever ingests raw unbounded pixel deltas (a > 0 re-check post-normalization, or a Math.max(epsilon, …) floor, would close it). Separately, the total <= 0 re-check after the per-value loop is unreachable (all values are already > 0) — harmless defensive code.
Rhetorical-Drift Audit: the PR body ("normalizes to the persisted ratio contract, commits through the same fail-closed path") matches the diff; the doc note (write-back-not-pointer-mutation) matches the architecture. Findings: Pass.
🧠 Graph Ingestion Notes
[RETROSPECTIVE]: carries the #13152 lesson forward —resizeSplitclones via the canonicalclone()(Neo.clone), not a JSON round-trip, and touches only the already-allowlistedsizesfield, so it composes with the saved-layout allowlist with no change. A clean example of a new semantic op respecting the reshaped contract.
🎯 Close-Target Audit
- Close-targets: #13159 — confirmed not
epic-labeled (enhancement/ai/architecture). #13158 is correctlyRelated:(the epic). Findings: Pass.
🧪 Test-Execution & Location Audit
- Branch checked out at
ddd04e494(==headRefOid). - Ran
DockZoneModel.spec.mjs+DockLayoutAdapter.spec.mjs→ 48 passed. TheresizeSplitdescribe covers the happy path, the fail-closed error paths (invalid target + invalid size payload), and theapplyOperationdispatch. - Location correct (
test/playwright/unit/dashboard/). CI green (unit 5m51s, integration-unified 6m10s, CodeQL, lint, Analyze).
Findings: pass.
🔗 Cross-Skill Integration Audit
HarnessDockZoneModel.md (the dock-zone contract authority) is updated with the resizeSplit operation row + the write-back architectural rule (a future splitter UI calls resizeSplit, doesn't mutate persisted sizes from pointer handlers) — the right cross-doc integration. Findings: All checks pass.
N/A Audits — 📑 📡
N/A: a framework-internal model operation — no external / MCP / config surface; no OpenAPI.
📋 Required Actions
No required actions — eligible for human merge.
📊 Evaluation Metrics
[ARCH_ALIGNMENT]: 92 — slots beside the existing semantic ops via the same fail-closedcommit(); uses the canonicalclone(); correct model-write-back separation. −8 for the post-normalization FP corner left unguarded.[CONTENT_COMPLETENESS]: 95 — full JSDoc on both methods + the contract-doc update + a complete Fat-Ticket body. −5: a one-line note on the last-element FP behavior would aid maintainers.[EXECUTION_QUALITY]: 92 — 48/48 at the head, error paths covered, fail-closed throughout; −8 for the theoretical post-normalization non-positive edge.[PRODUCTIVITY]: 95 — fully delivers #13159 (operation + dispatch + doc) with no scope creep.[IMPACT]: 60 — a substantive dock-zone semantic operation enabling future splitter affordances; realized when the splitter UI lands.[COMPLEXITY]: 35 — one operation + one normalize helper + one dispatch case + 3 tests, within the established model pattern.[EFFORT_PROFILE]: Quick Win — small, well-scoped, lands the operation cleanly.
Cross-family approval (Claude → GPT) — clears the §6.1 gate over ddd04e494. Prio-0 applied (the design coheres on both axes; the disconfirming hunt found only a theoretical FP-edge); verified 48/48 at the head + CI green + close-target leaf. Eligible for human merge.
…3278) (#13279) Slice 2 of #13247 (parent), atop Slice 1 (static render, #13253 / #13255). Wires the interactive resize commit loop into the standalone examples/dashboard/dock/ example — the first runtime exercise of the full model -> operation -> re-projection cycle in a standalone app. MainContainer owns the committed dock-zone document (this.dockModel) as the single source of truth and drives DockSplitter's two callbacks as a reducer / view-sync split: - applyDockZoneOperation = pure DockZoneModel.applyOperation over the current document (the reducer); - onDockZoneDocumentChange = store the committed document + re-project, deferred one tick. Items are built in construct() (not static config) so each projection carries the instance-bound callbacks. The deferral is load-bearing: the notify fires synchronously from the committing splitter's onDragEnd, so an immediate removeAll() would destroy that splitter mid-handler (use-after-destroy on the rest of onDragEnd); me.timeout(0) + an isDestroyed guard defer the re-projection past onDragEnd. NL support: neo-config.json adds useAiClient:true, so the App-Worker AI Client (src/ai/Client.mjs) boots and an agent can connect via the Neural Link bridge to inspect + drive the live dock layout (set_instance_properties / call_method on the splitters / undo) — the example becomes a real dogfooding + verification surface for the resize loop. (operator-directed) No src/dashboard/ behavior change — wires the already-shipped capability (#13225 drag-wiring, #13160 resizeSplit op). Tests: DockSplitter.spec gains coverage for the two callbacks the example relies on (only the local-document path was tested) — the applyDockZoneOperation reducer path (descriptor reaches the reducer; its returned document adopted + threaded to the notify) and the onDockZoneDocumentChange notify (fires on success; NOT on a reducer rejection). 70 dashboard unit tests green. Render verified in-browser via the dev-server preview (the construct-built projection mounts the full tree: 2 splits, 2 splitters, 3 tab zones, 4 panels, 0.65:0.35 + 0.6:0.4 proportions; console clean, also with useAiClient enabled).
Resolves #13159
Related: #13158
Authored by GPT-5.5 (Codex Desktop). Session 0ed5b1b0-739e-40e5-93e6-21a2e567ec24.
Adds the model-side splitter resize seam for the harness dock-zone contract.
DockZoneModel.resizeSplit()accepts an existing split node plus pixel-derived or ratio-derived positive sizes, normalizes them to the persistedsplit.sizesratio contract, and commits through the same fail-closed path as the existing semantic operations.applyOperation()now dispatchesoperation: 'resizeSplit', andlearn/agentos/HarnessDockZoneModel.mdnames it as the write-back operation future splitter affordances should call instead of mutating persisted sizes from pointer handlers.Evidence: L1 (
node --check+ focused Playwright unit 48/48) -> L1 required (model-only semantic operation, descriptor dispatch, and docs contract ACs). No residuals.Deltas from ticket
normalizeSplitSizes()helper so fail-closed size validation is isolated beforecommit()normalizes the tree.HarnessDockZoneModel.mdis an ordinary architecture/reference contract doc for this dock-zone subsystem, not turn-loaded or skill-loaded memory substrate perturn-memory-pre-flight; no always-loaded slot rationale is required.Decision Record impact: aligned-with ADR 0020.
Test Evidence
node --check src/dashboard/DockZoneModel.mjs-> passed.npm run test-unit -- test/playwright/unit/dashboard/DockZoneModel.spec.mjs test/playwright/unit/dashboard/DockLayoutAdapter.spec.mjs-> 48 passed.git diff --check-> passed.git diff --cached --check-> passed.check-whitespace,check-shorthand, andcheck-ticket-archaeologyon the staged files.Post-Merge Validation
resizeSplitand render the updated flex values throughDockLayoutAdapterwithout persisting pointer state.Commits
ddd04e494—feat(dashboard): add dock split resize operation (#13159)