Report TaskPipeline stage results to the originating Slack thread

KN
2d ago
+17272-547

What type of PR is this?

/kind feature

What this PR does / why we need it:

Stacked on #1853 and #1854. Only the top commit is new; review that one.
This closes the loop from #1761: results from a Slack-started TaskPipeline go
back to the thread that started it.

  • Stage Tasks inherit Slack reporting. Each stage Task gets the pipeline's
    kelos.dev/slack-reporting label and the kelos.dev/slack-reporting,
    -channel, -thread-ts and -user-id annotations. #1854 sets these on
    pipelines it creates from Slack messages.
  • The reporter is unchanged. internal/reporting already reports any Task
    that carries these keys, so each stage that runs posts its acceptance,
    progress and result into the thread. Skipped stages create no Task and post
    nothing.
  • Routing reads well in the thread. The route stage's one-word answer acts
    as the acknowledgement, and the selected handler posts the real answer.
  • Only those keys are copied. Reporter state (slack-report-phase), the
    spawner label (which would double count activeTasks), and unrelated
    metadata stay on the pipeline.
  • New example. examples/19-slack-pipeline-router is a front door that
    classifies each Slack request and runs one of three handlers, or a NotIn
    fallback.

This is the third of three stacked PRs:

  1. #1853: conditional stages.
  2. #1854: TaskSpawner pipelineTemplate.
  3. This PR: Slack reporting for stage Tasks.

Which issue(s) this PR is related to:

Part of #1760. Depends on #1853 and #1854.

Special notes for your reviewer:

  • Every stage that runs posts to the thread. For two-stage routing that is
    the acknowledgement plus the answer. Longer pipelines will be noisier, and a
    per-stage way to opt out of reporting could follow if needed. I kept it out
    so the API stays minimal.
  • Why the keys are duplicated. The controller keeps its own copy of the
    four keys instead of importing internal/reporting, which would pull
    slack-go into the controller binary for the first time.
    TestPipelineSlackReportingKeysMatchReporter pins them to the reporter's
    constants so they can't drift.
  • GitHub reporting is not propagated. Pipeline spawners are Slack-only
    (#1854), and GitHub comment and check reporting needs its own thought about
    one comment or check per stage.

Testing:

  • make verify, make test, and make test-integration are clean
    (180/180 specs, plus 12/12 install specs).
  • New unit tests cover:
    • every stage Task, across a conditional branch, carries exactly the Slack
      keys and not reporter state, the spawner label, or unrelated annotations;
    • a pipeline without reporting yields stage Tasks with no annotations or
      reporting label;
    • the key constants match internal/reporting.
  • The example is validated by an integration dry-run spec.
  • Slack delivery itself isn't covered by e2e, which has no Slack workspace.

Does this PR introduce a user-facing change?

TaskPipeline stage Tasks inherit the pipeline's Slack reporting metadata, so a
pipeline started by a Slack TaskSpawner posts each stage's status and result to
the originating thread.

🤖 Generated with Claude Code


Summary by cubic

TaskPipeline stages started from a Slack message now report each stage's status and result back to the thread that started the pipeline.

Stage Tasks inherit the pipeline's Slack reporting label and annotations (slack-reporting, slack-channel, slack-thread-ts, slack-user-id), so any stage that runs posts to the thread exactly like a spawned Task. Skipped stages create no Task and post nothing, and the new example examples/19-slack-pipeline-router routes each request through a classification stage to one of several handlers.

  • Only those four keys are copied from the pipeline; reporter state and the spawner label stay behind.
  • The controller keeps its own key constants instead of importing internal/reporting, pinned by a test so they can't drift.
  • GitHub comment and check reporting is not propagated to stage Tasks.
  • Adds conditional stage support (In/NotIn conditions) and TaskSpawner.spec.pipelineTemplate, which the stacked PRs introduce and this one reports on.