Commit Graph

2813 Commits (wkt/tipc_backend_378)

Author SHA1 Message Date
Gud Boi 935c8cf656 Guard receive-path transport rendering
Skip raw packet, decoded message, peer, and channel formatting when
transport logging is disabled. Keep message processing and wire
reads outside the guards so logging controls never affect IPC flow.

Also narrow the remaining pretty-struct TODO to require a
non-raising formatter with native-repr fallback.

(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))
2026-08-12 13:48:40 -04:00
Gud Boi 84ec895150 Drop resolved channel log-guard TODO
Remove the stale `Channel.from_addr()` design note now that its
`at_least_level()` guard avoids inactive pretty-rendering work.

(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))
2026-08-12 12:51:43 -04:00
Gud Boi 67280c2898 Honor log disable controls in hot-path guards
Use `Logger.isEnabledFor()` in `at_least_level()` so logger-local
and global disable controls short-circuit payload rendering.

Add `Channel.send()` coverage for effective-level, per-logger, and
global suppression while ensuring transport remains unchanged.

Caught-during: review remediation
Found-via: `/run-tests` test_log_guard_skips_payload_formatting

Review: PR #458 (goodboy)
https://github.com/goodboy/tractor/pull/458#issuecomment-5258207470

(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))
2026-08-11 21:56:27 -04:00
root 0e11ff7e9d Guard hot-path log calls to avoid payload rendering when disabled
Wrap `log.transport()` in `Channel.send()` and `log.runtime()` in
`PldRx.decode_pld()` with `log.at_least_level()` checks so that
expensive `pformat(payload)` / `repr(msg)` / `repr(pld)` calls are
skipped entirely when the respective log level is not active.

Previously the f-string arguments were eagerly evaluated before being
passed to the log method, even though `StackLevelAdapter.log()` would
then discard the message internally via its own `isEnabledFor()` check.
On high-frequency IPC paths this caused `pformat` to dominate CPU
usage (~60-70 %) as reported in #455.

This also restores the full diagnostic output (msg type, decoded
payload) that was temporarily commented out in 0373164 as a stopgap.

Resolves #455
2026-08-11 20:41:20 -04:00
mahmoud 148a098ca6 avoid format on the hot send path 2026-08-11 20:41:20 -04:00
Bd 83b3488455
Merge pull request #488 from goodboy/wkt/moc_teardown_completion
Wait for ctx exit in `maybe_open_context()`
2026-08-11 12:16:15 -04:00
Gud Boi daa661aba3 Clarify `maybe_open_context()` teardown notes
Drop the stale sentinel experiment and fix the cancellation-path
comment. Document that cached regular `__aexit__()` failures are
always re-raised at the final consumer boundary.

Review: PR #488 (goodboy)
https://github.com/goodboy/tractor/pull/488

(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))
2026-08-11 11:38:43 -04:00
Gud Boi 55ec3dbf51 Drop unused `_Cache` teardown bindings
Remove the unused `value` assignment after cache eviction and skip
unpacking stale resource state before raising its invariant error.

Review: PR #488 (Copilot)
https://github.com/goodboy/tractor/pull/488#pullrequestreview-4850557500

(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))
2026-08-07 22:24:27 -04:00
Gud Boi a753625fc6 Wait for ctx exit in `maybe_open_context()`
Block the final user on its cached resource's `__aexit__()` and
raise regular cleanup errors at that user's ctx boundary.

Deats,
- serialize user registration and teardown under each cache-key lock
- keep queued entrants on the same lock through resource replacement
- preserve `Cancelled`, `KeyboardInterrupt`, and `SystemExit` flow
- cover successful, failing, cancelled, and re-entry teardown paths

Prompt-IO: ai/prompt-io/opencode/20260804T030309Z_65bf9df5_prompt_io.md

(this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))
2026-08-03 23:45:42 -04:00
Bd 65bf9df5ba
Merge pull request #468 from goodboy/test_cpu_throttling
Test cpu throttling
2026-06-29 19:18:34 -04:00
Gud Boi 51326f4b7a Fix uds `get_random` reaper-regex break (+2 nits)
Copilot's 2nd-pass review (PR #468) caught a regression I landed in
the uds fix: `UDSAddress.get_random()` put the per-call token AFTER
`@{pid}` (`no_runtime_*@{pid}.{token}.sock`), which breaks the
`tractor._testing._reap` matcher
`^(?P<name>.+)@(?P<pid>\d+)\.sock$` — so no-runtime orphan socks
stopped matching and never got reaped/attributed. Move the token
INTO the name (`{prefix}.{token}@{pid}.sock`) so the canonical
`@{pid}.sock` suffix stays intact for both that regex and the
`spawn._reap` reconstruction; also bump the token to 8 hex chars.

Also two robustness nits from the same review,
- `tests.conftest._measure_sustained_headroom()`: guard `frac <= 0`
  before `1./frac` — a 0/parked-core freq read would
  `ZeroDivisionError`, get swallowed by the broad `except` into a
  1.0 (no-throttle), defeating the probe on the exact broken box it
  should flag; read 0 as max throttle.
- `scripts/cpu-perf-check`: mark the burn procs `daemon=True` and
  wrap sampling in `try/finally` so a Ctrl-C / error reaps them
  instead of leaving stray CPU hogs.

Regressed-by: 09c50f49 (uds no-runtime token placed after `@pid`)
Found-via: Copilot review #4595803812 (`_testing._reap` regex)
Review: PR #468 (Copilot)
https://github.com/goodboy/tractor/pull/468#pullrequestreview-4595803812

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-29 18:51:26 -04:00
Gud Boi 63498a80c2 Use `cpu_perf_headroom()` at remaining deadlines
Finish TODO #2 from PR #468: the last raw `cpu_scaling_factor()`
call-sites still used the static-only check (blind to the
sustained-load power-cap). Point them at the `cpu_perf_headroom()`
SUPERSET — it calls `cpu_scaling_factor()` internally + the
session-cached throttle probe, so it's always >= the old factor
(never LESS headroom, so CI stays green).

Migrated,
- `test_spawning`: the `fail_after(1 * ...)` smoke deadline
  (#465-added).
- `test_inter_peer_cancellation`: `this_fast` budget.
- `test_docs_examples`: example-run `timeout`.
- `test_resource_cache`: fan-out `timeout`.

`test_cancellation` already used `cpu_perf_headroom()`; only its
explanatory comments still name the static helper.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-29 18:13:47 -04:00
Gud Boi 09c50f495d Uniquify no-runtime UDS `get_random()` paths
W/o a live runtime `get_random()` named UDS socks purely by
`(prefix, pid)`, so two calls in one proc returned the SAME
`no_runtime_*@{pid}.sock` — the 2nd `.bind()` then tripped
`EADDRINUSE`. Append a per-call `uuid4().hex[:6]` token so
each call yields a distinct sockpath.

This fixes the 3 `tests.discovery.test_tpt_bind_addrs` uds
failures (one registrar + disjoint-bind, two non-registrar
binds) where `reg_addr` and a "random" bind addr aliased —
the uds CI job's only red, surfaced when this branch rebased
onto the newer base that carries those tests.

Scoped to the no-runtime branch ON PURPOSE: the runtime
`{name}@{pid}` convention stays deterministic so
`spawn._reap.unlink_uds_bind_addrs()` can still reconstruct
+ unlink a SIGKILL'd subactor's sock (#454).

Deats,
- `_uds.py`: add `uuid4` import + token in the no-runtime
  branch
- `_testing.addr`: tighten `get_rando_addr()` docstring re the
  intra-proc per-call token (not just pid-keyed namespacing)

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-29 18:08:50 -04:00
Gud Boi 5b1a9edeb3 Fix `_burn` bigint blowup, ctx-mgr `_read_mhz`
Both `_burn()` impls (the `cpu-perf-check` script + the
`_measure_sustained_headroom()` probe in `tests.conftest`) grew `x`
~x**2 per iter, so the loop quickly went bigint alloc/mul-bound — a
noisy CPU load + needless memory across N procs. Mask each step to
64-bit for a steady, fixed-width ALU burn (still pegs every core,
which is all the freq probe needs).

Also, `_read_mhz()` opened the sysfs freq files without a ctx-mgr;
`with open(...)` so the FD closes deterministically (matches the
script's own `_read()`).

Review: PR #468 (Copilot)
https://github.com/goodboy/tractor/pull/468

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-29 18:08:50 -04:00
Gud Boi 707caf63d1 Use `cpu_perf_headroom()` for timing-test deadlines
`cpu_perf_headroom()` is a strict SUPERSET of `cpu_scaling_factor()`
— it folds in static cpu-freq scaling + the slow-CI bump AND the
sustained-load power-cap throttle probe. Point the timing-deadline
call sites at it so they're robust to sustained throttling too (the
gremlin behind mass `trio` deadline-miss flakes),

- `test_legacy_one_way_streaming`: `time_quad_ex` cancel-deadline +
  `test_a_quadruple_example`'s `this_fast` smoke bound.
- `test_cancellation`: `test_cancel_via_SIGINT_other_task` +
  `test_fast_graceful_cancel_*` deadlines.

`cpu_perf_headroom >= cpu_scaling_factor` always, so never less
headroom (CI stays green); `cpu_scaling_factor()` remains the
internal static component.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-29 18:08:50 -04:00
Gud Boi 0ad5261905 Add `cpu-perf-check` sustained-throttle gate script
Standalone CLI companion to `cpu_perf_headroom()` (20cb99ec): idle
freq snapshots LIE — every static knob (`governor`, EPP,
`platform_profile`, `scaling_max_freq`) can read "performance"
while a firmware/EC power cap (AMD PPT/STAPM + friends) clamps the
package to ~30% the moment a sustained multi-core load lands,
masquerading as a `trio`-backend deadline-miss "regression" on
byte-identical code.

Deats,
- burns every core for `CPU_PERF_SECS` (default 4s) and samples the
  ACHIEVED `scaling_cur_freq` steady-state (post boost-ramp) vs the
  package max ceiling,
- exits 0 when the sustained fraction clears
  `CPU_PERF_HEALTHY_FRAC` (default 0.45), 1 when throttled — so it
  gates a suite run: `scripts/cpu-perf-check && pytest tests/ ...`,
- prints the static knobs first (to show they all read fine) then
  the remediation list on failure (`platform_profile` bounce, USB-C
  PD replug, `ryzenadj`, reboot) w/ the key reminder: do NOT bump
  test budgets — the box is slow, not the code.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-29 18:08:50 -04:00
Gud Boi 333af7debd Add `cpu_perf_headroom()` for throttle-aware deadlines
Mass `trio` deadline-miss failures on byte-identical code turned
out to be a firmware/EC power-cap (AMD PPT/STAPM) clamping the
all-core sustained clock while every static knob (`governor`,
`scaling_max_freq`, EPP, platform-profile) still read "performance"
— invisible to the existing `cpu_scaling_factor()` check. See
`scripts/cpu-perf-check` + the
`ai/conc-anal/trio_033_cancel_cascade_slowdown_depth3_issue.md`
notes.

Deats,
- add `_measure_sustained_headroom()` to `tests/conftest.py`: a
  one-shot ~0.9s all-core burn (explicit `fork`-ctx `mp` procs)
  sampling achieved-vs-max freq AFTER the boost window; under a 0.6
  gate it returns the full inverse fraction (capped 4x), else 1.0;
  best-effort 1.0 on non-linux or any error,
- add `cpu_perf_headroom()`: `max()` of the static scaling factor
  and the (session-cached) sustained probe,
- inflate deadline budgets by it in `test_dynamic_pub_sub`, both
  `test_clustering` cases, the
  `test_multi_nested_subactors_error_through_nurseries` pexpect
  waits + `test_nested_multierrors`,
- `xfail(strict=False)` `test_nested_multierrors` depth=3 under
  throttle: the deep tree trips tractor's INTERNAL reap deadlines
  (`soft_kill`/`hard_kill` `terminate_after=1.6`) minting a
  `Cancelled` inside the runtime — not fixable by test-budget
  inflation; auto-clears once the box un-throttles.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-29 18:08:50 -04:00
Bd f8b7233b3e
Merge pull request #460 from goodboy/docs_vibed_for_serious
Docs (vibed) for serious: real documentation with a modern theme
2026-06-29 16:22:31 -04:00
Gud Boi ca78eb2bed Skip the UDS example on macOS CI
`uds_transport_actor_tree.py` (new in 759d46dd) reliably fails on
macOS CI with a bare `returncode 1`. The example forces
`enable_transports=['uds']`, and UDS-on-macOS is otherwise
un-exercised by the matrix (there's no `tpt_proto=uds` macOS job),
so it's the first thing to surface a macOS UDS-path issue.

It passes cleanly on Linux, and the peer-cred paths are already
platform-guarded + graceful (`get_peer_info`/SO_PEERCRED on linux
vs `get_peer_pid`/LOCAL_PEERPID elsewhere) - so the crash is deeper
in the macOS UDS stack. The test swallows the subproc stderr (only
re-raises when the last line has "Error"), so the exact failure
can't be pinned from CI logs; needs a macOS box to root-cause.

Skip it on `_friggin_macos and ci_env` (same shape as the existing
`full_fledged_streaming_service` skip) so #460 lands green; the
macOS UDS root-cause is a follow-up.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-29 13:55:25 -04:00
Gud Boi 43216c8d4a Show error/cancel teardowns in the `Context` diagram
The `context_handshake` sequence diagram only showed the graceful
`Return` ending - underselling the whole SC pitch (errors + cancels
propagate *both* ways across the wire). Add a "... or, instead of a
graceful Return" group with the non-graceful endings,

- parent-initiated: `ctx.cancel()` (or a parent-side error) ->
  child relays `Error: ContextCancelled`,
- child-initiated: child ships `Error: <raised>` (or
  `ContextCancelled`).

Labelled `Error: ...` since `ContextCancelled` is an exception that
rides inside an `Error` wire msg, not its own msg type - keeping
the diagram's wire-level labels honest. Re-render the committed
`_diagrams/context_handshake.svg` fallback (CI has no `d2` bin) to
match.

Also cache-bust d2 images in `d2diagrams.py`: sphinx tags css/js
with `?v=<hash>` but not images, so an edited diagram kept serving
the browser's stale copy at the stable `_images/<stem>.svg` url
(cost us a manual hard-refresh). Hash each rendered svg + rewrite
only the d2 `<img src>` to `...svg?v=<hash8>` via the
`html-page-context` hook - content-addressed, so unchanged diagrams
keep their query.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-28 21:55:39 -04:00
Gud Boi 23edf03563 Slim README to lean on the hosted docs
Continuing the README slim-down: stop inlining content that now
lives (and renders better) on the GitHub Pages site, and just
point readers there.

- "Where do i start" drops the SC reading-list links in favor of
  a single nudge to the docs quickstart.
- "Example codez" drops the full `we_are_processes.py` listing -
  keep the one-minute pitch prose + the docs/examples links.
- "What's on the TODO" collapses the inline bullet list down to a
  link to the docs roadmap ("what the future holds").

Also,
- prune the now-dead RST link targets (`blog post`, `trio docs`,
  `SC`, `libdill-docs`, `async sandwich`, `messages`, ..).
- swap the `|docs|` badge from readthedocs over to the GitHub
  Pages `docs.yml` action badge + `goodboy.github.io` target.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-28 21:14:12 -04:00
Gud Boi 3753c671be Slim README to lean on the hosted docs
Continuing the README slim-down: stop inlining content that now
lives (and renders better) on the GitHub Pages site, and just
point readers there.

- "Where do i start" drops the SC reading-list links in favor of
  a single nudge to the docs quickstart.
- "Example codez" drops the full `we_are_processes.py` listing -
  keep the one-minute pitch prose + the docs/examples links.
- "What's on the TODO" collapses the inline bullet list down to a
  link to the docs roadmap ("what the future holds").

Also,
- prune the now-dead RST link targets (`blog post`, `trio docs`,
  `SC`, `libdill-docs`, `async sandwich`, `messages`, ..).
- swap the `|docs|` badge from readthedocs over to the GitHub
  Pages `docs.yml` action badge + `goodboy.github.io` target.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-28 14:20:50 -04:00
Gud Boi c028e03d32 Update quickstart `we_are_processes` walkthrough
The reworked `we_are_processes.py` (now `Context`-API based) prints
different stdout, so the hardcoded expected-output block went
stale: swap the old `Yo, i'm 'worker_N'...` / "self-destruct in 1
sec" lines for the real run - "self-destruct in 2s.." then the
per-worker `Started ep-task in subactor,` / `N::'worker_N'@<pid>`
blocks.

Also retell the prose to match: subs spawn concurrently from bg
`trio` tasks, each runs a `@tractor.context` `endpoint()` that
`ctx.started()`-hands its name + pid back through
`Portal.open_context()`, then parks in `trio.sleep_forever()`
before the root crashes + the tree is reaped.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-28 13:29:02 -04:00
Gud Boi 274cab948c Slim the README to one `Context` showcase
The README inlined six example scripts; per our own "point at
`examples/`, don't duplicate" philosophy that's a lot of rot
surface. Drop all but the showcase and rework it onto the modern
`Context` API to mirror the docs landing + `we_are_processes.py`:
spawn a subactor per core, `open_context()` each, crash the root,
reap the tree.

Replace the rest with a short "want more?" pointer to the docs site
+ the `examples/` dir (where the debugger, streaming, cancellation,
`asyncio`, msging + cluster demos all live, CI-run).

Also tidy a few nits while here,
- fix the title typo "structurred" -> "structured",
- close the unterminated quote in the `UV_PROJECT_ENVIRONMENT`
  install snippet,
- add the blank line a nested `trionics` bullet list needs so the
  PyPI long-desc (this file) renders as valid RST.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-28 13:29:02 -04:00
Gud Boi c3e5ed1bd7 Rework landing example onto the `Context` API
`run_in_actor()` is slated to become a hilevel wrapper
(`runtime/_supervise.py` "TODO: DEPRECATE THIS"), so the showcase
`we_are_processes.py` shouldn't lead with it. Move it to the modern
API: each `worker_<i>` subactor runs a `@tractor.context`
`endpoint()` that `started()`-hands its name + pid back over
`Portal.open_context()` and parks; the root sleeps then raises on
purpose so the runtime reaps the whole tree (zero zombies).

The subs spawn concurrently from bg `trio.Task`s so each child's
cold `import tractor` (~0.4s, see #470) overlaps instead of
stacking; a comment flags the coming `main_thread_forkserver`
backend (#463) which'll make serial spawns cheap enough to just
loop.

Match the landing prose to the snippet — name the `Context` +
`started()` handshake it now leads with.

Also, document `--watch examples` on the `sphinx-autobuild` cmds so
edits to `literalinclude`-d example scripts (which live outside
`docs/`) live-reload too.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-28 13:29:02 -04:00
Gud Boi d688eaba84 Prime the docs for GitHub Pages serving
The gh-pages deploy workflow already exists (build on PR + main,
deploy on main push via `actions/deploy-pages`); wire up the sphinx
side,

- `sphinx.ext.githubpages`: emits a `.nojekyll` so Pages serves the
  `_static/` + `_images/` dirs (Jekyll otherwise drops `_`-prefixed
  paths, breaking every asset),
- `html_baseurl`: the canonical site root
  (`https://goodboy.github.io/tractor/`) for the `<link
  rel="canonical">` + `og:url` tags.

The one remaining (one-time, manual) step is the repo setting:
Settings -> Pages -> Source = "GitHub Actions".

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-28 13:29:02 -04:00
Gud Boi 46197f00c3 Redesign the landing hero + nav branding
Rework the landing top into a left-anchored hero row and match the
navbar branding to it.

- `index.rst` + new `tractor_hero.html`: an inline-svg hero
  (`[logo] distributed structured concurrency`) with a full-width
  sub-tagline, plus a single screen-reader-only `<h1>` ("tractor")
  so the section headings become proper `<h2>` (was 4x `<h1>`), and
  the intro prose reflowed into 3 bullets,
- `conf.py`: a `logo.text` ("tractor") beside the navbar wireframe,
  polars-style,
- `custom.css`: the hero-row layout (logo + tagline + sub-line,
  single row on desktop / stack on mobile), the navbar brand styled
  like the centered nav tabs with `display:inline-block` to kill
  the parent link's propagated hover-underline, and smaller landing
  section headings w/ their `tl;dr` margin-note pulled level.

The hero linework stays `fill: currentColor` so the whole thing
flips with the light/dark toggle.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-28 13:29:02 -04:00
Gud Boi 4fdbc98438 Document logo tweaking + add `svgtool` helper
Capture the (easy-to-forget) logo recolour + theme-preview flow,

- new `notes_to_self/svgtool.py`: a headless-firefox svg helper
  (`colors`/`recolor`/`preview`/`page`); its `page --theme
  dark|light` injects a `localStorage` pin so a pydata `auto`-mode
  build renders its dark variant in a screenshot — the only way to
  verify theme-adaptive bits headlessly,
- `howtodocs.md`: a "Tweaking the logo" table (which file +
  `color:` knob per context) and an `svgtool` section that breaks
  down the `--theme` trick for the sphinx-rusty.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-28 13:29:02 -04:00
Gud Boi 1f84d5f529 Adopt the wireframe logo in navbar + README
Carry the landing hero's transparent-faces wireframe look to the
two other logo contexts. An `<img>`-embedded svg can't read the
page CSS (no `currentColor`), so the colours are baked per target,

- navbar: 2 variants (`tractor_logo_nav_light.svg` near-black
  lines, `…_nav_dark.svg` near-white) wired via the pydata
  `logo.image_light`/`image_dark` opts so it swaps with the theme
  toggle, matching the hero,
- README: `tractor_logo_wire.svg` — one neutral-grey, with INLINE
  fills (no `<style>`) so it reads on both GitHub light + dark and
  survives GitHub's svg sanitiser.

Faces are `fill: none` throughout; the filled `tractor_logo_side`
stays the recolour source + favicon.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-28 13:29:02 -04:00
Gud Boi eb87235835 Make the hero logo a theme-adaptive wireframe
Swap the landing-page hero from a static `<img>` (white-faced —
which glared as a light box on the dark theme) to an INLINE svg
whose linework uses `fill: currentColor` and whose faces are
transparent. The wireframe now inherits the theme text colour
(`svg.hero-logo { color: var(--pst-color-text-base); }`) and the
page background shows through, so it flips correctly with the
light/dark toggle.

- `tractor_logo_hero.html`: the inline svg partial (`.st0` ->
  `currentColor`, `.st1` -> `none`), `.. raw:: html :file:`-d into
  `index.rst`,
- the shared `tractor_logo_side.svg` is untouched here (navbar +
  favicon still ride it).

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-28 13:29:02 -04:00
Gud Boi 3072686c49 Document serving the docs over a LAN
Add a "Share on your LAN" blurb to both docs how-to homes
(`notes_to_self/howtodocs.md` + the dev-tips "Building these docs"
section): bind the server to all ifaces — via `sphinx-autobuild
--host 0.0.0.0` (live-reload) or `python -m http.server --bind
0.0.0.0` (static) — so a peer on your subnet can hit
`http://<lan-ip>:8000` (`hostname -I` prints the ip).

Verified a LAN-ip `curl` returns 200 + the socket binds `0.0.0.0`;
includes a trusted-LAN-only caveat since it's an unauthenticated
server on every interface.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-28 13:29:02 -04:00
Gud Boi c351671c16 Document the docs build/preview flow
Collect the sphinx build + live-preview one-liners (incl. the nix
`.#docs` opt-in shell and the `d2` diagram specifics) so
contributors don't have to reverse-engineer them,

- new `notes_to_self/howtodocs.md` terse cheat-sheet (force-added
  past the `notes_to_self/` ignore, same as `howtorelease.md`),
- a rendered "Building these docs" section in the dev-tips guide
  (`docs/project/dev-tips.rst`),
- a README pointer to the note.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-28 13:29:02 -04:00
Gud Boi 32d22abd93 Relock `uv.lock` for the `docs` dependency-group
The `docs` group (sphinx 9 + `pydata-sphinx-theme` stack) was added
to `pyproject.toml` but its lockfile half never landed — the
committed `uv.lock` still matched `main` and `uv lock --check`
flagged it out-of-sync. Relock to add the (additions-only) docs
deps so `uv sync --locked` and any CI lock-check pass.

(this commit msg was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-28 13:29:02 -04:00
Gud Boi be0a10b0d2 Add prompt-io provenance for d2-ext + docstring patches 2026-06-28 13:29:02 -04:00
Gud Boi 888162ea0c Fix informal-RST in docstrings for clean autodoc
The new `api/` reference pages surfaced 22 docutils warnings from
informal reST in public docstrings; fix the markup so the docs
build is warning-free (24 -> 0), clearing the path to a future
`-W`/`nitpicky` flip in CI.

Deats (docstring content only; no code/signature changes),
- give bullet lists a blank line + base-column indent (`Context`,
  `Context.cancel_called`/`.cancelled_caught`/ `.outcome`,
  `ActorNursery.cancel_called`, `query_actor`,
  `open_crash_handler`),
- demote the under-short `Behaviour:` underline in `Context.cancel`
  to a `**bold**` label,
- close an unbalanced backtick in the `wait_for_actor` summary and
  use the `` `role`\ s `` escaped-plural idiom where a role was
  pluralized (`gather_contexts`, `mk_pdb`, `MsgCodec`, msg `Error`,
  `open_context_from_portal`),
- make the `|_` method-tree in `ContextCancelled.canceller` a
  literal block (the bare `|` was read as a substitution ref),
- same blank-line fix for the `#318` entry in `NEWS.rst`.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-28 13:29:01 -04:00
Gud Boi 5bc15497b1 Harden the `.. d2::` directive render path
Three robustness fixes surfaced by the PR #460 self-review,

- a render that's *attempted and fails* (a `d2` bin is present but
  errors on the source) now raises a docutils error instead of
  silently serving the stale committed SVG — so `sphinx-build -W`
  fails on a broken `.d2` edit. The no-binary case stays a quiet
  committed-SVG fallback.
- render into a sibling temp-file then `os.replace()` so a
  failed/torn render can never clobber a good committed SVG.
- guard against 2 distinct `.d2` sources colliding on a single
  `_diagrams/<stem>.svg` within a build.

`render_svg()` now returns a `RenderResult` tristate that `run()`
maps to error / raw-source-literal / image.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-28 13:29:01 -04:00
Gud Boi 1c2048aefb Add opt-in `docs` dev-shell with `d2`
Factor the shared dev-shell toolchain into `basePkgs` + `baseHook`
so extra-tooling shells can extend it, then add a `docs` shell =
base + `pkgs.d2` (the diagram renderer our `.. d2::` sphinx
directive shells out to). Keeps `d2` OUT of the `default` shell so
casual dev envs stay lean.

Enter with `nix develop .#docs`, then build via `uv run --group
docs make -C docs html`.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-28 13:29:01 -04:00
Gud Boi b2eac01b37 Fix review nits from PR #460 self-review
Address the actionable findings from the `/code-review` pass
(#1-6); the d2-ext + docstring nits (#7-10) are left for a
follow-up.

Deats,
- `uds_transport_actor_tree.py`: `portal.chan.raddr.sockpath` is
  the *shared listener* socket (named for the root registrar), NOT
  the child's path — relabel it + lead with the per-child peer pid,
  and stop claiming it's the child addr in the docstring,
- `docs.yml`: scope the `pages` `concurrency` group to the `deploy`
  job w/ `cancel-in-progress: false` so a PR build can't cancel an
  in-flight production deploy,
- `architecture.rst`: `'subint'` is not a selectable `start_method`
  on this branch (`SpawnMethodKey` lacks it) — reframe as
  in-development/roadmap,
- `context.rst`: `StreamOverrun` isn't re-exported from `tractor`;
  point at `tractor._exceptions`,
- `debugging/`: sweep the 3 literalinclude'd examples off the
  deprecated `.result()` -> `.wait_for_result()`,
- `quickstart.rst`: proc-title is `name@pid` (per `Aid.reprol`),
  not `@uuid`.

NOTE, the `debugging/` examples are pexpect-tested; re-run
`tests/devx/test_debugger.py` for them.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-28 13:29:01 -04:00
Gud Boi f3ab10b103 Add gh-pages docs deploy workflow
`docs.yml`: sphinx build on PRs + main pushes (via `uv sync
--no-dev --group docs`), deploying to gh-pages only from main
pushes using the official
`actions/{upload-pages-artifact,deploy-pages}` pair - the
`msgspec`-style flow wished for in #123. No `d2` bin in CI (yet) so
the committed SVGs serve as-is.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-28 13:29:01 -04:00
Gud Boi bbb41b69c5 Write the big boi docs content tree
Replace the ancient `docs/index.rst` (still teaching
`tractor.run()`, `@stream` + arbiters..) with a full ~32 page tree
teaching ONLY the current api (`.wait_for_result()`, registrar
naming, `@context` + `open_context()` as the core model),

- landing: hero example, feature cards + canon links,
- `start/`: install + a 4-example quickstart on-ramp,
- `explain/`: an "SC across processes" essay distilling the essence
  per #157's orig ask + a runtime architecture tour,
- `guide/`: 12 task-focused pages incl the flagship multi-process
  debugging walkthrough, `Context` + `MsgStream` deep-dives,
  cancellation semantics (self-vs-cross cancel rules), discovery,
  infected `asyncio`, typed msging + the #126 testing-tips page,
- `api/`: 10 curated autodoc pages (all targets import-verified vs
  the reorg'd subpkg tree),
- `project/`: changelog include, ported dev-tips (drops old
  `docs/dev_tips.rst`) + roadmap.

Every code block is a `literalinclude` from `examples/`
- zero duplication, all CI-run - w/ `d2` figs floated
into the RHS margin per the 3-col design. Build is green; the 24
remaining warnings all source from lib docstring rst-isms or legacy
`NEWS.rst` content.

Substantially resolves #157 (refine round pending); chips at #175 +
#126.

Prompt-IO: ai/prompt-io/claude/20260611T175152Z_8526985c_prompt_io.md

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-28 13:29:01 -04:00
Gud Boi 4a1f633f8c Add `d2` diagram sources + rendered SVGs
7 hand-authored `docs/diagrams/*.d2` sources (sketch-mode,
grayscale theme, `elk` layout) w/ their pre-rendered fallback SVGs
committed under `docs/_diagrams/` (served as-is when no `d2` bin is
found, eg. in CI),

- `actor_tree`: the hero supervision-tree,
- `context_handshake`: seq diagram of the
  `Start`/`StartAck`/`Started`/`Yield`/`Stop`/`Return` ctx dialog,
- `streaming_pipeline`: 4-actor fan-in topology,
- `runtime_stack`: the per-actor layer cake,
- `debug_lock`: root-tty-lock REPL serialization,
- `error_propagation`: one-cancels-all boxed-err flow,
- `infected_aio`: guest-mode loop nesting.

Rendered w/ `d2` v0.7.1 via `nix run nixpkgs#d2`.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-28 13:29:01 -04:00
Gud Boi 6dafe85f54 Rebuild sphinx scaffold on `pydata` theme
Full `docs/conf.py` rewrite targeting `pydata-sphinx-theme` 0.18
(3-col layout: nav-index left, content middle, page-toc right)
skinned to a minimal b&w look via `_static/css/custom.css`, keeping
the `algol_nu` pygments style.

Also add 2 local sphinx exts under `docs/_ext/`,

- `d2diagrams.py`: a `.. d2::` directive rendering `d2lang` sources
  at build time when a `d2` bin is found (`D2_BIN` env supports
  argful values eg. `'nix run nixpkgs#d2 --'`), falling back to any
  git-committed SVG, else emitting the raw source as a literal
  block; no pypi ext was usable (all stubs or returncode-swallowing
  per the #157 research),
- `marginalia.py`: a theme-agnostic `.. margin::` directive
  (`sphinx-book-theme` style `Sidebar` subclass) for prose-anchored
  RHS asides; the custom css floats these (and `:margin:` d2 figs)
  into the right gutter on wide screens.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-28 13:29:01 -04:00
Gud Boi e8ec1bcc57 Add `docs` dependency-group for sphinx 9 stack
Fill in the long-TODO'd `[dependency-groups]` entry: `sphinx>=9.1`
+ `pydata-sphinx-theme>=0.18` +
design/copybutton/opengraph/togglebutton exts; relock.

Build via, `uv run --group docs make -C docs html`

Theme choice per the #157 research: `numpy`, `ray` + `polars` all
ride `pydata-sphinx-theme` these days (`ray` migrated off
`sphinx-book-theme`, which now hard-pins a stale pydata 0.16.1
anyway).

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-28 13:29:01 -04:00
Gud Boi 759d46dd17 Add 5 examples filling doc-tutorial gaps
New runnable (and so CI-auto-tested) scripts backing the new docs
guides, each following the `test_docs_examples.py` runner
conventions,

- `typed_payloads.py`: `@tractor.context(pld_spec=)` typed
  `started()`/stream roundtrip + a deliberate `MsgTypeError` catch
  demoing send-side validation,
- `nested_actor_tree.py`: 3-level tree w/ fan-out rpc through a
  mid-tier supervisor actor,
- `service_daemon_discovery.py`: registered daemon located via
  `find_actor()`/`wait_for_actor()` sans any spawn-portal ref,
- `uds_transport_actor_tree.py`: `enable_transports=['uds']` tree
  printing the filesystem sockaddr + kernel peer-pid creds,
- `streaming_broadcast_fanout.py`: one ipc stream fanned out to N
  local tasks via `MsgStream.subscribe()`.

All gaps were mined from in-code TODOs + the docs recon pass; see
#175 for the orig tutorial wishlist.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-28 13:29:01 -04:00
Gud Boi f11a74c15d Un-hide stdlib primes example, add `trio` shim
Rename `parallelism/_concurrent_futures_primes.py` ->
`concurrent_futures_primes.py` so the example-runner
(`test_docs_examples.py`) stops skipping it (leading `_` =
excluded) and CI finally exercises the `concurrent.futures`
baseline we compare against in the new parallelism guide.

Deats,
- keep the original executor code verbatim in a sync
  `check_primes()` fn for clean docs excerpting,
- add module docstring + zero-arg `async def main()` +
  `trio.run(main)` guard per the runner conventions.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-28 13:29:01 -04:00
Gud Boi fb8a6b2473 Use `.wait_for_result()` in dated examples
Swap the deprecated `portal.result()` calls for the modern
`.wait_for_result()` spelling in,
- `a_trynamic_first_scene.py` (x2)
- `actor_spawning_and_causality.py`
- `parallelism/single_func.py`

These 3 are literalinclude'd by the new docs tree so the rendered
code must teach the current api; the `debugging/` set still calls
`.result()` (pexpect pattern-matched tests, left for a follow-up
sweep).

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-28 13:29:01 -04:00
Bd 2e2d988bf7
Merge pull request #469 from goodboy/wkt/rm_test_warnings
Rm all the test suite warnings
2026-06-28 13:17:38 -04:00
Gud Boi bffeba952a Use `aid.uid` over manual `(name, uuid)` tuples
The `.uid`->`.aid` migration (prior commits) re-assembled the
legacy uid pair by hand as `(x.aid.name, x.aid.uuid)`.
`Aid.uid` (`msg/types.py`) is the non-deprecated canonical
property returning exactly that pair, so swap to `x.aid.uid`
everywhere — byte-identical, just DRY + consistent.

Covers the 5 review-flagged source sites (`msg._ops`,
`devx.debug._sync`, `experimental._pubsub`, `_exceptions`)
plus the ~22 unflagged identical sites (`_streaming` f-string
logs + 6 test modules); also tightens the `_exceptions`
`our_uid` annotation to `tuple[str, str]`.

Review: PR #469 (copilot-pull-request-reviewer)
https://github.com/goodboy/tractor/pull/469#pullrequestreview-4575979601

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-27 21:38:30 -04:00
Gud Boi 3e04968e79 Floor `get_rando_addr` port at 1024, not 1000
Ports below 1024 are privileged on linux
(`net.ipv4.ip_unprivileged_port_start = 1024`), so a non-root
`.bind()` on one raises `PermissionError`. The old `1000 +` floor
could roll into the 1000-1023 range and trip flaky `[Errno 13]
Permission denied` registry-listener binds; bump the base to 1024
so every generated port is non-privileged.

(this commit msg was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-27 20:35:58 -04:00
Gud Boi bc91a1bdfa Inline `send_yield` body to drop its deprecation
`experimental._pubsub`'s `fan_out_to_ctxs()` pushed each packet
via the now-deprecated `Context.send_yield()`, tripping its own
`DeprecationWarning` on every published msg.

Inline that method's exact body —
`await ctx.chan.send(Yield(cid=ctx.cid, pld=payload))` — so the
wire msg stays byte-identical (still a `Yield`) yet no warning
fires. The "proper" fix (swap to `MsgStream.send()` via
`Context.open_stream()`) needs BOTH sides migrated: the
subscriber still uses the legacy `Portal.open_stream_from()`
which never calls `.started()`, so a publisher-side
`open_stream()` raises a `RuntimeError` ("`started()` must be
called before opening a stream") — verified. Left as the
module's standing rework TODO.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-06-25 20:32:05 -04:00