Skip to content

Releases: alplabai/tan-cli

v0.6.0

Choose a tag to compare

@github-actions github-actions released this 24 Aug 05:56
74bb07d

The first stable release of the Python tan, and the first that requires — and is gate-verified against — a released alp-sdk. v0.6.0-rc1 was a prerelease nothing upgraded onto, so everything in it reaches users here for the first time.

Highlights

  • tan renode is removed, along with all 27 published renode.* issue codes — the one breaking change, details below.
  • alp-sdk v0.16.0 or newer is now required. tan's planner mirror and every vendored fixture pin to that released tag, so the gates measure tan against the SDK you actually install rather than an unreleased dev commit.
  • Bootstrap stopped handing Fedora/Rocky/Arch hosts sudo apt-get install -y cmake — install commands are now selected per package manager, and a gap degrades to a host-neutral hint instead of a guessed package name.
  • tan build no longer drops flash_args.slot0_load_address for a variant declaring jlink_flash_device: null, and a dual-M55 AEN SoM that declares no per-role <role>_slot0 region is refused rather than mis-mapped.
  • tan doctor resolves git / py / python to absolute paths before spawning instead of by bare argv[0].
  • A bare tan invocation is meaningfully faster to startclick.testing, jsonschema, PyYAML and urllib.request are no longer imported on every run (427 → 279 modules).
  • tan run --flash can arm the flash confirm gate directly, with a real --confirm flag.
  • Scaffolded project READMEs pin their doc links to the released SDK tag rather than a moving main.

Removed

  • tan renode, its modules, and all 27 renode.* issue codes. This is the breaking change in this release:
    • Any script invoking tan renode ... must stop; the verb no longer resolves and exits as an unknown command.
    • Any consumer matching on a renode.* code in issues[] will never see one again — the codes are unpublished, not merely unused.

Changed

  • tan/core/shapes.py's dedup is finished — eight duplicate definitions are gone, with a gate so the next half-finished dedup cannot ship green.
  • The Windows %PATH% walk no longer builds a pathlib.Path per candidate, and an unreadable %PATH% entry is skipped rather than aborting the whole lookup.

Added

  • The pin-move-verify sender (ADR-0029 clause 5) — a PR that moves a pin value dispatches the proposed tuple to alp-e2e instead of spell-checking it.
  • A clean-container end-to-end run on a schedule, rather than only when something touches it.
  • A gate requiring a pinned hand-port to name which tan code it governs, and symbol-level checking of scripts/alp_cli/explain.py.

Fixed

  • tan/planner/ is re-synced with alp-sdk, closing an emit divergence where tan wrote no CONFIG_SPI=y for any GD32-bearing SoM while alp-sdk did.
  • A storage entry can no longer reach status: ok on a defaulted Devicetree label, and every planner site resolves against the project's own metadata root.
  • install.ps1 rolls back a failure during the backup renames, not only after them, and no longer reports a successful install that did not happen.
  • tan flash's expect_dpidr wrong-board guard round-trips a bare YAML hex, and a --core/--helper filter matching nothing now fails instead of passing silently.
  • tan size / image / clean / run / validate surface sdk.discovery-divergent in the text channel instead of only in JSON.
  • A postCommands step skipped for a missing tool reaches issues[] rather than vanishing.
  • A v* tag can no longer publish while a changelog fragment sits unfolded.
  • The vendored toolchain lock and bootstrap manifest are re-vendored against released alp-sdk v0.16.0, and CI now fetches tags for its alp-sdk clone so tag-dependent emit matches what a real checkout produces.

Install

install.sh (macOS/Linux) and install.ps1 (Windows) resolve latest through GitHub and will install this release — unlike v0.6.0-rc1, which was a prerelease they skipped. Asset names, the measured glibc floor, and the attestation verify command are in the ## Release assets block below.

Full detail: CHANGELOG.md · full diff

Release assets

Four archives, each a PyInstaller --onedir freeze of the Python
tan (tan-cli#349 -- was a single-file --onefile freeze; --onedir
fixes a 13-19s macOS startup regression caused by --onefile
re-extracting its runtime on every invocation). Unpack the archive
and run the tan/tan.exe inside; install.sh/install.ps1 do
this for you.

  • tan-x86_64-pc-windows-msvc.zip -- Windows x64
  • tan-x86_64-apple-darwin.tar.gz / tan-aarch64-apple-darwin.tar.gz -- macOS
  • tan-x86_64-unknown-linux-gnu.tar.gz -- Linux x64, frozen on Debian 11.
    It requires GLIBC_2.30 or newer -- measured from the
    binary's own bundled payload at build time, not assumed from the
    build image. Debian 11+ / Ubuntu 20.04+ / RHEL 9+ are comfortably
    above it.

There is no arm64 Windows and no arm64 Linux asset in this release,
and no -musl asset. A frozen binary has to be built on the
architecture it runs on, and this release builds on four runners; if
you need an arm64 Linux or arm64 Windows tan, install from source
(pip install ./python) and say so on the issue tracker.

  • Every archive + checksums.txt carries a GitHub build-provenance
    attestation. Verify with:
    gh attestation verify <downloaded-file> --repo alplabai/tan-cli

v0.6.0-rc1

v0.6.0-rc1 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 14 Aug 20:13
ad6470c

The Rust oracle is retired and tan is Python end to end — plus a workflow-injection fix and a sweep through the commands that reported success while doing something else.

This is a release candidate. latest still resolves to v0.5.1, so nothing upgrades onto it — install it deliberately.

Highlights

  • The Rust oracle is gone. crates/tan-core, crates/tan-cli, Cargo.toml and Cargo.lock are deleted; python/tan/ is the implementation, not a port.
  • Workflow-injection fix in parity.yml — an attacker-controlled repository_dispatch payload reached four run: blocks.
  • Every uses: in .github/workflows/ is pinned to a full commit SHA, with persist-credentials: false on 31 of 32 checkouts.
  • Five commands and the Flow D planner stopped reporting success for something they did not doflash, doctor, quality, init and monitor, plus a declared-null jlink_flash_device no longer downgrading Flow D to the SE-UART path.
  • tan doctor gained scope (host or project) on every check, plus a libraries row for the project's curated-library selection.
  • tan explain --code <ALP-Bxxx|ALP_ERR_*> — diagnostic-code lookup, ported from alp-sdk.
  • ALP_FLASH_REQUIRE_DPIDR=1 makes an unarmed write refuse instead of warn, on every flash method that has a wrong-board guard.
  • A planner re-sync proposerpython/scripts/planner_resync.py opens the port PR when alp-sdk's scripts/alp_orchestrate/ moves.

Removed

  • The Rust oracle — see above. Existing v0.5.x assets are unaffected; this changes the repo, not the CLI's behaviour.

Fixed

  • tan flash refuses a run that wrote nothing instead of reporting ok: true and exit 0, and the confirm gate finally has a reachable --confirm flag (#719).
  • tan doctor refuses a --sdk-root that is not an alp-sdk checkout rather than reporting [pass] sdk for a path tan build correctly rejects (#727).
  • tan quality exits non-zero on a [FAIL]ing check, and refuses a profile that selected no checks at all (#721).
  • tan monitor accepts every port pyserial can open/dev/serial/by-id/... symlinks and socket:// / rfc2217:// URLs, not just what comports() enumerates (#569).
  • tan doctor's sevenZip check runs on every Windows host, not only while zephyrSdk is already failing (#736).
  • A declared-null jlink_flash_device reaches flash_args as a present key instead of silently downgrading Flow D to the SE-UART path (#734).
  • tan init no longer emits cores that do not exist on the requested SKU, nor copies build output into a new project (#494).
  • The installers' header comments no longer claim latest resolves to v0.4.1 — it resolves to the newest non-prerelease, v0.5.1 today (#749).

Install

Four binaries, one per host, plus checksums.txt and envelope-contract.json. There is no -musl assetinstall.sh probes for musl and refuses before downloading rather than failing at exec time.

Host Asset
Windows x86_64 tan-x86_64-pc-windows-msvc.zip
macOS Intel tan-x86_64-apple-darwin.tar.gz
macOS Apple silicon tan-aarch64-apple-darwin.tar.gz
Linux x86_64 tan-x86_64-unknown-linux-gnu.tar.gz

The Linux binary is built inside python:3.12-slim-bullseye (Debian 11). Its measured glibc floor is GLIBC_2.30, scanned over the 63 native files in the frozen payload — not read off the PyInstaller bootloader, which reports a container-invariant GLIBC_2.14 under any build image. It is a glibc binary and will not run on Alpine or another musl distro.

Verify what you downloaded:

gh attestation verify <downloaded-file> --repo alplabai/tan-cli

Because this is a prerelease, install.sh and install.ps1 resolve latest through GitHub and will keep installing v0.5.1 — download this one by hand.

Full detail: CHANGELOG.md · full diff

v0.5.1

Choose a tag to compare

@github-actions github-actions released this 05 Aug 10:37
6dbf617

Twelve command-surface and contract fixes on top of v0.5.0 — including one where a second project's bootstrap could silently make tan build compile the wrong SDK — plus a README rewritten as a user-facing guide.

Highlights

  • tan kconfig works on the workspace tan itself bootstrapped. It resolved neither the workspace venv's west nor the bootstrapped ZEPHYR_BASE, so it failed against the exact environment the quickstart produces. (#453)
  • tan quality and tan migrate can succeed at all. Neither could pass the west extension's required argument, under any input. (#454)
  • A second project's bootstrap no longer silently repoints the first. ~/.alp/sdk-default is machine-global and last-writer-wins; project A could resolve project B's checkout and build it with ok: true and no warning. (#464)
  • tan debug-config infers a real hardware target instead of defaulting to native-host and writing a launch.json pointing at a binary the build never produces. (#456)
  • tan generate --all is re-runnable. It succeeded once, then always exited 3 because one of nine targets refused to overwrite — leaving the other eight rewritten. (#457)
  • tan renode honours --project. It resolved the build root from the CWD and its own remedy told you to build the wrong directory. (#470)
  • Silent failures made audible: tan pinmux printed nothing on exit 2 (#458), tan diff reported "no differences" on a board.yaml that tan validate rejects (#455), and tan bootstrap --print-env described a workspace bootstrap would never create (#459).
  • README rewritten from ~4,000 words to under 1,000: quickstart, command table, SDK selection order, JSON envelope contract.

Fixed

  • Four debug-config preconditions reclassified from exit 5 to exit 2 — user-fixable input was being reported as a tan crash. (#462)
  • bootstrap.workspace-orphan-refused no longer prints a stringified None for its destination, or advises dropping a --workspace the invocation never passed. (#469)
  • contract/issue-codes.json registered two codes twice, one pair disagreeing on severity. JSON duplicate keys are last-wins, so the published severity depended on file order. Deduped, plus a new gate that rejects duplicates. (#467)

Behaviour worth knowing

  • On a multi-core SoM, tan debug-config now needs --core <name>; without it, it exits 2 with debug-config.target-kind-ambiguous rather than guessing.
  • tan quality requires --profile, tan migrate requires one of --check / --preview / --apply. Both refuse at exit 2 before spawning west.
  • When the machine-global default SDK was last written by a different project's bootstrap, commands now emit a sdk.global-default-foreign-project warning instead of resolving silently.

Install

# Linux / macOS
curl -fsSL https://raw.githubusercontent.com/alplabai/tan-cli/main/install.sh | sh
# Windows
irm https://raw.githubusercontent.com/alplabai/tan-cli/main/install.ps1 | iex
Platform Asset
Windows x64 tan-x86_64-pc-windows-msvc.zip
Linux x64 (glibc) tan-x86_64-unknown-linux-gnu.tar.gz
macOS x64 tan-x86_64-apple-darwin.tar.gz
macOS arm64 tan-aarch64-apple-darwin.tar.gz

The Linux binary requires GLIBC_2.30 or newer, measured from the frozen payload rather than the bootloader. There is no musl asset: a PyInstaller musl freeze runs only on musl distros, so install.sh probes for musl and refuses before downloading rather than failing at exec. Linux arm64 and Windows arm64 have no prebuilt archive — install from source on those hosts.

Verify a download:

gh attestation verify <downloaded-file> --repo alplabai/tan-cli

checksums.txt carries the SHA-256 of every asset; envelope-contract.json is the machine-readable command/issue-code contract consumers key off.


Full detail: CHANGELOG.md · full diff

v0.5.0

Choose a tag to compare

@github-actions github-actions released this 04 Aug 18:50
0277b4c

tan is now a Python program, not a Rust one — the first stable release of that rewrite, and it changes both what you download and what you unpack.

Cumulative since v0.4.1, the last Rust release. The 0.5.0-rc1-rc4 prereleases are folded in here; if you never installed one, everything below is new to you.

Highlights

  • The binaries are PyInstaller freezes of python/, not cargo builds of crates/. The Rust tree stays as a frozen reference oracle and ships no asset.
  • BREAKING — every asset is an archive now, not a raw binary. Unpack before running.
  • BREAKING — tan validate's spawn path exits 2, not 1. Details below; CI and the VS Code extension are affected.
  • tan now plans and executes — the planner relocated out of alp-sdk into tan.
  • macOS launch is fixed--version went from 13.25–19.74 s to 0.342 s.
  • All seven deferred verbs are real commands: scaffold, completion, diff, pinmux, inspect, trace, support-bundle (#260).
  • tan flash auto-signs an Alif Ensemble slot0 ATOC via SETOOLS, so Flow D no longer needs hand-signing outside tan (#353).
  • Several data-loss and wrong-hardware-write defects are fixed — read the next section before upgrading from an RC.

Fixed — data loss, wrong writes, and silent success

These are the reason to upgrade rather than stay on an RC.

  • tan bootstrap --dry-run moved the user's alp-sdk checkout and rewrote it (#323). A dry run mutated the workspace.
  • tan init and tan generate followed symlinked parents and wrote outside the project.
  • Flow D could write the wrong file to a board's MRAM. A fix for #289 had set the wrong artefact for the Alif flash path.
  • A pending TBD placeholder could reach a flasher (#222) — on both the Python and the Rust side.
  • tan init could pin a customer to the WRONG SDK, permanently (#263).
  • tan build reported ok: true / exitCode: 0 / issues: [] when every slice had failed.
  • Flow D's SETOOLS auto-sign could pass an unsigned ATOC through its own soft-failure guard (#373).
  • The macOS release asset shipped with no CA trust anchors at all (#304), so TLS failed everywhere.
  • A write could silently replace a hand-filled .vscode/launch.json value.

Breaking

  • tan validate's not-yet-ported spawn path now exits 2 (VALIDATION_FAILURE), not 1 (RUNTIME_FAILURE) (#262).
    • Before: a board.yaml with an unresolvable SDK answered validate.spawn-not-implemented at exit 1, indistinguishable from a tan crash. After: exit 2, matching every guard-level refusal.
    • Who must act: CI branching on -eq 1 specifically stops matching. alp-sdk-vscode renders exit 2 as warning and exit 1 as error, so a stale consumer shows a real validation gap as a warning.
    • A genuine tan crash — unreadable board.yaml, internal exception — is unaffected and still exits 5.
  • Release assets gained an archive extension (#349).
    • Before: tan-x86_64-unknown-linux-gnu. After: tan-x86_64-unknown-linux-gnu.tar.gz. Target triples are unchanged.
    • Who must act: anything building the URL from the bare triple. alp-sdk-vscode gains its unpack step separately (#268).

Also fixed

  • build reported a bare terminated with exit code: 1 when the Zephyr SDK was missing (#419), and validate reported validation failure when nothing had been validated (#350).
  • tan doctor exited 4 on every fresh install, and had dropped six checks the oracle emits.
  • tan build / tan flash could not find west on hosts that had it, and a bootstrapped venv could be invisible to both (#291).
  • A dangling $ZEPHYR_BASE silently dropped a core from a multi-core build.
  • install.sh handed musl hosts a binary that cannot exec; it now probes and refuses first.
  • tan monitor would have been a dead command in every published binarypyserial was not bundled.
  • tan <cmd> | head exited 1 on Linux and macOS where the oracle exits 0.
  • tan/planner/ had drifted from alp-sdk's scripts/alp_orchestrate/, and the test suite did not necessarily test this repo's tan (#423).

Contributors

@alpCaner · @hkngln

Release assets

Four archives, each a PyInstaller --onedir freeze of the Python
tan (tan-cli#349 -- was a single-file --onefile freeze; --onedir
fixes a 13-19s macOS startup regression caused by --onefile
re-extracting its runtime on every invocation). Unpack the archive
and run the tan/tan.exe inside; install.sh/install.ps1 do
this for you.

  • tan-x86_64-pc-windows-msvc.zip -- Windows x64
  • tan-x86_64-apple-darwin.tar.gz / tan-aarch64-apple-darwin.tar.gz -- macOS
  • tan-x86_64-unknown-linux-gnu.tar.gz -- Linux x64, frozen on Debian 11.
    It requires GLIBC_2.30 or newer -- measured from the
    binary's own bundled payload at build time, not assumed from the
    build image. Debian 11+ / Ubuntu 20.04+ / RHEL 9+ are comfortably
    above it.

There is no arm64 Windows and no arm64 Linux asset in this release,
and no -musl asset. A frozen binary has to be built on the
architecture it runs on, and this release builds on four runners; if
you need an arm64 Linux or arm64 Windows tan, install from source
(pip install ./python) and say so on the issue tracker.

  • Every archive + checksums.txt carries a GitHub build-provenance
    attestation. Verify with:
    gh attestation verify <downloaded-file> --repo alplabai/tan-cli

Full detail: CHANGELOG.md · full diff

v0.5.0-rc4

v0.5.0-rc4 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 02 Aug 22:58
fbbea03

Nine fixes found by running the published v0.5.0-rc3 binary as a customer
would — on real Windows, macOS and Linux hosts, in isolated environments — not
by testing the source. Two of them destroy or misplace a user's files; one
silently drops a core from a multi-core build.

Highlights

  • tan bootstrap --dry-run moved your alp-sdk checkout and rewrote your global SDK pointer — a preview flag that relocated a repository (#323).
  • tan init / tan generate followed symlinked parents and wrote outside the project, while reporting the in-project path and ok: true (#325).
  • A dangling $ZEPHYR_BASE silently dropped a core from a multi-core build, blaming west for a stale environment variable (#336).
  • tan --version was not eagertan --version init --destination <dir> printed the version and created the project (#326).
  • envelope.serialize-failed printed exitCode: 5 while the process exited 0, breaking the one invariant every consumer relies on (#327).
  • tan image rejected helper firmware the SDK actually ships, resolving a repo-relative firmware_path only under build/ (#330).
  • tan/planner/ had drifted from alp-sdk's scripts/alp_orchestrate/ — seven Kconfig symbols missing, and a board alp-sdk refuses reported ok (#320).

Fixed

  • tan bootstrap --dry-run moved the user's alp-sdk checkout and rewrote ~/.alp/sdk-default. No data was lost — all 4067 files survived and git log still resolved — but a preview flag must not move a repository or rewrite a global config; relocate_checkout() now takes dry_run and says "would move" / "would set" (#323).
  • tan init and tan generate followed symlinked parents and wrote outside the project while reporting success. A new shared guard (tan/core/fs_confine.py) compares two resolved paths and refuses the whole run rather than partway through; a symlinked project root still works (#325).
  • A dangling $ZEPHYR_BASE silently dropped a core from a multi-core build. Zephyr's build extension makes a separate west_topdir(self.source_dir) call that #307's cwd pin never covered, so a tan init project — always a sibling of the workspace — fell through to a stale $ZEPHYR_BASE west trusts with no existence check (#336).
  • tan --version was not eager: a version probe executed the following subcommand. Now handled through Typer's own is_eager mechanism, matching the Rust oracle (#326).
  • envelope.serialize-failed printed exitCode: 5 while the process exited 0. The fallback code now reaches the process boundary (#327).
  • tan image rejected helper firmware the SDK actually ships. Relative paths are tried against both roots in a defined order, and the error names every root tried with its absolute path (#330).
  • sdk list --online split table rows in half. Whitespace is collapsed before truncating releaseNotesSummary to 60 characters (#316).
  • bootstrap's INCOMPATIBLE $ZEPHYR_BASE message named the verdict but not the cause. The branch now accumulates the observed facts and renders them together; the decision and exit code are unchanged (#334).
  • tan/planner/ had drifted from alp-sdk's scripts/alp_orchestrate/. On mproc-mailbox the emitted Zephyr conf fragment was 56 lines against alp-sdk's 63; on rpmsg-imx93 alp-sdk refused the board while tan reported ok. Re-synced, and seam1 now compares a legitimate refusal on both sides (#320).

Internal

  • Closed the third occurrence of #250's ETXTBSY race — two test fixtures wrote an executable and immediately exec'd it with no guard, reddening a required check (3 failures in 40 full-suite runs, 0 after) (#318, #333).

Known issues

  • @alplabai/tan has never published to npm: NPM_TOKEN is a classic token and npm publish demands an OTP. Needs an automation token (#233).

Release assets

Four binaries, each a single-file freeze of the Python tan:

  • tan-x86_64-pc-windows-msvc.exe -- Windows x64
  • tan-x86_64-apple-darwin / tan-aarch64-apple-darwin -- macOS
  • tan-x86_64-unknown-linux-gnu -- Linux x64, frozen on Debian 11.
    It requires GLIBC_2.30 or newer -- measured from the
    binary's own bundled payload at build time, not assumed from the
    build image. Debian 11+ / Ubuntu 20.04+ / RHEL 9+ are comfortably
    above it.

There is no arm64 Windows and no arm64 Linux asset in this release,
and no -musl asset. A frozen binary has to be built on the
architecture it runs on, and this release builds on four runners; if
you need an arm64 Linux or arm64 Windows tan, install from source
(pip install ./python) and say so on the issue tracker.

  • Every binary + checksums.txt carries a GitHub build-provenance
    attestation. Verify with:
    gh attestation verify <downloaded-file> --repo alplabai/tan-cli

Full detail: CHANGELOG.md · full diff

v0.5.0-rc3

v0.5.0-rc3 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 02 Aug 15:21
acf132c

Six defects found by running the published v0.5.0-rc2 binary end to end on real Windows and macOS hosts — not by testing the source, and not by trusting a green CI run on a clean runner. Every one of them was invisible to both.

This is a pre-release. It does not take the Latest badge.

Highlights

  • tan doctor exited 4 on every fresh install — the guaranteed post-bootstrap state was reported as a broken host (#299).
  • A host where no build slice could run exited 0 — the opposite failure, exposed by fixing the first one (#299).
  • The macOS asset could not make an HTTPS request at all — no CA trust anchors in the freeze (#304, release-blocker).
  • tan bootstrap died with "Filename too long" on a fresh Windows install while doctor had just called the host fine (#306, release-blocker).
  • doctor and bootstrap stopped recommending a config change that was tried and reverted upstream (#300).
  • New clean-host.yml gate runs the shipped artefact on a host with no SDK, no ~/.alp and an empty cwd — the state that hid all six (#278).

Fixed

  • tan doctor exited 4 on every fresh install. tan bootstrap deliberately leaves west off PATH, so "west in the venv, absent from PATH" is the guaranteed post-bootstrap state — and the state a GUI-launched VS Code is always in (#299).
  • westResolved now fails when west resolves nowhere. west answers "is it on bare PATH" and is never fatal; westResolved answers "can a slice run at all" and owns the exit code (#299).
  • macOS releases could not verify any TLS certificate. A PyInstaller freeze bundles its own ssl but no CA bundle and does not fall back to the platform trust store, so every HTTPS call in tan sdk list --online failed CERTIFICATE_VERIFY_FAILED on the published rc2 tan-aarch64-apple-darwin asset (#304).
    • Requests now build their SSLContext through truststore (the OS trust store, so a corporate CA in the machine keychain keeps working), falling back to certifi only if that is unavailable.
    • The error text no longer asserts "usually a TLS-intercepting proxy or a corporate CA" — there was neither on the reporting host, and that wording sends users hunting in the wrong place.
  • longPaths checked the registry and nothing else. Windows' LongPathsEnabled governs manifested Win32 calls; it does nothing for git, which west update uses for every module clone and which refuses a long path unless its own core.longpaths is set. doctor said pass moments before bootstrap died inside hal_nxp's tf-psa-crypto tree (#306).
    • longPaths now reads both axes and fails — not warns — when the registry says yes and git does not. The remedy names the exact command: git config --global core.longpaths true.
    • tan bootstrap also forces core.longpaths=true on the west update child's environment, so a fresh install gets past the failure rather than only being warned about it.
  • doctor and bootstrap stopped telling users to raise prerequisites.pythonMinVersion — the change alp-sdk#1078 tried and reverted. That key is host-universal while the floor is Zephyr's, so raising it refuses a 3.10/3.11 host for a Yocto-only project that builds today (#300).
  • The sdk check names the tier it resolved through, and names a cwd checkout it did not select, so a report describing a different SDK than the one you are standing in is no longer indistinguishable from a wrong answer (#301).

Added

  • clean-host.yml — the shipped-artefact gate. Freezes tan per platform and runs tan --version, tan doctor --format json, tan sdk list --online (a real unmocked GitHub API call, the CA-trust canary) and tan bootstrap --dry-run on a host with no alp-sdk checkout, no ~/.alp and an empty cwd — a state no prior job in this repo ever constructed (#278).
  • doctor's envelope is checked for self-consistencyok/exitCode agreeing with checks[], and no <subject> / <subject>Resolved pair disagreeing. That generalises the #299 shape instead of grepping for westResolved by name.

Known issues

  • tan bootstrap still refuses the documented quickstart layout (tan.exe and alp-sdk/ in one directory) with "holds more than this checkout", and the remedy it offers moves the user's checkout (#302).
  • tan/planner/ is behind alp-sdk's scripts/alp_orchestrate/ (#320, blocks v0.5.0 final). On mproc-mailbox, tan generate's Zephyr conf fragment is 56 lines where alp-sdk emits 63; on rpmsg-imx93, alp-sdk refuses the board as not buildable (SdkRevisionNotBuildable, E1M-NX9101 hw_rev r1) and tan reports ok.

Release assets

Four binaries, each a single-file freeze of the Python tan:

  • tan-x86_64-pc-windows-msvc.exe -- Windows x64
  • tan-x86_64-apple-darwin / tan-aarch64-apple-darwin -- macOS
  • tan-x86_64-unknown-linux-gnu -- Linux x64, frozen on Debian 11.
    It requires GLIBC_2.30 or newer -- measured from the
    binary's own bundled payload at build time, not assumed from the
    build image. Debian 11+ / Ubuntu 20.04+ / RHEL 9+ are comfortably
    above it.

There is no arm64 Windows and no arm64 Linux asset in this release,
and no -musl asset. A frozen binary has to be built on the
architecture it runs on, and this release builds on four runners; if
you need an arm64 Linux or arm64 Windows tan, install from source
(pip install ./python) and say so on the issue tracker.

  • Every binary + checksums.txt carries a GitHub build-provenance
    attestation. Verify with:
    gh attestation verify <downloaded-file> --repo alplabai/tan-cli

Full detail: CHANGELOG.md · full diff

v0.5.0-rc2

v0.5.0-rc2 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 01 Aug 15:55
84ef4cc

Everything the first real v0.5.0-rc1 run turned up, plus what reviewing those fixes turned up in turn. Six release-blockers — and one theme: almost every defect was a check measuring a proxy instead of the thing it claimed to measure.

Still a pre-release. Nothing on the stable alp-sdk-vscode channel upgrades onto this. Delivery is unchanged from rc1: the extension's odd-minor pre-release channel, prerelease: true / make_latest: false, and both installers resolve latest, which excludes prereleases.

Highlights

  • tan build and tan flash could not find west on a host that had bootstrapped successfully (#289) — every GUI-launched VS Code, which is the extension's normal environment. New shared tan/core/venv.py resolver; five scattered private copies deleted.
  • A bootstrapped venv could be invisible to build and flash (#291) — creation picked the executable directory from disk, resolution picked it from the host, so a Git Bash Scripts/ venv was created and then not found.
  • typer>=0.12 was unbounded across a change in what typer is (#293) — now >=0.26,<0.28, both ends measured by wheel inspection.
  • tan init pinned a relative SDK root later invocations could not resolve (#263).
  • tan bootstrap moved the alp-sdk checkout before it could refuse (#284), and reported complete. after a step had already failed (#285).
  • doctor had silently dropped six checks the oracle emits (#286, #290, #294), each reintroducing a closed defect — found by one audit rather than one field at a time.
  • tan build reported ok: true when every slice was skipped (#283), and sat silent for 234 s during CMake configure (#287).

Fixed

  • Flow D could write the wrong file to a board's MRAM. flash_args.atoc was the one input never resolved against the build root, so a relative atoc: — which the repo's own fixtures use — silently changed which file was flashed.
    • Root cause worth naming: grep -rn "FLOW_D" crates/ returns nothing. Flow D is Python-only, so the Rust oracle's cwd-safety audit was inherited without ever covering the one backend that writes on-die MRAM.
  • tan bootstrap emitted relative paths a consumer could not resolvedata.sdkRoot, workspaceDir, venvDir and zephyrBase all came back relative from --sdk-root ./alp-sdk, reintroducing #217. --print-env was emitting export ZEPHYR_BASE="./zephyr" under a heading reading "Add to your shell profile" — and a profile is sourced from $HOME.
  • tan bootstrap --print-env wrote to stderr, so tan bootstrap --print-env > env.sh left the file empty while the block still appeared on the terminal.
  • doctor refused hosts that work — a bootstrapped host with no board.yaml in cwd exited 4; an inconclusive venv probe failed closed where the oracle fails open; an Apple-silicon Mac on an x86_64 Python was told to build on Linux.
  • NO_COLOR was checked two different ways and faultdecode diverged from the spec and the oracle (#288).
  • tan bootstrap --non-interactive exited 2 — the literal first-blink command in the docs.
  • Smaller: the published asset filename leaking into --help (#280); python_repr on nested mappings (#277); the TBD sentinel (#276); a venv_has_usable_pip flake (#250); zephyr_board.py escaping PINNED_HASHES (#279); and getting-started.yml smoke-testing the Rust tan while the release ships a PyInstaller freeze (#278).

Changed

  • doctor --build is accepted and inert. The check set is unconditional now, so there is no build-gated half.
  • doctor gained sdkProvenance and data.missingPrerequisites — two envelope keys that did not exist in rc1. The latter restores the extension's one-click dependency install.
  • --fix is still not accepted (#295). alp-sdk-vscode calls tan bootstrap instead — accepting the flag as a no-op would give users a Fix button that reports success having repaired nothing.

Requires

alp-sdk v0.15.0-rc1. Pairs with alp-sdk-vscode on the pre-release channel.

Full detail: CHANGELOG.md · full diff

Release assets

Four binaries, each a single-file freeze of the Python tan:

  • tan-x86_64-pc-windows-msvc.exe -- Windows x64
  • tan-x86_64-apple-darwin / tan-aarch64-apple-darwin -- macOS
  • tan-x86_64-unknown-linux-gnu -- Linux x64, frozen on Debian 11.
    It requires GLIBC_2.30 or newer -- measured from the
    binary's own bundled payload at build time, not assumed from the
    build image. Debian 11+ / Ubuntu 20.04+ / RHEL 9+ are comfortably
    above it.

There is no arm64 Windows and no arm64 Linux asset in this release,
and no -musl asset. A frozen binary has to be built on the
architecture it runs on, and this release builds on four runners; if
you need an arm64 Linux or arm64 Windows tan, install from source
(pip install ./python) and say so on the issue tracker.

  • Every binary + checksums.txt carries a GitHub build-provenance
    attestation. Verify with:
    gh attestation verify <downloaded-file> --repo alplabai/tan-cli

v0.5.0-rc1

v0.5.0-rc1 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 01 Aug 01:00
6321f74

The first release in which tan is a Python program: the planner moved into it, so tan now plans and executes, and the four assets are PyInstaller freezes of python/ rather than cargo builds of crates/.

No stable user upgrades onto this release. The tag publishes with prerelease: true / make_latest: false, and both installers resolve latest through GitHub — which excludes prereleases — so install.sh and install.ps1 still fetch the last stable release. SUPPORTED_CLI_VERSION in alp-sdk-vscode moves to 0.5.0-rc1 only on that extension's pre-release channel (extension v0.5.0, an odd minor); stable extension users stay on an even minor pinned at the Rust tan until GA (#268). Everyone else installs by hand.

Highlights

  • The planner relocated into tan. alp-sdk's scripts/alp_orchestrate/ (20 modules, ~6.2k lines) is now python/tan/planner/, and tan build renders the build plan in-process instead of shelling PYTHONPATH=<sdk>/scripts python -m alp_orchestrate --emit build-plan.
  • Four PyInstaller assets replace the eight-way cargo matrix. The Linux binary is -gnu and honestly named: it is frozen in python:3.12-slim-bullseye (Debian 11, glibc 2.31).
  • tan build --execute runs a plan that arrived via --plan-from.
  • tan debug-config resolves a real J-Link device / pyOCD target id from the SDK, before a project has ever been built.
  • A pending TBD placeholder can no longer reach a flasher (#222) — on both the Python and the Rust side.
  • tan monitor would have been a dead command in every published binary; the monitor extra is now frozen in.
  • install.sh no longer hands a musl host a binary that cannot exec.

Added

  • tan build --execute — run a plan produced by --plan-from, instead of re-planning it.
  • tan debug-config fills device / targetId / configFiles from the SoC's published variants[].debug block (alp-sdk#1026), and discloses with debug-config.sdk-identity-overwrite when doing so replaces a value you filled in by hand.

Changed

  • scaffold, completion, diff, pinmux, inspect and trace are not ported yet — see #260 for the deferred set.

Fixed

  • A pending TBD placeholder reached real flashers (#222). flash_method: TBD failed safely against the backend registry, but output_artefact/firmware_path: TBD resolved to <build_root>/TBD and reached a real J-Link write. One definition (flash_plan.is_pending) now answers it for the whole path; the Rust half fixed the same defect in fa_str / fa_str_checked.
  • tan init could pin a customer to the WRONG SDK, permanently (#263).
  • tan validate answered "not ported yet" (exit 1) in a fresh project where the shipped binary answers validate.board-yaml-missing (exit 2); an empty or non-mapping board.yaml is now refused at exit 2 instead of reported clean.
  • tan sdk install / tan sdk switch refused at exit 5 (InternalFailure) where the oracle refuses at exit 1.
  • tan <cmd> | head exited 1 on Linux and macOS where the oracle exits 0. The defect was POSIX, not Windows — an earlier note had it backwards.
  • project.boardYaml now agrees with the filesystem in both directions (#236, #170) — the field's contract has always read "if found", and it now reports null when nothing is there.
  • tan build --pristine reports the slices it did not wipe (#183).
  • Linux and macOS see the manual-install hints the SDK provides for them (#230).
  • The npm shim asked for a -musl Linux asset this release does not publish, so every npm install on Linux x64 requested a 404.

What this RC has and has not been exercised on

  • Built and driven end to end on Windows before the tag: init --from-example peripheral-io/blink -> validate --offline -> generate --all (9/9 targets), all six bundled --template starters, and the packaged-binary conformance suite (7/7).
  • The macOS and Linux binaries are built by CI and self-verified there, but have not been driven through a real project by hand.
  • tan build against real silicon is not covered by any of that. Exercising it is what this RC is for.

Release assets

Four binaries, each a single-file freeze of the Python tan:

  • tan-x86_64-pc-windows-msvc.exe -- Windows x64
  • tan-x86_64-apple-darwin / tan-aarch64-apple-darwin -- macOS
  • tan-x86_64-unknown-linux-gnu -- Linux x64, frozen on Debian 11.
    It requires GLIBC_2.30 or newer -- measured from the
    binary's own bundled payload at build time, not assumed from the
    build image. Debian 11+ / Ubuntu 20.04+ / RHEL 9+ are comfortably
    above it.

There is no arm64 Windows and no arm64 Linux asset in this release,
and no -musl asset. A frozen binary has to be built on the
architecture it runs on, and this release builds on four runners; if
you need an arm64 Linux or arm64 Windows tan, install from source
(pip install ./python) and say so on the issue tracker.

  • Every binary + checksums.txt carries a GitHub build-provenance
    attestation. Verify with:
    gh attestation verify <downloaded-file> --repo alplabai/tan-cli

Full detail: CHANGELOG.md · full diff

v0.4.1

Choose a tag to compare

@github-actions github-actions released this 29 Jul 22:22
e4e0c53

The documented Quickstart works end to end for the first time — and tan bootstrap now exits 1 instead of 0 when it could not install what your next command needs.

Read the breaking change first. This is a patch number, so it does not carry the warning: tan bootstrap used to print bootstrap: complete. and exit 0 after failing to install the Python dependencies its own next step needs. It now prints bootstrap: INCOMPLETE, names which installs failed, and exits 1. Anything scripting that exit code on such a host sees 1 where it saw 0. Pass --allow-partial to accept the workspace as-is. Every phase is still non-fatal and the workspace is still left on disk — only the verdict changed (#220).

First release paired with alp-sdk v0.14.0.

Highlights

  • tan init can find the SDK tan bootstrap just created — the documented Quickstart was broken at step 3 (#218).
  • The Zephyr SDK finally carries a Fix button, and 7-Zip has a real check instead of one line of prose (#203, #204, #210).
  • tan doctor prints its remedies without --verbose and reads the debug target from board.yaml instead of hardcoding native-host (#208).
  • tan bootstrap will not report a success it cannot back up — breaking, see above (#220).
  • CI now runs the commands a customer types: install.shbootstrapdoctorinitbuild, on a runner that starts with none of it (#207).
  • Every emitted issue code is registered and gatedenvelope-contract.json goes from 4 codes to 68 (#219).
  • A tag whose CHANGELOG section is missing now fails instead of publishing a one-line stub body (#212).
  • Re-vendored at alp-sdk v0.14.0, macOS prerequisites included (#231).

Changed

  • BREAKING — tan bootstrap exit code. Detailed above.
    • Before: dependency install fails → bootstrap: complete., exit 0.
    • After: bootstrap: INCOMPLETE -- <names> did not install, exit 1; --allow-partial restores exit 0.
    • Applies to zephyr-requirements, sdk-extras and editable-install. pip-upgrade is excluded — the pip already present still installs packages.
  • macOS reads its own prerequisite list. alp-sdk v0.14.0 added xz and wget to prerequisites.posix plus a prerequisites.macos that omits them; tan keyed off an is_windows bool, which would have made tan bootstrap refuse on stock macOS (#231).
  • envelope-contract.json now carries the whole issue-code registry, all three statuses, not a frozen-only subset (#219).
  • tan bootstrap reports absolute paths in data.* and --print-env, matching project.root in the same envelope (#217).

Added

  • tan debug-config --svd <PATH> — the first and only producer of LaunchResolution.svd (#197).
  • --allow-partial on tan bootstrap — report success despite a failed dependency install (#220).
  • sevenZip check in tan doctor --build, native Windows only and only while the Zephyr SDK is still absent (#204).

Fixed

  • SDK discovery now considers a checkout that is a child of the workspace root — it checked self, siblings and ancestors, never a child, which is exactly where the documented flow puts it (#218).
  • zephyrSdk reaches missingPrerequisites with a runnable west sdk install --version 1.0.1 -t arm-zephyr-eabi rather than being structurally invisible to consumers (#203, #210).
  • tan doctor no longer hides every remedy it computed behind --verbose (#208).
  • debug-config keeps the comments in your launch.json instead of reserialising the document (#182).
  • debug-config's baremetal-mcu draft carries configFiles/targetId, so OpenOCD no longer gets a serverpath with nothing to load (#139).
  • The workspace guard records where it moved your checkout, so the next documented command still resolves (#206).
  • The npm shim's version tracks the workspace, and verify-version now fails a tag where it does not (#202).

Install

One-liner — resolves this release, verifies the sha256 against checksums.txt, and installs:

curl -fsSL https://raw.githubusercontent.com/alplabai/tan-cli/main/install.sh | sh
irm https://raw.githubusercontent.com/alplabai/tan-cli/main/install.ps1 | iex

Or pick an asset directly:

Platform Asset
Linux x86_64 tan-x86_64-unknown-linux-musl
Linux arm64 tan-aarch64-unknown-linux-musl
macOS Intel tan-x86_64-apple-darwin
macOS Apple Silicon tan-aarch64-apple-darwin
Windows x64 tan-x86_64-pc-windows-msvc.exe
Windows arm64 tan-aarch64-pc-windows-msvc.exe

crates.io (Rust 1.86+, edition 2024) — published as alp-tan-cli; the installed binary is still tan:

cargo install alp-tan-cli --locked

npm is not available. @alplabai/tan does not exist on the registry at any version — the publish job failed with npm error code EOTP because the configured token requires an interactive one-time password (#233). Use a release asset, the installer, or crates.io.

Release assets

  • -gnu Linux binaries are cross-built with a pinned glibc 2.31
    floor -- they run on Debian 11 (bullseye) / Ubuntu 20.04 and newer.
    -musl Linux binaries are fully static and run on any distro/libc.
  • Every binary + checksums.txt carries a GitHub build-provenance
    attestation. Verify with:
    gh attestation verify <downloaded-file> --repo alplabai/tan-cli

Full detail: CHANGELOG.md · full diff

v0.4.0-rc1

v0.4.0-rc1 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 28 Jul 02:46
6516480

Added

  • The JSON envelope vocabulary alp-sdk-vscode gates on is now a frozen,
    tested, published contract (#106).
    The extension matches four issue codes
    with === and reads a dozen data field names behind ?? [] fallbacks, and
    every one of those matches fails open — rename any and the extension does
    not error, does not log and does not warn, it silently skips the check or
    renders stale data, CI green on both sides. The headline case: rename
    data.soms and the New Project wizard falls back to a static catalogue that
    carries no cores, so a heterogeneous SoM scaffolds single-core with no IPC.
    The reference part E1M-AEN801 is multi-core, so that is the default path, not
    an edge case.
    • contract/issue-codes.json is the single source for the frozen codes
      (bootstrap.windows-unsupported — retired but RESERVED,
      bootstrap.yocto-host, bootstrap.prerequisites-missing,
      presets.sdk-root-unresolved), gated by frozen_issue_codes in
      crates/tan-cli/tests/contract.rs. The consumer is deliberately NOT
      loosened to prefix matching: a prefix match on bootstrap. would swallow
      codes it has no verdict for.
    • Four new golden envelopes extend the existing contract/envelopes/ suite
      (12 → 18 tests): presets-no-sdk, presets-heterogeneous-som (an a55
      yocto + m33 zephyr fixture SoM — the worked example above, made
      executable), explain-overview, and examples-catalog. A case fixture can
      now be a directory tree, so a case can carry a synthetic sdk/ checkout
      and pass --sdk-root ./sdk.
    • doctor --build's data keys get a key-set assertion rather than a golden
      (its values are host facts): summary.{pass,warn,fail}, nextSteps,
      checks[].{name,status}, and the literal check name workspace.
    • Tagged releases now publish envelope-contract.json beside the
      binaries — the frozen codes plus one golden envelope per command family —
      so the extension's contract test can diff against a published artefact
      instead of a hand-copied fixture.
    • Two consumer fields stay UNCOVERED and are documented as such in
      contract/README.md rather than quietly omitted: build --materialise's
      data.written (needs a resolvable SDK + a Python spawn) and sdk list's
      data.releases (network).
  • tan sdk list carries GitHub's draft/prerelease flags through (#122).
    Both booleans were already in the Releases API response tan parses but were
    dropped before reaching either the JSON envelope or the text table — a
    consumer asking "what is the latest SDK?" could not tell a release candidate
    apart from a genuine release, with no error and no log line. SdkRelease
    now carries draft/prerelease (default false when GitHub omits or
    misencodes either key, never a reason to drop the release), and the
    tan sdk list table marks a flagged entry with [draft]/[prerelease].
    tan does not filter on either flag or add a --include-prereleases switch —
    the consumer decides what "latest" means; tan's job is only to publish the
    fact it already has instead of destroying it. One caveat: fetch_releases
    sends no Authorization header, and GitHub returns draft: true entries
    only to a caller with push access, so against the public alp-sdk repo
    [draft] never renders today — it activates the moment a token is added.
  • tan doctor --build checks git, python, dtc and gperf, and every
    check can now carry a resolved version (#120, #123).
    Four of the six
    host tools a build needs were previously invisible to data.checks[]; git
    and python are checked unconditionally (every backend's build-plan
    emission runs alp_project.py through both, not just Zephyr's), dtc and
    gperf are gated on the Zephyr entry in data.osSet (Yocto/baremetal-only
    projects never see them) and — matching the retired alp doctor's own
    _check_dtc/_check_gperf — stay warn rather than fail. python
    reports a version FLOOR, not bare presence: an interpreter below the
    manifest's pythonMinVersion fails with its own detail, distinct from "not
    found".
    • Each data.checks[] entry gains an optional version — absent, never
      null, when unresolved or not meaningful (zephyrSdk, vendorToolchain)
      — reporting whatever tan itself resolved rather than leaving a consumer to
      re-probe PATH and risk a second, disagreeing answer. westResolved's
      version comes from the SAME workspace-venv resolver its status does,
      kept independent of west's bare-PATH version so the two rows can never
      be attributed to the wrong resolver.
    • missingPrerequisites[].tool for python is now host-correct — python3
      on a served POSIX host, python on Windows — matching prerequisites. install.linux/.macos's own key and tan bootstrap's posix_refusal
      naming for the identical missing tool, instead of always python, which
      a POSIX consumer could not re-key back into that same install map.
  • Vendor board-diagnostics and iot-starter from the SDK scaffold catalog
    (#14).
    Closes out the last two vendorable entries from alp-sdk#864's
    scaffold catalog (added by alp-sdk#903): board-diagnostics now emits the
    SDK's real board self-test app (SoM/SoC identity, RUN operating-point
    profile, on-module I2C management-bus scan) for both
    E1M-AEN801/E1M-V2N101, and iot-starter emits the SDK's real Wi-Fi +
    mqtts:// MQTT/TLS telemetry app on the CC3501E bridge — E1M-AEN801 only,
    matching the SDK catalog's AEN-only + preview status.
    • iot-starter narrows --som to E1M-AEN801: any other SKU is rejected
      with init.invalid-som before a single file is planned, never a silent
      fall-back onto the retired hand-written generator.
  • The JSON envelope now names which alp-sdk root a command actually
    resolved (#110).
    A new optional top-level sdk: { root, sourceTier } key
    reports the exact path + precedence tier (sdkRootFlag/projectPin/
    globalDefault/discovery) the command used — so a consumer (the vscode
    extension) can finally tell which SDK produced a result instead of guessing,
    especially on the unpinned/first-run path where discovery now walks up to
    an enclosing checkout (#101).
    • Populated from a value RECORDED at the moment one of tan's three
      resolvers actually resolved something, never from a second, fresh
      resolution — the three resolvers have different candidate sets, so
      re-resolving to fill the envelope could report a path the command never
      actually used.
    • Absent entirely (not null) when nothing resolved, keeping every
      existing contract golden byte-identical.
  • tan renode --sim-mode serves the studio hardware-simulator socket contract
    (#77, socket half).
    The flag existed for CLI-surface stability but errored
    "not yet ported", so studio had nothing to connect to. It now boots the
    --image-bundle's firmware in headless Renode and exposes the two sockets the
    gateway needs. The contract was ported from the RETIRED Python
    (west alp-renode --sim-mode, deleted in alp-sdk@df312cec under ADR-0020
    Phase 4), not re-derived from issue prose — the prose omits four things the
    implementation carries, and all four are honoured: the ERR <reason> reply,
    the ready (timeout <N>s). readiness marker, LOWERCASE 0xnn reply hex, and
    the Secure SCB->VTOR (0xE000ED08) write the generated boot script needs on
    ARMv8-M + TrustZone, where LoadELF does not seed it and the core otherwise
    HardFault-storms from address 0.
    • Both listeners are bound on ephemeral 127.0.0.1 ports before the
      descriptor names them, so a client that reads sim-descriptor.json and
      connects at once can never race into an ECONNREFUSED. They are bound on
      port 0 and their assigned ports read back rather than picked-then-rebound,
      which removes the Python's bind-then-close TOCTOU window outright.
    • <bundle>/sim-descriptor.json carries exactly the schema's four keys —
      control_socket, uart_socket (tcp://127.0.0.1:<port> URIs),
      framebuffers, peripherals.
    • The control socket is line-oriented, one request → one reply, with three
      verbs: sysbus ReadBytes <base> <count> (reply normalised from Renode's
      bracketed UPPER-case list to count space-separated lowercase 0xnn
      tokens, scoped to the brackets so an echoed command address cannot leak in
      as a phantom byte, and a short read is an error never a padded answer);
      sysbus WriteBytes <base> <hex…> (expanded to per-byte sysbus WriteByte <base+i>, because Renode's own WriteBytes takes (bytes, addr) — the
      reverse of studio's order); and any other line forwarded verbatim. A
      malformed line or monitor fault answers ERR <reason> and keeps the
      connection, and every reply is flattened to a single line so a client can
      never desynchronise.
    • The data payload records descriptor, controlPort and uartPort, so a
      JSON consumer reads the descriptor's path and the two ports out of the
      envelope instead of assuming <bundle>/sim-descriptor.json and parsing them
      back out of the file it first has to find.
    • A CPU that halts on its first instruction fetch fails the run with an
      renode.cpu-halted error issue and exit 1, matching the plain smoke's latch
      (issue #64). In sim mode the monitor owns Renode's stdout, so the halt is
      latched in the pump thread — a halt landing between two client commands
      belongs to no command's collection window, and previously would have
      resurfaced at best as an ERR on whichever command came next while tan
      still exited 0. Sim mode is exactly where a mis-seeded VTOR shows up this way.
    • Teardown sends the monitor's quit, polls up to 1 s for Renode to act on it,
      and only then kills — the Python's terminate() + wait(10) + kill on a
      shorter budget. Killing immediately after the flush g...
Read more