Skip to content

Deploy skill Phase 0 misreads CI-deployed solutions as never-deployed #46

@krisrowe

Description

@krisrowe

Problem

The gapp:deploy skill's Phase 0: Assess the Situation cannot
distinguish a CI-deployed solution from a never-deployed one,
and actively routes the agent toward a local setupdeploy on a
solution that is already live via CI/CD.

Phase 0 instructs the agent to assess using only two calls:

  • gapp_list
  • gapp_status

Neither reveals CI state. gapp_status is documented as "local, fast"
— it reads local machine state. For a solution that was deployed from
CI (or simply from a different machine), the local checkout never ran
gapp setup, so gapp_status returns:

{
  "initialized": true,
  "deployment": { "project": null, "pending": true, "services": [] },
  "next_step": { "action": "setup", "hint": "No GCP project attached..." }
}

This is indistinguishable from a solution that was never deployed.
The skill's own "Solution Lifecycle" table then maps that exact signal
("Initialized, no project" → next_step.action: setup) to "run
gapp setup <project-id>," and the deploy phase follows with
gapp deploy. Following the skill as written leads the agent to
attempt a fresh local setup + deploy against a solution that is
already CI-deployed and healthy.

A gapp_ci_status tool exists and is listed in the skill's MCP Tools
Reference table, but Phase 0 never instructs the agent to call it,
and nothing in the assessment flow cross-checks it. The one tool that
would disambiguate local-deployed from CI-deployed is omitted from the
one step whose entire job is disambiguation.

Impact

An agent assisting with "deploy the latest version" on a CI-deployed
solution will, by following the skill:

  1. Read gapp_status, see project: null / next_step: setup.
  2. Conclude the solution has never been deployed.
  3. Attempt gapp_setup (provisioning/binding infrastructure locally)
    and gapp_deploy (a local terraform/docker build path).

This diverges from how the solution actually ships (CI), can trip
infrastructure-mutation permission gates, and risks creating a second,
machine-local deploy path for a solution whose source of truth is the
CI pipeline. The correct action — gapp_ci_trigger — is never reached
because the assessment never establishes that CI is the deploy channel.

How it surfaced

While deploying a new version of an mcp-app solution, the agent
followed Phase 0 as written:

  • gapp_status reported project: null, pending: true,
    next_step.action: setup — local state had no project binding.
  • gapp_list(all_owners=True) showed the same solution already
    deployed
    to a project, contradicting gapp_status. This
    contradiction (status says "never deployed," list says "deployed
    here") is itself the tell, but the skill offers no guidance to
    resolve it and the lifecycle table sided with gapp_status.
  • The agent attempted gapp_setup (denied by an infra-mutation
    permission gate) and gapp_deploy (errored with a NoneType
    resolution failure because no project was bound locally).
  • Only after stepping outside the skill's prescribed Phase 0 and
    calling gapp_ci_status did the true state become clear:
    { "repo": "<ci-repo>", "workflow": true } — the solution is
    CI-wired. gapp_ci_trigger(ref=<tag>) then deployed successfully.

The CI deploy path worked perfectly once reached. The defect is
purely in the assessment guidance, which omits the CI check and
trusts a local-only signal as authoritative for global deploy state.

Proposed solution

Make CI state a first-class input to Phase 0 assessment, and teach the
skill to treat a gapp_status / gapp_list contradiction as a signal
rather than resolving it in favor of local state.

Specifically:

  1. Add gapp_ci_status to the Phase 0 assessment calls. Phase 0
    should call gapp_list, gapp_status, and gapp_ci_status (in
    parallel) before concluding anything about deploy state.

  2. Add a disambiguation rule. When gapp_status reports
    project: null / next_step: setup but gapp_list shows the
    solution already deployed to a project (or gapp_ci_status reports
    workflow: true), the solution is deployed elsewhere (CI or
    another machine), not un-deployed. The correct next action is to
    redeploy via the established channel — gapp_ci_trigger when CI is
    wired — not local setup + deploy.

  3. Update the Solution Lifecycle table so the "Initialized, no
    project" row notes that this local signal does not imply
    "never deployed" — it must be cross-checked against gapp_list
    and gapp_ci_status. Local state reflects the local machine only.

  4. Establish a CI-first preference in the redeploy guidance. When
    gapp_ci_status shows the solution is CI-wired, the skill should
    prefer gapp_ci_trigger for redeploys and treat local gapp_deploy
    as the fallback for non-CI solutions, rather than presenting local
    deploy as the default path.

Work breakdown

  • Add gapp_ci_status to the Phase 0 assessment step in
    skills/deploy/SKILL.md (call it alongside gapp_list and
    gapp_status).
  • Add an explicit disambiguation rule to Phase 0: a local
    project: null / next_step: setup signal combined with the
    solution appearing in gapp_list (or workflow: true from
    gapp_ci_status) means "deployed elsewhere," not "never
    deployed."
  • Update the Solution Lifecycle table's "Initialized, no project"
    row to flag that the local signal is not authoritative for global
    deploy state and must be cross-checked.
  • Add CI-first redeploy guidance: prefer gapp_ci_trigger when the
    solution is CI-wired; local gapp_deploy is the fallback for
    non-CI solutions.
  • If feasible, surface CI/deployed-elsewhere state directly in
    gapp_status output (e.g., a field indicating the solution is
    known-deployed in a project per labels even when local state has
    no binding), so the local-only signal is less misleading at the
    source. Track separately if it warrants its own issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions