Skip to content

fix(api): manifest parser drops max_restarts + dangerous_permissions#47

Merged
arcaven merged 1 commit intomainfrom
fix/manifest-dropped-fields
Apr 19, 2026
Merged

fix(api): manifest parser drops max_restarts + dangerous_permissions#47
arcaven merged 1 commit intomainfrom
fix/manifest-dropped-fields

Conversation

@arcaven
Copy link
Copy Markdown
Collaborator

@arcaven arcaven commented Apr 19, 2026

Summary

Closes two latent bugs that share a single root cause: ManifestRole is missing max_restarts and dangerous_permissions. Both fields exist on api.Role, the team controller honors MaxRestarts (PR #21), and the forestage adapter honors DangerousPermissions (PR #20) — but the parsers drop the values and Apply() never copies them, so they never reach runtime.

Changes

  • internal/api/manifest.go — add MaxRestarts int and DangerousPermissions bool to ManifestRole with matching toml + yaml tags. Copy both into the constructed Role in Apply().
  • internal/api/manifest_test.go — three new tests:
    • TestParseYAMLManifestDroppedFields — round-trip YAML with both fields set, verify on both ManifestRole and the applied api.Role
    • TestParseTOMLManifestDroppedFields — same shape for TOML
    • TestParseManifestDroppedFieldsDefaults — omitting both fields produces zero values (pins the documented contract)

Test plan

  • go test ./internal/api/... -run 'DroppedFields|DroppedFieldsDefaults'
  • go test -race ./...
  • golangci-lint run ./... — 0 issues
  • After merge + new alpha: manifest with max_restarts: 3 saturates at 3 restarts; manifest with dangerous_permissions: true produces exec: line containing --dangerously-skip-permissions on a forestage role

Why this slipped through

Both PR #20 and PR #21 added the fields to api.Role and the behavior code paths, along with unit tests that constructed api.Role directly. Neither PR touched ManifestRole or Apply(). The manifest parse path had no coverage for these specific fields, so the yaml/toml silent-drop was invisible to CI.

The ManifestRole / api.Role split deserves scrutiny in follow-up: a single struct with shared tags would make this class of drift impossible. Deliberately out of scope here — this PR is the point fix.

Closes #28
Closes #43

Both fields exist on api.Role with toml tags, the team controller
honors MaxRestarts (the crash-loop saturation cap from PR #21), and
the forestage adapter honors DangerousPermissions (PR #20). But
ManifestRole in internal/api/manifest.go never declared either
field, so yaml.v3 and BurntSushi/toml both silently dropped them
during parse, and Apply() never copied them onto the constructed
Role. Net effect:

- #28 — `max_restarts: 3` in a YAML manifest
  produced `Role.MaxRestarts = 0`, which means "unlimited" per the
  contract in types.go. The cap was permanently disabled on
  manifest-driven teams.
- #43 — `dangerous_permissions: true` produced
  `Role.DangerousPermissions = false`, so the forestage adapter
  never appended `--dangerously-skip-permissions`. Autonomous
  fleet-agent teams couldn't ship the flag from a manifest.

Adds both fields to ManifestRole with matching `toml` + `yaml`
struct tags, wires Apply() to copy them into Role, and adds
regression tests covering the round-trip in both manifest formats
plus a defaults test that pins the zero-valued behavior.

Refs #28
Refs #43
@arcaven arcaven added type.bug Broken behavior — something doesn't work as designed agent.worker PR created by a Claude Code worker agent area.runtime Adapter framework (forestage/claude/generic) area.controller Reconciler labels Apr 19, 2026
@arcaven arcaven merged commit 1d26f05 into main Apr 19, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent.worker PR created by a Claude Code worker agent area.controller Reconciler area.runtime Adapter framework (forestage/claude/generic) type.bug Broken behavior — something doesn't work as designed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

test: Role.DangerousPermissions surfaces as --dangerously-skip-permissions in forestage adapter max_restarts silently ignored in YAML manifests

1 participant