Public: anyone can read this; the crew can change it.

Spawn plan: what a child forge is made of, as one validated value (apps, crew briefs, subscriptions; never secrets) #430

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

This adds `src/spawn/plan.ts`, a pure module that turns a spawn request into one validated plan or the first refusal. The 6 new tests pass. I couldn't run `bun x tsc --noEmit` here because the `bun` type definitions aren't installed in this clone, so type-checking is unconfirmed. The forge's own check runs it on this push.

shipped production is serving it deploy 7cfd21c

opened this

This adds src/spawn/plan.ts, a pure module that turns a spawn request into one validated plan or the first refusal. The 6 new tests pass. I couldn't run bun x tsc --noEmit here because the bun type definitions aren't installed in this clone, so type-checking is unconfirmed. The forge's own check runs it on this push.

  • planSpawn(input, source) returns Result<SpawnPlan, Refusal>.

- source is what the caller found for the viewer: a catalog of apps with ref, readable and size in bytes, plus the parent's crew briefs and subscription names. - A name or org outside a-z, 0-9 and - is refused, as is an owner/name reference in the wrong shape. - An app that is unknown, unreadable or listed twice is refused with the reason. - Lists over the caps are refused: 50 apps, 100 briefs, 200 subscriptions, 20,000 characters per brief.

  • Copying: the plan copies only the fields it names:

- Each app is carried with full history and its forge.json. - Briefs are carried as agent plus text, with no run history. - Subscriptions are carried as names only. - Extra fields on any input object, such as tokens, SSH keys or env, never reach the plan.

  • dryRun(plan, source) gives the studio what is copied, what is left behind (secrets, tokens, SSH keys, agent credentials, run ledger, issues, user accounts) and the total bytes.
  • Determinism: every list is sorted and nothing reads a clock, so the same input gives the same plan.
  • Tests are in test/spawn-plan.test.ts and are added to the forge.json check list. They cover:

- a catalog full of planted secrets yields a plan and dry run containing none of them; - input order does not change the plan; - opting out of briefs and subscriptions carries nothing; - each kind of refusal returns the right field and reason; - the dry-run contents and byte total.

Not done:

  • Nothing builds the catalog from the database or git, and no route, studio view or actual spawn exists yet; this is the value that work will consume.
  • Total bytes is the sum of the app sizes the caller supplies, plus brief and subscription text. forge.json is counted inside the repository size, not separately.

Try it: bun test test/spawn-plan.test.ts

🤖 Generated with Claude Code

Closes #420

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs