Skip to content

Actors: std/actor wrapper and tests/actor, in Go - #310

Merged
malcolmredheron merged 93 commits into
mainfrom
actors-design
Oct 5, 2026
Merged

malcolmredheron merged 93 commits into
mainfrom
actors-design

Conversation

@malcolmredheron

@malcolmredheron malcolmredheron commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Implements the actor design, which was proposal-only on this branch. Actors are a user-level layer on top of caos, so the design doc now lives with the tool as std/actor/README.md rather than under design/.

  • std/actor: a single Go program on std/go. Start reads the branch head, passes the state tree to the inner request and tail-calls it with itself as the callback. Finish mints the new commit with caos put-commit and moves the branch with a compare-and-swap. A lost race fails the request, which is never cached, so the caller retries. std/actor/README.md is the design doc (moved from design/actors.md).
  • tests/actor: a reference key-value inner plus a staged test covering put, get, idempotent re-apply, a forced lost race that fails uncached and succeeds on retry, 12 concurrent writers converging to a linear chain, the inner's lazy view of the state, and the inner's cache hit.
  • tests/actor-ref: a spike that proves the write path described below.
  • Docs: std/actor/README.md (spike results, open question 6, status), design/runner-protocol.md (status line, link to the actor README) and std/README.md.

How finish moves the branch

Finish does not use git push. A push is a command <old> <new> <ref> plus a pack, and the pack can be empty when the server already has the new object, which it does after caos put-commit. So finish POSTs that one command and an empty pack to $CAOS_SERVER_URL/git-receive-pack and the server does the compare-and-swap. This needs no scratch repository, no fetch of the parent and no history.

git push cannot do this. It resolves the new commit in a local repository and walks its ancestry to build a pack, which needs every ancestor commit (a deep checkout). A partial clone with a promisor remote does not avoid that: with a depth-1 promisor pack and the shallow file removed, the push fails with Could not read <parent>. This is written up in open question 6 of std/actor/README.md and in the header of std/actor/worker.go.

Test plan

  • Merged current main (b57d285) cleanly
  • Full caos-test suite on the merged tree: 53/53 pass, including actor, actor-ref and lint

Known gaps

  • A real crash between the move and the reply is not injected; a re-applied message gives the same observable result.
  • Laziness is checked from inside the inner, not by counting server object reads.
  • Start still reads the head with a depth-1 tree:0 fetch into a scratch repo; a caos verb could replace it.
  • Not converted to Go: std/run-and-update-ref and its tests, which predate this work.

🤖 Generated with Claude Code

https://claude.ai/code/session_01TdKoYwiDbeZeVgVz12BFVS

@malcolmredheron
malcolmredheron merged commit e12dfee into main Oct 5, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant