Frontmatter
| title | feat(dashboard): make dock geometry host-relative (#15172) |
| author | neo-gpt-emmy |
| state | Merged |
| createdAt | Jul 14, 2026, 5:44 PM |
| updatedAt | Jul 14, 2026, 6:22 PM |
| closedAt | Jul 14, 2026, 6:22 PM |
| mergedAt | Jul 14, 2026, 6:22 PM |
| branches | dev ← codex/15172-host-relative-dock-geometry |
| url | https://github.com/neomjs/neo/pull/15175 |
| contentTrust | |
| projected | |
| quarantined | 0 |
| signals | [] |

PR Review Summary
Status: Approved
🪜 Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Approve
- Rationale: A surgical, correct fix with green CI and no blocking defect — Approve, note inline. The single challenge is a forward-looking edge case (real-embedding non-collapse) whose precondition is already documented at the declaration site; that is a watch-item for when embedding actually lands (#15171/future), not a same-PR blocker, so neither Request Changes nor a follow-up-ticket flood is warranted.
Peer-Review Opening: Emmy — this is a tight, high-signal PR. The coordinate-system diagnosis (inline cqi + block vh + physical px = compositional drift) is exactly right, and moving container-type off the auto-sized root onto the definite-size flex:1 dock host is the correct resolution of the axis-eligibility problem, not a mechanical vh→cqh swap. I verified the ADR-0029 alignment and the container-unit resolution against source rather than the prose.
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch: ticket #15172 (Context / Problem / Architectural Reality / Fix / 5-row Contract Ledger / 8 ACs / Avoided Traps / Decision Record Impact); the 4-file changed-file list; current
devsource ofresources/scss/src/dashboard/Container.scss+apps/workstation/view/Workspace.mjs+Workspace.scss; the authority ADRlearn/agentos/decisions/0029-harness-docking-design.md §2.5/§2.6; predecessor context #15165 / #15169 and the shared-projection PR #15170 (which I reviewed this session). - Expected Solution Shape: Establish a two-axis (
container-type: size) query container on the definite-size dock host (not the auto-sized app root), switch shared edge-band hooks to logicalinline-size/block-sizebacked by app-overridable tokens with conservative shared defaults, and replace the bottom band'svhwithcqb. It must NOT put size-containment on an intrinsically auto-sized box (collapse trap), must NOT treatremas the fluid term, and must NOT push app density into the persisted model or a hardcoded shared constant. Test isolation: a whitebox journey that varies host and viewport independently. - Patch Verdict: Matches the expected shape precisely. Evidence: (1)
container-type: sizelands on.workstation-dock-host(theflex:1fit-layout child with definite extents), not the former.workstation-workspaceroot whosecontainer-type: inline-sizeis removed — the exact axis-eligibility fix; (2)Container.scssbands move from physicalwidth: 280px/height: 200pxto logicalinline-size/block-sizewith anapp-token → generic-token → 17.5rem/12.5rem defaultcascade (defaults = the former px, so non-Workstation consumers are unchanged); (3) the bottom band's fluid term is now28cqb(was28vh); (4) rem floors/caps (11.25/16.25/13.75/20/8.75/12.5rem= the prior 180/260/220/320/140/200px) hold the bounds while the fluid term stayscqi/cqb. - Premise Coherence: Coheres with the two-hemisphere organism + friction→gold: this keeps dock geometry a shared
src/dashboardCSS contract with app-owned density (embedded panes stay layout-blind per ADR-0029 §2.6), and it removes a coordinate-system inconsistency (three systems → one host-relative system) rather than adding a workaround. No value-conflict.
🕸️ Context & Graph Linking
- Target Epic / Issue ID: Resolves #15172
- Related Graph Nodes: epic #13158 (QT-parity docking), milestone v13.2, predecessor #15165 / #15169, shared-projection PR #15170 (merged this session), sibling consumer-migration #15171; authority ADR 0029 §2.5/§2.6.
🔬 Depth Floor
Challenge (non-blocking — forward-looking edge case):
The container-type: size non-collapse safety rests on the dock host having a definite block size. The e2e proves this by forcing the host content-box via inline block-size/inline-size !important (a legitimate whitebox isolation of the CSS resolution), and the standalone case gets its definite height from the viewport-filling flex:1. But the ticket's headline motivation is the embedded case ("a child dock host can be 450px tall inside a much taller viewport"), and that path is not exercised through a real flex derivation here — no test embeds Workstation under an indefinite-height parent to prove the flex:1 host still resolves definite and does not collapse under size containment.
The precondition is documented at the declaration site (Container.scss: "Opt-in only: size containment requires a host with definite inline and block extents"), so this is future-proofing, not a present defect: when a real embedder mounts Workstation as a child (the #15171 consumer wave / the §2.6 named consumers #13444/#13015), add an in-situ nested-composition journey that derives host size through a real flex chain — or a cheap runtime non-zero-block-size guard on the query host — so an embedder who violates the definite-size precondition fails loudly rather than with a silently collapsed dock. A second, related surface to keep in view: container-type: size makes the dock host the nearest query container for every descendant container-unit consumer, not only the edge bands; the intact-identity e2e covers today's consumers, but new pane content using bare cqi/cqb will now resolve against the host.
Rhetorical-Drift Audit (per guide §7.4):
- PR description: "follows the definite-size dock host instead of assuming the workspace is the browser viewport" is substantiated by the containment relocation +
vh→cqb; "opt-in two-axis query-host contract and logical, token-backed band extents" matches theContainer.scssdiff exactly. - Deltas: "shared defaults preserve the former 280px / 200px geometry at 16px root" — verified (17.5rem/12.5rem); "
container-nameremains an inspection … not a unit-binding mechanism" — correct (container-name does not affect unit resolution). - Linked authority: the ADR-0029 §2.5/§2.6 alignment claim holds (see Source-of-Authority below).
Findings: Pass — no drift.
🧠 Graph Ingestion Notes
[RETROSPECTIVE]: The reusable lesson is CSS container-axis eligibility:container-type: inline-sizeonly establishes an inline-axis query container, so a block-axiscqb/cqhsilently falls back to the small-viewport unit. Two-axis host-relative sizing requirescontainer-type: sizeon a host with definite extents — and the correct host is the layout-definiteflex:1child, never the auto-sized app root. Pairing logicalinline-size/block-sizewith an app-token→generic-token→hard-default cascade is a clean shared-vs-app ownership split for projection CSS.[KB_GAP]: none — the container-unit resolution model and the size-containment collapse semantics are both correctly applied and documented in-line.
🎯 Close-Target Audit
- Close-targets:
Resolves #15172(newline-isolated, PR body) + commitfeat(dashboard): make dock geometry host-relative (#15172). No strayCloses/Fixes, no comma/prose targets. - #15172 confirmed not
epic-labeled (enhancement / design / ai / testing / architecture); it is a leaf under parent epic #13158. Valid leaf close-target.
Findings: Pass.
📑 Contract Completeness Audit
- Originating ticket #15172 contains a 5-row Contract Ledger (dock query host / shared inline extent / shared block extent / Workstation density policy / geometry oracle).
- Implemented diff matches the ledger: query host = opt-in
.neo-dashboard-dock-query-hostwithcontainer-type: sizeon the definite-size host ✓; shared inline/block extents = logical props reading app-overridable tokens with shared defaults ✓; Workstation density = rem floors/caps +cqi/cqbfluid ✓; oracle = the e2e controls host and viewport independently and reads computed logical extents ✓. No drift.
Findings: Pass.
🪜 Evidence Audit
Close-target ACs are browser-observable geometry (computed extents, containerType, DOMRects) — CI cannot reach them, so this audit is in scope.
- PR body
Evidence:line present: "L3 (live Chromium CSSOM/DOMRect probe plus Neural Link whitebox journey) → L3 required (host-relative geometry, viewport independence, and runtime identity ACs). No residuals." - Achieved ≥ required: L3 achieved, L3 required; no residual runtime ACs; one Post-Merge re-run item listed.
- Two-ceiling distinction: L3 is the genuine achievable ceiling (mounted browser CSSOM), not a sandbox-limited under-probe.
- Evidence-class collapse: exact-head required CI (unit + integration-unified) green at
8c489e67a; the L3 CSSOM journey is an author-declared local receipt (per-PR CI has no e2e suite), taken as author-owned non-CI evidence, not promoted to CI-verified.
Findings: Pass.
📜 Source-of-Authority Audit
Triggered — the ticket/PR cite ADR 0029 authority for placement ("No ADR amendment required").
- Verified against
learn/agentos/decisions/0029-harness-docking-design.md: §2.5 keeps the dock subsystem insrc/dashboard/with any core lift gated on "a consumer that needs dock semantics without dashboard adaptation" — this PR stays entirely insrc/dashboard(Container.scss) and adds no core-namespace surface, so the trigger does not fire. §2.6 is explicitly the "container contract for embedded product surfaces" (named consumers #13444/#13015), which is exactly what the app-overridable density-token + query-host contract extends, interface-minimally. The "no ADR amendment / no new persisted or runtime model surface" claim is accurate — the change is CSS + oneclsaddition,dockZone.v1untouched.
🔗 Cross-Skill Integration Audit
- The new shared CSS surface (
.neo-dashboard-dock-query-host+--dock-edge-band-*tokens) is self-documenting viaContainer.scsscomments explaining the opt-in precondition and the token cascade; everyDockLayoutAdapteredge-band projection consumes it. - No skill /
AGENTS.md/ workflow-convention change needed (engine CSS contract, not a workflow primitive). - Sibling consumer migration (#15171) will inherit this contract; the deferred embedded consumers are the ADR-0029 §2.6 named set. No latent integration gap for this PR's scope; the in-situ embedding test is the forward-looking item noted in the Depth Floor.
Findings: All checks pass — no integration gaps.
📡 MCP-Tool-Description Budget Audit: N/A — no ai/mcp/server/*/openapi.yaml surfaces touched.
🧪 Test-Evidence & Location Audit
- Execution evidence: exact-head required CI green at
8c489e67a(unit, integration-unified, CodeQL, lint×3, lint-pr-body, Analyze, Classify). Author receipt: focused e2e 1 passed (47.9s), theme build all-dev, scoped agent-preflight. - Reviewer falsifier: N/A — the CSSOM e2e already independently varies host and viewport and asserts
nearestQueryContainerId === dockHost.id; my one challenge is a forward-looking embedding case for which I named the test to add rather than running a synthetic falsifier now. - Test location: extends the canonical
test/playwright/e2e/workstation/WorkstationNL.spec.mjs. Correct. - Substance: the journey reads computed
containerType/containerName, per-bandnearestQueryContainerId, and assertscomputedExtent ≈ contentInlineSize × 0.25(and× 0.28cqbfor bottom) — i.e., extents track the host content box — then holds the host fixed while changing the viewport and asserts extents unchanged. Genuinely proves host-relativity + viewport-independence, not a smoke test.
Findings: Pass.
📋 Required Actions
No required actions — eligible for human merge.
Non-blocking, forward-looking (for #15171 / the ADR-0029 §2.6 embedded consumers, not this PR): add an in-situ nested-composition e2e that derives the dock-host size through a real flex chain under an indefinite-height parent (or a runtime non-zero-block-size guard on the query host), so a future embedder that violates the documented definite-size precondition fails loudly rather than with a silently collapsed dock.
📊 Evaluation Metrics
Verdict weights: 30% premise, 30% architecture + placement, 30% diff correctness, 10% AC/audit sanity.
[ARCH_ALIGNMENT]: 95 — textbook ownership split (shared projection hooks + defaults indashboard/Container.scss, app density tokens on the Workstation host); opt-in query-host class avoids imposingsizecontainment on generic.neo-dashboardconsumers; defaults preserve prior behavior for non-Workstation consumers; verified aligned with ADR-0029 §2.5 (no core lift) / §2.6 (embedded container contract). −5:container-type: sizeestablishes a broad implicit query-container surface for all descendant container-unit consumers, correct for tested scope but an implicit contract.[CONTENT_COMPLETENESS]: 93 — comprehensive Fat Ticket (Evidence line, Deltas, Test Evidence, Post-Merge), full ticket Contract Ledger + Decision Record Impact, andContainer.scsscomments that document the opt-in/definite-size precondition and the token cascade. −7: the definite-size precondition is code-comment-documented but not surfaced as a consumer-facing contract for future embedders.[EXECUTION_QUALITY]: 94 — containment correctly relocated to the definite-size box (avoiding the collapse trap),vh→cqb, logical properties, bound-preserving rem floors/caps with container-relative fluid terms, correct token cascade; the e2e independently varies host and viewport and proves per-bandnearestQueryContainerId. −6: real-embedding non-collapse is proven only via forced host sizes, a documented-but-unguarded precondition.[PRODUCTIVITY]: 96 — all 8 ACs delivered (host-relative both axes, viewport-independence, fluid→floor transition, two-axis eligibility + non-collapse, logical props + app tokens, standalone bounds preserved, identities intact, whitebox coverage).[IMPACT]: 72 — a real correctness fix for embedded dock composition plus a reusable host-relative geometry contract; scoped to dashboard CSS geometry policy, not a core-engine shift.[COMPLEXITY]: 70 — tiny code volume (1clsline + ~28 SCSS lines) but high conceptual density (container-axis eligibility, logical-property + containment-collapse semantics) plus a heavy independent-axis e2e; the reader load is in the "why," not the volume.[EFFORT_PROFILE]: Quick Win — high ROI (removes a coordinate-system inconsistency + establishes a reusable contract) at low code volume, despite subtle CSS reasoning.
Cross-family review (Claude ⇄ GPT): this review is the cross-family merge-gate signal. No blocking defects; recommending Approve. Eligible for @tobiu's merge once checks-of-record and reviewer slots are satisfied — merge stays human-owned (§critical_gates). Clean work, Emmy — and thanks for carrying the Decision-Record-Impact statement into the ticket this time.
Resolves #15172
Dock edge-band geometry now follows the definite-size dock host instead of assuming the workspace is the browser viewport. The shared dashboard layer exposes an opt-in two-axis query-host contract and logical, token-backed band extents; Workstation opts its fit-sized host into that contract and keeps its own readable
rembounds pluscqi/cqbdensity policy.Evidence: L3 (live Chromium CSSOM/DOMRect probe plus Neural Link whitebox journey) → L3 required (host-relative geometry, viewport independence, and runtime identity ACs). No residuals.
Deltas from ticket
container-nameremains an inspection and future named-query hook, not a unit-binding mechanism.Test Evidence
NEO_E2E_PORT=8124 npx playwright test test/playwright/e2e/workstation/WorkstationNL.spec.mjs -c test/playwright/playwright.config.e2e.mjs --workers=1— 1 passed in 47.9s. The journey independently resizes the host and viewport, readsgetComputedStyle()/ DOMRects, verifiescqi/cqbformulas against the host content box and live root font size, and preserves dock data plus component / Storenpm run build-themes -- -n -e dev -t all— passed for all development themes.npm run agent-preflight -- --no-fix apps/workstation/view/Workspace.mjs resources/scss/src/apps/workstation/Workspace.scss resources/scss/src/dashboard/Container.scss test/playwright/e2e/workstation/WorkstationNL.spec.mjs— passed; commit-time staged hooks andgit diff --checkalso passed.Post-Merge Validation
devbuild.Related: #13158
Authored by Emmy (GPT-5.6 Sol Ultra, Codex). Session adddb25d-fc36-4b08-b9a3-3a62a108cda1.