Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/bench.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ permissions:
contents: read
env:
CARGO_TERM_COLOR: never
TAG: v0.8.0
TAG: v0.8.1

jobs:
bench:
Expand Down
6 changes: 3 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
All notable changes to this project are documented here. The format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## Unreleased
## 0.8.1 - 2026-10-10

### Fixed
- Reject invalid JSON number grammar and raw control characters, platform-sized integer overflow, overflowing linear-cap
Expand Down Expand Up @@ -33,8 +33,8 @@ All notable changes to this project are documented here. The format follows
- Independent enumeration/router oracles, actual WASM boundary tests, real Chromium interaction/layout checks, Node process
contracts and cross-platform clean-prefix install tests (including Windows PowerShell 5.1/7 and npm 12).

These changes are a source candidate, not an update to the published 0.8.0 artifacts. Probability gate thresholds and frozen
benchmark corpora are unchanged. Passing finite tests is not exhaustive validation of every possible program or application.
This patch release hardens validation, lifecycle handling and the host-facing contracts. Probability gate thresholds and
frozen benchmark corpora are unchanged. Passing finite tests is not exhaustive validation of every possible program or application.

## 0.8.0 - 2026-10-09

Expand Down
10 changes: 5 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ resolver = "2"
members = ["probbit-core", "probbit-ir", "probbit-decide", "probbit-cli", "probbit-wasm"]

[workspace.package]
version = "0.8.0"
version = "0.8.1"
edition = "2021"
license = "Apache-2.0"
rust-version = "1.78"
Expand Down
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,7 @@ modes"). The tables are in [BENCHMARKS.md](BENCHMARKS.md).

## Install

One line, no sudo, the archive's SHA-256 checked before anything is installed. The current release is v0.8.0; the one-liners
were verified from clean machines on macOS (Apple silicon) and Linux (x86_64).
One line, no sudo, the archive's SHA-256 checked before anything is installed. The current release is v0.8.1.

| how | command |
|---|---|
Expand Down Expand Up @@ -534,7 +533,7 @@ anywhere ([docs/persona.md](docs/persona.md) §5.8). No strand yet? The tutor's

```sh
probbit monitor --demo --open
probbit monitor --demo drives --open # source checkout: synthetic goals/drive demo, not yet in the 0.8.0 release
probbit monitor --demo drives --open # synthetic goals/drive demo (0.8.1)
```

![probbit monitor: the tutor's week in the browser, the bars moving with every event](docs/probbit-monitor.gif)
Expand Down
2 changes: 1 addition & 1 deletion docs/CHEATSHEET.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# probbit cheat sheet (0.8.0)
# probbit cheat sheet (0.8.1)

The CLI's own help and docs, shortened; `probbit <command> --help` has every flag.

Expand Down
5 changes: 3 additions & 2 deletions docs/persona.md
Original file line number Diff line number Diff line change
Expand Up @@ -698,7 +698,7 @@ credits every learned trait with the level it took, so a reward aimed at one tra
demo below, praise for short answers also raised the light joke the tutor was making): learn the traits the feedback judges.

**The strand.** `--strand FILE` logs the life. Line 1 is the header, compact JSON:
`{"probbit_strand":1,"engine":"probbit 0.8.0","persona":{"name","version","digest"},"seed":N,"state":{...},"document":{...}}`,
`{"probbit_strand":1,"engine":"probbit 0.8.1","persona":{"name","version","digest"},"seed":N,"state":{...},"document":{...}}`,
with the initial state as canonical JSON (one individual has one header, whether it comes from `init` or from a state file) and
the persona document in its own key order (the compiled program, and `engine.program` with it, follows the document's key order).
Then one line per event, canonical JSON: `{"inputs":{...,"elapsed_hours":h},"n":k,"prev":"sha256:...","stance":"sha256:...",
Expand Down Expand Up @@ -790,7 +790,8 @@ anchor. Historical measurement before this hardening, on an Apple M4: a 10,000-e
bytes, 10 checkpoint lines) opens in `monitor --once` from its last checkpoint in 0.005 s (load 3.3), where a full `verify`
takes 192 s. A replay from a checkpoint costs what the events after it cost: 500 events past the last one took 26 s to draw
(load 6-13, about 50 ms an event for this persona), so K bounds the wait; a smaller K costs a few KB per checkpoint line. A strand without checkpoint or control lines (shorter than K events, or `--checkpoint-every 0`) is the
strand of 0.8.0, byte for byte; a binary before this one does not read the new lines.
same format as in 0.8.0. New strand headers record the current engine version, so their chain hashes differ; existing
0.8.0 strands remain replayable. Binaries before 0.8.0 do not read checkpoint or control lines.

Exit codes: `live` 0 when every event got its stance; 2 for a bad persona, state or flag, and after a bad event (each bad event
prints one `{"error"}` object on stdout, changes nothing and the run goes on); 4 when the writer lock is held by another writer
Expand Down
6 changes: 3 additions & 3 deletions install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
# and installs probbit.exe. No administrator rights needed.
#
# irm https://raw.githubusercontent.com/BitmapAsset/probbit/main/install.ps1 | iex
# & ([scriptblock]::Create((irm https://raw.githubusercontent.com/BitmapAsset/probbit/main/install.ps1))) -Version v0.8.0
# & ([scriptblock]::Create((irm https://raw.githubusercontent.com/BitmapAsset/probbit/main/install.ps1))) -Version v0.8.1
#
# Parameters (each also read from the environment variable named after it):
# -Version PROBBIT_VERSION release tag, e.g. v0.8.0 (default: the latest release)
# -Version PROBBIT_VERSION release tag, e.g. v0.8.1 (default: the latest release)
# -InstallDir PROBBIT_INSTALL_DIR where probbit.exe goes (default: $HOME\.local\bin)
# -DownloadBase PROBBIT_DOWNLOAD_BASE the archive is fetched from <DownloadBase>/<tag>/probbit-<tag>-<target>.zip
# (default: https://github.com/BitmapAsset/probbit/releases/download); needs -Version
Expand Down Expand Up @@ -37,7 +37,7 @@ $customBase = [bool]$DownloadBase
if (-not $DownloadBase) { $DownloadBase = "https://github.com/$Repo/releases/download" }
$DownloadBase = $DownloadBase.TrimEnd('/')
if (-not $Version) {
if ($customBase) { throw 'probbit install: set -Version (or PROBBIT_VERSION), e.g. v0.8.0, together with -DownloadBase' }
if ($customBase) { throw 'probbit install: set -Version (or PROBBIT_VERSION), e.g. v0.8.1, together with -DownloadBase' }
$Version = (Invoke-RestMethod -UseBasicParsing -Uri "https://api.github.com/repos/$Repo/releases/latest").tag_name
if (-not $Version) { throw 'probbit install: no published release found (set -Version)' }
}
Expand Down
6 changes: 3 additions & 3 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
# probbit installer: fetches a prebuilt release archive, checks its SHA-256 and installs the `probbit` binary. Never uses sudo.
#
# curl -fsSL https://raw.githubusercontent.com/BitmapAsset/probbit/main/install.sh | sh
# curl -fsSL https://raw.githubusercontent.com/BitmapAsset/probbit/main/install.sh | PROBBIT_VERSION=v0.8.0 sh
# curl -fsSL https://raw.githubusercontent.com/BitmapAsset/probbit/main/install.sh | PROBBIT_VERSION=v0.8.1 sh
#
# Environment (all optional):
# PROBBIT_VERSION release tag, e.g. v0.8.0 (default: the latest release)
# PROBBIT_VERSION release tag, e.g. v0.8.1 (default: the latest release)
# PROBBIT_INSTALL_DIR where `probbit` goes (default: ~/.local/bin; never overwrites a system-wide install implicitly)
# PROBBIT_DOWNLOAD_BASE the archive is fetched from $PROBBIT_DOWNLOAD_BASE/<tag>/probbit-<tag>-<target>.tar.gz
# (default: https://github.com/BitmapAsset/probbit/releases/download); needs PROBBIT_VERSION
Expand Down Expand Up @@ -90,7 +90,7 @@ main() {

version="${PROBBIT_VERSION:-}"
if [ -z "$version" ]; then
[ -z "${PROBBIT_DOWNLOAD_BASE:-}" ] || die "set PROBBIT_VERSION (e.g. v0.8.0) together with PROBBIT_DOWNLOAD_BASE"
[ -z "${PROBBIT_DOWNLOAD_BASE:-}" ] || die "set PROBBIT_VERSION (e.g. v0.8.1) together with PROBBIT_DOWNLOAD_BASE"
version=$(latest_tag) || exit 1
[ -n "$version" ] || die "no published release found (set PROBBIT_VERSION)"
fi
Expand Down
2 changes: 1 addition & 1 deletion npm/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "probbit",
"version": "0.8.0",
"version": "0.8.1",
"description": "probbit, a virtual p-bit processor for joint decisions under hard rules: installs the prebuilt probbit CLI (JSON in, JSON out).",
"license": "Apache-2.0",
"repository": {
Expand Down
6 changes: 3 additions & 3 deletions probbit-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ name = "probbit"
path = "src/main.rs"

[dependencies]
probbit-core = { path = "../probbit-core", version = "0.8.0" }
probbit-decide = { path = "../probbit-decide", version = "0.8.0" }
probbit-ir = { path = "../probbit-ir", version = "0.8.0" }
probbit-core = { path = "../probbit-core", version = "0.8.1" }
probbit-decide = { path = "../probbit-decide", version = "0.8.1" }
probbit-ir = { path = "../probbit-ir", version = "0.8.1" }
12 changes: 10 additions & 2 deletions probbit-cli/tests/persona.rs
Original file line number Diff line number Diff line change
Expand Up @@ -650,8 +650,9 @@ fn src_events() -> Vec<String> {
e.push(format!(r#""src":"{}""#, ["self", "human:owner", "env:tests", "clock"][t % 4])); format!("{{{}}}", e.join(",")) }).collect()
}
/// A persona without `reward_from` gives 0.8.0's bytes with `src` in its events (an undeclared input, listed in `ignored`): the
/// trace, the strand and the final state of 300 events of the drives fixture (seed 4) are the ones the 0.8.0 binary writes, and
/// the run leaves no lock file behind. The same persona with `reward_from: [human, env]` refuses the rewards from `self` and the
/// trace, the continued 0.8.0 strand and the final state of 300 events of the drives fixture (seed 4) match the historical
/// digests. Fresh headers identify the current binary; the run leaves no lock file behind. The same persona with
/// `reward_from: [human, env]` refuses the rewards from `self` and the
/// clock (exit 2, one error at `inputs.src` per refused event) and accepts the others.
#[test]
fn src_without_reward_from_gives_0_8_0_bytes() {
Expand All @@ -661,8 +662,15 @@ fn src_without_reward_from_gives_0_8_0_bytes() {
let (c, _, e) = probbit(&["persona", "replay", &fx, "--seed", "4", "--script", &script], ""); assert_eq!(c, 0, "{e}");
assert_eq!(e.trim(), "replay: 300 turns, trace sha256 ce8f247d1fe761ea651998f48360491030f15ba3c8530b0ed59d824868f71b71, final state sha256:52312b3cb8744360e7613e4db2fc5e3d326cb3c2204af7312e2a4196f9781551");
let (_, s0, _) = probbit(&["persona", "init", &fx, "--seed", "4"], ""); std::fs::write(&st, &s0).unwrap();
let (c, _, e) = probbit(&["live", &fx, "--state", &st, "--clock", "fixed", "--strand", &sd], ""); assert_eq!(c, 0, "{e}");
let header = read(&sd); assert_eq!(header.lines().count(), 1);
let current_engine = concat!("\"engine\":\"probbit ", env!("CARGO_PKG_VERSION"), "\"");
assert!(header.contains(current_engine), "{header}");
// Continue a historical header: its version participates in every chained hash. Keep the 0.8.0 golden, not a new hash per release.
std::fs::write(&sd, header.replacen(current_engine, "\"engine\":\"probbit 0.8.0\"", 1)).unwrap();
let (c, out, e) = probbit(&["live", &fx, "--state", &st, "--clock", "fixed", "--strand", &sd], &(evs.join("\n") + "\n")); assert_eq!(c, 0, "{e}");
assert!(e.contains("strand head sha256:c37fea55abbec95d0c0f1f1703741e20c26cd5d66587132917772435a5e94655, final state sha256:52312b3cb8744360e7613e4db2fc5e3d326cb3c2204af7312e2a4196f9781551"), "{e}");
let (c, verified, e) = probbit(&["live", "verify", &sd], ""); assert_eq!(c, 0, "{verified}{e}");
assert_eq!(out.lines().filter(|l| l.contains(r#""ignored":["src"]"#)).count(), 300);
assert!(!std::path::Path::new(&format!("{sd}.lock")).exists(), "the lock is released");
// with reward_from: the rewards from self and the clock are refused, the others accepted
Expand Down
4 changes: 2 additions & 2 deletions probbit-decide/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ keywords = ["p-bit", "assignment", "routing", "constraints", "probabilistic"]
categories = ["algorithms", "science"]

[dependencies]
probbit-core = { path = "../probbit-core", version = "0.8.0" }
probbit-ir = { path = "../probbit-ir", version = "0.8.0" }
probbit-core = { path = "../probbit-core", version = "0.8.1" }
probbit-ir = { path = "../probbit-ir", version = "0.8.1" }
2 changes: 1 addition & 1 deletion probbit-ir/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ keywords = ["p-bit", "constraints", "gibbs-sampling", "probabilistic", "ising"]
categories = ["algorithms", "science", "mathematics"]

[dependencies]
probbit-core = { path = "../probbit-core", version = "0.8.0" }
probbit-core = { path = "../probbit-core", version = "0.8.1" }
2 changes: 1 addition & 1 deletion scripts/bench/test_install_ps1.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# installs it with -DownloadBase, then the `irm | iex` form (environment variables), then the tampered copy (must fail).
# pwsh -File scripts/bench/test_install_ps1.ps1 -Srv <dir> [-Tag v0.2.0] [-AddToPath]
# powershell -ExecutionPolicy Bypass -File scripts/bench/test_install_ps1.ps1 -Srv <dir>
param([Parameter(Mandatory = $true)][string]$Srv, [string]$Tag = 'v0.8.0', [switch]$AddToPath)
param([Parameter(Mandatory = $true)][string]$Srv, [string]$Tag = 'v0.8.1', [switch]$AddToPath)
$ErrorActionPreference = 'Stop'
"PowerShell $($PSVersionTable.PSVersion) ($($PSVersionTable.PSEdition))"
$oldPath = $env:Path
Expand Down
4 changes: 2 additions & 2 deletions scripts/tests/test_install_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def run_fixture(self, os_name, arch, libc, **extra):
script.chmod(0o755)
env = dict(os.environ, PATH=str(root) + os.pathsep + os.environ["PATH"],
FIXTURE_OS=os_name, FIXTURE_ARCH=arch, FIXTURE_LIBC=libc,
PROBBIT_VERSION="v0.8.0", PROBBIT_INSTALL_DIR=str(root / "bin"))
PROBBIT_VERSION="v0.8.1", PROBBIT_INSTALL_DIR=str(root / "bin"))
for key in ["PROBBIT_TARGET", "PROBBIT_DOWNLOAD_BASE"]:
env.pop(key, None)
env.update(extra)
Expand All @@ -45,7 +45,7 @@ def test_supported_target_selection(self):
with self.subTest(target=target):
output = self.run_fixture(os_name, arch, libc)
self.assertIn("FIXTURE_FETCH", output)
self.assertIn("probbit-v0.8.0-" + target + ".tar.gz", output)
self.assertIn("probbit-v0.8.1-" + target + ".tar.gz", output)

def test_unsupported_architecture_never_fetches(self):
output = self.run_fixture("Linux", "riscv64", "glibc")
Expand Down
Loading