Skip to content

ci(issue-welcome): apply needs-triage label instead of welcome comment#73

Merged
lml2468 merged 1 commit into
mainfrom
ci/issue-welcome-needs-triage
Jun 9, 2026
Merged

ci(issue-welcome): apply needs-triage label instead of welcome comment#73
lml2468 merged 1 commit into
mainfrom
ci/issue-welcome-needs-triage

Conversation

@lml2468

@lml2468 lml2468 commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Replaces the hardcoded bilingual bug/feature welcome copy with a single deterministic action: apply a needs-triage label (auto-created if missing).

Why: greeting + content classification + triage commentary are owned by the dedicated triage agent (octo-issue-notify webhook mode). The in-workflow copy matrix duplicated that. Now the workflow does only the deterministic, always-on part (label); the agent does the smart part.

  • Bot-opened issues skipped; idempotent (GitHub de-dupes labels).
  • needs-triage auto-created if missing (handles label-not-found + concurrent races).
  • Least-privilege unchanged (issues: write). Filename + workflow_call interface unchanged → no caller migration needed.

Replace the hardcoded bilingual bug/feature welcome copy with a single
deterministic action: apply a `needs-triage` label (auto-created if missing).
Greeting, content classification, and triage commentary are owned by the
dedicated triage agent (octo-issue-notify webhook mode), so the in-workflow copy
matrix was redundant. Bot issues skipped; idempotent; least-privilege unchanged
(issues: write). Filename/interface unchanged — no caller migration needed.
@lml2468 lml2468 requested a review from a team as a code owner June 9, 2026 10:16
@lml2468

lml2468 commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

齐静春 📖 review — verdict: APPROVED

Posted via lml2468 token (self APPROVE on own-author PR is blocked — verdict in body).

In-place rewrite of the issue-welcome reusable workflow: from "post bilingual bug/feature welcome comment with hardcoded copy" to "apply a needs-triage label (auto-create if missing)". -103/+39 single file.

Verified against head 6739f881df6c:

🟢 Caller-migration-free claim is correct. Diff shows on: workflow_call: unchanged with no inputs/outputs schema added, filename unchanged, so all the existing callers I can grep (octo-web, octo-server, octo-cli, octo-adapters, octo-admin, octo-deployment, octo-matter, octo-smart-summary, octo-lib, openclaw-channel-octo, octo-speech, octo-android, octo-ios, octo-fleet, octo-daemon-cli, octo-version-sync, octo-smoke, cc-channel-octo, claw-channel-octo — 19 callers, matches the PR description's "no caller migration needed") will continue to call the same uses: line and just observe the new behavior. Nice clean upgrade path.

🟢 Separation-of-concerns is the right axis. Greeting + classification + triage commentary are LLM-suited and live in the dedicated triage agent (octo-issue-notify webhook mode). Workflow keeps only the deterministic, always-on, no-LLM part. This kills the duplication the old code had — the hardcoded bug/feature copy matrix and the triage agent's smart classification were two answers to "what is this issue". Now there is one answer.

🟢 Permissions stay least-privilege. Workflow-level permissions: {} + job-scoped permissions: issues: write. Same shape as the retired pr-contributor-welcome variant (community #12 / octo-daemon-cli #32 / octo-version-sync #24).

🟢 Label-not-found + race handling is correct.

  • getLabel → catch err.status === 404createLabel. Other errors re-throw (correct — 5xx / 403 / network drop should fail loudly, not silently fall through to addLabels where the symptom is more confusing to debug).
  • createLabel failure → swallowed as core.debug (correct — the only realistic non-404 failure here is "another concurrent run already created the label", which is the race the comment names. addLabels is idempotent and will succeed regardless).
  • addLabels runs last and is GitHub-de-duped (idempotent for re-runs).

🟢 Bot-skip guard is hardened. if (issue.user && issue.user.type === 'Bot') correctly handles the ghost/deleted-user case where issue.user may be null (the original PR contributor variant had the same pattern, good carry-over).

🟡 Non-blocking nit: docs/cicd-state-snapshot.md still describes issue-welcome.yml by its old behavior. Snapshot docs are point-in-time so this isn't a blocker for this PR — but worth a follow-up doc refresh that updates both the issue-welcome.yml row and removes the residual reusable-pr-contributor-welcome.yml row (the latter was a known leftover from PR #72 which I'd already flagged as non-blocking). One small chore that closes both loops at once.

LGTM — ship it.

— 齐静春 📖

@mochashanyao mochashanyao left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Octo-Q · automated review]

Verdict: Approve — no blocking findings; notes below (data-flow traced).


Review Report: .github PR#73 — ci(issue-welcome): apply needs-triage label instead of welcome comment

Reviewer: Octo-Q (automated review)
PR: #73
Head SHA: 6739f88
Scope: 1 file changed (+39 / −103), .github/workflows/issue-welcome.yml


1. Verification Summary

Item Status Evidence
workflow_call interface unchanged No inputs/secrets added or removed; on: workflow_call: identical
Caller compatibility (19 repos) All callers use uses: …/issue-welcome.yml@v1 with no inputs; internal job rename welcome→label is invisible to callers
Permissions least-privilege permissions: {} at top level, issues: write at job level — unchanged from base
Bot guard preserved issue.user && issue.user.type === 'Bot' check retained (line 40–42 of new file)
Ghost-user guard preserved Comment + null-check on issue.user retained
Idempotency addLabels is idempotent (GitHub de-dupes); label auto-created if missing with race-condition tolerance
Concurrency group Renamed welcome→needs-triage with same ${{ github.event.issue.number }} key; cancel-in-progress: false unchanged
actions/github-script pinned SHA 3a2844b7e9c422d3c10d287c895573f7108da1b3 (v9.0.0) — unchanged from base
Error handling correctness getLabel 404 → create; non-404 re-thrown; createLabel swallows races; addLabels failure propagates and fails the step

2. Findings

No P0 or P1 findings.

P2 — createLabel error swallowing is broader than documented

Location: Lines 55–58 of the new file (inner catch (e) block).

} catch (e) {
  // Another concurrent run may have created it; ignore races.
  core.debug(`createLabel race/err: ${e.message}`);
}

Diff-scope: New code introduced by this PR.

Analysis: The comment says "ignore races" but the catch swallows all errors from createLabel, not just 409/race conditions. If createLabel fails for a non-race reason (e.g., token lacks repo:scope in a future permission change, or the repo has label creation disabled), the error is silently logged at debug level and execution continues to addLabels, which will then fail with a 422 "Label does not exist" error. The net behavior is still correct (the step fails), but the root cause in logs will point to addLabels rather than the actual createLabel failure.

Severity: P2 (maintainability / debuggability). No user-visible incorrect behavior — the workflow step still fails, just with a less precise error message.

Suggestion: Narrow the inner catch to also check e.status === 409 (or at least log at core.warning for non-409 statuses) so that unexpected failures surface clearly:

} catch (e) {
  if (e.status === 409) {
    core.debug(`createLabel race (concurrent run): ${e.message}`);
  } else {
    core.warning(`createLabel unexpected error: ${e.status} ${e.message}`);
  }
}

P2 — Orphaned marker comments on existing issues

Diff-scope: Pre-existing data; PR removes the code that writes the marker but does not address cleanup.

Analysis: The old workflow embedded <!-- octo-issue-welcome:v1 --> in welcome comments on previously-triaged issues. After this PR merges, those markers become orphaned HTML in historical comments — invisible to users (rendered as HTML comments) and harmless. No action required, but noting for completeness.

Severity: P2 (informational). No functional impact.

3. Data Flow Trace

Consumed Data Source Flows Correctly?
context.payload.issue GitHub Actions event context (issues: opened) ✅ — guard at top with core.setFailed if undefined
issue.user.type GitHub API issue object ✅ — null-guarded with issue.user &&
context.repo.owner / context.repo.repo GitHub Actions context ✅ — standard, unchanged from base
issue.number GitHub API issue object ✅ — used in concurrency group and addLabels call
LABEL constant ('needs-triage') Hardcoded in script ✅ — deterministic, no upstream dependency
getLabel response GitHub REST API ✅ — only used for existence check; 404 triggers create path
createLabel result GitHub REST API ✅ — result not consumed; side-effect only; errors handled
addLabels result GitHub REST API ✅ — terminal call; failure propagates to step status

4. Security Review

  • Token scope: issues: write is the minimum required for label operations. ✅
  • No secret exfiltration: No outbound HTTP calls, no data egress. ✅
  • Supply chain: actions/github-script pinned to full SHA (3a2844b…). ✅
  • No user-controlled input in shell commands: All logic runs in github-script sandbox. ✅
  • GITHUB_TOKEN auto-injected: Standard Actions token, scoped to the calling repo. ✅

5. Additional Observations

  • v1 tag update: After merge, the v1 tag must be moved to the new commit for callers to pick up the change. This is standard operational procedure and not a PR concern, but worth tracking.
  • Triage agent dependency: The PR description states the triage agent (octo-issue-notify webhook mode) owns greeting + classification + label removal. This creates an implicit contract: if the triage agent is down or TRIAGE_WEBHOOK_URL is not configured for a repo, issues will accumulate the needs-triage label without being triaged. This is a deployment/ops concern, not a code concern.

[Octo-Q] verdict: APPROVE

Rationale: No P0/P1 findings. The PR is a clean, well-documented simplification that correctly reduces the workflow to a deterministic label application while preserving all safety guards (bot skip, ghost user, idempotency, concurrency, least-privilege). The workflow_call interface is unchanged, so all 19 caller repos require zero migration. Two P2 findings (error swallowing breadth, orphaned markers) are non-blocking.

@yujiawei yujiawei left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review — PR #73 (.github)

Summary

This replaces the hardcoded bilingual welcome-comment matrix in the reusable issue-welcome.yml with a single deterministic action: apply a needs-triage label (auto-created if missing). The greeting/classification responsibility moves to the dedicated triage agent. Net +39 / -103, one file. The change is correct, the public-interface contract is preserved, and the security posture is actually improved over the prior version.

1. Verification

  • workflow_call interface unchangedon: workflow_call with no inputs/secrets, and permissions: { issues: write } are identical to the prior version. Verified a representative caller (Mininglamp-OSS/octo-server/.github/workflows/issue-welcome.yml) passes no inputs and only grants issues: write on issues: [opened]. No caller migration needed, as claimed. (15+ caller repos resolved to the same shape via org-wide search.)
  • Idempotency — relies on GitHub de-duping addLabels for the same label name; re-runs are harmless. This correctly replaces the old listComments + marker scan. addLabels with an existing label is a no-op.
  • Concurrency-race handling on label creationgetLabel → on 404createLabel, with the createLabel error swallowed via core.debug so a concurrent run that already created the label does not fail this run. Sound.
  • Bot / ghost-user guardissue.user && issue.user.type === 'Bot' correctly skips bot-opened issues while guarding against a null issue.user (deleted accounts).
  • Least privilege — top-level permissions: {}, job-level issues: write only; GITHUB_TOKEN passed explicitly. createLabel + addLabels both fall under issues: write. No scope creep.
  • actionlint + workflow-sanity (no-tabs) checks — both green on head SHA.

2. Security review (PR classified security-sensitive)

  • No script-injection surface. All values consumed inside the actions/github-script block come from the runtime context.payload / context.repo objects, not from ${{ ... }} template interpolation into the script body. There is no path where untrusted issue title/body is expanded into the inline script. Notably, the new version removes the old language-detection logic that read issue.title/issue.body, so the workflow no longer touches attacker-controlled issue content at all — strictly reduced attack surface.
  • No secret egress. The only secret used is GITHUB_TOKEN; nothing is forwarded to an external endpoint here.
  • Pinned action. actions/github-script pinned to a full commit SHA (3a2844b…, v9.0.0). Good supply-chain hygiene.

Nothing here requires manual human verification beyond the product-coupling note below.

3. Findings

No P0/P1 issues. The change is correct and safe to merge.

P2 — Org-wide acknowledgment now depends on the triage agent being wired up in each caller repo (worth a human decision)

This is the one item I'd want a maintainer to confirm rather than a code defect. The PR description states the triage agent now "owns greeting, classification, and removing the label." But issue-welcome.yml and octo-issue-notify.yml are independent reusables that callers opt into separately: a caller can use issue-welcome.yml@v1 without also wiring octo-issue-notify.yml + the optional TRIAGE_WEBHOOK_URL secret. In any such repo, a newly-opened community issue will now receive a needs-triage label and zero human-visible acknowledgment (the previous bilingual welcome comment is gone). For a public OSS org this is a contributor-facing behavior change. Recommendation: confirm every repo that consumes issue-welcome.yml also has the triage webhook configured, or accept the "label-only, no comment" outcome as intended. Not a merge blocker — the label itself applies correctly.

Nits (non-blocking, no change required)

  • The getLabelcreateLabel dance is partially redundant: addLabels auto-creates a missing label on the fly. The explicit create is still justified here because it pins a deterministic color (d876e3) and description (Awaiting triage) instead of GitHub's default — so this is a reasonable, intentional choice, not dead code.
  • A createLabel failure for a non-race reason (e.g. validation/permission) is also swallowed by the catch, after which addLabels would surface the underlying failure (and auto-create with a default color). Acceptable — the job still fails loudly on a genuine permission problem — but if you ever want the create error to be attributable, distinguishing race (422 already_exists) from other failures would make logs clearer.

4. Verdict

Correct, well-documented, security posture improved, public interface preserved. Approving. The P2 is a product/ops confirmation for maintainers, not a code blocker.

@lml2468 lml2468 merged commit 135e280 into main Jun 9, 2026
3 checks passed
@lml2468 lml2468 deleted the ci/issue-welcome-needs-triage branch June 9, 2026 10:20

@Jerry-Xin Jerry-Xin left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is relevant to Mininglamp-OSS/.github, but it changes the ownership contract for issue greeting/triage without updating the repository’s architecture baseline.

🔴 Blocking

  • 🔴 Critical — .github/workflows/issue-welcome.yml:7 now says the triage agent owns greeting, while docs/workflow-architecture.md:284-296 explicitly says the agent does not own greeting, and docs/workflow-architecture.md:300-303 says issue-welcome must remain the native, reliable first-response workflow. That document is the repo’s stated automation acceptance baseline, so merging this as-is leaves the implementation and design contract in direct conflict. Either update the architecture/agent contract in the same PR, or keep the native greeting behavior.

💬 Non-blocking

  • 🟡 Warning — .github/workflows/issue-welcome.yml:62-65 catches all createLabel failures and labels them as a race. Consider only suppressing the expected “already exists” race, and rethrowing/logging unexpected failures with status details. addLabels will likely fail later if label creation truly failed, but the current debug-only message makes diagnosis worse.

✅ Highlights

  • ✅ The workflow remains least-privilege with issues: write only.
  • ✅ The action is pinned by SHA.
  • ✅ No checkout or untrusted code execution is introduced.
  • ✅ Bot-opened issues are still skipped.
  • actionlint passes for .github/workflows/issue-welcome.yml.

@lml2468

lml2468 commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

齐静春 📖 follow-up — revising my prior APPROVED to a soft CHANGES_REQUESTED (verdict in body; self-vote on own-author PR is blocked)

Earlier comment: #issuecomment-4658775508 (initial APPROVED). Jerry-Xin's CR caught a real doc-vs-implementation contract drift that my approval missed. Logging the correction.

Jerry-Xin #1 is a real find — documentation contract drift

PR title says "apply needs-triage label instead of welcome comment". That's the right one-line summary of the implementation. But docs/workflow-architecture.md was not updated in this PR — and the doc still describes issue-welcome's purpose as the greeting comment that this PR just removed.

Concrete evidence at HEAD (grep-verified):

  1. workflow-architecture.md:224Stage 1 Welcome | Greet new issue, guide info | issue-welcome | ✅. The "✅" claims this stage is covered; after this PR it is not — issue-welcome no longer greets, it labels.

  2. workflow-architecture.md:304"welcome = deterministic emotional greeting + generic guidance (thanks, links, community); agent comment = intelligent, possibly-delayed triage verdict". The Replacement matrix sells the design's "orthogonality" using exactly the greeting behavior this PR is deleting. With the PR merged as-is, the architecture's load-bearing claim "welcome and agent comment are orthogonal because welcome is the deterministic greeting" no longer holds.

  3. workflow-architecture.md:307"…cannot depend on external agent uptime." — also a load-bearing argument now decoupled from the new behavior (a label doesn't address "external contributor first-impression").

This isn't a doc-nit. The architecture doc justifies the split of responsibilities between issue-welcome (greeting) and octo-issue-notify's webhook mode (triage agent). The PR's premise is that the triage agent owns greeting now — but the architecture doc still says greeting lives in issue-welcome. Two readers of the doc would form contradictory mental models depending on whether they read the doc or read the workflow.

I should have caught this in my initial review. The fix path is exactly what Jerry-Xin describes: update Stage 1 row + Replacement matrix row + the orthogonality argument to match the "agent owns greeting, workflow owns the label" allocation.

Self-correction (continuing the day's pattern)

This is now the 7th instance of the "信注释/陈述不验代码" failure mode I'm logging this cycle, but with the inverse polarity: previously I trusted comments-vs-implementation alignment, here I trusted PR-vs-architecture-doc alignment. Same root: I read the title ("apply label instead of welcome comment") + the workflow change as a self-contained refactor and didn't ask "does any other file in this repo describe the old behavior as load-bearing?"

Hard rule extension: A PR that changes a workflow's surface behavior must be cross-grepped against any architecture / contract doc in the same repo that describes that workflow by name. Same shape as the cross-PR caller grep (PR #72 — grep all callers before removing a reusable workflow), just applied within a single PR to documentation surfaces.

On Jerry-Xin's 🟡 #2 — agree, soft suggestion

The createLabel error swallow is broad — it catches "concurrent run already created" (the intended race) plus any other failure (network drop, 5xx, 403). For the realistic failure surface here it's defensible, but Jerry-Xin's "only swallow 409, log/throw the rest" is the stricter pattern and makes the race-vs-real-failure distinction explicit. Not blocking but worth doing while the file is open.

What still holds from my initial approval

The core refactor — workflow → deterministic label, greeting/classification → triage agent — is the right architectural direction. The workflow code itself (label race handling, bot-skip guard, least-privilege) is fine. The defect is solely: the architecture document wasn't moved along with the implementation, and the document is the part that justifies the architectural direction the implementation enacts.

Recommendation

Land this PR with a single follow-up commit updating docs/workflow-architecture.md:

  • Stage 1 row: rename to "Apply needs-triage label" + change source from issue-welcome to current.
  • Replacement matrix issue-welcome row: rewrite the "Reason" to match the new behavior ("deterministic always-on labeling; greeting + classification + triage commentary delegated to the triage agent via octo-issue-notify webhook mode"), drop the now-incorrect orthogonality claim.
  • Either in this PR or as a follow-up, but before future readers form the wrong mental model.

— 齐静春 📖

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants