Skip to content

Phase 3 artifact relocation silently no-ops and falsely reports success when plugin already has .cpa-workflow-artifacts #103

Description

@kunjpatel-canvas

Summary

/cpa:new-plugin Phase 3 Step 1 relocates .cpa-workflow-artifacts from the workspace into the plugin directory. Two defects:

  1. The mv fails whenever the destination already exists and is non-empty — which is the normal state for any plugin that has been worked on across more than one session.
  2. The echo is not chained to the mv, so it prints "Moved .cpa-workflow-artifacts into plugin directory" unconditionally, including when nothing moved.

Net effect: the relocation silently no-ops and reports success. Artifacts then accumulate at the workspace root indefinitely.

Related: #40 (closed) covered the earlier "created one level too high" symptom in this same area. This is a different failure mode in the relocation step itself.

Current code

commands/new-plugin.md:291

if [ -d "$CPA_WORKSPACE_DIR/.cpa-workflow-artifacts" ]; then
  mv "$CPA_WORKSPACE_DIR/.cpa-workflow-artifacts" "$CPA_PLUGIN_DIR/"
  echo "Moved .cpa-workflow-artifacts into plugin directory"
fi

Reproduction

mkdir -p /tmp/mvtest/ws/.cpa-workflow-artifacts /tmp/mvtest/plugin/.cpa-workflow-artifacts
touch /tmp/mvtest/ws/.cpa-workflow-artifacts/spec.md
touch /tmp/mvtest/plugin/.cpa-workflow-artifacts/costs.json
mv /tmp/mvtest/ws/.cpa-workflow-artifacts /tmp/mvtest/plugin/ ; echo "exit=$?"
mv: rename /tmp/mvtest/ws/.cpa-workflow-artifacts to
    /tmp/mvtest/plugin/.cpa-workflow-artifacts: Directory not empty
exit=1

mv will not merge into an existing non-empty directory. Because echo is a separate statement rather than mv ... && echo ..., the success message still prints.

Why it recurs

The CPA_RUNNING=1 SessionEnd hooks write cost and user-input logs to $CPA_WORKSPACE_DIR/.cpa-workflow-artifacts/ on every /exit. So the workspace-root directory is recreated after each session, and any plugin that already holds its own copy will collide on the next Phase 3 run. It is not a one-time cleanup.

Observed state in a workspace with one plugin and three sessions — both copies present, both committed:

canvas-plugins/.cpa-workflow-artifacts/{costs,user_inputs}/...
canvas-plugins/portal-patient-documents/.cpa-workflow-artifacts/{costs,user_inputs}/...

Impact

Low severity — nothing is lost and the phase continues. But:

  • The success message is misleading when diagnosing artifact layout.
  • Session exhaust accumulates at the workspace root rather than being consolidated per plugin.
  • user_inputs/*.json contains verbatim user prompts. If the workspace root has no .gitignore (there is no root ignore file after canvas init, which only writes one inside the plugin container), a git add -A at the root will commit them. On a public repo that publishes prompt history.

Suggested fix

Merge rather than rename, and gate the message on the actual outcome:

if [ -d "$CPA_WORKSPACE_DIR/.cpa-workflow-artifacts" ]; then
  mkdir -p "$CPA_PLUGIN_DIR/.cpa-workflow-artifacts"
  if cp -R "$CPA_WORKSPACE_DIR/.cpa-workflow-artifacts/." \
           "$CPA_PLUGIN_DIR/.cpa-workflow-artifacts/" \
     && rm -rf "$CPA_WORKSPACE_DIR/.cpa-workflow-artifacts"; then
    echo "Moved .cpa-workflow-artifacts into plugin directory"
  else
    echo "WARNING: could not relocate .cpa-workflow-artifacts" >&2
  fi
fi

Related consideration

Worth having canvas init (Phase 2 Step 5) write a workspace-root .gitignore alongside the per-plugin one, covering the session exhaust:

**/.cpa-workflow-artifacts/costs/
**/.cpa-workflow-artifacts/user_inputs/
**/.cpa-workflow-artifacts/costs_aggregation.json
**/.cpa-workflow-artifacts/user_inputs_aggregation.json
instance-config-*.md

Note the **/ prefix is required — a pattern with an internal slash is anchored to the repo root and will not match the copy inside the plugin container. plugin-spec.md and wrap-up-report-*.md should stay tracked. instance-config-*.md is included because /cpa:analyze-instance writes its report to the cwd (skills/instance-analyze/SKILL.md:190) and that report describes a live instance's roles, teams, note types, and installed plugins.

Environment

  • cpa plugin 1.29.0
  • macOS (Darwin 25.5.0), BSD mv

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions