Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .deepsource.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ exclude_patterns = ["**/pkg/**", "generated/**", "services/ws-web-runner/mingw-s
# Repo convention: tests live in a `tests/` directory or in source files prefixed `test_`.
test_patterns = ["**/test_*.py", "**/tests/**"]

# Dart is explicitly deactivated; its coverage comes from the mise pipeline's check:dart instead.
# DeepSource's Dart support is an AI-only analyzer (no classic static analysis), so with AI review off it
# auto-surfaces as a perpetually-skipped "DeepSource: Dart" check on every PR.
[[analyzers]]
enabled = false
name = "dart"

[[analyzers]]
enabled = true
name = "python"
Expand Down
39 changes: 35 additions & 4 deletions .mise/config.dotnet.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,14 @@
[tools]
# Pinned: SDK churn re-keys the wasm-tools workload manifest, forcing a ~1.5GB pack re-download on every bump.
dotnet = "10.0.300"
dotnet-core = "10.0.300"
"dotnet:roslynator.dotnet.cli" = "latest"

[vars]
# MSBuild dir inside the mise dotnet SDK, for the roslynator `-m` flags below.
# `$DOTNET_ROOT` stays literal here; the task shell expands it. The version segment is the [tools] dotnet
# pin above -- bump together.
dotnet_msbuild = "$DOTNET_ROOT/sdk/10.0.300"

[tasks.dotnet-fmt]
description = "Format dotnet C# code"
run = "dotnet format"
Expand All @@ -14,15 +19,41 @@ run = "dotnet format"
description = "Check dotnet C# formatting"
run = "dotnet format --verify-no-changes"

# Namespaced aggregators picked up by the default config's globbed `check`/`fmt`.
[tasks.roslynator-check]
description = "Analyze C# sources (Roslynator)"
# Roslynator analyzes with its embedded analyzer assemblies, against the mise dotnet SDK's own MSBuild.
# The dotnet:roslynator.dotnet.cli tool ships the analyzers, so the csproj needs no analyzer
# PackageReference. Diagnostics at the default info-and-up severity fail the task; loading the project
# performs an implicit restore, so no `dotnet restore` dependency is needed.
#
# `-m` pins MSBuild to the mise dotnet SDK instead of MSBuildLocator's automatic discovery. On Windows the
# inline-task shell is busybox ash (windows_default_inline_shell_args), and busybox-w32 rewrites `\` to `/`
# in every env var it passes to children -- DOTNET_ROOT arrives as `C:/Users/...`, a form hostfxr accepts
# (dotnet-check works) but MSBuildLocator's SDK discovery does not, failing with:
# Cannot choose MSBuild location automatically. Use option '-m, --msbuild-path' to specify MSBuild location
# Observed on commit ef55945932f5d417b8d205530f0868cff6d73ffa (locally; reproduced under `mise exec` by
# setting a forward-slashed DOTNET_ROOT). The env var itself is fine as the `-m` argument -- mise's core
# dotnet plugin exports DOTNET_ROOT on every OS, and the forward-slashed form ash delivers on Windows is
# accepted there; only MSBuildLocator's own probing of it breaks.
run = 'roslynator analyze -m "{{ vars.dotnet_msbuild }}" services/ws-modules/dotnet-data1/dotnet-data1.csproj'

[tasks.roslynator-fix]
description = "Apply Roslynator diagnostics' machine-applicable C# fixes in place"
run = 'roslynator fix -m "{{ vars.dotnet_msbuild }}" services/ws-modules/dotnet-data1/dotnet-data1.csproj'

# Namespaced aggregators picked up by the default config's globbed `check`/`fmt`/`fix`.
[tasks."check:dotnet"]
depends = ["dotnet-check"]
description = "Run .NET checks (format verification)"
depends = ["dotnet-check", "roslynator-check"]
description = "Run .NET checks (format verification + Roslynator analysis)"

[tasks."fmt:dotnet"]
depends = ["dotnet-fmt"]
description = "Format .NET sources"

[tasks."fix:dotnet"]
depends = ["roslynator-fix"]
description = "Apply .NET lint-fix passes (roslynator fix)"

[tasks.build-ws-dotnet-data1-module]
description = "Build the dotnet-data1 C# WASM workflow module"
dir = "services/ws-modules/dotnet-data1"
Expand Down
15 changes: 9 additions & 6 deletions .mise/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,10 @@ a_rp_wasm_short = "08a1d6f"
# ("C:/Users/runneradmin/AppData/Local"), and a mixed-slash path trips uutils-coreutils' Windows path
# normalizer (`cp: The system cannot find the path specified. (os error 3)`).
gh_http = "--http-url https://github.com --progress --ignore-existing"
# OpenObserve docker image for the openobserve/o2 dev-observability task.
o2_image = "openobserve/openobserve:v0.70.3"
# pywasm1's own module version, templated into the pkg/package.json its build task emits.
pywasm1_pkg_version = "0.1.0"
rp_wasm_dir = '''{% if os() == "windows" -%}
{%- set base = (env?.LOCALAPPDATA or "") | replace(from="\\", to="/") -%}
{{- base -}}/mise/installs/http-rp-wasm/{{- vars.a_rp_wasm_short -}}
Expand Down Expand Up @@ -634,16 +638,15 @@ description = "Cross-check Dockerfiles against mise [tools] pins + heredoc body-
# 2. `ignore` parser, which preserves every line of the file as a separate entry -- conftest's dockerfile parser
# flattens heredoc bodies out of the AST, so the body-first-line `set -euo pipefail` check lives in its
# own namespace + parser.
# Each git-tracked Dockerfile* gets both passes.
# Each git-tracked Dockerfile* gets both passes, except that the `ignore` pass only visits Dockerfiles that
# actually contain heredocs: conftest 0.68.2's ignore parser panics with `runtime error: slice bounds out of
# range` on plain Dockerfiles (no heredocs), and the body-first-line rule has nothing to check there anyway.
run = """
files=$(git ls-files '*Dockerfile' '*Dockerfile.*')
# $files is a newline-separated path list; word-splitting is intentional (no spaces in paths).
# shellcheck disable=SC2086
conftest test --combine --namespace dockerfile -p config/conftest/policy $files .mise
# Filter to Dockerfiles that actually use heredocs before the `ignore` parser.
# conftest 0.68.2's ignore parser panics with
# `runtime error: slice bounds out of range` on plain Dockerfiles (no
# heredocs). The body-first-line rule has nothing to check there anyway.
for f in $files; do
if rg -q '^RUN[^\n]*<<' "$f"; then
conftest test --parser ignore --namespace dockerfile_heredoc -p config/conftest/policy "$f"
Expand Down Expand Up @@ -1110,7 +1113,7 @@ description = "Run both the ws-server and ws-wasm-agent using Chrome"

[tasks.openobserve]
alias = "o2"
run = "docker run --rm -it --name openobserve -p 5080:5080 --env-file config/o2.env openobserve/openobserve:v0.70.3"
run = "docker run --rm -it --name openobserve -p 5080:5080 --env-file config/o2.env {{ vars.o2_image }}"

[tasks.demo]
depends = ["openobserve", "ws-server"]
Expand Down Expand Up @@ -1237,7 +1240,7 @@ coreutils cat > pkg/package.json <<'PKG_JSON'
{
"name": "et-ws-pywasm1",
"type": "module",
"version": "0.1.0",
"version": "{{ vars.pywasm1_pkg_version }}",
"main": "index.js",
"files": [
"index.js",
Expand Down
45 changes: 25 additions & 20 deletions .mise/config.windows.toml
Original file line number Diff line number Diff line change
Expand Up @@ -212,18 +212,31 @@ _.path = ["{{ vars.m2_gnupg_bin }}", "{{ vars.maven_bin }}", "{{ vars.win_libcla
# flips rustup's default host to gnullvm so both host and target link via llvm-mingw rather than the absent
# MSVC link.exe (no Visual Studio Build Tools needed). The prereqs mise CAN'T supply (a recent mise + the
# VC++ runtime) are in the README.
#
# The body opens with a sha256sum fail-fast diagnostic for the Nano CI lane. mise's conda backend (mise
# 2026.6.5, src/hash.rs:file_hash_sha256, files > 50 MB only) shells out to whichever `sha256sum` PATH finds
# to verify each conda tarball download. On the Nano docker build that lookup historically hit a
# sha256sum.exe that fails to load with `STATUS_ENTRYPOINT_NOT_FOUND` (0xC0000139 == decimal -1073741511,
# the msys2-runtime autoload-trap signature), surfacing as:
# mise ERROR Failed to install conda:m2-git@latest: command ["sha256sum",
# "<path>"] exited with code -1073741511
# Dockerfile.nanoserver stages a busybox-w32-backed `sha256sum.exe` ahead of the broken shim on PATH so the
# check should now pass; failing fast tells us which binary PATH picked when the next CI break hits.
#
# The pipx bootstrap's rustpython arm carries pinned-version baggage: RustPython's bundled ensurepip is pip
# 26.1.1, which crashes on import via `sys.addaudithook` (rustpython 0.5.0 doesn't implement --
# RustPython#7956), so that arm fetches pip 26.0.1 (the last release before that audit hook landed, commit
# fb01b1830 / 2026-04-14), unzips the wheel, and puts it on RUSTPYTHONPATH so `rustpython -m pip` resolves
# to that copy. config.maint.toml's `rustpython-investigation` task documents the workaround at length, and
# also explains the PIPX_SHARED_LIBS pre-creation: pipx's first install creates a shared-libs venv via
# `python -m venv --clear` (no --without-pip), which triggers RustPython's bundled ensurepip audit-hook
# crash again. Pre-creating that venv with --without-pip and dropping the unpacked pip site-packages in lets
# pipx's `is_valid()` short-circuit past `create()`. The Nano Dockerfile then exports PATH + PIPX_* env vars
# so `mise install pipx:<tool>` can find this pipx and reuse the pre-created shared venv.
depends = ["_setup_all"]
description = "Preinstall: toolchain + pipx + flip rustup to the gnullvm host"
run = """
# sha256sum diagnostic for the Nano CI lane.
# mise's conda backend in 2026.6.5 shells out to a `sha256sum` it finds on PATH (via src/hash.rs:file_hash_sha256,
# only for files > 50 MB) to verify each conda tarball download. On the Nano docker build that lookup
# historically hit a sha256sum.exe that fails to load with `STATUS_ENTRYPOINT_NOT_FOUND` (0xC0000139 ==
# decimal -1073741511, the msys2-runtime autoload-trap signature), surfacing as:
# mise ERROR Failed to install conda:m2-git@latest: command ["sha256sum",
# "<path>"] exited with code -1073741511
# Dockerfile.nanoserver stages a busybox-w32-backed `sha256sum.exe` ahead of the broken shim on PATH so this
# should now pass; the diagnostic is fail-fast so the next CI break here tells us which binary PATH picked.
# sha256sum fail-fast diagnostic for the Nano CI lane.
sha256sum_path="$(command -v sha256sum 2>/dev/null || true)"
echo "[sha256sum-check] command -v sha256sum: ${sha256sum_path:-<not found>}"
if [ -z "$sha256sum_path" ]; then
Expand Down Expand Up @@ -256,17 +269,9 @@ mise exec -- rustup set default-host x86_64-pc-windows-gnullvm
# pipx backs the pipx:* tools but isn't a mise tool on Windows.
# On a workstation, the system python's Scripts dir already has pipx on PATH; use that python. On the Nano
# container there's no CPython (Dockerfile.nanoserver drops the `mise install python` step now that we can
# pipx-bootstrap via the `http:et-rp` rustpython mise installs as part of the global tool set). RustPython's
# bundled ensurepip is pip 26.1.1, which crashes on import via `sys.addaudithook` (rustpython 0.5.0 doesn't
# implement -- RustPython#7956), so the rustpython arm fetches pip 26.0.1 (the last release before that audit
# hook landed, see commit fb01b1830 / 2026-04-14), unzips the wheel, and puts it on RUSTPYTHONPATH so
# `rustpython -m pip` resolves to that copy. The matching workaround is documented at length in config.maint.toml's
# `rustpython-investigation` task. The same task also explains the PIPX_SHARED_LIBS pre-creation below:
# pipx's first install creates a shared-libs venv via `python -m venv --clear` (no --without-pip), which
# triggers RustPython's bundled ensurepip + pip 26.1.1 audit-hook crash again. Pre-creating that venv with
# --without-pip and dropping the unpacked pip-26.0.1 site-packages in lets pipx's `is_valid()` short-circuit
# past `create()`. The Nano Dockerfile then exports PATH + PIPX_* env vars so `mise install pipx:<tool>` can
# find this pipx and reuse the pre-created shared venv.
# pipx-bootstrap via the `http:et-rp` rustpython mise installs as part of the global tool set), so the
# rustpython arm fetches a pinned pre-audit-hook pip wheel, unzips it, and puts it on RUSTPYTHONPATH so
# `rustpython -m pip` resolves to that copy.
if command -v python >/dev/null 2>&1; then
python -m pip install pipx
elif [ "${ENABLE_RUSTPYTHON_PIPX_BOOTSTRAP:-}" = "1" ]; then
Expand Down
10 changes: 7 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -413,8 +413,8 @@ If you believe a skip is genuinely warranted, stop and ask the user; do not add

### Known intermittent CI failure: pyo3-runner torch registration timeout

`et-ws-pyo3-runner`'s `module_behaves::case_5_torch` intermittently fails on test.yaml's Windows lane with the
literal failure line
`et-ws-pyo3-runner`'s `module_behaves::case_5_torch` intermittently fails on test.yaml's Windows and macOS lanes

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 HIGH RISK

The PR title indicates the enablement of Roslynator for C#, but the changes only update documentation for an unrelated Python CI failure.

Try running the following prompt in your coding agent:

Add the missing Roslynator configuration files or update the PR title to reflect that this is a CI failure documentation update.

with the literal failure line

Error: "runner never registered"

Expand All @@ -426,7 +426,11 @@ torch's import when the test's registration timeout expired. The ~117 MB `pipx:t
cold runner is the slow step; a rerun passes because the import caches warm. Observed on commit
`6479913bdc288dd680fbe0520f63054e8c71fe6c` at
`https://github.com/edge-toolkit/core/actions/runs/28686533955/job/85080173283` (PR #70; the rerun passed and the PR
merged). If this signature recurs, stop rerunning and fix the root cause: raise (or make torch-case-specific) the
merged), and on the `default (macos-latest, 45)` job -- same signature, unix-form

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 MEDIUM RISK

The backtick opened on line 428 is not closed, which causes the backticks on line 429 to incorrectly toggle the code span. This results in the job name appearing as plain text and the surrounding description as code.

Try running the following prompt in your coding agent:

Fix the markdown formatting in CLAUDE.md around lines 428-432 to ensure each identifier is correctly wrapped in its own pair of backticks.

`torch/lib/python3.13/site-packages/torch/_subclasses/functional_tensor.py:362` warning path -- on commit
`f2a85307a2415f4a50625627795e02c84f1c8e5d` at
`https://github.com/edge-toolkit/core/actions/runs/28865327221/job/85613919558` (PR #73), 20.68s into the test
run. If this signature recurs, stop rerunning and fix the root cause: raise (or make torch-case-specific) the
runner-registration timeout in the pyo3-runner module tests, or warm the torch import before the registration clock
starts.

Expand Down
30 changes: 25 additions & 5 deletions config/conftest/policy/mise/mise.rego
Original file line number Diff line number Diff line change
Expand Up @@ -50,24 +50,44 @@ deny contains msg if {

# `compgen` is a bash builtin that busybox-w32 ash (Nano Server's shell) does not provide.
# A task using it fails on Nano with the literal error `<compgen>: not found` (verified in the build-rp-native task).
# Skip lines whose first non-whitespace char is `#` so explanatory comments (like this one's siblings) don't
# false-positive. POSIX-portable alternatives include `[ -e "$prefix/bin/foo" ] || [ -e "$prefix/bin/foo.exe" ]` for an
# The whole run body is checked, comments included -- compgen-narrating prose belongs in a TOML comment on
# the task, not inside the body. config.maint.toml is exempt: maintainer-only, never runs on Nano.
# POSIX-portable alternatives include `[ -e "$prefix/bin/foo" ] || [ -e "$prefix/bin/foo.exe" ]` for an
# extension-agnostic existence check, and `for f in "$prefix/bin/foo"*` to walk a literal glob (no-match leaves the
# literal as the loop var).
deny contains msg if {
some file in input
is_mise(file)
replace(file.path, "\\", "/") != ".mise/config.maint.toml"
some name, task in file.contents.tasks
is_string(task.run)
some line in split(task.run, "\n")
not startswith(trim_space(line), "#")
regex.match(`\bcompgen\b`, line)
regex.match(`\bcompgen\b`, task.run)
msg := sprintf(
"%s: task %q uses `compgen`, which is bash-only -- busybox ash (Nano) errors `compgen: not found`",
[file.path, name],
)
}

# A task `run` must not embed version-like text (an `X.Y.Z` literal), comments included.
# A version baked into a run body silently goes stale when the pin it mirrors is bumped -- version_drift
# only cross-checks [vars]/[env] values, never run strings. Keep the versioned fragment in a [vars] entry
# beside the [tools] pin it tracks and template it into the run with `{{ vars.<name> }}`; version-narrating
# prose belongs in a TOML comment on the task, not inside the body.
# config.maint.toml is exempt: its maintainer-only investigation/publish tasks narrate and probe specific
# upstream versions by design.
deny contains msg if {
some file in input
is_mise(file)
replace(file.path, "\\", "/") != ".mise/config.maint.toml"
some name, task in file.contents.tasks
is_string(task.run)
some m in regex.find_all_string_submatch_n(`[0-9]+\.[0-9]+\.[0-9]+`, task.run, -1)
msg := sprintf(
"%s: task %q run embeds version-like text %q -- move it into a [vars] entry beside the pin it tracks",
[file.path, name, m[0]],
)
}

# `cargo:` tools may build from source; prefer a prebuilt backend.
# Allowed only when either (a) allowlisted by name below -- cargo-binstall fetches a prebuilt there (e.g. a
# cargo-quickinstall release, routed via an `install_env` CARGO_BUILD_TARGET override), or the tool has no prebuilt
Expand Down
Loading