arrayview 0.4.0__tar.gz → 0.5.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {arrayview-0.4.0 → arrayview-0.5.1}/.claude/skills/invocation-consistency/SKILL.md +84 -1
- {arrayview-0.4.0 → arrayview-0.5.1}/.github/workflows/python-publish.yml +4 -4
- arrayview-0.5.1/AGENTS.md +219 -0
- arrayview-0.5.1/CHUNK_PLAN.md +179 -0
- arrayview-0.5.1/LOG_LARGE_ARRAYS.md +214 -0
- {arrayview-0.4.0 → arrayview-0.5.1}/PKG-INFO +11 -1
- {arrayview-0.4.0 → arrayview-0.5.1}/README.md +10 -0
- arrayview-0.5.1/TODO.md +41 -0
- arrayview-0.5.1/VSCODE_DETECTION.md +82 -0
- {arrayview-0.4.0 → arrayview-0.5.1}/docs/large-arrays.md +2 -2
- arrayview-0.5.1/plans/speed/LOG.md +219 -0
- arrayview-0.5.1/plans/speed/PLAN.md +266 -0
- arrayview-0.5.1/plans/tunnel-fix/PLAN.md +148 -0
- arrayview-0.5.1/plans/tunnel-fix-local/LOG.md +65 -0
- {arrayview-0.4.0 → arrayview-0.5.1}/pyproject.toml +2 -2
- {arrayview-0.4.0 → arrayview-0.5.1}/src/arrayview/__init__.py +2 -1
- {arrayview-0.4.0 → arrayview-0.5.1}/src/arrayview/_app.py +1 -0
- {arrayview-0.4.0 → arrayview-0.5.1}/src/arrayview/_io.py +27 -14
- {arrayview-0.4.0 → arrayview-0.5.1}/src/arrayview/_launcher.py +425 -124
- {arrayview-0.4.0 → arrayview-0.5.1}/src/arrayview/_platform.py +77 -6
- {arrayview-0.4.0 → arrayview-0.5.1}/src/arrayview/_server.py +296 -18
- {arrayview-0.4.0 → arrayview-0.5.1}/src/arrayview/_session.py +43 -3
- {arrayview-0.4.0 → arrayview-0.5.1}/src/arrayview/_viewer.html +2060 -317
- {arrayview-0.4.0 → arrayview-0.5.1}/src/arrayview/_vscode.py +119 -47
- arrayview-0.5.1/src/arrayview/arrayview-opener.vsix +0 -0
- {arrayview-0.4.0 → arrayview-0.5.1}/tests/test_api.py +477 -79
- {arrayview-0.4.0 → arrayview-0.5.1}/tests/test_browser.py +84 -28
- {arrayview-0.4.0 → arrayview-0.5.1}/tests/test_cli.py +24 -17
- arrayview-0.5.1/tests/test_rgb_pixel_art.py +66 -0
- {arrayview-0.4.0 → arrayview-0.5.1}/tests/visual_smoke.py +572 -25
- {arrayview-0.4.0 → arrayview-0.5.1}/uv.lock +1 -1
- {arrayview-0.4.0 → arrayview-0.5.1}/vscode-extension/extension.js +135 -15
- {arrayview-0.4.0 → arrayview-0.5.1}/vscode-extension/package.json +1 -1
- arrayview-0.4.0/AGENTS.md +0 -186
- arrayview-0.4.0/TODO.md +0 -2
- arrayview-0.4.0/src/arrayview/arrayview-opener.vsix +0 -0
- {arrayview-0.4.0 → arrayview-0.5.1}/.claude/skills/modes-consistency/SKILL.md +0 -0
- {arrayview-0.4.0 → arrayview-0.5.1}/.claude/skills/task-workflow/SKILL.md +0 -0
- {arrayview-0.4.0 → arrayview-0.5.1}/.claude/skills/viewer-ui-checklist/SKILL.md +0 -0
- {arrayview-0.4.0 → arrayview-0.5.1}/.gitignore +0 -0
- {arrayview-0.4.0 → arrayview-0.5.1}/.python-version +0 -0
- {arrayview-0.4.0 → arrayview-0.5.1}/.tmp-vsix/extension/extension.js +0 -0
- {arrayview-0.4.0 → arrayview-0.5.1}/.tmp-vsix/extension/package.json +0 -0
- {arrayview-0.4.0 → arrayview-0.5.1}/LICENSE +0 -0
- {arrayview-0.4.0 → arrayview-0.5.1}/docs/superpowers/specs/2026-03-14-todo-batch-design.md +0 -0
- {arrayview-0.4.0 → arrayview-0.5.1}/plans/tunnel-fix/LOG.md +0 -0
- {arrayview-0.4.0/plans/tunnel-fix → arrayview-0.5.1/plans/tunnel-fix-local}/PLAN.md +0 -0
- {arrayview-0.4.0 → arrayview-0.5.1}/scripts/demo.py +0 -0
- {arrayview-0.4.0 → arrayview-0.5.1}/src/arrayview/_icon.png +0 -0
- {arrayview-0.4.0 → arrayview-0.5.1}/src/arrayview/_render.py +0 -0
- {arrayview-0.4.0 → arrayview-0.5.1}/src/arrayview/_shell.html +0 -0
- {arrayview-0.4.0 → arrayview-0.5.1}/tests/conftest.py +0 -0
- {arrayview-0.4.0 → arrayview-0.5.1}/tests/make_vectorfield_test_arrays.py +0 -0
- {arrayview-0.4.0 → arrayview-0.5.1}/tests/test_large_arrays.py +0 -0
- {arrayview-0.4.0 → arrayview-0.5.1}/vscode-extension/LICENSE +0 -0
|
@@ -142,7 +142,90 @@ uv run pytest tests/test_cli.py -x # CLI entry point
|
|
|
142
142
|
uv run python -c "from arrayview import view; import numpy as np; view(np.zeros((10,10)))"
|
|
143
143
|
```
|
|
144
144
|
|
|
145
|
-
##
|
|
145
|
+
## tmux and VS Code Terminal Detection
|
|
146
|
+
|
|
147
|
+
tmux is the single most common reason `_find_vscode_ipc_hook()` fails even though the user IS in a VS Code terminal.
|
|
148
|
+
|
|
149
|
+
### Why the ancestor-walk fails inside tmux
|
|
150
|
+
|
|
151
|
+
Normal process tree (no tmux):
|
|
152
|
+
```
|
|
153
|
+
VS Code terminal shell (has VSCODE_IPC_HOOK_CLI)
|
|
154
|
+
└─ uv run python / arrayview ← walks up, finds it ✓
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Process tree inside tmux:
|
|
158
|
+
```
|
|
159
|
+
VS Code terminal shell (has VSCODE_IPC_HOOK_CLI)
|
|
160
|
+
└─ tmux (client process — also has VSCODE_IPC_HOOK_CLI)
|
|
161
|
+
↕ socket IPC (not parent/child)
|
|
162
|
+
tmux-server (independent daemon — does NOT have VSCODE_IPC_HOOK_CLI)
|
|
163
|
+
└─ pane shell
|
|
164
|
+
└─ uv run python / arrayview ← walks up through tmux-server, never finds it ✗
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
The arrayview process's parent chain goes through `tmux-server`, which is an independent daemon that was started at some point and does NOT inherit the VS Code terminal's environment.
|
|
168
|
+
|
|
169
|
+
### Why `tmux show-environment` fails
|
|
170
|
+
|
|
171
|
+
`tmux show-environment VSCODE_IPC_HOOK_CLI` queries tmux's *session* environment. tmux only tracks variables listed in its `update-environment` option. The default list is:
|
|
172
|
+
```
|
|
173
|
+
DISPLAY SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION WINDOWID XAUTHORITY
|
|
174
|
+
```
|
|
175
|
+
`VSCODE_IPC_HOOK_CLI` is **not** in the default list, so it is never copied into tmux's session environment. The command returns `-VSCODE_IPC_HOOK_CLI` (meaning unset) even when every client has it.
|
|
176
|
+
|
|
177
|
+
### Why `#{client_pid}` alone is unreliable
|
|
178
|
+
|
|
179
|
+
`tmux display-message -p '#{client_pid}'` returns **one** client PID (the "current" client). This fails when:
|
|
180
|
+
- Multiple clients are attached to the session (e.g., shared session, or user has the session open in both VS Code and a regular terminal)
|
|
181
|
+
- A session was created outside VS Code and then attached from VS Code
|
|
182
|
+
|
|
183
|
+
### Correct approach: enumerate ALL clients for the current session
|
|
184
|
+
|
|
185
|
+
```python
|
|
186
|
+
# Get current session ID
|
|
187
|
+
session_id = subprocess.run(["tmux", "display-message", "-p", "#{session_id}"], ...).stdout.strip()
|
|
188
|
+
|
|
189
|
+
# List ALL clients for this session
|
|
190
|
+
client_pids = subprocess.run(
|
|
191
|
+
["tmux", "list-clients", "-t", session_id, "-F", "#{client_pid}"], ...
|
|
192
|
+
).stdout.strip().splitlines()
|
|
193
|
+
|
|
194
|
+
# Check each client's environment
|
|
195
|
+
for pid_str in client_pids:
|
|
196
|
+
val = _ipc_from_pid(int(pid_str))
|
|
197
|
+
if val and os.path.exists(val):
|
|
198
|
+
return val # found VSCODE_IPC_HOOK_CLI in one of the VS Code clients ✓
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
`list-clients -t <session_id>` scopes to the current session only, so we don't accidentally pick up a `VSCODE_IPC_HOOK_CLI` from a completely different VS Code window on another session.
|
|
202
|
+
|
|
203
|
+
### Detection order in `_find_vscode_ipc_hook()` (when TERM_PROGRAM=tmux)
|
|
204
|
+
|
|
205
|
+
1. `tmux show-environment VSCODE_IPC_HOOK_CLI` — cheap, works if user set `update-environment`
|
|
206
|
+
2. `tmux list-clients -t <session_id> -F '#{client_pid}'` → `ps ewwww` each — robust, handles all cases
|
|
207
|
+
|
|
208
|
+
### What `--diagnose` should show when working
|
|
209
|
+
|
|
210
|
+
```json
|
|
211
|
+
"detection": {
|
|
212
|
+
"in_vscode_terminal": true,
|
|
213
|
+
"vscode_ipc_hook_recovered": "/var/folders/.../vscode-ipc-xxx.sock"
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
If `vscode_ipc_hook_recovered` is `null` despite being in VS Code+tmux, the strategies above both failed. Check:
|
|
218
|
+
- Is the tmux session detached (no clients attached)?
|
|
219
|
+
- Is `ps ewwww -p <client_pid>` working on this OS? (Some Linux distros restrict it)
|
|
220
|
+
- Is the IPC socket path valid (does the `.sock` file exist)?
|
|
221
|
+
|
|
222
|
+
### Red flags for tmux detection
|
|
223
|
+
|
|
224
|
+
- "I fixed it with `#{client_pid}`" → only works with one client; use `list-clients` instead
|
|
225
|
+
- "I fixed it with `show-environment`" → only works if user customised `update-environment`; both strategies needed
|
|
226
|
+
- "It works for me but not for the user" → check if they have multiple clients or a session created before VS Code
|
|
227
|
+
|
|
228
|
+
|
|
146
229
|
|
|
147
230
|
- "I changed how the server starts but only tested CLI" → test all paths
|
|
148
231
|
- "The feature works locally but not in tunnel" → check `_is_vscode_remote()` path and port exposure
|
|
@@ -20,9 +20,9 @@ jobs:
|
|
|
20
20
|
runs-on: ubuntu-latest
|
|
21
21
|
|
|
22
22
|
steps:
|
|
23
|
-
- uses: actions/checkout@
|
|
23
|
+
- uses: actions/checkout@v6
|
|
24
24
|
|
|
25
|
-
- uses: actions/setup-python@
|
|
25
|
+
- uses: actions/setup-python@v6
|
|
26
26
|
with:
|
|
27
27
|
python-version: "3.x"
|
|
28
28
|
|
|
@@ -33,7 +33,7 @@ jobs:
|
|
|
33
33
|
python -m build
|
|
34
34
|
|
|
35
35
|
- name: Upload distributions
|
|
36
|
-
uses: actions/upload-artifact@
|
|
36
|
+
uses: actions/upload-artifact@v7
|
|
37
37
|
with:
|
|
38
38
|
name: release-dists
|
|
39
39
|
path: dist/
|
|
@@ -59,7 +59,7 @@ jobs:
|
|
|
59
59
|
|
|
60
60
|
steps:
|
|
61
61
|
- name: Retrieve release distributions
|
|
62
|
-
uses: actions/download-artifact@
|
|
62
|
+
uses: actions/download-artifact@v8
|
|
63
63
|
with:
|
|
64
64
|
name: release-dists
|
|
65
65
|
path: dist/
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# ArrayView Agent Guide
|
|
2
|
+
|
|
3
|
+
This file defines how coding agents should work in this repository.
|
|
4
|
+
|
|
5
|
+
## Mission
|
|
6
|
+
|
|
7
|
+
Build and maintain a smooth `arrayview` experience across:
|
|
8
|
+
|
|
9
|
+
- Local: CLI, Python scripts, Jupyter, Julia via PythonCall
|
|
10
|
+
- Display modes: native `pywebview` and browser
|
|
11
|
+
- VS Code terminals: browser opens should prefer VS Code Simple Browser
|
|
12
|
+
- VS Code remote/tunnel sessions: viewer should open in the developer's VS Code client, not on the remote host browser
|
|
13
|
+
|
|
14
|
+
## Product Overview
|
|
15
|
+
|
|
16
|
+
`arrayview` is an interactive viewer for multi-dimensional arrays and medical/scientific volumes.
|
|
17
|
+
It runs a local FastAPI server with an HTML/JS frontend, then displays it either:
|
|
18
|
+
|
|
19
|
+
- in a native `pywebview` window,
|
|
20
|
+
- in a browser (including VS Code Simple Browser in VS Code terminals), or
|
|
21
|
+
- inline in Jupyter notebooks.
|
|
22
|
+
|
|
23
|
+
## Architecture
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
CLI / Python API
|
|
27
|
+
|
|
|
28
|
+
+- view() Python entry point (_launcher.py)
|
|
29
|
+
+- arrayview() CLI entry point (`uvx arrayview file.npy`) (_launcher.py)
|
|
30
|
+
|
|
|
31
|
+
+- FastAPI server (_server.py)
|
|
32
|
+
+- / viewer HTML
|
|
33
|
+
+- /shell pywebview shell HTML
|
|
34
|
+
+- /ws/{sid} WebSocket for render updates
|
|
35
|
+
+- /load register arrays
|
|
36
|
+
+- /ping health check
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Core Files
|
|
40
|
+
|
|
41
|
+
### Backend (server-side)
|
|
42
|
+
|
|
43
|
+
| File | Responsibility |
|
|
44
|
+
|------|---------------|
|
|
45
|
+
| `src/arrayview/_launcher.py` | Entry points (`view()`, `arrayview()` CLI), process management, window opening |
|
|
46
|
+
| `src/arrayview/_server.py` | FastAPI app, all REST routes, WebSocket handlers, HTML templates |
|
|
47
|
+
| `src/arrayview/_session.py` | Sessions, global state, caches, render thread, constants |
|
|
48
|
+
| `src/arrayview/_render.py` | Rendering pipeline: colormaps, LUTs, slice extraction, RGBA/mosaic/RGB |
|
|
49
|
+
| `src/arrayview/_vscode.py` | VS Code extension management, signal-file IPC, browser opening |
|
|
50
|
+
| `src/arrayview/_platform.py` | Platform/environment detection |
|
|
51
|
+
| `src/arrayview/_io.py` | Array I/O (load from file, format detection) |
|
|
52
|
+
| `src/arrayview/_app.py` | **Compat shim only** — re-exports from the modules above; do not add logic here |
|
|
53
|
+
|
|
54
|
+
### Frontend
|
|
55
|
+
|
|
56
|
+
| File | Responsibility |
|
|
57
|
+
|------|---------------|
|
|
58
|
+
| `src/arrayview/_viewer.html` | Viewer UI (single-file, all JS/CSS embedded) |
|
|
59
|
+
| `src/arrayview/_shell.html` | Shell page for native tab/window management |
|
|
60
|
+
|
|
61
|
+
### VS Code Extension
|
|
62
|
+
|
|
63
|
+
| File | Responsibility |
|
|
64
|
+
|------|---------------|
|
|
65
|
+
| `vscode-extension/extension.js` | VS Code opener behavior |
|
|
66
|
+
| `vscode-extension/package.json` | Extension metadata and version |
|
|
67
|
+
| `src/arrayview/arrayview-opener.vsix` | Packaged extension installed by Python code |
|
|
68
|
+
|
|
69
|
+
## Skills — When to Use
|
|
70
|
+
|
|
71
|
+
**Always invoke the relevant skill before touching the corresponding area.**
|
|
72
|
+
|
|
73
|
+
| Skill | Trigger |
|
|
74
|
+
|-------|---------|
|
|
75
|
+
| `viewer-ui-checklist` | ANY UI change: keyboard shortcuts, layout, new panels, canvas behavior. Keeps `visual_smoke.py` in sync. |
|
|
76
|
+
| `modes-consistency` | ANY visual feature: zoom, eggs, colorbars, canvas events, new rendering modes. Ensures the feature works across all six viewing modes (normal, multi-view, compare, diff, registration, qMRI). |
|
|
77
|
+
| `invocation-consistency` | ANY server, startup, or display-opening change. Ensures the feature works across all six invocation paths: CLI, Python script, Jupyter, Julia, VS Code tunnel, plain SSH. |
|
|
78
|
+
| `vscode-simplebrowser` | ANY change to VS Code extension install logic, signal-file IPC, `_ensure_vscode_extension()`, `_VSCODE_EXT_VERSION`, or `vscode-extension/`. Encodes the root-cause history of the extension-host reload race condition. |
|
|
79
|
+
| `task-workflow` | Feature or fix tasks — enforces one-commit-per-TODO-item workflow and required collateral updates (README/help/tests/CHANGELOG). |
|
|
80
|
+
|
|
81
|
+
Skill files live in `.claude/skills/` and are symlinked from `~/.claude/skills/`.
|
|
82
|
+
|
|
83
|
+
## Non-Negotiables
|
|
84
|
+
|
|
85
|
+
- Run commands directly when possible; avoid asking the user to run routine commands.
|
|
86
|
+
- Before trying a new fix, check whether it was already attempted in prior logs/notes.
|
|
87
|
+
- If re-trying a previously failed approach, explicitly note why it may work now.
|
|
88
|
+
- Avoid manual cleanup requirements for users. Viewer shutdown should be automatic and reliable.
|
|
89
|
+
- Do not regress existing working paths while fixing tunnel/remote behavior.
|
|
90
|
+
- Do not add logic to `_app.py` — it is a compat shim only. Add new logic to the appropriate module.
|
|
91
|
+
|
|
92
|
+
## Testing
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
uv sync --group test
|
|
96
|
+
uv run playwright install chromium
|
|
97
|
+
|
|
98
|
+
# Fast: HTTP API only (~2s)
|
|
99
|
+
uv run pytest tests/test_api.py -v
|
|
100
|
+
|
|
101
|
+
# CLI entry-point tests
|
|
102
|
+
uv run pytest tests/test_cli.py -v
|
|
103
|
+
|
|
104
|
+
# Browser/Playwright tests (~100s)
|
|
105
|
+
uv run pytest tests/test_browser.py -v
|
|
106
|
+
|
|
107
|
+
# All tests
|
|
108
|
+
uv run pytest tests/
|
|
109
|
+
|
|
110
|
+
# Visual smoke test — run after any UI change, review screenshots
|
|
111
|
+
uv run python tests/visual_smoke.py
|
|
112
|
+
# Screenshots saved to tests/smoke_output/
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Visual regression baselines are in `tests/snapshots/`. Delete a snapshot file to reset its baseline.
|
|
116
|
+
|
|
117
|
+
## Validation Matrix
|
|
118
|
+
|
|
119
|
+
After any change, verify the affected paths:
|
|
120
|
+
|
|
121
|
+
| What changed | Minimum checks |
|
|
122
|
+
|---|---|
|
|
123
|
+
| Server / API | `pytest tests/test_api.py` |
|
|
124
|
+
| CLI / entry points | `pytest tests/test_cli.py` |
|
|
125
|
+
| Viewer UI | `pytest tests/test_browser.py` + `python tests/visual_smoke.py` |
|
|
126
|
+
| VS Code / platform | Manual: VS Code local terminal, VS Code remote/tunnel |
|
|
127
|
+
| Large array handling | `pytest tests/test_large_arrays.py` |
|
|
128
|
+
|
|
129
|
+
Manual smoke paths (for platform/display changes):
|
|
130
|
+
- Local CLI: `arrayview file.npy`
|
|
131
|
+
- Python script: `view(arr)`
|
|
132
|
+
- Jupyter inline (default)
|
|
133
|
+
- VS Code terminal browser path
|
|
134
|
+
- VS Code remote/tunnel path
|
|
135
|
+
|
|
136
|
+
## Platform Behavior (Must Preserve)
|
|
137
|
+
|
|
138
|
+
- Local Python/CLI: native window by default, browser fallback available
|
|
139
|
+
- Jupyter: inline iframe by default; explicit window mode still supported
|
|
140
|
+
- VS Code terminal: browser opens should target VS Code Simple Browser
|
|
141
|
+
- VS Code tunnel/SSH remote: should open in VS Code Simple Browser, never open UI on remote host browser by mistake
|
|
142
|
+
- Use `localhost` in URLs (not `127.0.0.1`) for reliable VS Code port forwarding
|
|
143
|
+
|
|
144
|
+
## VS Code Integration
|
|
145
|
+
|
|
146
|
+
Key functions (all in `_vscode.py`):
|
|
147
|
+
|
|
148
|
+
- `_ensure_vscode_extension()` — installs/updates the VSIX; must handle stale versions robustly
|
|
149
|
+
- `_configure_vscode_port_preview()` — sets up port forwarding for the viewer URL
|
|
150
|
+
- `_open_via_signal_file()` — IPC mechanism to open URLs in the VS Code client
|
|
151
|
+
- `_schedule_remote_open_retries()` — retries for tunnel environments where IPC may not be immediately available
|
|
152
|
+
|
|
153
|
+
`_VSCODE_EXT_VERSION` is defined in `_vscode.py` and must match `vscode-extension/package.json`.
|
|
154
|
+
If extension behavior changes, rebuild the VSIX and keep versioning in sync.
|
|
155
|
+
|
|
156
|
+
## Rebuild VS Code Extension
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
cd vscode-extension
|
|
160
|
+
vsce package -o ../src/arrayview/arrayview-opener.vsix
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Then update `_VSCODE_EXT_VERSION` in `src/arrayview/_vscode.py`.
|
|
164
|
+
|
|
165
|
+
## High-Risk Areas
|
|
166
|
+
|
|
167
|
+
- VS Code extension install/update detection and stale extension versions
|
|
168
|
+
- Recovering VS Code IPC hook when env vars are stripped (`uv run` and subprocesses)
|
|
169
|
+
- Deciding when to use native window vs browser vs VS Code Simple Browser
|
|
170
|
+
- Port-forward/autoforward behavior in tunnel environments
|
|
171
|
+
- Shutdown lifecycle and orphan process prevention
|
|
172
|
+
|
|
173
|
+
## Workflow For Complex Debugging
|
|
174
|
+
|
|
175
|
+
1. Start a logfile `LOG_<FEATURE>.md`.
|
|
176
|
+
2. Record each significant attempt: hypothesis → change made → result → decision (keep/revert/follow-up).
|
|
177
|
+
3. Prefer incremental, testable changes.
|
|
178
|
+
4. Verify behavior in the most failure-prone environments: VS Code local terminal, VS Code remote/tunnel.
|
|
179
|
+
5. If behavior is not as expected, re-read the logfile before a new attempt.
|
|
180
|
+
|
|
181
|
+
## Source Of Truth
|
|
182
|
+
|
|
183
|
+
- End-user usage and setup: `README.md`
|
|
184
|
+
|
|
185
|
+
## Changelog
|
|
186
|
+
|
|
187
|
+
- **multi-overlay**: `view(arr, overlay=[mask1, mask2, ...])` now accepts a list of overlay masks, each auto-assigned a distinct palette color. Binary masks use the palette color; multi-label masks use per-label colors; continuous/float masks render as heatmap. Server compositing uses `_composite_overlays` in `_server.py`.
|
|
188
|
+
- **welcome-screen**: Canvas capped to 50% viewport height; yellow hint text (⌘O / Ctrl+O · drop file) shown below canvas instead of centered overlay. `body.welcome-mode` CSS class applied.
|
|
189
|
+
- **smart-colormap**: REMOVED. Automatic colormap selection at load time has been removed. `_recommend_colormap()` and `session.recommended_colormap` deleted; `/metadata` no longer returns `recommended_colormap`. `_recommend_colormap_reason()` is retained to power the info overlay (i key) Colormap row.
|
|
190
|
+
- **watch-mode**: `arrayview file.npy --watch` polls file mtime every 1 s and POSTs to `/reload/{sid}` on change; server reloads array in-place, clears caches, bumps `data_version`; frontend polls `/data_version/{sid}` every 1.5 s and re-renders on version bump.
|
|
191
|
+
- **export-slice**: `N` key exports the current 2-D slice (raw float data) as a `.npy` file download via `/export_slice/{sid}`. Works in all viewing modes; not available in RGB mode.
|
|
192
|
+
- **view-handle**: `view()` now returns a `ViewHandle` (str subclass) exposing `.update(arr)`, `.sid`, `.url`, `.port`. `ViewHandle.update()` POSTs new .npy bytes to `/update/{sid}` endpoint, which replaces session data in-place, clears caches, recomputes stats, and bumps `data_version` so the viewer re-renders automatically.
|
|
193
|
+
- **histogram-strip**: `W` key toggles a pixel-value histogram strip below the colorbar. `/histogram/{sid}` endpoint returns `{counts, edges, vmin, vmax}` for the current 2-D slice; frontend renders it on a `<canvas>` via `drawHistogram()`. Refreshes automatically on slice/index changes. Disabled in compare and RGB modes.
|
|
194
|
+
- **histogram-drag-clim**: Dragging the yellow vertical lines in the histogram (W key) changes `manualVmin`/`manualVmax` live. Hit radius is 7 px. Hovering anywhere on the histogram shows a tooltip with the bin value range and count. Cursor changes to `ew-resize` near a line. Smoke: scenario 55.
|
|
195
|
+
- **linked-crosshair**: REMOVED. The linked crosshair feature introduced in commit a778ab7 caused a visual bug (small array rendering in top-left corner of the window with info overlaid). All `.cv-crosshair` overlay canvases, `_drawCrossHair()`, `_clearAllCrossHairs()`, and mousemove/mouseleave listeners on compare canvases have been removed.
|
|
196
|
+
- **drag-reorder**: In compare mode, dragging a panel title (`.compare-title`) and dropping it onto another swaps their order instantly without re-fetching frames. Swaps `compareDisplaySids`, `compareFrames`, and per-pane `cmpManualVmin/cmpManualVmax`. Disabled in registration mode. Drag-over pane gets a dashed outline highlight.
|
|
197
|
+
- **screenshot-annotation**: `s` key screenshot now burns filename and current slice index into the bottom-left corner of the exported PNG. `_buildAnnotation()` collects name/shape/indices; `_annotateCanvas(src, lines)` renders a semi-transparent black box with white monospace text onto the offscreen canvas before `toDataURL`. Works in normal and multi-view modes.
|
|
198
|
+
- **rect-roi**: `A` key toggles rectangle ROI draw mode on the main canvas. Drag to select a rectangular region; on release, fetches `/roi/{sid}` with `x0,y0,x1,y1` pixel coordinates (data-space) and displays `{n, min, max, mean, std}` in the existing `#roi-panel`. Disabled in compare, multi-view, and qMRI modes. Circular ROI draw (drag without A mode) remains unchanged.
|
|
199
|
+
- **info-overlay-enhanced**: `i` key info overlay now includes a "Colormap" row showing the auto-selection reason (e.g. `"RdBu_r (signed data — vmin < 0)"`). `/info/{sid}` endpoint returns `recommended_colormap` and `recommended_colormap_reason` fields. Reason derived from `_recommend_colormap_reason()` in `_session.py`.
|
|
200
|
+
- **screenshot-save-location**: `s` screenshot status now reads "Screenshot saved to Downloads." and `N` slice export reads "slice saved to Downloads (.npy)". Help overlay keys `s` and `N` updated to show "(PNG → Downloads)" and "(.npy → Downloads)" respectively.
|
|
201
|
+
- **vscode-simplebrowser**: `_ensure_vscode_extension()` now skips `--force` reinstall when the correct version is already on disk (avoids extension-host reload that caused signal-file miss). `_VSCODE_SIGNAL_MAX_AGE_MS` raised from 30 s to 60 s. Local VS Code terminal path now schedules 2 retry signal writes at 10 s intervals (matches remote retry pattern) to survive any residual reload gap.
|
|
202
|
+
- **shift-o-picker**: `Shift+O` now opens the picker (same as `Cmd/Ctrl+O`). Welcome hint updated to "⌘O / Shift+O · drop array in window"; empty-hint and help overlay updated to match.
|
|
203
|
+
- **hover-info-immediate**: Pressing `H` to enable hover info now immediately shows the pixel tooltip at the current mouse position by dispatching a synthetic `mousemove` event on the canvas, instead of waiting for the user to move the mouse.
|
|
204
|
+
- **picker-rewrite**: Picker rewritten as a single unified mode (no tabs, no Open/Compare/Overlay switching). Space toggles selection on any listed array (up to 4); Enter with 0–1 selected opens/navigates; Enter with 2–4 selected enters compare mode with exactly those arrays (current session not auto-included). Overlay mode removed from picker. `enterCompareModeByMultipleSids(sids)` added; `_compareExplicitSids` state bypasses the always-prepend-current logic in `getCompareRenderSids()`. `applyCompareLayout()` and `updateCompareTitles()` use `_compareExplicitSids` for correct pane count before first render. Selected items get a green checkmark and highlighted border. Help overlay updated.
|
|
205
|
+
- **vscode-tab-title**: VS Code tab now shows "ArrayView: <array name>" instead of the URL. Extension switched from `simpleBrowser.show()` (title always "Simple Browser") to `vscode.window.createWebviewPanel()` with a custom label; title is passed in the signal payload (`data.title`) derived from `session.name`. Panels are reused by URL (revealed on repeat open). Multi-window fix: `_write_vscode_signal` now always writes to the per-window targeted file (`open-request-ipc-<hookTag>.json`) when `VSCODE_IPC_HOOK_CLI` is found — the registration-file (`window-<hookTag>.json`) existence check has been removed, eliminating the race where the shared fallback was written and claimed by the wrong window. Extension-side: shared-fallback signals with a mismatched `hookTag` are forwarded to the correct targeted file instead of being processed. Extension version bumped to 0.9.15. **Fix (v0.9.16)**: `enableScripts` was inadvertently left `false` in `createWebviewPanel`, which disabled all JavaScript inside the iframe and caused a "Connecting..." hang. Fixed by setting `enableScripts: true, enableForms: true`, adding a nonce-based CSP (`script-src 'nonce-...'`), and setting the iframe `src` via an inline script (matching VS Code's own Simple Browser pattern) rather than as an HTML attribute.
|
|
206
|
+
- **vscode-tunnel-signal**: Fixed VS Code tunnel: `_write_vscode_signal` now writes to the shared fallback file (`open-request-v0900.json`) when `_is_vscode_remote()` is True, instead of the per-window targeted file. Root cause: on a remote/tunnel, the extension host is spawned by VS Code Server (not the user's terminal) and does NOT inherit `VSCODE_IPC_HOOK_CLI`, so `OWN_HOOK_TAG=""` and `TARGETED_SIGNAL_FILE=null` in the extension — it only polls the shared fallback. On a tunnel there is only one VS Code session per remote, so there is no multi-window race concern. Also: tab title now correctly passed from all `_open_browser` call sites via `title=f"ArrayView: {name}"` — previously `title` was `None` in the CLI path because the session lives in a subprocess and `SESSIONS.get(sid)` returns `None` in the calling process. Retries (2× at 10 s) now also enabled on remote path since `createWebviewPanel` is idempotent.
|
|
207
|
+
- **histogram-colormap-bars**: Histogram bars (W key) are now colored using the active colormap. An offscreen 256-wide canvas draws the colormap gradient; each bar samples the gradient color at the fraction corresponding to its bin center within the current vmin/vmax window. Falls back to flat gray when no gradient stops are available. Smoke: scenario 60.
|
|
208
|
+
- **histogram-left-side**: Histogram strip (W key) repositioned from below the colorbar to the left side of the canvas, vertically aligned with it. Each bin maps to a y-band (value increases upward); bars grow rightward from the left edge. Clim lines are now horizontal; drag interaction is vertical (`ns-resize`). `bottomReserve` in `scaleCanvas` no longer includes histogram height. `_histVminY`/`_histVmaxY` replace old `_histVminX`/`_histVmaxX` for hit-testing. Smoke: scenarios 54, 55, 60.
|
|
209
|
+
- **axes-colormap-color**: Axis arrow indicators (`.axes-indicator`) now use a colormap-specific color instead of sampling canvas brightness. `gray` colormap → `var(--active-dim)` theme yellow; known colormaps (viridis, plasma, magma, inferno, hot, cool, RdBu_r/RdBu, bwr, seismic, coolwarm, jet, turbo, PiYG, PRGn) → a Nord/pastel color not present in that colormap; custom/unknown → white. `refreshAxesColor()` is also called on `c` and `C` (colormap change) key presses. Smoke: scenario 50.
|
|
210
|
+
- **welcome-hint-text**: Welcome hint and empty-hint now show `{cmd,ctrl,shift}+o · drop to open array` (plain ASCII, no platform-specific unicode). Help overlay updated to mention `Ctrl+O, Shift+O` alongside `Cmd+O`.
|
|
211
|
+
- **vscode-tmux-detection**: `_find_vscode_ipc_hook()` uses two tmux fallback strategies when `TERM_PROGRAM=tmux`. Strategy 1: `tmux show-environment VSCODE_IPC_HOOK_CLI` (works if the variable is in tmux's tracked env). Strategy 2: `tmux display-message -p '#{session_id}'` to get the current session, then `tmux list-clients -t <session_id> -F '#{client_pid}'` to enumerate ALL clients for that session, then reads each client's environment via `ps ewwww`. This correctly handles multiple attached clients (e.g. shared sessions, session created outside VS Code then attached from VS Code terminal). Scoping to the current session prevents false-positive detection from a VSCODE_IPC_HOOK_CLI belonging to a different VS Code window in another tmux session. See `invocation-consistency` skill for full tmux process-tree explanation.
|
|
212
|
+
- **picker-fix**: Removed duplicate stale `showUnifiedPicker` definition that was left by the picker-rewrite commit. The old version (second in the file) referenced undefined `_UNI_MODES`/`_UNI_LABELS`/`_UNI_COLORS` constants, causing a `TypeError` crash every time the picker was opened. Also removed the duplicate `getCompareCandidates` and old `enterComparePrompt` that used the superseded return format.
|
|
213
|
+
- **compare-pane-ordering**: Fixed wrong visual order and wrong pane names for 3/4-array compare. Root cause: `.compare-secondary` had CSS `order: 2` while `.compare-tertiary`/`.compare-quaternary` had no `order` (defaulting to `0`), so in a 3-pane compare the tertiary pane appeared before secondary. Fix: `applyCompareLayout()` now explicitly sets `pane.style.order = idx` overriding all class-based CSS orders. Also fixed drag-reorder to sync `_compareExplicitSids` when swapping panes.
|
|
214
|
+
- **native-window-tabs**: Fixed multiple pywebview windows spawning when calling `view()` more than once from a CLI script or Julia. Root cause (subprocess path): `/load` POST was missing `notify=True`, so `_notify_shells` was never called server-side and a new shell window was always opened. Fix: add `"notify": True` to the `/load` POST; if `result["notified"]` is True the tab was injected and no new window is opened. Also fixed the in-process `view()` path: `run_coroutine_threadsafe(_notify_shells(...))` result was previously ignored — if no shell socket was connected (window closed/crashed) no new window was opened. Fix: wait for the future result (3 s timeout); if `notified=False`, open a fresh native window.
|
|
215
|
+
- **histogram-in-colorbar**: Replaced the separate left-side histogram strip (`W` key toggle, `#hist-wrap`/`#hist-canvas`) with an integrated histogram that lives inside the colorbar. The colorbar is normally 8px tall; on mouse hover it smoothly expands to 40px, auto-fetches histogram data for the current slice, and draws colormap-colored bars growing upward from the gradient strip. Vertical vmin/vmax clim lines (yellow) appear when expanded and can be dragged horizontally (`ew-resize`). Hovering over the expanded colorbar shows a single-value tooltip. On mouse leave, the colorbar collapses back to 8px after a 200ms delay. The `W` key shortcut and help overlay entry have been removed. Histogram data is cached per slice and lazily re-fetched when the slice changes while expanded. Disabled in compare and RGB modes. Smoke: scenarios 54, 55.
|
|
216
|
+
- **lebesgue-mode**: `w` key toggles Lebesgue integral mode. When active, the colorbar stays expanded; hovering over a histogram bin highlights all canvas pixels whose raw data values fall in that bin. Non-matching pixels are dimmed with a semi-transparent dark overlay on `#lebesgue-canvas`. The hovered bin is outlined in yellow on the histogram. A new `/lebesgue/{sid}` endpoint returns the raw 2-D slice as float32 binary (fetched once per slice, cached client-side) for per-pixel bin lookup without server round-trips. Disabled in compare and RGB modes. Smoke: scenario 61.
|
|
217
|
+
- **compare-qmri**: Pressing `q` while in compare mode enters a combined compare-qMRI view: rows = compared arrays (up to 4), columns = parameter maps. Compact mode (T₁, T₂, |PD| only) is triggered by pressing `q` again when n>3; `q` once more exits. State: `compareQmriActive`, `compareQmriViews`, `compareQmriSids`, `compareQmriDim`. Render pipeline mirrors `qvRender` but uses each view's `sid`. Layout: `compareQmriScaleAllCanvases()` fits the grid into the viewport with column headers (`.cq-header-label`) and row labels (`.cq-row-label`). Per-pane slim colorbars via `drawCqSlimCb`. Smoke: scenario 62.
|
|
218
|
+
- **compare-multiview**: Pressing `v` (or `V`) while in compare mode enters a combined compare × 3-plane view: rows = compared arrays (up to 4), columns = Axial/Coronal/Sagittal planes (using `defaultMultiViewDims()`). `v` again exits back to compare mode. State: `compareMvActive`, `compareMvViews`, `compareMvSids`, `compareMvDims`. Render pipeline uses per-view `dimX`/`dimY`/`sliceDir` — same message format as `mvRender` but with per-row `sid`. Layout: `compareMvScaleAllCanvases()` mirrors `compareQmriScaleAllCanvases()`. Per-pane slim colorbars via `drawCmvSlimCb` (delegates to `drawQvSlimCb`). Canvas wheel scrubs the slice along `sliceDir`. `exitCompareMode()` calls `exitCompareMv()` if active. Zoom, resize, scrollbar, border key, and egg positioning all handle `compareMvActive`. Smoke: scenario 63.
|
|
219
|
+
- **ui-text-sizing**: Increased font sizes across the viewer: `#array-name` 11→13px; `#slim-cb-labels`/`#mv-cb-labels` 11→13px; `.qv-label`/`.cq-header-label` 14→16px; `.qv-cb-labels`/`.compare-pane-cb-labels` 9→11px. Row labels in compare-qMRI and compare-multiview (`.cq-row-label`) rotated 90° CCW (`writing-mode: vertical-rl; transform: rotate(180deg)`) to a narrow 24px-wide vertical strip, centered in the row. `.cq-header-row` `padding-left` removed (was a hack for the old horizontal label width). `.qv-row` `align-items` changed from `flex-start` to `center`.
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# Chunked Large-Array Support Plan (NumPy + Zarr)
|
|
2
|
+
|
|
3
|
+
## 1. Considerations First
|
|
4
|
+
|
|
5
|
+
### 1.1 Product goals
|
|
6
|
+
- Keep `arrayview` smooth for arrays from a few GB up to tens of GB.
|
|
7
|
+
- Preserve current behavior for existing users and formats.
|
|
8
|
+
- Avoid regressions across local CLI, Python API, Jupyter, VS Code local, and VS Code remote/tunnel.
|
|
9
|
+
|
|
10
|
+
### 1.2 User interaction model (drives chunk strategy)
|
|
11
|
+
- Primary interaction is 2D slice viewing with scroll on one axis.
|
|
12
|
+
- Secondary interactions are axis swaps, playback along slice dimension, compare mode, and overlay/vectorfield display.
|
|
13
|
+
- Latency sensitivity:
|
|
14
|
+
1. First frame should appear quickly.
|
|
15
|
+
2. Scroll should feel continuous.
|
|
16
|
+
3. Playback should degrade gracefully (lower FPS) instead of stalling UI.
|
|
17
|
+
|
|
18
|
+
### 1.3 Technical constraints in current codebase
|
|
19
|
+
- `.npy` already uses `np.load(..., mmap_mode="r")`.
|
|
20
|
+
- Slice extraction is already on-demand and cached.
|
|
21
|
+
- Some features force broad materialization and can blow memory/latency on huge data:
|
|
22
|
+
1. FFT path materializes full array.
|
|
23
|
+
2. Grid/GIF operations stack many slices.
|
|
24
|
+
3. Full preload is skipped above estimated threshold.
|
|
25
|
+
- Current cache limits are fixed, not adaptive.
|
|
26
|
+
- Frontend loading overlay is mostly initial-load UX, not per-slice latency UX.
|
|
27
|
+
|
|
28
|
+
### 1.4 Performance constraints to explicitly target
|
|
29
|
+
- Storage variability: NVMe vs network filesystems.
|
|
30
|
+
- CPU variability: decompression cost vs I/O savings.
|
|
31
|
+
- Memory ceilings: avoid unbounded growth in session/cache paths.
|
|
32
|
+
|
|
33
|
+
### 1.5 Format strategy constraints
|
|
34
|
+
- Must support both classic NumPy pipelines and chunked pipelines.
|
|
35
|
+
- Do not force migration to Zarr for all users.
|
|
36
|
+
- Large-array users need a documented and predictable “best path.”
|
|
37
|
+
|
|
38
|
+
### 1.6 Non-negotiables
|
|
39
|
+
- No regressions in VS Code Simple Browser and remote/tunnel routing behavior.
|
|
40
|
+
- No manual cleanup burden.
|
|
41
|
+
- Keep local workflows simple (`arrayview file.npy` continues to work).
|
|
42
|
+
|
|
43
|
+
## 2. Architecture Direction
|
|
44
|
+
|
|
45
|
+
### 2.1 Dual-path data access model
|
|
46
|
+
- Path A: `.npy` + memmap for straightforward lazy reads with low complexity.
|
|
47
|
+
- Path B: `.zarr` for interaction-optimized chunked access and better random slicing behavior.
|
|
48
|
+
|
|
49
|
+
### 2.2 Recommended workload mapping
|
|
50
|
+
- Use `.npy` when:
|
|
51
|
+
1. Access is mostly sequential in a predictable dimension.
|
|
52
|
+
2. Dataset size is large but still performs acceptably with memmap on local fast disk.
|
|
53
|
+
- Use `.zarr` when:
|
|
54
|
+
1. Users frequently swap axes and jump around.
|
|
55
|
+
2. Datasets are tens of GB and smooth random slice access matters.
|
|
56
|
+
3. Storage is remote or high-latency.
|
|
57
|
+
|
|
58
|
+
### 2.3 Chunking design principle
|
|
59
|
+
- Chunk to match interaction, not mathematical symmetry.
|
|
60
|
+
- Keep displayed dimensions broad, scrolled dimension shallow.
|
|
61
|
+
- Initial target chunk byte size: 1-8 MB uncompressed (allow up to ~16 MB on fast systems).
|
|
62
|
+
|
|
63
|
+
## 3. Detailed Execution Plan
|
|
64
|
+
|
|
65
|
+
## Phase 0: Baseline and Logging
|
|
66
|
+
- Create `LOG_LARGE_ARRAYS.md`.
|
|
67
|
+
- Record each attempt with hypothesis, change, result, decision.
|
|
68
|
+
- Build representative benchmark set:
|
|
69
|
+
1. 3D scalar volume.
|
|
70
|
+
2. 4D volume/time or channel data.
|
|
71
|
+
3. Large compare use case (2-3 arrays).
|
|
72
|
+
4. One remote filesystem scenario if available.
|
|
73
|
+
- Capture baseline metrics for current main branch:
|
|
74
|
+
1. First-frame latency.
|
|
75
|
+
2. p50/p95 scroll latency.
|
|
76
|
+
3. Playback FPS.
|
|
77
|
+
4. Peak RSS and cache bytes.
|
|
78
|
+
5. CPU utilization during scroll/playback.
|
|
79
|
+
|
|
80
|
+
## Phase 1: Define and Document Chunk Presets
|
|
81
|
+
- Specify chunk presets by shape archetype:
|
|
82
|
+
1. 3D volume `(Y, X, Z)`: example `(512, 512, 1)` or `(1024, 1024, 1)` depending on pixel size.
|
|
83
|
+
2. 4D `(Y, X, Z, T)`: example `(512, 512, 1, 2-4)`.
|
|
84
|
+
3. If T-playback is dominant, increase T depth and reduce XY chunk if needed.
|
|
85
|
+
- Define compression defaults for Zarr:
|
|
86
|
+
1. Start with lightweight compressor to minimize decode stalls.
|
|
87
|
+
2. Keep option for no compression when storage is very fast and CPU is constrained.
|
|
88
|
+
- Add clear guidance in docs:
|
|
89
|
+
1. “When to keep `.npy`.”
|
|
90
|
+
2. “When to convert to `.zarr`.”
|
|
91
|
+
3. “How to pick chunk shapes by interaction.”
|
|
92
|
+
|
|
93
|
+
## Phase 2: User-Facing Conversion Workflow
|
|
94
|
+
- Add a documented conversion recipe from `.npy`/NIfTI to `.zarr`.
|
|
95
|
+
- Include optional rechunk step and examples per shape archetype.
|
|
96
|
+
- Include verification checklist:
|
|
97
|
+
1. Shape/dtype parity.
|
|
98
|
+
2. Slice value parity spot checks.
|
|
99
|
+
3. Compression ratio and resulting storage size.
|
|
100
|
+
|
|
101
|
+
## Phase 3: Runtime Behavior Improvements for Large Arrays
|
|
102
|
+
- Add per-slice “loading” indicator behavior:
|
|
103
|
+
1. Only show when render exceeds a small threshold to avoid flicker.
|
|
104
|
+
2. Hide immediately on frame receipt.
|
|
105
|
+
- Keep latest-request-wins behavior to avoid queue buildup while scrolling.
|
|
106
|
+
- Add bounded neighbor prefetch:
|
|
107
|
+
1. Direction-aware (`+/-` around current index).
|
|
108
|
+
2. Respect strict memory budget.
|
|
109
|
+
3. Auto-throttle when latency rises.
|
|
110
|
+
|
|
111
|
+
## Phase 4: Guardrails for Heavy Operations
|
|
112
|
+
- Add explicit large-array guardrails/warnings for:
|
|
113
|
+
1. FFT.
|
|
114
|
+
2. GIF/grid generation.
|
|
115
|
+
3. Full-dimension preloads.
|
|
116
|
+
- Offer safe fallback behavior:
|
|
117
|
+
1. Cancel heavy action with clear status message.
|
|
118
|
+
2. Allow explicit override for advanced users.
|
|
119
|
+
|
|
120
|
+
## Phase 5: Cache Policy and Memory Budgeting
|
|
121
|
+
- Make cache budgets configurable (env var or settings).
|
|
122
|
+
- Add optional adaptive defaults based on detected RAM.
|
|
123
|
+
- Define hard ceilings per session and total process budget.
|
|
124
|
+
- Improve visibility:
|
|
125
|
+
1. Debug endpoint or logs for cache hit/miss and byte usage.
|
|
126
|
+
2. Include prefetch hit rate and eviction churn metrics.
|
|
127
|
+
|
|
128
|
+
## Phase 6: Validation and Regression Testing
|
|
129
|
+
- Extend automated tests:
|
|
130
|
+
1. API tests for `.zarr` and `.npy` parity on slice outputs.
|
|
131
|
+
2. Browser tests for loading indicator behavior under artificial delay.
|
|
132
|
+
3. Tests for guardrail behavior on large synthetic shapes.
|
|
133
|
+
- Run validation matrix:
|
|
134
|
+
1. Local CLI.
|
|
135
|
+
2. Python `view(arr)` and `view(zarr_array)`.
|
|
136
|
+
3. Jupyter inline.
|
|
137
|
+
4. VS Code terminal local.
|
|
138
|
+
5. VS Code remote/tunnel.
|
|
139
|
+
- Add manual smoke checklist for large arrays:
|
|
140
|
+
1. Scroll responsiveness.
|
|
141
|
+
2. Axis swap responsiveness.
|
|
142
|
+
3. Compare mode with large datasets.
|
|
143
|
+
4. No orphan server processes after close.
|
|
144
|
+
|
|
145
|
+
## Phase 7: Rollout Strategy
|
|
146
|
+
- Release as staged rollout:
|
|
147
|
+
1. Documentation + conversion first.
|
|
148
|
+
2. UX/caching/prefetch improvements next.
|
|
149
|
+
3. Guardrails + configurability final.
|
|
150
|
+
- Add release notes with:
|
|
151
|
+
1. Recommended format by dataset profile.
|
|
152
|
+
2. Known tradeoffs.
|
|
153
|
+
3. Tuning checklist for advanced users.
|
|
154
|
+
|
|
155
|
+
## 4. Acceptance Criteria
|
|
156
|
+
- Large dataset workflows (tens of GB) function without OOM in normal slice navigation.
|
|
157
|
+
- p95 scroll latency meets target in benchmark environments.
|
|
158
|
+
- First-frame latency remains acceptable on both `.npy` memmap and `.zarr`.
|
|
159
|
+
- No regressions in VS Code local/remote opening behavior.
|
|
160
|
+
- Heavy operations are clearly bounded or warned when unsafe.
|
|
161
|
+
|
|
162
|
+
## 5. Risks and Mitigations
|
|
163
|
+
- Risk: Bad chunk shapes cause many-chunk reads and stutter.
|
|
164
|
+
- Mitigation: Presets + benchmark-driven tuning + documented heuristics.
|
|
165
|
+
|
|
166
|
+
- Risk: Compression improves I/O but hurts CPU latency.
|
|
167
|
+
- Mitigation: Offer lightweight/no-compression profiles and measure p95 latency.
|
|
168
|
+
|
|
169
|
+
- Risk: Prefetch increases memory pressure.
|
|
170
|
+
- Mitigation: Hard prefetch budget and eviction policy.
|
|
171
|
+
|
|
172
|
+
- Risk: Feature regressions in compare/overlay paths.
|
|
173
|
+
- Mitigation: Targeted integration tests for those modes with large arrays.
|
|
174
|
+
|
|
175
|
+
## 6. Open Decisions (to resolve before implementation)
|
|
176
|
+
- Final latency targets per environment (local NVMe vs remote FS).
|
|
177
|
+
- Default chunk presets per modality/workflow.
|
|
178
|
+
- Default compressor settings.
|
|
179
|
+
- Whether large-array guardrails are soft warnings or hard blocks by default.
|