interlock.sh docs

Verify a host #

Raw markdown: /verify.md

For humans #

Run this on a first setup, a fresh clone, a new machine, or after somebody changed the deploy. Skip it as a daily ritual. It does not replace your own tests.

Do this #

  1. Start at step 1, the CLI can see your project.
  2. Work down. Eight commands, in order.
  3. Stop at the first red result and read the page that step names.

The order matters #

The two that pay for the page #

If a step fails #

For robots #

The commands that prove a host is wired correctly, in order. Run them top to bottom. Each one checks a single thing and tells you which page explains the failure.

Do not skip ahead. Every step assumes the ones above it passed, and a failure three steps down is usually a failure one step up that nobody checked.

1. The CLI can see your project #

interlock whoami

Prints the account, the project and the server the CLI is pointed at. If the project is not the one you expect, you are about to sync into somebody else's tree. Stop and read Operating a project.

Confirm the key file is where you think it is:

ls -la .interlock-key && head -c 8 .interlock-key && echo

Never print more than the first 8 characters. The whole file is a credential.

2. The tree and the server agree #

interlock sync code --dry

A dry run lists what WOULD change and touches nothing. On a clean tree it should report no changes. If it proposes deleting every unit you have, the CLI is authenticated against a different project. That is the failure described in Operating a project.

3. No unresolved conflicts #

find code -name '*.conflict-server'

Empty output, or you have unresolved conflicts. Resolve them deliberately with --ours <id> or --theirs <id>. If you are an agent: do not resolve these on the human's behalf without being asked.

4. Every Java unit compiles against the PACKAGED application #

This is the two-second gate, and it is the highest-value check on the page. It compiles every unit against the real packaged classpath, transformed jar first, before anything boots.

./scripts/check-units-compile.sh

The script is on the Testing page, ready to copy. Run it in CI and as a pre-commit hook.

Failures here are almost always the entity rule:

error: status has protected access in Presence

That means the entity has no hand-written accessor. Presence is the entity of the real host application this was measured on (Team Lakes); yours will name your own class. See the entity rule.

5. Package the host and boot it #

./gradlew build -x test

Package before checking anything entity-related. quarkusDev transforms bytecode in memory and writes no jar, so a unit that touches an entity behaves differently there. The SDK logs a one-time boot WARN saying so. See Quarkus.

6. A unit actually runs #

interlock run <unit-id>

Runs it server-side and streams the logs back. If the unit has no handler you get the library-unit refusal, which is correct behaviour for a library and explained on The model.

7. Assert an EFFECT, not a status code #

The single most valuable test you can write against a host. A 200 proves the request was accepted, not that it did anything:

curl -s -X POST "$HOST/app/reminders/mute" -H 'content-type: application/json' -d '{"minutes":30}'
curl -s "$HOST/app/reminders/state" | grep -q '"muted":true' && echo OK || echo FAILED

The second line is the test. The first one passed even when req.str() ignored request bodies entirely, which is exactly how that bug survived. See Testing.

8. Refusals answer with a status #

curl -s -o /dev/null -w '%{http_code}\n' -X POST "$HOST/app/reminders/touch"

A unit that can only answer 200 turns every "no" into an apparent success. A refusal should come back as its real status with {"ok":false,"reason":...}. See Refusal.

If something failed #

Go to the Failure catalogue and search for your literal error text. Every entry is symptom first.