# Compose the control-plane store path with clone secrets + deploy history

**Found during** the w2/m8+m9 live acceptance (2026-07-12, mock cluster). Two halves of the platform don't compose:

1. **Store-managed apps can't build private repos.** The rows→CR projector (`lego/backend/internal/store/reconciler.go`, `projectSpec`) never mints an installation token / `spec.cloneSecret`, so an app created via the internal `POST /v1/apps` (control-plane path) from a private connected repo fails its build with `fatal: could not read Username for 'https://github.com'` — observed live (`bld-tea-…-hello-live-sm-gen-1` Failed). m9's clone-token seam lives only in the public create/redeploy/webhook verbs (`apps.Service.ensureCloneSecret`).
2. **Public-surface creates have no deploy history.** `POST /v1/services` / GraphQL `createService` / MCP `deploy` write the App CR directly (with the tenant label but no store app-id label), so they are not "store-managed" and w2/m5's deploys API returns `[]` for them; deploy rows only open for internal-API-created apps. The m9 live run evidenced revisions via CR status + build Jobs instead.

**Why it matters:** whichever path a service is born through, private-repo builds and deploy history should both work — today each path has one of the two.

**Possible shape:** either the projector asks the github service for a clone token when the row's repo matches the workspace connection (needs a github seam in the reconciler), or public creates go through the store when it's wired (making every app store-managed, which also fixes history). The second matches ADR003's "Postgres is the source of truth" direction.
