aboutsummaryrefslogtreecommitdiff
path: root/teams/deepsat/claude/rules/publishing.md
blob: c184c0898d1444e5deae1ad61584b6f2c367a5e1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# DeepSat Publishing Overlay

Applies to: `**/*` — but only present in the DeepSat work project. This file is **not** a global rule. It is copied into a single project's `.claude/rules/` via `make install-team TEAM=deepsat PROJECT=<path>` and loads only there. Its canonical source lives in `teams/deepsat/claude/rules/publishing.md` in the rulesets repo.

This overlay extends the publish flow in the global `commits.md` with DeepSat's ticket and chat integration. The global flow defines the universal skeleton (identity, attribution, commit format, the review-and-publish gate, verification); the seams in that flow say "if the project defines a publishing overlay, run its steps here." This is that overlay. A project without it commits, opens PRs, and reviews exactly as the global flow describes — just without the Linear and Slack steps below.

## Ticket system (Linear)

DeepSat tracks work in Linear. Tickets carry IDs like `SE-289`.

**PR title.** Append the ticket ID in parentheses to the conventional-commit subject: `refactor: remove dead if-count check in admin (SE-289)`. If there is no ticket, omit the parenthetical.

**PR body cross-link.** Include a `Linear: [<TICKET-ID>](<linear-url>)` line linking the PR to the ticket. If there is no ticket, state it explicitly (`Linear: n/a`) so reviewers know it was considered.

**Linear ticket bodies** (when you write or update a ticket) carry two sections, in order:

1. **Problem** — what's wrong, with enough detail that a teammate can recognize the same failure mode in their own work.
2. **Fix** — what changed (or what's proposed).

The causal "why" and the test verification belong in the PR, not the ticket. The ticket reader reaches the PR through the manual cross-link comment in the post-create step below, not through any automatic integration.

## Linear ticket state is manual (no GitHub-integration automation)

The Linear↔GitHub integration does **not** move ticket state for us. It never advances a ticket to Dev Review when a PR opens, and it never moves a merged ticket onward to PM Acceptance or Done — confirmed 2026-05-22, when two merged PRs (SE-286, SE-399, both chores) sat in Dev Review until moved to Done by hand. Treat every ticket-state transition as a manual step we own. Don't wait for the integration to catch up, because it won't.

## After `gh pr create` (ticket reconciliation)

Run these where the global PR-description subflow says to run the project's post-create overlay steps:

1. Post a comment on the linked Linear ticket with the PR URL (Linear MCP `save_comment`, or open the ticket manually if MCP is unavailable). This is the reliable PR↔ticket cross-link.
2. Move the Linear ticket to the **Dev Review** status (`save_issue` with `state="Dev Review"`, or the Linear UI). The ticket should not remain "In Progress" once a PR is open against it.

## After merge (ticket → PM Acceptance or Done)

When a PR merges, move its linked Linear ticket yourself (`save_issue`, or the Linear UI) — nothing does this automatically. The target state depends on whether the PM can review the work:

- **Bug or feature with functionality or UI the PM should review** → **PM Acceptance** (`save_issue` with `state="PM Acceptance"`). The merge is done, but the ticket isn't closed until the PM signs off on the behavior. The later PM Acceptance → Done move is the PM's call, not ours.
- **Chore, tests, or an infra change the PM can't meaningfully review** → **Done** (`state="Done"`) directly. There's nothing for the PM to accept.

The ticket's label is the quick signal (Bug/Feature vs Chore/Test/Infra), but the real test is whether there's user-facing behavior to approve. Do the move right after `gh pr merge` reports the merge, the same way the Dev Review move rides along with `gh pr create`. If a batch of PRs merged without their tickets following, reconcile them: list the merged PRs, pull each `SE-xxx` ID, and route each ticket to PM Acceptance or Done by the same test.

## GitHub Enterprise host

DeepSat's GitHub is `deepsat.ghe.com`, not `github.com`. Pass `--hostname deepsat.ghe.com` to `gh api` calls (the `gh pr` porcelain picks the host up from the remote, but raw `gh api` needs it explicit).

## Slack review notification

Run this where the global PR-review Shape 1 flow says to run the project's review-notification overlay step.

**Notify the PR author on Slack** (`APPROVE` or `REQUEST_CHANGES` verdicts only). After the review posts, send a one-line Slack message to the PR-review group DM `C0B1B0NH2N5` (the mpdm with Craig, Eric, Vrezh, Kostya — *not* `C0AM2MWHCJU`, which is a separate 3-person Craig/Vrezh/Kostya mpdm and is *not* an "#ai" channel despite older notes calling it that) via the `slack-deepsat` MCP. No `/voice personal` pass — the message is short and templated. Two cases:

- Approved: `<@author-slack-id> Approved PR #N.\n<pr-url>`
- Changes requested: `<@author-slack-id> Changes Requested PR #N\n<pr-url>`

Replace `#N` with the PR number and `<pr-url>` with the GHE URL of the PR. Always lead with an `<@author-slack-id>` mention so the engineer who owns the merge decision gets pinged — the message is useless without it. Resolve the Slack user ID via the slack-deepsat `users_search` tool using the PR author's name or email. The URL goes on its own line, immediately after the message. If the MCP doesn't have a post-message tool registered (for example, where the Slack MCP is read-only), surface that to the user and skip the post — don't fall back to a different channel or asking the user to paste it.

**MCP payload format.** The `mcp__slack-deepsat__conversations_add_message` tool's `payload` parameter is the **raw Slack mrkdwn message body**, not a Slack API JSON envelope. Pass the message body string directly:

```
payload: <@U09AUV4087N> Approved PR #171.
https://deepsat.ghe.com/deepsat/orchestration_dashboard_mvp/pull/171
```

Wrapping the body in `{"text": "..."}` posts the literal JSON object as the message — the `<@>` mention strips to plain text, escaped `\n` renders as the letter `n`, and the `text:` key prefix appears in the post. The engineer doesn't get pinged. Use real newlines in the string (a literal newline character), not the escape sequence. The MCP has no delete method, so a garbled post can only be removed manually from Slack — surface garble to the user immediately so they can clean it up before reposting.

Slack mrkdwn that the `payload` string supports: `<@USER_ID>` for user mentions, `<#CHANNEL_ID>` for channel refs, real newlines for line breaks, `*bold*`, `_italic_`, `` `code` `` and ``` ``` ``` blocks, and `<url|label>` for labeled links.

**Thread under the engineer's review-request post.** Before posting, scan the channel's recent history (`mcp__slack-deepsat__conversations_history`) for the engineer's original post containing the PR URL — typically a "New PR" message or just the PR link. Post the verdict notification with `thread_ts=<original-message-ts>` so it lands in the reply thread off that original. This keeps each PR's review state contained in one thread instead of fragmenting across top-level posts in a mixed feed. The same threading rule applies to both `APPROVE` and `REQUEST_CHANGES` verdicts.

**No review-request post found?** Don't auto-pick a fallback. Ask the user which they prefer:

- Post the verdict at the top level of the channel.
- DM the engineer directly.
- Don't post at all.

Skip Slack for `event=COMMENT` reviews (informal feedback, not a verdict) and for issue-thread comments and inline replies. Approve and request-changes are the only verdicts that warrant the notification.

## Merge practice

The team's practice is **approve-then-author-merges**, not approve-and-merge. The Slack notification above hands the merge decision to the PR author. Reviewing a PR never authorizes merging it; the global `Merge Strategy` rules apply only to merges you perform on your own branches, and each of those needs its own explicit user confirmation.