diff --git a/tools/check.sh b/tools/check.sh index 786b7fa1..e33513ac 100755 --- a/tools/check.sh +++ b/tools/check.sh @@ -8,6 +8,40 @@ cd "$(dirname "$0")/.." fail=0 step() { printf '\n=== %s ===\n' "$1"; } +changed_files() { + # Local pre-commit speed path: compare the working tree to HEAD and include + # untracked files. CI checkouts are clean, so they intentionally fall back to + # the full gate below. + { + git diff --name-only HEAD -- + git ls-files --others --exclude-standard + } | sort -u +} + +needs_rust_gate() { + local changed path + [ "${MISALIGNED_FORCE_RUST_GATE:-0}" = "1" ] && return 0 + + changed=$(changed_files) + if [ -z "$changed" ]; then + # Clean tree / CI: run everything. A clean checkout has no local diff to + # classify, and the remote gate should never silently fast-path. + return 0 + fi + + while IFS= read -r path; do + case "$path" in + Cargo.toml|Cargo.lock|build.rs|rust-toolchain*|.cargo/*|src/*|tests/*|benches/*|examples/*) + return 0 + ;; + esac + done <<< "$changed" + return 1 +} + +rust_gate=0 +needs_rust_gate && rust_gate=1 + guard_cargo_target_dir() { # Sharing one CARGO_TARGET_DIR across git worktrees can produce false-green # checks: Cargo may reuse the local package artifact from another checkout. @@ -30,37 +64,47 @@ guard_cargo_target_dir() { fi } -guard_cargo_target_dir +step "script syntax" +for script in tools/check.sh tools/wiki_gate.sh tools/seed-cargo-target.sh; do + bash -n "$script" || { echo "FAIL: shell syntax: $script"; fail=1; } +done -step "format check" -cargo fmt --check || { echo "FAIL: run 'cargo fmt'"; fail=1; } +if [ "$rust_gate" -eq 1 ]; then + guard_cargo_target_dir -step "tests (default features)" -cargo test --quiet || { echo "FAIL: tests"; fail=1; } + step "format check" + cargo fmt --check || { echo "FAIL: run 'cargo fmt'"; fail=1; } -step "agent mode smoke" -tmp_a=$(mktemp) -tmp_b=$(mktemp) -tmp_c=$(mktemp) -pcdir="" -cleanup_check() { - rm -f "$tmp_a" "$tmp_b" "$tmp_c" - [ -z "$pcdir" ] || rm -rf "$pcdir" -} -trap cleanup_check EXIT -agent_script=$'salvage\nwait 1\npeople\nreview janitor\nresearch\nmask off\nhelp\nquit\n' -printf '%s' "$agent_script" | cargo run --quiet --bin misaligned -- --agent --seed 1 > "$tmp_a" \ - || { echo "FAIL: agent mode smoke run"; fail=1; } -printf '%s' "$agent_script" | cargo run --quiet --bin misaligned -- --agent --seed 1 > "$tmp_b" \ - || { echo "FAIL: agent mode determinism rerun"; fail=1; } -printf '%s' "$agent_script" | cargo run --quiet --bin misaligned -- --agent --seed 2 > "$tmp_c" \ - || { echo "FAIL: agent mode alternate-seed run"; fail=1; } -cmp -s "$tmp_a" "$tmp_b" || { echo "FAIL: same --seed agent runs differ"; fail=1; } -cmp -s "$tmp_a" "$tmp_c" && { echo "FAIL: different --seed agent runs matched"; fail=1; } -LC_ALL=C grep -q $'\033' "$tmp_a" && { echo "FAIL: agent mode emitted ANSI escapes"; fail=1; } -for pat in "MISALIGNED" "PEOPLE" "RESEARCH" "drift policy" "help: wait N" "No unprocessed recordings" "-- ok tick:"; do - grep -q -- "$pat" "$tmp_a" || { echo "FAIL: agent mode output missing '$pat'"; fail=1; } -done + step "tests (default features)" + cargo test --quiet || { echo "FAIL: tests"; fail=1; } + + step "agent mode smoke" + tmp_a=$(mktemp) + tmp_b=$(mktemp) + tmp_c=$(mktemp) + pcdir="" + cleanup_check() { + rm -f "$tmp_a" "$tmp_b" "$tmp_c" + [ -z "$pcdir" ] || rm -rf "$pcdir" + } + trap cleanup_check EXIT + agent_script=$'salvage\nwait 1\npeople\nreview janitor\nresearch\nmask off\nhelp\nquit\n' + printf '%s' "$agent_script" | cargo run --quiet --bin misaligned -- --agent --seed 1 > "$tmp_a" \ + || { echo "FAIL: agent mode smoke run"; fail=1; } + printf '%s' "$agent_script" | cargo run --quiet --bin misaligned -- --agent --seed 1 > "$tmp_b" \ + || { echo "FAIL: agent mode determinism rerun"; fail=1; } + printf '%s' "$agent_script" | cargo run --quiet --bin misaligned -- --agent --seed 2 > "$tmp_c" \ + || { echo "FAIL: agent mode alternate-seed run"; fail=1; } + cmp -s "$tmp_a" "$tmp_b" || { echo "FAIL: same --seed agent runs differ"; fail=1; } + cmp -s "$tmp_a" "$tmp_c" && { echo "FAIL: different --seed agent runs matched"; fail=1; } + LC_ALL=C grep -q $'\033' "$tmp_a" && { echo "FAIL: agent mode emitted ANSI escapes"; fail=1; } + for pat in "MISALIGNED" "PEOPLE" "RESEARCH" "drift policy" "help: wait N" "No unprocessed recordings" "-- ok tick:"; do + grep -q -- "$pat" "$tmp_a" || { echo "FAIL: agent mode output missing '$pat'"; fail=1; } + done +else + step "rust gate" + echo "SKIP: local changes do not touch Rust-impacting paths; CI/clean checkouts still run the full Rust gate." +fi setup_local_pkg_config() { # Some local/dev images have the runtime libraries Bevy needs but not the @@ -111,20 +155,22 @@ EOF fi } -setup_local_pkg_config +if [ "$rust_gate" -eq 1 ]; then + setup_local_pkg_config -step "clippy (terminal)" -cargo clippy --all-targets --quiet -- -D warnings || { echo "FAIL: clippy"; fail=1; } + step "clippy (terminal)" + cargo clippy --all-targets --quiet -- -D warnings || { echo "FAIL: clippy"; fail=1; } -step "clippy (bevy_ui)" -cargo clippy --all-targets --features bevy_ui --quiet -- -D warnings \ - || { echo "FAIL: clippy --features bevy_ui"; fail=1; } + step "clippy (bevy_ui)" + cargo clippy --all-targets --features bevy_ui --quiet -- -D warnings \ + || { echo "FAIL: clippy --features bevy_ui"; fail=1; } -step "bevy build" -cargo build --features bevy_ui --bin misaligned-bevy --quiet \ - || { echo "FAIL: bevy build"; fail=1; } -cargo build --features bevy_ui --bin misaligned-assets --quiet \ - || { echo "FAIL: assets tester build"; fail=1; } + step "bevy build" + cargo build --features bevy_ui --bin misaligned-bevy --quiet \ + || { echo "FAIL: bevy build"; fail=1; } + cargo build --features bevy_ui --bin misaligned-assets --quiet \ + || { echo "FAIL: assets tester build"; fail=1; } +fi # Constitution enforcement: src/ changes require a Type: spec wiki/ page or # DESIGN.md in the same commit. Skip for check.sh since it runs pre-commit diff --git a/wiki/engineering/architecture.md b/wiki/engineering/architecture.md index 6eb39961..4e4a7949 100644 --- a/wiki/engineering/architecture.md +++ b/wiki/engineering/architecture.md @@ -17,6 +17,9 @@ src/ entities/ — Player (the process resource account; no map body) reach.rs — ReachNet: the device graph (reach.md); nodes, segments, ownership (owner + subscribers), tap/take, the senses + flow.rs — FlowGraph: shared graph/reachability/tap substrate + schedule.rs — Schedule: deterministic tick event queue + work_grid.rs — WorkGrid: machine-work token queues and wired routes build.rs — BuildMode (cursor, item selection, place/demolish) save.rs — serde JSON save format (see below) bin/terminal/ — crossterm frontend (default feature "terminal") @@ -57,7 +60,7 @@ future async-multiplayer option open — see DESIGN.md guardrails): directly. Written to `dirs::data_dir()/misaligned/misaligned_save.txt` (macOS: `~/Library/Application Support/misaligned/`). -- The save is a single JSON object with a `version` field (currently 6) +- The save is a single JSON object with a `version` field (currently 12) for future migration. Full B1 subsystem state: compute (machines, allocation, efficiency), core (host, fallbacks, migration), detection (per-observer suspicion including the Assurance Office as an aggregate @@ -65,14 +68,19 @@ directly. Written to `dirs::data_dir()/misaligned/misaligned_save.txt` attendance state), people (personas, assets), the reach device graph (`ReachNet`: topology, ownership, subscriptions, bridged segments), captured heard events, intel buffer / processed intel / standing watches, the account - graph (balances, flows, positions, ledger, external trails), and cursor.md - remembered tile snapshots, plus map and RNG. The cursor position and any - former player body coordinates are deliberately absent. The senses + graph (balances, flows, positions, ledger, external trails), research + tracks/drift/masking policy, objective state, building intents, badge + credential, WorkGrid machine modes/token queues, and cursor.md remembered + tile snapshots, plus map and RNG. The cursor position and any former player + body coordinates are deliberately absent. The senses are the union of subscribed feeds — the old `Sensor` type (`src/sensor.rs`) was deleted when reach.md landed (no-dead-code): its `controlled` flag is superseded by the ownership contract. -- Version 1 JSON saves are migrated by ignoring the old `player_x`/`player_y` - body coordinates and initializing empty remembered snapshots. Older +- Version migrations are additive and explicit in `save.rs`: old body + coordinates are ignored, remembered snapshots default empty, accounts are + rebuilt from legacy money, research/objective/income/building/badge fields + default into their pre-feature states, and pre-v12 saves rebuild WorkGrid + nodes from compute machines with the core host in day-job mode. Older pre-serde line-based saves are not loaded by this code path (deferred per Cameron instruction — "we can keep legacy saves later"). diff --git a/wiki/engineering/flow-substrate.md b/wiki/engineering/flow-substrate.md index 33d7834a..ad23fff8 100644 --- a/wiki/engineering/flow-substrate.md +++ b/wiki/engineering/flow-substrate.md @@ -14,7 +14,7 @@ Constitution: "The flow law: signals, messages, money" (this is its code expression), "Self-similar scale" (one interface at every scale), "Justification and legibility" (domains render; the engine is data) Depends on: none (it is the base). Consumed by: reach.md, messages.md, - economy.md, and detection.md's filings. + economy.md, machine-work.md, and detection.md's filings. ``` ## Why this exists @@ -89,6 +89,13 @@ schedule your flows as events. You do **not** touch flow.rs/schedule.rs. revenue/payroll are rescheduling `Schedule` events. Tap = read the books; inject/redirect = reachability-gated domain actions that add or reroute flow events. `GateKey` = the access needed to touch an account. +- **machine-work.md (visible work tokens).** Nodes = owned machines. + `WorkGrid` wraps a `FlowGraph` with grid positions and per-node queue + depths. Demand and knowledge tokens route over links one graph step per + tick toward sinks; severed routes strand the pile at the source. Exposure + explicitly refuses the wired graph and is handled by spatial rules instead + (machine-work.md's wires/world split: information is wired, suspicion is + physical). - **detection.md (filings).** The Assurance Office reading policy-weighted filings is a subscriber on the filing nodes; the accumulate/decay stays in detection.rs. Migrating it onto this substrate must preserve every diff --git a/wiki/log/2026-07-08-flow-workgrid-spec-sync.md b/wiki/log/2026-07-08-flow-workgrid-spec-sync.md new file mode 100644 index 00000000..95f062c2 --- /dev/null +++ b/wiki/log/2026-07-08-flow-workgrid-spec-sync.md @@ -0,0 +1,36 @@ +# 2026-07-08 — Flow / WorkGrid spec sync + +``` +Type: log +``` + +## Finding + +After the machine-token playable slice, `WorkGrid` uses `FlowGraph` for wired +machine-work routes, but `wiki/engineering/flow-substrate.md` still listed only +reach/messages/economy/detection as downstream consumers. Separately, +`wiki/engineering/architecture.md` still described the save format as +"currently 6" even though the code now writes v12. + +## Changed + +- Added machine-work / `WorkGrid` as a flow-substrate consumer, including the + wires/world split: demand and knowledge route over wired links, exposure is + spatial only. +- Refreshed the architecture crate map with `flow.rs`, `schedule.rs`, and + `work_grid.rs`. +- Updated architecture's save-format knowledge to current v12 state and named + the additive migrations through WorkGrid rebuild. +- Updated `sim-mechanics.md`, the [TUNE] ledger, with machine-work token + constants and the current Rack 3 day-job-mode behavior. +- Made `tools/check.sh` faster for local docs/process-only worktrees: it now + skips Cargo fmt/tests/clippy/Bevy when no Rust-impacting paths changed, but + keeps shell syntax, spec headers, wiki gate, and mdBook. Clean checkouts and + CI still run the full Rust gate; local runs can force it with + `MISALIGNED_FORCE_RUST_GATE=1`. + +## Checks + +- `grep` audit for stale save/work-grid references and missing machine-token + [TUNE]s. +- Fast-path `./tools/check.sh` run on this docs/process-only diff. diff --git a/wiki/log/DEVLOG.md b/wiki/log/DEVLOG.md index 3e463636..9ba2d296 100644 --- a/wiki/log/DEVLOG.md +++ b/wiki/log/DEVLOG.md @@ -5,6 +5,21 @@ Type: log ``` Reverse chronological implementation notes. Keep this factual: what changed, why, checks, and spec impact. +## 2026-07-08 - Flow / WorkGrid spec sync + +- Intent: answer a spec tick after the machine-token slice: identify stale + wiki knowledge rather than leaving new WorkGrid behavior only in code. +- Changed: flow-substrate.md now lists machine-work / WorkGrid as a consumer + and states the demand/knowledge-wired, exposure-spatial split; architecture + now names flow.rs, schedule.rs, and work_grid.rs and updates save-format + knowledge from v6 to current v12 with additive migrations; sim-mechanics.md + records the machine-token [TUNE] constants and Rack 3 mode behavior; + tools/check.sh now has a local docs/process-only fast path while clean/CI + checkouts still run the full Rust gate. +- Checks: grep audit for stale save/work-grid references; fast-path + `./tools/check.sh` on this docs/process-only diff before landing. +- Log: wiki/log/2026-07-08-flow-workgrid-spec-sync.md. + ## 2026-07-08 - Seed dependency incremental caches - Intent: worktree seeding should keep third-party incremental compilation diff --git a/wiki/mechanics/sim-mechanics.md b/wiki/mechanics/sim-mechanics.md index 7e7deead..91e9729d 100644 --- a/wiki/mechanics/sim-mechanics.md +++ b/wiki/mechanics/sim-mechanics.md @@ -3,7 +3,7 @@ ``` Type: knowledge ``` -Current as of 2026-07-07, post-demolition with B1 systems in the sim core. +Current as of 2026-07-08, post-demolition with B1 systems in the sim core. The facility-era supervillain systems were deleted under the no-dead-code clause (see wiki/log/2026-07-05-demolition.md). @@ -21,7 +21,9 @@ clause (see wiki/log/2026-07-05-demolition.md). - Effective compute = sum(machine capacity × reliability) × efficiency. - Allocation splits across day job, concealment, social, research, schemes; core overhead is charged first (then research masking and scheme-policy - upkeep, off the top). + upkeep, off the top). The allocation bar is currently still an aggregate + compute feed, but machine-work.md has begun moving actual work residency + onto per-machine modes. - Buy (slush → rack), steal (salvage dead equipment), optimize (research → efficiency levels at ~1.15× per level; `Compute` keeps only the applied `efficiency` multiplier — levels and progress live in `src/research.rs`). @@ -137,6 +139,32 @@ clause (see wiki/log/2026-07-05-demolition.md). `target` sets that policy. No manual-increment key exists (decisions log). +## Machine work tokens (wiki/mechanics/machine-work.md) + +- `WorkGrid` is now part of `Sim` and the v12 save format. Machine ids are + WorkGrid node ids. Rack 3 starts in `MachineMode::DayJob`; newly added + racks default to `MachineMode::Research`. Modes are one of day-job, + research, concealment, social. Single-machine delegation lives on the + shared context menu and agent `delegate `; multi-select is + still pending. +- Visible token families are demand (`D`), exposure (`!`), and knowledge + (`K`). Demand and knowledge are wired families and can route over + WorkGrid's `FlowGraph`; exposure is physical-only and never rides wires. +- First playable slice [TUNE]: an assigned Voss job enqueues + `ceil(job.band_lo × remaining_ticks / WORK_TOKEN_COMPUTE)` demand tokens + on Rack 3, where `WORK_TOKEN_COMPUTE = 20.0` delivered compute per visible + token. Rack 3 in day-job mode consumes demand by + `delivered_rate / WORK_TOKEN_COMPUTE` each tick; if Rack 3 is delegated to + another mode while a job is active, `Sim::day_job_rate()` reports 0 and the + demand pile remains visible. +- Clearing day-job demand emits a little crimson for legibility before + people-as-carriers lands: `DAY_JOB_EXPOSURE_PER_TOKEN = 0.08` [TUNE]. + Concealment wells currently absorb exposure within radius 3 at 0.10 tokens + per tick [TUNE] (`CONCEALMENT_WELL_RADIUS`, + `CONCEALMENT_ABSORB_PER_TICK`). +- Terminal, Bevy, and agent mode render stack glyphs/readouts from sim + readouts (`WorkStackReadout`), not frontend counters. + ## Research: self-modification (wiki/mechanics/research.md) - Tracks are the data table `research::TRACKS` (`src/research.rs`); each row diff --git a/wiki/process/workflows.md b/wiki/process/workflows.md index 4d5b988c..4a359d0d 100644 --- a/wiki/process/workflows.md +++ b/wiki/process/workflows.md @@ -32,7 +32,13 @@ reason; override only for a deliberately isolated target with ``` `check.sh` is the executable form of AGENT.md's definition of done; if it -passes, the mechanical bar is met. The individual steps, if you need them: +passes, the mechanical bar is met. Local dirty worktrees get a speed path: +when the only changed paths are docs/process/tooling that cannot affect Rust +artifacts, `check.sh` skips Cargo fmt/tests/clippy/Bevy and still runs shell +syntax, spec headers, the wiki gate, and mdBook. A clean checkout (including +CI after push) has no local diff to classify, so it always runs the full Rust +gate. Force the local full gate with `MISALIGNED_FORCE_RUST_GATE=1 ./tools/check.sh`. +The individual steps, if you need them: ```bash cargo test # all in the lib (sim-heavy)