Test Spec: Core Lifecycle
What to do with this file
You are a coding agent. Your job is to execute this test spec by running commands in a shell, step by step, from Phase 0 through Phase 8. For each step:
- Run the command shown in the code block.
- Read the output.
- Check every Assert listed for that step.
- Record the result: PASS or FAIL with the actual output.
- When a step says Capture, save the value into the named variable and use it in subsequent steps.
At the end, produce a summary table showing which phases passed and which failed, with the actual vs. expected values for any failures.
If a prerequisite is not met (binary not found, fixture script missing), stop and report that instead of continuing.
What this test is checking
The day-to-day workflow of thinslice: creating state directories, creating worktrees, binding worktrees to state, starting and stopping processes, swapping state between worktrees, verifying port isolation across simultaneous slices, and cleaning everything up.
This test assumes slice setup works correctly (tested separately in
test-setup.md). The fixture script handles workspace creation so we can
focus on the commands you use after setup.
Important context: Processes defined in the test template are trivial
(python3 -m http.server and sleep infinity). They exist to validate that
thinslice can start, track, and stop processes — not to test any real
application. The httpd process is useful because we can curl it to confirm
the process is actually listening on the assigned port.
Prerequisites
The slice binary and slice-test-fixture helper must be on $PATH.
Python 3 must be available (for the httpd test process). No external
infrastructure is required.
As a quick smoke test, run:
$ slice --version
If this succeeds, proceed. If it fails, stop and report the error.
Fixture: slice-test-fixture workspace
The workspace subcommand creates a ready-to-use thinslice workspace:
- Creates a temp directory with a git repo and minimal
thinslice.new-state - Runs
slice setupto transform it into a workspace - Caches the result on disk — subsequent calls return the cached path instead of rebuilding (safe for parallel test runs)
- Prints the absolute path to the workspace
The template defines two processes:
process.httpd—python3 -m http.server $HTTPD_PORT -d $SLICE_STATE_DIR/wwwprocess.idle—sleep infinity
Usage:
$ slice-test-fixture workspace
/tmp/thinslice-workspace-b3e9a0
$ slice-test-fixture destroy /tmp/thinslice-workspace-b3e9a0
destroyed /tmp/thinslice-workspace-b3e9a0
Notation
$WS— absolute path to the workspace, captured from fixture output$S1,$S2— state directory names created during the test$HTTPD_PORT_*— httpd port values captured from various slices$IDLE_PORT_*— idle process port values- Lines starting with
$inside code blocks are commands to run
Phase 0: Get workspace
0.1 Create workspace
$ slice-test-fixture workspace
Capture the output as $WS.
0.2 Verify workspace is ready
$ ls -1 $WS
Assert:
- Contains
+clone+,+state+,main,local,pr,tmp
$ test -f $WS/+state+/template-clean/thinslice.toml && echo "ready" || echo "not ready"
Assert:
- Output is
ready
Phase 1: State creation
1.1 Create a state from template
$ cd $WS/main && slice state new dev-alpha --from template-clean
Expect: output confirming the state was created.
1.2 Create a second state
$ cd $WS/main && slice state new dev-beta --from template-clean
Expect: output confirming the state was created.
1.3 List states
$ cd $WS/main && slice state ls
Assert:
- Output includes
template-clean,dev-alpha, anddev-beta - All three show status
stopped(or equivalent "not running" indicator) - None are bound to a worktree
1.4 Verify state directories exist
$ test -f $WS/+state+/dev-alpha/thinslice.toml && echo "found" || echo "missing"
$ test -f $WS/+state+/dev-beta/thinslice.toml && echo "found" || echo "missing"
Assert:
- Both output
found
1.5 Verify ports are distinct
$ cd $WS/main && slice state new __port-check --from template-clean
This is a throwaway state just to verify port allocation.
Capture the HTTPD_PORT values from all three thinslice.toml files:
$PORT_ALPHAfrom$WS/+state+/dev-alpha/thinslice.toml$PORT_BETAfrom$WS/+state+/dev-beta/thinslice.toml$PORT_CHECKfrom$WS/+state+/__port-check/thinslice.toml
Assert:
$PORT_ALPHA,$PORT_BETA, and$PORT_CHECKare all different — eachslice state newallocates fresh ports
$ cd $WS/main && slice state rm __port-check
Expect: cleanup succeeds.
Phase 2: Worktree creation
2.1 Create a local worktree
$ cd $WS && slice local feature-one
Expect: worktree created at local/feature-one.
2.2 Create a tmp worktree
$ cd $WS && slice tmp experiment
Expect: worktree created at tmp/experiment.
2.3 Verify directories exist
$ test -d $WS/local/feature-one && echo "found" || echo "missing"
$ test -d $WS/tmp/experiment && echo "found" || echo "missing"
Assert:
- Both output
found
2.4 Verify git branches were created
$ git -C $WS/+clone+ branch --list
Assert:
- Branch list includes
local/feature-oneandtmp/experiment mainis also present
2.5 Verify worktrees are git worktrees of +clone+
$ git -C $WS/local/feature-one rev-parse --git-common-dir
Assert:
- Output points to
$WS/+clone+
$ git -C $WS/tmp/experiment rev-parse --git-common-dir
Assert:
- Output points to
$WS/+clone+
Phase 3: Binding and process lifecycle
3.1 Bind feature-one to dev-alpha
$ cd $WS/local/feature-one && slice use dev-alpha
Expect: output confirming binding.
3.2 Verify binding in state ls
$ cd $WS/main && slice state ls
Assert:
dev-alphais bound tolocal/feature-onedev-betais not bound to anything
3.3 Start processes
$ cd $WS/local/feature-one && slice up
Expect: processes start without errors.
3.4 Check status
$ cd $WS/main && slice status
Assert:
local/feature-oneshows statedev-alphaand statusrunninglocal/feature-oneshows port allocations (at least two ports listed)tmp/experimentshows no state binding and is not running
3.5 Check ports
$ cd $WS/local/feature-one && slice ports
Capture:
$HTTPD_PORT_ALPHA= the port shown forhttpd$IDLE_PORT_ALPHA= the port shown foridle
Assert:
- Two processes listed:
httpdandidle - Both ports are integers in valid range (1024–65535)
3.6 Verify httpd is actually listening
$ curl -s -o /dev/null -w "%{http_code}" http://localhost:$HTTPD_PORT_ALPHA/
Assert:
- HTTP status is
200— the python http server is running and serving from the state directory'swww/folder
3.7 Check config
$ cd $WS/local/feature-one && slice config
Assert:
- Output is valid TOML
- Contains
[env]section withHTTPD_PORT = "$HTTPD_PORT_ALPHA" - Contains
[process.httpd]and[process.idle]
3.8 Stop processes
$ cd $WS/local/feature-one && slice down
Expect: processes stop without errors.
3.9 Verify processes stopped
$ curl -s -o /dev/null -w "%{http_code}" http://localhost:$HTTPD_PORT_ALPHA/ 2>&1 || echo "connection refused"
Assert:
- Connection is refused — the httpd process is no longer running
$ cd $WS/main && slice status
Assert:
local/feature-oneshows statedev-alphabut status is no longerrunning(binding is preserved, processes are stopped)
Phase 4: State swapping
This tests the key scenario: moving state from one worktree to another. The same database, same ports, different code.
4.1 Start feature-one again
$ cd $WS/local/feature-one && slice up
Expect: processes start (feature-one is still bound to dev-alpha from Phase 3).
4.2 Verify it's running
$ curl -s -o /dev/null -w "%{http_code}" http://localhost:$HTTPD_PORT_ALPHA/
Assert:
- HTTP status is
200
4.3 Swap dev-alpha to the experiment worktree
$ cd $WS/tmp/experiment && slice use dev-alpha
Expect: output confirming binding. This should automatically stop feature-one's processes and unbind it.
4.4 Verify feature-one was stopped and unbound
$ cd $WS/main && slice status
Assert:
local/feature-oneis NOT bound to any state (or shows—)local/feature-oneis NOT runningtmp/experimentis bound todev-alpha
$ curl -s -o /dev/null -w "%{http_code}" http://localhost:$HTTPD_PORT_ALPHA/ 2>&1 || echo "connection refused"
Assert:
- Connection is refused — feature-one's processes were stopped during the swap
4.5 Start experiment with the same state
$ cd $WS/tmp/experiment && slice up
Expect: processes start.
4.6 Verify same ports
$ cd $WS/tmp/experiment && slice ports
Assert:
httpdport is$HTTPD_PORT_ALPHA— same port as before, because it's the same stateidleport is$IDLE_PORT_ALPHA
$ curl -s -o /dev/null -w "%{http_code}" http://localhost:$HTTPD_PORT_ALPHA/
Assert:
- HTTP status is
200— processes are running on the same ports as before, now under the experiment worktree
4.7 Stop experiment
$ cd $WS/tmp/experiment && slice down
Phase 5: Port isolation — two slices running simultaneously
5.1 Bind feature-one to dev-alpha, experiment to dev-beta
$ cd $WS/local/feature-one && slice use dev-alpha
$ cd $WS/tmp/experiment && slice use dev-beta
Expect: both bindings succeed.
5.2 Start both slices
$ cd $WS/local/feature-one && slice up
$ cd $WS/tmp/experiment && slice up
Expect: both start without errors.
5.3 Check status shows both running
$ cd $WS/main && slice status
Assert:
local/feature-oneshows statedev-alphaand statusrunningtmp/experimentshows statedev-betaand statusrunning
5.4 Verify port isolation
$ cd $WS/tmp/experiment && slice ports
Capture:
$HTTPD_PORT_BETA= the port shown forhttpd
Assert:
$HTTPD_PORT_BETAis different from$HTTPD_PORT_ALPHA— each state has its own port allocation
5.5 Verify both httpds are listening
$ curl -s -o /dev/null -w "%{http_code}" http://localhost:$HTTPD_PORT_ALPHA/
Assert:
- HTTP status is
200
$ curl -s -o /dev/null -w "%{http_code}" http://localhost:$HTTPD_PORT_BETA/
Assert:
- HTTP status is
200
Both slices are running simultaneously on different ports, sharing the same git repo but using different state directories.
5.6 Stop both
$ cd $WS/local/feature-one && slice down
$ cd $WS/tmp/experiment && slice down
Expect: both stop cleanly.
Phase 6: Inspection
6.1 Restart feature-one for inspection
$ cd $WS/local/feature-one && slice up
6.2 Check logs
$ cd $WS/local/feature-one && slice logs httpd 2>&1 | head -5
Assert:
- Output contains log lines from the python http server (e.g., "Serving HTTP on ..." or similar startup message)
- No error about missing log files
6.3 Check slice edit target
$ cd $WS/local/feature-one && slice config
Assert:
- Output contains the resolved configuration
- The
SLICE_STATE_DIRor equivalent path points to$WS/+state+/dev-alpha
6.4 Stop
$ cd $WS/local/feature-one && slice down
Phase 7: Cleanup
7.1 Detach feature-one
$ cd $WS/local/feature-one && slice detach
Expect: worktree is unbound from dev-alpha.
$ cd $WS/main && slice state ls
Assert:
dev-alphais not bound to any worktree
7.2 Remove tmp worktree with slice rm
$ cd $WS && slice rm tmp/experiment
Expect: worktree removed, branch deleted.
Assert:
$WS/tmp/experimentdirectory no longer exists
$ git -C $WS/+clone+ branch --list
Assert:
tmp/experimentbranch no longer existslocal/feature-onestill exists
7.3 Test slice gc (garbage collection)
Create two throwaway worktrees, leave them stopped, and gc.
$ cd $WS && slice tmp gc-test-1
$ cd $WS && slice tmp gc-test-2
$ test -d $WS/tmp/gc-test-1 && echo "found" || echo "missing"
$ test -d $WS/tmp/gc-test-2 && echo "found" || echo "missing"
Assert:
- Both output
found
$ cd $WS && slice gc
Expect: both tmp worktrees removed (neither is running).
$ test -d $WS/tmp/gc-test-1 && echo "found" || echo "missing"
$ test -d $WS/tmp/gc-test-2 && echo "found" || echo "missing"
Assert:
- Both output
missing
7.4 Remove states
$ cd $WS/main && slice state rm dev-alpha
$ cd $WS/main && slice state rm dev-beta
Expect: both removed without errors (neither is bound or running).
$ cd $WS/main && slice state ls
Assert:
- Only
template-cleanremains
7.5 Verify state directories are gone
$ test -d $WS/+state+/dev-alpha && echo "found" || echo "missing"
$ test -d $WS/+state+/dev-beta && echo "found" || echo "missing"
Assert:
- Both output
missing
7.6 Remove the local worktree
$ cd $WS && slice rm local/feature-one
Expect: prompts for confirmation (this is a local/ worktree). Confirm
yes.
Assert:
$WS/local/feature-onedirectory no longer exists
$ git -C $WS/+clone+ branch --list
Assert:
- Only
mainremains (all test branches cleaned up)
Phase 8: Teardown
8.1 Destroy the workspace
$ slice-test-fixture destroy $WS
Assert:
- Output confirms destruction
$WSdirectory no longer exists
Summary of Key Assertions
| Phase | What is tested | Key assertion |
|---|---|---|
| 0 | Fixture | Workspace is ready with template-clean state |
| 1 | State creation | New states created with distinct ports |
| 2 | Worktree creation | Directories and git branches created correctly |
| 3 | Bind + lifecycle | Processes start on correct ports, curl confirms httpd, clean shutdown |
| 4 | State swapping | Old worktree auto-stopped and unbound, new worktree uses same ports |
| 5 | Port isolation | Two slices run simultaneously on different ports |
| 6 | Inspection | Logs and config commands work against a running slice |
| 7 | Cleanup | rm, gc, detach, state rm all clean up completely |
| 8 | Teardown | Temp workspace removed, global state cleaned up |

