Skip to content

[Klaud Cold] Fix signoff-verify parse error: move verifier prompt out of workflow YAML / 修复 signoff-verify 解析错误:将验证器提示词移出 workflow YAML#2156

Merged
functionstackx merged 1 commit into
mainfrom
klaud/fix-signoff-prompt-length
Jul 10, 2026
Merged

[Klaud Cold] Fix signoff-verify parse error: move verifier prompt out of workflow YAML / 修复 signoff-verify 解析错误:将验证器提示词移出 workflow YAML#2156
functionstackx merged 1 commit into
mainfrom
klaud/fix-signoff-prompt-length

Conversation

@functionstackx

Copy link
Copy Markdown
Collaborator

Summary

Fixes the broken workflow file currently on main (Invalid workflow file: .github/workflows/codeowner-signoff-verify.yml — (Line: 237, Col: 19): Exceeded max expression length 21000, e.g. this run). GitHub compiles any ${{ }}-bearing workflow scalar into a single format() expression capped at 21,000 characters; the Check 9 addition in #2155 pushed the inline verifier prompt to ~21,030 compiled characters. Until this lands, the required codeowner-signoff-verify status cannot run for any sign-off.

  • .github/codeowner-signoff-verify-prompt.md (new): the full verifier prompt, moved verbatim, with ${{ needs.gate.outputs.* }} / ${{ github.repository }} replaced by ${PR_NUMBER}-style placeholders.
  • codeowner-signoff-verify.yml: new "Render verifier prompt" step substitutes those six values with envsubst (template read from the trusted default-branch checkout — same trust level as the workflow itself, never PR-head content) and writes /tmp/codeowner-signoff-verify-prompt.md; the Claude action now gets a tiny static pointer prompt. Largest remaining expression in the file is ~450 chars, so the checklist can keep growing without ever hitting this limit again. A grep guard in the render step fails fast if substitution ever breaks.
  • AGENTS.md: checklist ↔ verifier sync rule now points at the template file and warns not to move the prompt back inline.

Verified locally: YAML parses; an expression-length audit of every scalar passes with wide margin; a render simulation substitutes all six placeholders with zero leftovers and preserves the sha-pinned marker, PR #<n> references, and the Check 9 section.

中文说明

修复当前 main 上损坏的 workflow 文件Exceeded max expression length 21000,见此运行)。GitHub 会将含 ${{ }} 的 workflow 标量编译为单个 format() 表达式,上限 21,000 字符;#2155 新增的 Check 9 使内联提示词达到约 21,030 字符。在本 PR 合并前,必需的 codeowner-signoff-verify 状态检查无法对任何签署运行。

  • .github/codeowner-signoff-verify-prompt.md(新增):完整验证器提示词原样迁入,${{ }} 表达式替换为 ${PR_NUMBER} 等占位符。
  • codeowner-signoff-verify.yml:新增 "Render verifier prompt" 步骤,用 envsubst 替换六个动态值(模板来自受信任的默认分支检出,信任级别与 workflow 本身相同,绝不使用 PR head 内容)并写入 /tmp/codeowner-signoff-verify-prompt.md;Claude action 仅接收极短的静态指针提示词。文件中剩余最大表达式约 450 字符,清单今后可任意增长而不会再触及该上限。渲染步骤中的 grep 守卫可在替换失效时立即失败。
  • AGENTS.md:清单 ↔ 验证器同步规则改为指向该模板文件,并注明不要将提示词移回内联。

本地已验证:YAML 可解析;对所有标量的表达式长度审计通过且余量充足;渲染模拟替换全部六个占位符、无残留,并保留 sha 固定标记、PR #<n> 引用及 Check 9 小节。

🤖 Generated with Claude Code

GitHub caps a ${{ }}-bearing workflow scalar at 21000 chars when compiled
to a format() expression; the Check 9 addition in #2155 pushed the inline
verifier prompt to ~21030, so the workflow file fails to parse on main
("Invalid workflow file ... Exceeded max expression length 21000") and the
required codeowner-signoff-verify status can never be published.

Move the prompt body verbatim to .github/codeowner-signoff-verify-prompt.md
with ${VAR} placeholders, render it with envsubst in a new step (from the
trusted default-branch checkout, same trust level as before), and point the
action at the rendered file with a tiny static prompt. Largest remaining
expression is now ~450 chars, so future checklist growth cannot re-trigger
the limit. AGENTS.md sync rule updated to point at the template.

中文:GitHub 将含 ${{ }} 的 workflow 标量编译为 format() 表达式并限制在
21000 字符以内;#2155 新增的 Check 9 使内联提示词达到约 21030 字符,导致
main 上该 workflow 文件解析失败,必需的 codeowner-signoff-verify 状态无法
发布。现将提示词原样移至 .github/codeowner-signoff-verify-prompt.md 模板
(使用 ${VAR} 占位符),由新步骤通过 envsubst 渲染(模板来自受信任的默认
分支检出,信任级别不变),action 仅接收指向渲染文件的极短静态提示词。剩余
最大表达式约 450 字符,日后清单增长不会再触发该上限。AGENTS.md 同步规则已
更新为指向该模板。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM — mechanical fix that moves the verifier prompt verbatim to a template file rendered via envsubst, unblocking the required check that's currently failing to parse on main.

Extended reasoning...

Overview

Three-file change to fix a broken required workflow on main. The verifier prompt in .github/workflows/codeowner-signoff-verify.yml overflowed GitHub's 21,000-char cap on ${{ }}-bearing scalars after Check 9 was added in #2155. The prompt is moved verbatim into a new .github/codeowner-signoff-verify-prompt.md template, a new "Render verifier prompt" step runs envsubst on it to substitute six placeholders (REPO, PR_NUMBER, HEAD_SHA, SIGNOFF_AUTHOR, SIGNOFF_KIND, SIGNOFF_FETCH_CMD), and the Claude action receives a 4-line pointer prompt. AGENTS.md is updated to point the checklist↔verifier sync rule at the new template.

Security risks

The workflow is privileged (write perms + secrets: CLAUDE_PAT, ANTHROPIC_API_KEY) and runs on comment triggers, so untrusted content is a real concern. However, the security perimeter is preserved:

  • The template is read from the trusted default-branch checkout (ref: ${{ github.event.repository.default_branch }}), same trust level as the workflow file itself — never PR-head content.
  • envsubst is passed an explicit allowlist ('${REPO} ${PR_NUMBER} ...') which prevents unintended expansion of any other shell-style tokens in the prompt body.
  • GitHub logins (SIGNOFF_AUTHOR) are alphanumeric+hyphen so cannot smuggle shell metachars; SIGNOFF_KIND is one of three hard-coded strings; SIGNOFF_FETCH_CMD is constructed in the gate step from vetted API paths and integer IDs.
  • A grep -q "PR #${PR_NUMBER}" guard in the render step fails fast if substitution silently breaks.

Level of scrutiny

Medium — the file touched is a security-sensitive merge gate (CODEOWNER sign-off verification) and CODEOWNER-owned under the * @InferenceX/core catch-all. But the change itself is purely mechanical: the prompt body is unchanged in meaning, only the delivery mechanism moved from an inline YAML scalar to a file rendered by envsubst. The 10 check specifications, the trusted-branch checkout, and the verdict-publishing step are all untouched.

Other factors

The PR fixes a currently-failing required check (Exceeded max expression length 21000 on run 29115095503), so it's unblocking. PR description reports local verification of YAML parse, expression-length audit, and a render simulation that substitutes all six placeholders with zero leftovers. No bugs were found by the bug hunter. Comfortable shadow-approving.

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

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

1 participant