DashboardpublishDistillation

Distillation

ID: ab551349-e186-4f6c-8bc1-40128600b10d
Session: 1BpBuVO0t33J
Generation: 0
Tokens: 2334
R_compression: 20.296
C_norm: 0.000
Archived: No
Created: 2026-09-09 13:26:29
Source IDs:
["lore_tm_v1_y60iC7hzu0eAlBm5L-FRPFZK71a8_CI3ZbtnDDqhRsc","lore_tm_v1_takw38NLEG1pjPTjaSniHgWaCxeYL2fcs4oANOBNrbA","lore_tm_v1_9xPTcLVF9fw8sbrCs6o0i8ycxDUE1pHPupAI5c7yip0","lore_tm_v1_65zRbYYY1-YkqznnFC32zndl_-XsUVkTTzr1nHtURL0","lore_tm_v1_QPOOE3JSAcGrzGnd_0R0SzgFRHW25y7r3oNyKc36Ul4","lore_tm_v1_EDnMs6sxpvJnyeflchUcUx0VBXTJsRYaEnV_Ai5d_08"]

Observations

🔴 (12:53) Current checked-out branch is main.

🔴 (12:53) /home/byk/Code/getsentry/publish/.github/workflows/auto-approve.yml is 54 lines. Workflow auto-approve non-sdks runs on opened issues with contents: read and issues: write; job auto-approve uses environment: production only when actor is sentry-release-bot[bot] or getsantry[bot] and the title starts with publish: .

🔴 (12:53) .github/workflows/auto-approve.yml checks out only auto-approve-repos.txt using actions/checkout@11d5960a326750d5838078e36cf38b85af677262, obtains a Sentry Internal App token using SENTRY_INTERNAL_APP_ID and SENTRY_INTERNAL_APP_PRIVATE_KEY, runs node src/publish/record-auto-approval-attestation.js, posts the resulting auto_approval_attestation with ${{ github.token }}, then extracts REPO using sed -n 's/^publish: \(.*\)@.*/\1/p' and adds accepted if grep -qxF "$REPO" auto-approve-repos.txt succeeds.

🔴 (12:54) Current parsePublishTitle() behavior accepts traversal-like title publish: getsentry/toolkit/../.__publish__@1.2.3 as {"repo":"toolkit","path":"/../.__publish__","version":"1.2.3"}, rejects publish: getsentryreit/space name@1.2.3 as null, and accepts option-like version publish: getsentry/toolkit@--dry-run as {"repo":"toolkit","version":"--dry-run"}.

🔴 (12:54) User’s workflow security directive is exact: “Always run trusted code.” In .github/workflows/ci-poller.yml, the Get publish code checkout therefore pins ref: ${{ github.event.repository.default_branch }} and sets persist-credentials: false.

🔴 (12:54) User’s release-integrity directive is exact: “Never move a release to ci-ready after it changes.”

🔴 (12:54) User requires that a renamed or re-approved issue “never reaches ci-ready”; .github/workflows/ci-poller.yml revalidates the approval after final CI checks, when recording CI-ready proof, and immediately before adding ci-ready.

🔴 (12:54) User states the poller “always adds ci-ready” on the happy path; .github/workflows/publish.yml relies on waiting-for-ci first removing any existing ci-ready label so the poller’s fresh addition generates the labeled event that triggers publishing.

🔴 (12:54) /home/byk/Code/getsentry/publish/.github/workflows/ci-poller.yml is 463 lines. Workflow CI Status Poller runs on cron */5 * * * *, repository_dispatch type ci-poller, and completed workflow_run events from Run CI Status Poller; job check-ci uses environment: production, concurrency group ci-status-poller, and cancel-in-progress: false.

🔴 (12:54) The CI poller runs only when vars.CI_POLLER_HAS_PENDING == 'true', on repository_dispatch, or after a successful workflow_run whose head_branch equals github.event.repository.default_branch. Repository-dispatch attempt must match ^(0|[1-5][0-9])$; invalid values produce repository_dispatch attempt must be an integer from 0 through 59.

🔴 (12:54) The CI poller requests at most 200 open issues having both ci-pending and accepted. Before CI inspection it runs src/publish/current-accepted-event.js, binds accepted_actor and accepted_event_id, and validates via src/publish/validate-approval-attestation.js; failures remove both ci-pending and accepted and post Approval is invalid or could not be verified. Re-add the accepted label to retry after resolving the issue.

🔴 (12:54) The CI poller parses each issue title using parsePublishTitle from ./src/modules/details-from-context.js, forms repository identity as getsentry/${parsed.repo}, extracts the release commit from a 40-character SHA in an issue-body /commit/{SHA}/checks URL, discovers the branch via repos/${repo}/commits/${issue_sha}/check-suites, and resolves current branch HEAD via repos/${repo}/git/ref/heads/${branch}. API failures fall back to the issue SHA; if the branch moved, the poller replaces the old SHA in the issue body.

🔴 (12:54) CI readiness requires at least one check run or commit status, commit status success or exactly 0 reported statuses, exactly 0 pending check runs, and exactly 0 unsuccessful check runs. Completed conclusions success, neutral, and skipped count as passing; other completed conclusions count as unsuccessful.

🔴 (12:54) Before adding ci-ready, the poller runs src/publish/record-ci-ready-attestation.js with the issue title and expected accepted actor/event ID, requires output beginning ci_ready_attestation=, posts the proof using ${{ github.token }}, and validates approval once more. Any proof-generation, proof-posting, or final-validation failure removes ci-pending and accepted.

🔴 (12:54) When CI passes, the poller removes ci-pending, adds ci-ready, and comments CI checks passed for ${repo}@${version}. Publishing is starting now. When check runs fail, it removes ci-pending and accepted, adds ci-failed, lists failed check names, and asks that accepted be re-added after repair. A failed commit status with otherwise passing check runs follows the same label transition and lists failed/error status contexts with available links.

🔴 (12:54) The CI poller synchronizes CI_POLLER_HAS_PENDING using a dedicated app token from CI_POLLER_APP_CLIENT_ID and CI_POLLER_APP_PRIVATE_KEY: sets it to "false" when no open issue has both ci-pending and accepted, otherwise "true". Self-dispatch increments with attempt=$((10#$ATTEMPT + 1)), stops when the incremented attempt is >= 60, and otherwise posts {event_type: "ci-poller", client_payload: {attempt: $attempt}} to repos/$GITHUB_REPOSITORY/dispatches.

🔴 (12:54) /home/byk/Code/getsentry/publish/.github/workflows/publish.yml is 435 lines. Workflow Publish runs on issue-label events with concurrency grouped by ${{ github.event.issue.title }}, cancel-in-progress: false, and permissions contents: read, issues: write, and packages: write.

🔴 (12:54) The waiting-for-ci job runs in environment: production when an open publish: issue receives accepted. It obtains Sentry Internal App and Release Bot tokens, runs node src/publish/authorize-approval.js, posts the returned approval attestation, validates it with node src/publish/validate-approval-attestation.js, rejects invalid approval by removing accepted, then resets labels by removing ci-failed and ci-ready and adding ci-pending.

🔴 (12:54) The waiting-for-ci job sets CI_POLLER_HAS_PENDING to "true" on a best-effort basis and immediately triggers repository_dispatch with event_type=ci-poller; its normal comment is Approved. Checking CI status on the release branch. Publishing will start automatically when CI passes., while retries after ci-failed use Retrying — CI was previously failed. Checking CI status now.

🔴 (12:54) The publish job runs only for an open issue’s ci-ready label event when labels include both accepted and ci-ready and exclude both ci-pending and ci-failed; it uses environment: production and timeout-minutes: 90.

🔴 (12:54) Before publishing, .github/workflows/publish.yml checks out the controller into .__publish__, requires REQUIRE_CI_READY_ATTESTATION: "true" in both initial and final calls to .__publish__/src/publish/validate-approval-attestation.js, uses Node 24, installs with yarn install --cwd ".__publish__", and parses inputs using node .__publish__/src/publish/inputs.js.

🔴 (12:54) The target-repository checkout defaults to its default branch but conditionally uses protected merge targets for: sentry-migr8tmp-merge-target; sentry-javascriptv10, v9, v8, v7, or master; sentry-pythonalpha; and sentry-wizard1.x. It checks out getsentry/${repo} into __repo__ with fetch-depth: 0.

🔴 (12:54) Current .github/workflows/publish.yml constructs Craft state using manual CRAFT_PUBLISH_PATH concatenation into container cwd /github/workspace/__repo__ or /github/workspace/__repo__/${CRAFT_PUBLISH_PATH#./}, strips one trailing slash, hashes it with SHA-1 truncated to 12 characters, sanitizes owner/repository/version with lowercase plus sed, and writes .craft-state/craft/publish-state-${owner_sanitised}-${repo_sanitised}-${cwd_hash}-${version_sanitised}.json.

🔴 (12:54) Current Craft invocation uses docker://getsentry/craft@sha256:9a4a5d5efa44a00c2215078ead39800d4aaa5a97908b94f45a64d7d506d6e14b, executes cd __repo__/${{ fromJSON(steps.inputs.outputs.result).path }} followed by exec craft publish ${{ fromJSON(steps.inputs.outputs.result).version }}, and sets XDG_STATE_HOME: /github/workspace/.craft-state. The current invocation does not pass a pinned release revision to craft publish.

🔴 (12:54) Publish result handling runs node .__publish__/src/publish/update-issue.js on cancellation or failure, node .__publish__/src/publish/post-result.js cancelled on cancellation, node .__publish__/src/publish/post-result.js failure on failure, and node .__publish__/src/publish/post-result.js success to close on success.