Skip to content

feat(web): labs toggle + workspace editing affordances (0282) - #412

Merged
crs48 merged 7 commits into
mainfrom
claude/0282-workspace-editing-affordances
Jul 8, 2026
Merged

crs48 merged 7 commits into
mainfrom
claude/0282-workspace-editing-affordances

Conversation

@crs48

@crs48 crs48 commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Implements 0282_[x]_WORKSPACE_EDITING_AFFORDANCES_AND_LABS_TOGGLE.md — making 0280's workspace editing discoverable without flipping the default.

What landed

  • Settings › Labs (phase 1): a declarative flag registry (apps/web/src/lib/labs.ts) renders honest toggles for the three xnet:experiment:* flags, with staging badges and a "Reload to apply" chip. Named Labs because the habit tracker owns "Experiments". The Appearance→Workspaces row points here when the malleable shell is off.
  • Ambient affordances (phase 2): grab handle + cursor: grab on panel headers (flag-gated so legacy shells stay inert); a slot-drag lifecycle store lights up all docks while dragging — closed docks materialize as labeled edge strips, fixing the "drops silently no-op" mechanical bug; drag ghost + 40% source opacity; 700ms landing ring; the Move menu rebuilt on DropdownMenu (kills the 0280 popover click-swallow race); a tree-diff SlotAnnouncer gives every mutation road (drag/menu/⌘K/agent) the same aria-live announcement + landing flash + focus restoration.
  • Arrange mode (phase 3): Workspace: Customize layout… renders the shell as a schematic — four labeled dock slots, every view a draggable chip with tier toggle, hide control, and the Move menu; hidden tray; Esc/Done exits (Esc claims the ladder rung before docks close); a changed tree earns a "Save as…" nudge into the 0280 switcher. Entries: ⌘K, workspace switcher, Move menus, Labs.
  • Within-dock reorder (phase 4): insertSlot(tree, viewId, region, index) in @xnetjs/plugins (minor, purely additive; moveSlot = insert-at-end), slot.reorder:* palette commands, and TabBar-style insertion indicators on arrange chips.

Verified live (worktree preview, real UI events only)

Fresh-profile enable path entirely through UI (Labs toggle → reload chip → arrange); flag-off renders zero drag affordances; header drag lit both closed docks as edge strips and the open dock as a ringed target, drop onto a closed dock moved the view, opened the dock and announced "Explorer moved to right dock"; Move menu executed 5/5 consecutive clicks; arrange mode moved a chip into the empty corner dock, reordered console→first with the insertion indicator visible, surfaced the exit nudge, and saved the arrangement as a workspace node that survived reload; quiet posture kept its summon hot-zones intact alongside arrange mode.

Deliberate non-moves per the doc: no default flip, no DnD library (menu road remains the touch/a11y fallback), no docking compass.

Implements and checks off docs/explorations/0282_[x]_WORKSPACE_EDITING_AFFORDANCES_AND_LABS_TOGGLE.md.

🤖 Generated with Claude Code

xNet Test and others added 6 commits July 8, 2026 07:59
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Grab handle + ghost on panel headers (flag-gated); a slot-drag lifecycle
store lights up ALL docks while dragging — closed docks materialize as
labeled edge strips, so drops land anywhere; landing flash; Move menu on
DropdownMenu (kills the popover dismissal race); diff-driven aria-live
announcer + focus restoration covering every mutation road.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
workspace.customize renders every dock as a labeled slot of draggable
view chips (tier toggle, hide, Move menu intact); Esc/Done exits with a
save-as nudge when the tree changed; entries in the palette, workspace
switcher, Move menus and Labs; grab-handle coachmark on first run.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…0282)

Positional insertSlot in the workspace layout primitives (moveSlot =
insert-at-end); slot.reorder up/down palette commands per view; drop-edge
insertion indicator on arrange-mode chips (TabBar's pattern).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…oggle

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@crs48
crs48 temporarily deployed to pr-412 July 8, 2026 15:36 — with GitHub Actions Inactive
@github-actions

github-actions Bot commented Jul 8, 2026 •

Copy link
Copy Markdown
Contributor

Preview removed for PR #412.

github-actions Bot added a commit that referenced this pull request Jul 8, 2026
setDropEdge(event.clientX < rect.left + rect.width / 2 ? 'before' : 'after')
}}
onDragLeave={() => setDropEdge(null)}
onDrop={(event) => {
}

/** One view as a draggable, editable chip. */
function ViewChip({
.map((placement, index) => ({ placement, index }))
.filter(({ placement }) => placement.tier !== 'hidden')

const onDrop = (event: DragEvent) => {
* animation, so reduced-motion needs no special casing; the flash uses
* the same mechanism and simply appears/disappears without motion).
*/
function DockDropDress({ region, children }: { region: RegionId; children: ReactNode }) {
* without it, "pop this out and slot it in over there" silently no-ops
* (0282's one mechanical bug). Dropping opens the dock with the view.
*/
function DockEdgeStrip({ region }: { region: RegionId }) {
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@crs48
crs48 temporarily deployed to pr-412 July 8, 2026 16:02 — with GitHub Actions Inactive
github-actions Bot added a commit that referenced this pull request Jul 8, 2026
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

🖼️ UI changes in this PR

Screens

✏️ Settings _(SSIM 0.976)_
before after diff
before after diff

Auto-captured by CI · run. Informational — not a blocking check.

@crs48
crs48 merged commit 8f0a0b8 into main Jul 8, 2026
16 of 18 checks passed
@crs48
crs48 deleted the claude/0282-workspace-editing-affordances branch July 8, 2026 16:25
github-actions Bot added a commit that referenced this pull request Jul 8, 2026
crs48 added a commit that referenced this pull request Jul 8, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @xnetjs/plugins@0.7.0

### Minor Changes

- [#412](#412)
[`a5813fc`](a5813fc)
Thanks [@crs48](https://github.com/crs48)! - `insertSlot(tree, viewId,
region, index)` joins the workspace layout primitives (exploration
0282): positional insertion for within-dock reorders and cross-region
moves; `moveSlot` is now insert-at-end. Purely additive.

### Patch Changes

- Updated dependencies []:
  - @xnetjs/data@0.7.0
  - @xnetjs/abuse@0.7.0
  - @xnetjs/core@0.7.0
## @xnetjs/abuse@0.7.0

### Patch Changes

- Updated dependencies []:
  - @xnetjs/identity@0.7.0
  - @xnetjs/crypto@0.7.0
## @xnetjs/cli@0.0.12

### Patch Changes

- Updated dependencies
[[`a5813fc`](a5813fc)]:
  - @xnetjs/plugins@0.7.0
  - @xnetjs/runtime@0.1.8
  - @xnetjs/data@0.7.0
  - @xnetjs/sqlite@0.7.0
  - @xnetjs/sync@0.7.0
  - @xnetjs/identity@0.7.0
  - @xnetjs/crypto@0.7.0
  - @xnetjs/core@0.7.0
## @xnetjs/crypto@0.7.0

### Patch Changes

- Updated dependencies []:
  - @xnetjs/core@0.7.0
## @xnetjs/data@0.7.0

### Patch Changes

- Updated dependencies []:
  - @xnetjs/storage@0.7.0
  - @xnetjs/sqlite@0.7.0
  - @xnetjs/sync@0.7.0
  - @xnetjs/identity@0.7.0
  - @xnetjs/crypto@0.7.0
  - @xnetjs/core@0.7.0
## @xnetjs/data-bridge@0.7.0

### Patch Changes

- Updated dependencies []:
  - @xnetjs/data@0.7.0
  - @xnetjs/sqlite@0.7.0
  - @xnetjs/sync@0.7.0
  - @xnetjs/core@0.7.0
## @xnetjs/history@0.7.0

### Patch Changes

- Updated dependencies []:
  - @xnetjs/data@0.7.0
  - @xnetjs/sync@0.7.0
  - @xnetjs/core@0.7.0
## @xnetjs/identity@0.7.0

### Patch Changes

- Updated dependencies []:
  - @xnetjs/crypto@0.7.0
  - @xnetjs/core@0.7.0
## @xnetjs/react@0.7.0

### Patch Changes

- Updated dependencies
[[`a5813fc`](a5813fc)]:
  - @xnetjs/plugins@0.7.0
  - @xnetjs/runtime@0.1.8
  - @xnetjs/history@0.7.0
  - @xnetjs/data-bridge@0.7.0
  - @xnetjs/data@0.7.0
  - @xnetjs/sync@0.7.0
  - @xnetjs/identity@0.7.0
  - @xnetjs/crypto@0.7.0
  - @xnetjs/core@0.7.0
## @xnetjs/runtime@0.1.8

### Patch Changes

- Updated dependencies
[[`a5813fc`](a5813fc)]:
  - @xnetjs/plugins@0.7.0
  - @xnetjs/history@0.7.0
  - @xnetjs/data-bridge@0.7.0
  - @xnetjs/data@0.7.0
  - @xnetjs/storage@0.7.0
  - @xnetjs/sync@0.7.0
  - @xnetjs/identity@0.7.0
  - @xnetjs/crypto@0.7.0
  - @xnetjs/core@0.7.0
## @xnetjs/storage@0.7.0

### Patch Changes

- Updated dependencies []:
  - @xnetjs/sqlite@0.7.0
  - @xnetjs/crypto@0.7.0
  - @xnetjs/core@0.7.0
## @xnetjs/sync@0.7.0

### Patch Changes

- Updated dependencies []:
  - @xnetjs/identity@0.7.0
  - @xnetjs/crypto@0.7.0
  - @xnetjs/core@0.7.0
## @xnetjs/core@0.7.0


## @xnetjs/sqlite@0.7.0


## xnet-cloud@0.0.10

### Patch Changes

- Updated dependencies []:
  - @xnetjs/crypto@0.7.0
  - @xnetjs/cloud@0.0.1
## @xnetjs/brain@0.0.11

### Patch Changes

- Updated dependencies []:
  - @xnetjs/data@0.7.0
  - @xnetjs/vectors@0.0.1
## @xnetjs/comms@0.0.11

### Patch Changes

- Updated dependencies []:
  - @xnetjs/data@0.7.0
  - @xnetjs/crypto@0.7.0
## @xnetjs/dashboard@0.0.11

### Patch Changes

- Updated dependencies
[[`a5813fc`](a5813fc)]:
  - @xnetjs/plugins@0.7.0
  - @xnetjs/react@0.7.0
  - @xnetjs/data@0.7.0
  - @xnetjs/social@0.0.11
## @xnetjs/labs@0.0.11

### Patch Changes

- Updated dependencies
[[`a5813fc`](a5813fc)]:
  - @xnetjs/plugins@0.7.0
  - @xnetjs/data@0.7.0
## @xnetjs/licenses@0.0.11

### Patch Changes

- Updated dependencies []:
  - @xnetjs/crypto@0.7.0
## @xnetjs/maps@0.0.11

### Patch Changes

- Updated dependencies []:
  - @xnetjs/data@0.7.0
## @xnetjs/meetings@0.0.4

### Patch Changes

- Updated dependencies
[[`a5813fc`](a5813fc)]:
  - @xnetjs/plugins@0.7.0
  - @xnetjs/data@0.7.0
## @xnetjs/server@0.0.10

### Patch Changes

- Updated dependencies []:
  - @xnetjs/data-bridge@0.7.0
  - @xnetjs/data@0.7.0
  - @xnetjs/identity@0.7.0
  - @xnetjs/crypto@0.7.0
## @xnetjs/social@0.0.11

### Patch Changes

- Updated dependencies []:
  - @xnetjs/data@0.7.0
  - @xnetjs/crypto@0.7.0
## @xnetjs/unreal@0.0.11

### Patch Changes

- Updated dependencies []:
  - @xnetjs/data@0.7.0
## xnet-desktop@0.7.0

Desktop shell release riding the @xnetjs/core 0.7.0 train.
Desktop-specific changes are not tracked here; see the core packages'
changelogs for what shipped.
crs48 added a commit that referenced this pull request Jul 8, 2026
…e real signal (0283) (#414)

Implements docs/explorations/0283 — CI failure patterns and pipeline
health.

Over the last ~500 Actions runs, ~75% of failures came from four causes
unrelated to code correctness, while the one real breakage (Electron
Release) went unnoticed in the noise.

## Tier 1 — stop the bleeding
- **mobile-e2e.yml**: quoted the two `run:` lines whose `: ` made the
file unparseable — GitHub emitted a phantom failed run *on every push*
(48/48 failures, ~40% of all failure volume).
- **audiotee `Package.swift`**: deployment floor `.macOS(.v14)` →
`.macOS("14.2")` (`AudioHardwareCreateProcessTap` is 14.2+). Every
Electron Release macOS build since 0279 failed on this; verified locally
with `swift build -c release`. Runtime capability selection already
gates on darwin ≥ 23.4 before probing the helper.
- **Fallow**: removed from PR CI entirely (user decision — stronger than
the exploration's report-only option). Weekly schedule + manual dispatch
keep the hard `--fail-on-issues` gate; turbo cache re-enabled. It was
the slowest job (~17 min) and failed 44% of PR runs on advisory notes.
- **visual-capture**: job-level `continue-on-error` so the
self-described informational check can't red a PR.

## Tier 2 — prevent the classes
- **actionlint 1.7.12** in the required `lint` job + guarded pre-commit
pass (shellcheck severity floor `warning` in both). Fixed what it flags:
untrusted `head.ref` inlined in ai-changeset.yml (moved to env),
unquoted command substitutions in schema-check.yml, unused loop vars.
- **`.husky/prepare-commit-msg`**: dependency-free DCO auto-sign-off
(survives `--no-verify`; merges/squashes untouched). DCO failed 76% of
recent runs.
- **`scripts/check-storybook-shim.mjs`** (`pnpm check:storybook-shim`):
walks the story import graph with storybook's own alias map and fails
the `lint` job in seconds when the plugins shim misses a name — the
drift that broke Visual UI Capture in 0279, 0280, and #412. Backfills
`ImporterContribution`.
- **plugins-registry.yml**: daily rebuild now refreshes a standing
`plugins-registry/data` PR (signed off, `skip-changelog`) instead of
pushing to protected `main`, which repo rules rejected every time.

## Tier 3 — ratchets
- **Native Helpers workflow**: path-filtered `macos-14` `swift build` on
PRs touching `apps/electron/native/**`, so availability drift surfaces
pre-release.
- **`scripts/changelog/assert-fragment.mjs`** Stop-hook nudge (mirrors
the changesets hook): one-shot turn-end reminder when app/package source
changed without a changelog fragment.

## Deferred (calendar-gated, unchecked in the doc)
- Adding DCO to required checks after ≥1 week of green.
- Two-week failure-rate re-measurement.

Expected outcome: failed-run rate drops from ~21% to ~2-3%, and a red ✗
regains meaning.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

This branch was previously deployed

1 inactive deployment
pr-412 — 12686705 Deployed Jul 8, 2026 by crs48 via deploy-preview #718
Sign up for free to 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