feat: Worker portal Stage 2 ADR — promote-PR mechanism

Description

Ratify the promote-PR mechanism as an ADR before any Stage 3 runtime code lands. This ADR defines the git-host integration surface, signing of generated PRs, rollback story, and the service/component that owns git-host API access. ADR-only — no runtime code.

The "promote live → baseline" mechanism converts a jurisdiction's live overrides into a real PR against the jurisdiction's TOML baseline. This is the most novel architectural commitment in Stage 3 and needs careful ratification.

Acceptance Criteria

  • docs/modules/ROOT/pages/adrs/adr-NNN-promote-pr-mechanism.adoc
  • ADR documents:
    • Git-host integration surface: where does git-host API access live? canopy-ops service (new), inline in canopy-web, or a dedicated canopy-promotion service — pick one with rationale
    • Supported git hosts: GitLab (primary), GitHub (later?), self-hosted Gitea (possibly)
    • PR generation contract: diff format, commit author identity, signing strategy
    • PR signing: GPG/EdDSA per project signing convention; how the service holds signing keys
    • Rollback story: if a promote produces a bad TOML, how does the jurisdiction recover?
    • Failure modes: git-host unreachable, auth expired, base branch moved, merge conflict
    • Secrets: where does the git-host PAT live? (See ADR-017 for encrypted-secrets pattern)
  • Antora nav updated
  • Cross-referenced from worker-portal-redesign.adoc Design section
  • cargo xtask check-docs clean

Open questions (resolve in ADR)

  • Service ownership: new canopy-ops/canopy-promotion service vs inline in canopy-web vs library used by canopy-web? (See #460 open question 1.)
  • PR signing identity: per-jurisdiction bot vs single canopy service identity?
  • Branch naming convention for generated PRs: studio-promote/{jurisdiction}/{date} or similar?

Context & References

  • Tracking issue: #460
  • Epic: &51
  • Plan: worker-portal-redesign.adoc, Stage 2
  • Blocks: Stage 3 promote-live-to-baseline child issue
  • Related: ADR-017 (encrypted secrets at rest), ADR-019 (service identity)

Labels

type::feature, priority::medium, program::infrastructure, service::web, workflow::ready