Test Spec: Status and Detection

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 6. For each step:

  1. Run the command shown in the code block.
  2. Read the output.
  3. Check every Assert listed for that step.
  4. Record the result: PASS or FAIL with the actual output.
  5. 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

slice status is the canonical inspection command, but it also serves as the detection mechanism for scripts and agents: "am I in a thinslice workspace, and if so, where exactly?" That makes its failure modes — not in a git repo at all, in a git repo that hasn't been slice setup-ed — as important as its happy path.

This test verifies all six location states a caller can find itself in, both through the human-readable output and through the --json shape that scripts consume. Exit codes are tested separately from output because shell callers branch on them without parsing prose.

The six location states are:

StateExitNotes
Not in a git repository2No git ancestor at all
Git repo, but no +clone+ ancestor1Slice setup hasn't run
Slice workspace root0At the workspace root (sibling of +clone+/)
Slice worktree, unbound0In a worktree with no state binding
Slice worktree, bound, stopped0Bound but processes not running
Slice worktree, bound, running0Bound and processes up

Prerequisites

The slice binary and the slice-test-fixture helper must be on $PATH. Python 3 must be available (for the bound+running test). 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

This test uses two helpers from slice-test-fixture:

  • init-repo — creates a vanilla git repo (no slice setup run). Used for the "git-repo-but-not-slice" failure case.
  • workspace — creates a fully-initialized slice workspace. Used for all the happy-path location states.

Both helpers print the absolute path on stdout. destroy <path> cleans up.

Notation

  • $WS — absolute path to the slice workspace
  • $REPO — absolute path to the vanilla (non-slice) git repo
  • Lines starting with $ inside code blocks are commands to run

Phase 0: Set up fixtures

We need two starting points: a vanilla git repo (for the "git but not slice" failure case) and a fully-set-up slice workspace (for all happy paths).

0.1 Vanilla git repo

$ slice-test-fixture init-repo

Capture the output as $REPO.

$ git -C $REPO rev-parse --is-inside-work-tree

Assert: Output is true — a real git repo exists.

$ test -d $REPO/+clone+ && echo "found" || echo "missing"

Assert: Output is missingslice setup has not been run.

0.2 Slice workspace

$ slice-test-fixture workspace

Capture the output as $WS.

$ test -d $WS/+clone+ && echo "found" || echo "missing"

Assert: Output is found — workspace is set up.


Phase 1: Failure mode — not in a git repository

Run from a directory with no git ancestor. The command should report a clear reason, exit with code 2, and produce valid JSON in --json mode.

1.1 Human output

$ cd / && slice status; echo "exit=$?"

Assert:

  • Output is slice: not in a git repository
  • Exit code is 2

1.2 JSON output

$ cd / && slice status --json

Assert: Output is valid JSON with:

  • thinslice_managed: false
  • reason: "not in a git repository"
  • cwd: "/"
  • No git_common_dir field
$ cd / && slice status --json; echo "exit=$?"

Assert: Exit code is 2 — same as human mode.


Phase 2: Failure mode — git repo, but not slice-managed

Run from $REPO, which is a git repo but has no +clone+ ancestor. The command should distinguish this from "not a git repo" with a different reason and a different exit code.

2.1 Human output

$ cd $REPO && slice status; echo "exit=$?"

Assert:

  • Output is slice: git repository found, but no +clone+ directory — run slice setup to convert it
  • Exit code is 1

2.2 JSON output

$ cd $REPO && slice status --json

Assert: Output is valid JSON with:

  • thinslice_managed: false
  • reason matches the human message exactly
  • cwd equals $REPO
  • git_common_dir is present and points to $REPO/.git

2.3 Same behavior in a subdirectory

$ mkdir -p $REPO/subdir && cd $REPO/subdir && slice status; echo "exit=$?"

Assert:

  • Same reason and exit code as Phase 2.1 — the detection walks up to find the git common dir, so depth inside the repo doesn't matter.

Phase 3: Happy path — workspace root

Run from $WS itself (the workspace root, sibling of +clone+/). The command should report location: workspace root and list all worktrees.

3.1 Human output

$ cd $WS && slice status; echo "exit=$?"

Assert:

  • First line: location: workspace root ($WS)
  • Blank line follows
  • Each worktree listed with leading two-character marker ( for not-current)
  • main worktree is listed and shows unbound and
  • No worktree is marked with * (no current worktree at root)
  • Exit code is 0

3.2 JSON output

$ cd $WS && slice status --json

Assert: Output is valid JSON with:

  • thinslice_managed: true
  • workspace.root equals $WS
  • workspace.clone equals $WS/+clone+
  • workspace.state equals $WS/+state+
  • current.location equals "root"
  • current.path is null
  • current.rel is null
  • current.namespace is null
  • current.binding is null
  • worktrees is a list containing at least one entry for main
  • Every entry has current: false

Phase 4: Happy path — worktree, unbound

Run from $WS/main. The worktree exists but isn't bound to any state.

4.1 Human output

$ cd $WS/main && slice status; echo "exit=$?"

Assert:

  • First line: location: worktree main
  • The main entry is marked with * (current worktree)
  • State shown as unbound, status shown as
  • Exit code is 0

4.2 JSON output

$ cd $WS/main && slice status --json

Assert:

  • current.location equals "worktree"
  • current.path equals $WS/main
  • current.rel equals "main"
  • current.namespace equals "main" (the first path segment; main is its own segment since the worktree path is flat, not local/... or tmp/...)
  • current.binding.bound is false
  • current.binding.state is null
  • current.binding.processes is null
  • In worktrees, the entry for main has current: true

Phase 5: Happy path — worktree, bound and running

Bind a worktree to a state and start processes. slice status should report the binding, the state name, the running status, and port allocations.

5.1 Set up the binding

$ cd $WS/main && slice state new dev-alpha --from template-clean
$ cd $WS && slice local feature-status
$ cd $WS/local/feature-status && slice use dev-alpha
$ cd $WS/local/feature-status && slice up

Expect: Each step succeeds. Processes start.

5.2 Human output, bound + running

$ cd $WS/local/feature-status && slice status; echo "exit=$?"

Assert:

  • First line: location: worktree local/feature-status
  • The local/feature-status entry is marked with *
  • State shown as dev-alpha, status shown as running
  • A port list appears in brackets, e.g. [httpd:NNNN]
  • The main entry still appears, unmarked, with unbound and
  • Exit code is 0

5.3 JSON output, bound + running

$ cd $WS/local/feature-status && slice status --json

Capture the port value shown for httpd as $HTTPD_PORT.

Assert:

  • current.location equals "worktree"
  • current.rel equals "local/feature-status"
  • current.namespace equals "local"
  • current.binding.bound is true
  • current.binding.state equals "dev-alpha"
  • current.binding.processes equals "running"
  • The local/feature-status entry in worktrees has current: true, state: "dev-alpha", status: "running", and a non-null ports string

5.4 Stop, then check status again

$ cd $WS/local/feature-status && slice down
$ cd $WS/local/feature-status && slice status; echo "exit=$?"

Assert:

  • State still shown as dev-alpha (binding preserved)
  • Status now shown as stopped
  • Exit code is 0

5.5 JSON output, bound + stopped

$ cd $WS/local/feature-status && slice status --json

Assert:

  • current.binding.bound is true
  • current.binding.state equals "dev-alpha"
  • current.binding.processes equals "stopped"

Phase 6: Teardown

$ cd $WS/local/feature-status && slice detach
$ cd $WS && slice rm local/feature-status
$ cd $WS/main && slice state rm dev-alpha
$ slice-test-fixture destroy $WS
$ slice-test-fixture destroy $REPO

Assert:

  • Each step succeeds.
  • $WS and $REPO directories no longer exist.

Summary of Key Assertions

PhaseWhat is testedKey assertion
0FixturesVanilla git repo and slice workspace both available
1Not a git repoExit 2, reason not in a git repository, JSON shape
2Git repo, not sliceExit 1, reason mentions +clone+, JSON includes git_common_dir
3Workspace rootExit 0, location: workspace root, no current marker
4Worktree, unboundExit 0, * marks current, binding.bound: false
5Worktree, bound + runningExit 0, port list shown, binding.processes: "running"
6TeardownAll fixtures cleaned up