Python jobs under nsjail experience slow imports (~465ms for `import
requests`) because dependency directories are mounted read-only. Without
pre-compiled `.pyc` files, Python recompiles `.py` source to bytecode
in-memory on every import in every fresh nsjail process, paying the cost
repeatedly.
Add `--compile-bytecode` to both `uv pip install` invocations (the
Rust-driven install in python_executor.rs and the nsjail
download_deps.py.sh script) so `.pyc` files are generated at install
time and available at runtime even through read-only mounts. The files
are included in both the local cache and S3 piptar uploads.
The flag is supported by the uv version (0.9.24+) shipped in the
Dockerfile. The existing `__pycache__` skip only filters top-level dirs
for dedup logic, not subdirs within packages, so there is no conflict.
Fixes WIN-2001
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat: add global ai chat test tools
* fix: avoid session id in flow test preview
* test: cover global flow preview ids
* test: require script and flow test tools
* fix: harden global flow test fallback
* Revert "fix: harden global flow test fallback"
This reverts commit 97254ef33a.
* fix: fallback from inactive flow test hook
* fix: list nested flow steps in errors
* feat(frontend): surface local drafts in drawer editors with an unsaved-changes banner
Drawer-based editors (the 11 trigger types, plus resource and variable)
restore unsaved edits from browser localStorage on open using the same
mechanism as flows/scripts, but only showed a transient "Reset to deployed"
toast with no way to review the diff.
Add a persistent "You have unsaved changes" banner below the drawer header
with Show diff / Discard actions, shown whenever the form diverges from the
deployed baseline. Replaces the toast for these editors; flows/scripts/apps
(full-page) keep their existing toast.
- new shared LocalDraftBanner.svelte (Alert-styled bar + DiffDrawer)
- DrawerContent: optional `banner` snippet rendered below the header
- useTriggerDraftSync: reactive `hasDraft`, `deployed`/`current` getters and
`resetToDeployed`; drop the restore toast (banner supersedes it)
- wire the banner into all 11 trigger editors + variable; resource lifts its
dirty state up to ResourceEditorDrawer via a callback + accessors
- fix ScheduleEditorInner.openNew not resetting initialConfig (reused editor
instance kept a stale baseline, wrongly flagging a new schedule dirty)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(frontend): address PR review on local-draft drawer banners
- LocalDraftBanner: snapshot diff sides at click time so the diff drawer
doesn't keep updating as the user types behind it.
- VariableEditor / ResourceEditor: scope the banner and its Discard action
to the selected workspace; the cross-workspace dirty state stays surfaced
by the existing otherDirty Alert. Forward can_write via a new
onCanWriteChange callback so the resource banner hides Discard in
read-only mode (matching the trigger editors).
- useTriggerDraftSync: drop the now-unused path arg from maybeRestore and
update all 11 trigger editor call sites.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(frontend): deep-clone fallback in UserDraft.discard to avoid baseline aliasing
When a caller passed a live $state proxy as `fallback` (Variable/Resource
editors handed `initialStates[selected]` to the banner's Discard), the
handle's draft cell ended up sharing the same proxy as the caller's
baseline. Subsequent form edits mutated both sides in lock-step and the
dirty check kept reporting equal, so the banner never reappeared and
the Update button stayed disabled until the drawer was reopened.
Cloning the fallback inside `discard` (via `snapshotDraftValue`) gives
the handle a fresh tree and decouples the two reactive graphs. Trigger
editors already cloned at their call site (resetToDeployed); this just
makes the API self-contained for all callers.
Also switch the variable form's "Audit log for each access" alert from
warning to info — it's informational, not a warning.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(frontend): honor disabled prop in LocalDraftBanner's diff drawer
The banner's `disabled` prop hid the inline Discard button but the diff
drawer's "Discard changes" action was still wired unconditionally, so a
read-only user could bypass the hidden inline action via Show diff.
Gate the diff-drawer button on the same flag so both surfaces agree.
Flagged by cubic and Codex on PR #9335.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>