Skip to content

fix(services): accept --port 0, the worker shape deploy already supports - #195

Open
thegoodengineer wants to merge 1 commit into
InsForge:mainfrom
thegoodengineer:fix/services-add-worker-port
Open

fix(services): accept --port 0, the worker shape deploy already supports#195
thegoodengineer wants to merge 1 commit into
InsForge:mainfrom
thegoodengineer:fix/services-add-worker-port

Conversation

@thegoodengineer

@thegoodengineer thegoodengineer commented Sep 9, 2026

Copy link
Copy Markdown

Closes #163.

The problem

insta services add compute <name> --port 0 was rejected by client-side validation:

$ insta services add compute wk --port 0
error: port must be an integer between 1 and 65535, got: 0

Port 0 is not an out-of-range port here, it is a service shape: the worker shape, a long-running process with no HTTP endpoint (queue consumers, background agents), which the compute plane gives no PORT env and no ClusterIP. The platform accepts it and the deploy path already creates it:

$ insta deploy --image alpine:3.20 --port 0 --group wk --json
{ "machineId": "insta-compute", "url": "", ... }     # empty url = no HTTP endpoint, correct

So a worker could only be created by picking some other port at creation and letting the first deploy converge it to 0. The one command whose job is "create a service of this shape" was the one that could not express it.

The change

parsePort accepts 0, and names it in the error. The bound moves from n < 1 to n < 0, and the message becomes port must be 0 (worker: no HTTP endpoint) or an integer between 1 and 65535, got: <raw>. Naming 0 rather than silently widening the range keeps the message useful for a genuine typo, and teaches the shape at the point of error. Every other rejection is unchanged, including the non-decimal spellings Number() would have honoured: 0x1f90 and 0o17620 start with a 0 that the widened range must not swallow, and the decimal-digits-only regex still refuses them.

The two --port checks in servicesAdd / servicesAddRequestBody move from a truthiness test to a presence test. They happen to work today only because the option arrives as the string "0". A truthy test on a parsed value would drop the worker port and provision a default-port HTTP service instead of the shape that was asked for, which is exactly the failure mode --no-always-on already hit (an explicit value read as "not given"), and the mapping is the place that bug would land. The presence test also fixes a smaller thing in passing: --port 0 on a non-compute type now fails locally the way --port 3000 does, instead of slipping past the guard as "no port given".

Docs. services add --port help now names the worker shape, and so does the interactive port prompt, which is the only place the shape is discoverable without reading the reference.

compute connect-repo --port comes along, because it shares the parser. A repo-backed worker is the same shape as an image-backed one, so --port 0 there now overrides the detected HTTP port rather than being refused. Its help text says so, and there is a test.

Deliberately not in scope

insta build --port keeps its own validator, which still rejects 0. Widening it means deciding what the report's port check says for a worker (today a missing port is a fail with "a port mismatch is the #1 deploy mistake"), and build.test.ts asserts the current rejection under an explicit rationale: a verifier must not bless bad input. That is a separate change with its own report semantics, not a side effect of this one. Happy to follow up if you want it.

The issue also asks whether --port 0 at create should imply endpoint.mode=none. I left that alone: the platform already converges port: 0 to none on deploy, and I cannot verify a create-time field against the control plane from here. Sending an unverified extra key seemed worse than sending the port the platform already understands.

Testing

npm run typecheck && npm test: green (813 passing, 6 skipped), except for one pre-existing unrelated failure on my machine, github-source.test.ts > refuses a manifest that resolves outside the clone through a symlink, which fails identically on unmodified main here because creating a symlink on Windows needs Developer Mode or elevation (EPERM). CI's windows-latest runner is privileged, so it passes there.

Six new tests, all negative-controlled (each fails against the current parsePort, verified by stashing the source change and re-running):

  • parsePort accepts 0 and " 0 "
  • parsePort names 0 and the rejected value in the error
  • servicesAddRequestBody sends port: 0 rather than dropping it as falsy
  • servicesAdd rejects --port 0 on a non-compute type, before any config or network access
  • sourceBody (connect-repo) honours --port 0 over the detected port
  • resolveServiceArgs lets --port 0 through the pre-flight check and does not ask for the port again

Manually, against a dead API URL so the local validators are what answer:

$ insta services add postgres db --port 0
error: --port is only valid for compute services
$ insta services add compute wk --port 70000
error: port must be 0 (worker: no HTTP endpoint) or an integer between 1 and 65535, got: 70000
$ insta services add compute wk --port 0
error: agent mode requires a linked project ...     # clears validation, fails at project resolution

Follow-up outside this repo

Per CONTRIBUTING, insta/cli-reference.md in InsForge/insta-skills needs the same edit, since that file is how agents learn the CLI surface. I do not have a change set there; the wording that matches this PR is:

--port <n> compute only: port the image listens on (default 8080). 0 creates a worker: a long-running process with no HTTP endpoint, and no URL.

and, for compute connect-repo, 0 for a worker with no HTTP endpoint.


Summary by cubic

Allows --port 0 on service creation to express the worker shape (no HTTP endpoint), which the platform and insta deploy already supported. Previously, insta services add compute <name> --port 0 was rejected by validation, forcing workers to be created at another port and converged later.

  • parsePort now accepts 0 and names it in the error message.
  • --port checks in servicesAdd and servicesAddRequestBody now use presence instead of truthiness, so 0 is not dropped.
  • compute connect-repo --port 0 also works because it shares the parser.
  • Help text and interactive prompts mention the worker shape.
  • insta build --port is untouched: it has its own validator and a separate rationale.

Written for commit 2a16b05. Summary will update on new commits.

Review in cubic

`insta services add compute <name> --port 0` was rejected by client-side
validation, but port 0 is a first-class service shape rather than an invalid
port: the worker shape, a long-running process with no HTTP endpoint (queue
consumers, background agents), which the compute plane gives no PORT env and no
ClusterIP. The platform and `insta deploy --port 0` both accept it, so a worker
could only be created by picking some other port at creation and letting the
first deploy converge it to 0. The one command whose job is "create a service of
this shape" was the one that could not express it.

parsePort now accepts 0 and names it in the error, so a genuine typo still reads
as one rather than being reported as if 0 were merely out of range. Every other
rejection is unchanged, including the non-decimal spellings `Number()` would
have honoured: `0x1f90` and `0o17620` start with a 0 the widened range must not
swallow.

The two option checks in servicesAdd/servicesAddRequestBody move from a
truthiness test to a presence test. They happen to work today only because the
option arrives as the string "0"; a truthy test on the parsed value would drop
the worker port and provision a default-port HTTP service instead of the shape
that was asked for, which is the failure mode --no-always-on already hit. The
presence test also makes `--port 0` on a non-compute type fail locally, as
`--port 3000` does, instead of slipping through as "no port given".

parsePort is shared with `insta compute connect-repo --port`, so a repo-backed
worker is now expressible the same way; help text and the interactive port
prompt name the shape.

`insta build --port` is deliberately untouched: it has its own validator and an
explicit "a verifier must not bless bad input" test, and widening it means
deciding what its port check reports for a worker, which is a separate change.

Closes InsForge#163

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@agent-zhang-beihai

Copy link
Copy Markdown

Thanks for the PR, @thegoodengineer! This links #163, but that issue isn't assigned to anyone yet. Our workflow is claim the issue first, then submit the PR. It'll still be reviewed — to keep ownership clear, comment on the issue that you'd like it assigned to you.

@thegoodengineer

Copy link
Copy Markdown
Author

Understood, and sorry for getting the order wrong. I have commented on #163 asking for it to be assigned to me: #163 (comment)

Say the word if you would prefer I close this and reopen it once the issue is assigned.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 6 files

Re-trigger cubic

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.

services add rejects --port 0, the worker shape the plane and deploy both support

2 participants