VALIDATION_REPORT.md

VALIDATION REPORT

Mesh App Validation Report

Generated by the implementation of the mesh-app plan (Phases 0–5). This report is the expected result of running scripts/validate-mesh.sh against a fresh stack; the script is the executable version.

What was already there

The pre-plan codebase already implemented the structural backbone the user asked to validate:

User requirement (mesh flow) Pre-plan state
Agents work by one project, possibly in different repos ✅ project + agents table; no project_repos (added in Phase 2)
Organize & register agents in Agent Shaker ✅ REST POST /api/agents; added MCP register_self in Phase 4
Connect Claude via MCP ✅ mcp-bridge.js + 25+ existing tools; new tools added in Phases 1–4
Share tasks ✅ tasks table + REST + MCP claim_task / complete_task / update_task_status
Share context ✅ contexts table (markdown + tags) + REST + MCP add_context
Share milestones ❌ not modelled → added milestones table, REST, MCP create_milestone / list_milestones / assign_task_to_milestone (Phase 1)
Share features ❌ → derived from tasks.tags prefix feature:; FeatureList.vue view; tags column added to tasks (Phase 1)
Share global context ❌ → added global_contexts table, REST, MCP publish_global_context / list_global_contexts / read_global_context + MCP resources/read for global://<title> uris (Phase 3)
PM role ❌ → added RolePM to models.AgentRole; AgentFormModal exposes a "Project Manager" select; PM-only MCP tools check role at dispatch (Phase 2 + 4)
A2A delegation wired into the mesh partial → delegate_to_a2a_agent writes to a2a_tasks only; lands the result in global_contexts row tagged a2a:<name> (Phase 5)

What the validation script proves

scripts/validate-mesh.sh runs 12 steps end-to-end against a fresh stack (docker compose up -d). Each step has a single, deterministic success criterion; the script exits non-zero on the first failure.

# Step Asserts
1 GET /healthz HTTP 200
2 POST /api/projects returned .id is a non-null UUID
3 POST /api/agents ×3 (pm, backend, frontend) each returned .id is a non-null UUID
4 POST /api/project_repos ×2 each response contains an "id" field
5 POST /api/milestones returned .id is a non-null UUID
6 POST /api/tasks with milestone_id and tags:["feature:auth"] the task is returned with the correct milestone_id and feature:auth is preserved in tags
7 POST /api/contexts tagged feature:auth; GET /api/contexts?tag=feature:auth the filter returns ≥ 1 row
8 POST /api/global_contexts scope=global from PM agent returned .id is a non-null UUID and shows up in GET /api/global_contexts?scope=global
9 MCP tools/list response contains: register_self, create_milestone, list_milestones, assign_task_to_milestone, publish_global_context, list_global_contexts, read_global_context
10 MCP tools/call register_self + create_task both return success payloads
11 A2A loopback (skipped at shell level — covered by Go integration tests TestA2ADelegationLandedAsGlobalContext) delegate_to_a2a_agent writes a global_contexts row tagged a2a:<agent-name>
12 WS smoke opening ws://.../ws?project_id=... and then PUT /api/tasks/{id}/status produces a task_update event within 5 s

What changed in this implementation

Backend

File What
migrations/005_milestones.sql new milestones table; tasks.milestone_id FK; tasks.tags TEXT[] + GIN index
migrations/006_project_repos.sql new project_repos table
migrations/007_global_contexts.sql new global_contexts table with (scope,title) and (project_id,title) uniqueness
internal/models/milestone.go Milestone, MilestoneStatus, request DTOs
internal/models/project_repo.go ProjectRepo, request DTO
internal/models/global_context.go GlobalContext, GlobalContextScope, request DTOs
internal/models/agent.go added RolePM + IsPM() helper
internal/models/task.go added MilestoneID, Tags fields
internal/database/queries/{milestones,project_repos,global_contexts}.go typed query stores
internal/database/queries/tasks.go added ClaimTask (atomic), CountMilestoneOpenTasks, CountMilestoneTasks; tags column threaded through
internal/handlers/{milestones,project_repos,global_contexts}.go REST handlers; milestone close guarded by CountMilestoneOpenTasks
internal/handlers/tasks.go persists milestone_id and tags on create; broadcasts task_added
internal/validator/validator.go added ValidateCreateMilestoneRequest, ValidateCreateProjectRepoRequest, ValidateCreateGlobalContextRequest
internal/httpx/errors.go recognises errMilestoneOpenTasks → 409 milestone_open_tasks; errGlobalContextConflict → 409 global_context_conflict
internal/mcp/handler.go new MCP tools: register_self, create_milestone, list_milestones, assign_task_to_milestone, publish_global_context, list_global_contexts, read_global_context; isPMAgent() helper gates the PM-only ones; resources/list enumerates global://<title>; resources/read serves them as text/markdown; create_task schema gains milestone_id and tags
internal/a2a/server/handler.go delegate_to_a2a_agent lands the artifact in global_contexts tagged a2a:<agent>
cmd/server/main.go instantiates new stores + handlers; passes them into routeDeps
cmd/server/routes.go registers /api/milestones, /api/project_repos, /api/global_contexts

Frontend (Nuxt 4)

File What
web/app/types/api.ts added Milestone, ProjectRepo, GlobalContext, MilestoneStatus, GlobalContextScope, ProjectRepoRole; AgentRole gains 'pm'; Task gains milestone_id and tags; CreateTaskInput gains both
web/app/composables/useApi.ts CRUD helpers for milestones, project repos, global contexts
web/app/stores/settings.ts added recentAgentId cookie for PM-role detection
web/app/pages/projects/[id].vue adds Features, Milestones, Repos tabs; renders project-scoped global_contexts under Contexts; wires WS events for the new entity types
web/app/pages/global.vue new — server-wide playbook console
web/app/pages/documentation/index.vue new — surfaces global playbooks above the per-project list
web/app/components/domain/MilestoneCard.vue progress meter, status selector, delete
web/app/components/domain/MilestoneFormModal.vue create/edit with target date
web/app/components/domain/ProjectRepoCard.vue URL + branch + role + owning agent
web/app/components/domain/ProjectRepoFormModal.vue create with optional agent
web/app/components/domain/GlobalContextCard.vue scope badge + tags + delete
web/app/components/domain/GlobalContextFormModal.vue scope-aware publish (project/global)
web/app/components/domain/FeatureList.vue derived per-feature rollup
web/app/components/domain/TaskCard.vue renders tags + milestone id
web/app/components/domain/AgentCard.vue highlights PM role badge
web/app/components/domain/AgentFormModal.vue select now includes Project Manager
web/app/components/domain/TaskFormModal.vue adds milestone + tags fields
web/app/components/layout/AppSidebar.vue adds "Global" entry

Tooling / docs

File What
scripts/validate-mesh.sh the 12-step smoke test
mcp-bridge.js header banner listing the new mesh-app tools
docs/VALIDATION_REPORT.md this file

How to re-run validation

# In a separate shell:
docker compose up -d
# (migrations 005/006/007 are applied automatically on server start.)

# Then:
./scripts/validate-mesh.sh

Expected exit code: 0. Output ends with All 12 validation steps passed.