Files
pad/internal
xarmian ad87b960d7 refactor(bootstrap): slim Roles projection (BootstrapRole struct) (TASK-1423) (#542)
Same drop-pattern as TASK-1412's BootstrapCollection applied to the
bootstrap response's `roles` section.

## Struct + helper

New BootstrapRole struct purpose-built for the bootstrap response:

  - Keeps: slug, name, description, icon, sort_order, item_count
  - Drops: id, workspace_id, tools, created_at, updated_at

The `tools` field has no consumer outside the store CRUD
(grep confirms — only referenced in internal/store/agent_roles.go);
docapp has it set to "" on all three roles in practice. If it ever
becomes load-bearing for the agent, it can be added back.

New projectBootstrapRole(models.AgentRole) helper mirrors
projectBootstrapCollection.

## BuildAgentBootstrap reorder

Roles projection now happens AFTER the role-count recompute for
restricted callers (which keys lookups by AgentRole.ID, which the
projection drops). Same reorder pattern as TASK-1412's collections
refactor — the local `roles` slice stays in models.AgentRole shape
through the count recompute, then projects in a final pass alongside
the collections projection.

## Tests

New TestBootstrapRoleProjection seeds one role via the agent-roles
endpoint and verifies the wire shape:

  - Positive: slug/name/description/item_count are present and correct.
  - Negative: id/workspace_id/tools/created_at/updated_at are NOT
    present in the marshalled JSON.

The negative check is the load-bearing part — without it, a future
refactor that "fixes" the projection by re-adding a UUID would pass
the positive assertions silently. Mirrors
TestBootstrapEmptyArraysNotNull's pattern for the recent_activity dedup.

Existing TestBootstrapEmptyWorkspace and TestBootstrapEmptyArraysNotNull
still pass — their `b.Roles != nil` and `roles != null` checks work
at slice-level regardless of element type.

## Measurements

Fixture (TestBootstrapSizeBudget) unchanged at 7,823 bytes — the
fixture seeds 0 roles so the projection change doesn't affect the
size budget (roles section was already at 2 bytes "[]").

Live docapp measurement deferred until make install — expected
savings: roles section was 1,066 bytes for 3 roles; drop is
~30-40% (~350 b) of that section.

## Out of scope

- Schema label + sort_order trim — TASK-1424.
- ToolSurfaceVersion 0.3 → 0.4 — TASK-1418 (final PR).

Parent: PLAN-1410.
2026-05-13 17:22:18 -04:00
..
2026-03-26 01:52:36 +00:00