DashboardcraftSession 1YRxdVOOo2Lq

Session 1YRxdVOOo2Lq

Full ID: 1YRxdVOOo2Lq5wyFo
Messages: 37
Distillations: 1
Time range: 2026-09-02 11:14:19 — 2026-09-02 11:19:03

Conversation (37 messages)

Perform a strict read-only adversarial review of the uncommitted compact workspace publish-contract changes in BOTH worktrees:

  • /home/byk/Code/getsentry/craft-workspace-action-propagation (branch feat/workspace-action-propagation)
  • /home/byk/Code/getsentry/publish-workspace-acceptance (branch feat/workspace-acceptance)

Do not modify files. Inspect the full diffs and relevant source/tests/workflows. Focus on: exact CI-approved revision binding from the canonical Quick links check-runs URL through checkout, discovery, state path, and craft publish --rev; compact title grammar and legacy JSON title compatibility; workspace/path mutual exclusivity; raw case-sensitive workspace identity; CI poller behavior and title parsing; state filename parity and no repository-local fallback; GitHub Actions expression/YAML validity; parser generation freshness; action input validation/order; security/path traversal/injection; and commit hygiene (including untracked pnpm-lock.yaml).

Return only prioritized findings with exact file:line citations and PASS/FAIL assessments, ending with MERGE or DO-NOT-MERGE. If no blockers, explicitly state that. Do not rely on previous review results.

gateway · 2026-09-02 11:14:19
result
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation</path>
<type>directory</type>
<entries>
.craft.yml
.dockerignore
.eslintcache
.git
.github/
.gitignore
.lore.md
.nojekyll
.npmignore
.prettierignore
.prettierrc.yml
.tsbuildinfo
.vscode/
action.yml
AGENTS.md
blog-post-draft.md
build.mjs
CHANGELOG.md
CONTRIBUTING.md
dist/
Dockerfile
docs/
eslint.config.mjs
img/
LICENSE
node_modules/
package.json
pnpm-lock.yaml
README.md
src/
tsconfig.build.json
tsconfig.json
vitest.config.mts

(33 entries)
</entries>
gateway · 2026-09-02 11:14:58
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance</path>
<type>directory</type>
<entries>
.eslintrc.js
.git
.github/
.gitignore
AGENTS.md
auto-approve-repos.txt
docs/
LICENSE
node_modules/
package.json
pnpm-lock.yaml
README.md
scripts/
src/
vitest.config.js
yarn.lock

(16 entries)
</entries>
gateway · 2026-09-02 11:15:02
result
 M action.yml
 M docs/src/content/docs/targets/github.md
 M src/__tests__/action.test.ts
 M src/__tests__/config.test.ts
 M src/commands/__tests__/publish.test.ts
 M src/commands/publish.ts
 M src/config.ts
 M src/index.ts
 M src/schemas/project_config.ts
?? src/commands/workspace.ts
?? src/commands/workspace_cmds/
feat/workspace-action-propagation
 action.yml                              |  18 ++---
 docs/src/content/docs/targets/github.md |  36 ++++++++-
 src/__tests__/action.test.ts            | 125 +++++++++++++++++++++++++++---
 src/__tests__/config.test.ts            | 130 ++++++++++++++++++++++----------
 src/commands/__tests__/publish.test.ts  |  27 +++++++
 src/commands/publish.ts                 |  18 ++++-
 src/config.ts                           |  48 ++++++++----
 src/index.ts                            |   2 +
 src/schemas/project_config.ts           |  63 +++++++++++-----
 9 files changed, 370 insertions(+), 97 deletions(-)
diff --git a/action.yml b/action.yml
index ...
gateway · 2026-09-02 11:15:09
result
 M .github/workflows/publish.yml
 M docs/publish-issue-format.md
 M package.json
 M src/modules/__tests__/details-from-context.js
 M src/modules/__tests__/publish-workflow.js
 M src/modules/details-from-context.js
 M src/modules/post-workflow-details.js
 M src/publish/inputs.js
 M yarn.lock
?? pnpm-lock.yaml
?? scripts/
?? src/modules/__tests__/publish-location.js
?? src/modules/__tests__/release-revision.js
?? src/modules/publish-issue-title.js
?? src/modules/publish-issue-title.peggy
?? src/modules/publish-location.js
?? src/modules/release-revision.js
?? src/publish/resolve-location.js
?? src/publish/resolve-release-revision.js
feat/workspace-acceptance
 .github/workflows/publish.yml                 | 59 ++++++++++++++-------------
 docs/publish-issue-format.md                  | 55 +++++++++++++++----------
 package.json                                  |  5 ++-
 src/modules/__tests__/details-from-context.js | 20 +++++++++
 src/modules/__tests__/publish-workflow.js     | 36 ...
gateway · 2026-09-02 11:15:13
result
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/commands/workspace.ts</path>
<type>file</type>
<content>
1: import { Argv, CommandBuilder } from 'yargs';
2: 
3: import * as list from './workspace_cmds/list';
4: 
5: export const command = ['workspace <command>'];
6: export const description = 'Manage release workspaces';
7: 
8: export const builder: CommandBuilder = (yargs: Argv) =>
9:   yargs.demandCommand().command(list);
10: 
11: export const handler = (): void => {
12:   /* pass */
13: };

(End of file - total 13 lines)
</content>

<system-reminder>
Instructions from: /home/byk/Code/getsentry/craft-workspace-action-propagation/AGENTS.md
# AGENTS.md

This file provides guidance for AI coding assistants working with the Craft codebase.

## Package Management

- **Always use `pnpm`** for package management. Never use `npm` or `yarn`.
- Node.js version is managed by [Volta](https://volta.sh/) (currently v22.12.0). ...
gateway · 2026-09-02 11:15:17
result
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/commands/workspace_cmds/list.ts</path>
<type>file</type>
<content>
1: import { getWorkspaceNames } from '../../config';
2: import { formatJson } from '../../utils/strings';
3: 
4: export const command = ['list'];
5: export const description = 'List defined release workspaces as a JSON array';
6: 
7: export function handler(): void {
8:   console.log(formatJson(getWorkspaceNames()));
9: }

(End of file - total 9 lines)
</content>
gateway · 2026-09-02 11:15:21
result
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/commands/workspace_cmds/__tests__/list.test.ts</path>
<type>file</type>
<content>
1: import { describe, expect, test, vi } from 'vitest';
2: 
3: vi.mock('../../../config', () => ({
4:   getWorkspaceNames: vi.fn(),
5: }));
6: vi.mock('../../../utils/strings', () => ({
7:   formatJson: vi.fn(value => JSON.stringify(value)),
8: }));
9: 
10: import { getWorkspaceNames } from '../../../config';
11: import { handler } from '../list';
12: 
13: describe('workspace list command', () => {
14:   test('prints exact configured workspace names', () => {
15:     vi.mocked(getWorkspaceNames).mockReturnValue(['cli', 'mcp.v2']);
16:     const log = vi.spyOn(console, 'log').mockImplementation(() => {});
17: 
18:     handler();
19: 
20:     expect(log).toHaveBeenCalledWith('["cli","mcp.v2"]');
21:   });
22: 
23:   test('prints an empty array when no workspaces are configured', () => {
24:     ...
gateway · 2026-09-02 11:15:24
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/publish-issue-title.peggy</path>
<type>file</type>
<content>
1: {
2:   function join(characters) {
3:     return characters.join("");
4:   }
5: }
6: 
7: // Canonical grammar for publish issue titles. A path suffix is syntactic only:
8: // the controller resolves a single segment as a workspace after checking out
9: // the CI-approved revision.
10: PublishIssueTitle
11:   = "publish: " "getsentry/"? repo:Repository path:Path? workspace:LegacyWorkspace? "@" version:Version !. {
12:       return {
13:         repo,
14:         path: path || "",
15:         version,
16:         ...(workspace ? { workspace } : {}),
17:       };
18:     }
19: 
20: Repository
21:   = characters:RepositoryCharacter+ { return join(characters); }
22: 
23: RepositoryCharacter
24:   = [A-Za-z0-9_.-]
25: 
26: Path
27:   = segments:("/" segment:PathSegment { return `/${segment}`; })+ { return join(segments); }
28: 
29: PathSegment
30:   = ...
gateway · 2026-09-02 11:15:27
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/publish-issue-title.js</path>
<type>file</type>
<content>
1: /* eslint-disable */
2: // @generated by Peggy 5.1.0.
3: //
4: // https://peggyjs.org/
5: 
6: "use strict";
7: 
8: class peg$SyntaxError extends SyntaxError {
9:   constructor(message, expected, found, location) {
10:     super(message);
11:     this.expected = expected;
12:     this.found = found;
13:     this.location = location;
14:     this.name = "SyntaxError";
15:   }
16: 
17:   format(sources) {
18:     let str = "Error: " + this.message;
19:     if (this.location) {
20:       let src = null;
21:       const st = sources.find((s) => s.source === this.location.source);
22:       if (st) {
23:         src = st.text.split(/\r\n|\n|\r/g);
24:       }
25:       const s = this.location.start;
26:       const offset_s =
27:         this.location.source &&
28:         typeof this.location.source.offset === "function"
29:           ? ...
gateway · 2026-09-02 11:15:31
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/publish-location.js</path>
<type>file</type>
<content>
1: function needsWorkspaceDiscovery({ path, workspace }) {
2:   return !workspace && /^\.\/[A-Za-z0-9_.-]+$/.test(path);
3: }
4: 
5: function resolvePublishLocation({ path, workspace, workspaceNames }) {
6:   if (workspace) {
7:     if (path !== ".") {
8:       throw new Error("A publish workspace must use the repository root path.");
9:     }
10:     return { path, workspace };
11:   }
12: 
13:   if (!needsWorkspaceDiscovery({ path, workspace })) {
14:     return { path };
15:   }
16: 
17:   if (!workspaceNames.every(isWorkspaceName)) {
18:     throw new Error(
19:       "Craft workspace discovery returned an invalid workspace list."
20:     );
21:   }
22: 
23:   const segments = path.slice(2).split("/");
24:   if (
25:     path.startsWith("./") &&
26:     segments.length === 1 &&
27:     workspaceNames.includes(segments[0])
28:   ) {
29:     return { path: ...
gateway · 2026-09-02 11:15:35
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/src/publish/resolve-location.js</path>
<type>file</type>
<content>
1: const core = require("@actions/core");
2: const {
3:   needsWorkspaceDiscovery,
4:   resolvePublishLocation,
5: } = require("../modules/publish-location");
6: 
7: function resolveLocation() {
8:   const input = JSON.parse(process.env.PUBLISH_ARGS || "");
9:   const workspaceNames = needsWorkspaceDiscovery(input)
10:     ? JSON.parse(process.env.CRAFT_WORKSPACE_NAMES || "")
11:     : [];
12: 
13:   if (!Array.isArray(workspaceNames)) {
14:     throw new Error(
15:       "Craft workspace discovery returned an invalid workspace list."
16:     );
17:   }
18: 
19:   core.setOutput(
20:     "result",
21:     resolvePublishLocation({
22:       path: input.path,
23:       workspace: input.workspace,
24:       workspaceNames,
25:     })
26:   );
27: }
28: 
29: resolveLocation();

(End of file - total 29 lines)
</content>
gateway · 2026-09-02 11:15:39
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/release-revision.js</path>
<type>file</type>
<content>
1: const CHECK_RUNS_LINK =
2:   /^- \[View check runs\]\(https:\/\/github\.com\/getsentry\/(?<repo>[A-Za-z0-9_.-]+)\/commit\/(?<revision>[0-9a-f]{40})\/checks\/?\)\r?$/m;
3: 
4: function getReleaseRevision({ issueBody, repo }) {
5:   const match = issueBody.match(CHECK_RUNS_LINK);
6:   if (!match?.groups || match.groups.repo !== repo) {
7:     throw new Error(
8:       `Expected a View check runs link for getsentry/${repo} in the publish issue body.`
9:     );
10:   }
11: 
12:   return match.groups.revision;
13: }
14: 
15: module.exports = { getReleaseRevision };

(End of file - total 15 lines)
</content>
gateway · 2026-09-02 11:15:43
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/src/publish/resolve-release-revision.js</path>
<type>file</type>
<content>
1: const core = require("@actions/core");
2: const { getReleaseRevision } = require("../modules/release-revision");
3: 
4: function resolveReleaseRevision() {
5:   const { repo } = JSON.parse(process.env.PUBLISH_ARGS || "");
6:   core.setOutput(
7:     "revision",
8:     getReleaseRevision({
9:       issueBody: process.env.PUBLISH_ISSUE_BODY || "",
10:       repo,
11:     })
12:   );
13: }
14: 
15: resolveReleaseRevision();

(End of file - total 15 lines)
</content>
gateway · 2026-09-02 11:15:47
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/scripts/generate-publish-issue-title-parser.js</path>
<type>file</type>
<content>
1: const fs = require("fs");
2: const path = require("path");
3: const peggy = require("peggy");
4: const prettier = require("prettier");
5: 
6: const grammarPath = path.join(
7:   __dirname,
8:   "..",
9:   "src",
10:   "modules",
11:   "publish-issue-title.peggy"
12: );
13: const outputPath = path.join(
14:   __dirname,
15:   "..",
16:   "src",
17:   "modules",
18:   "publish-issue-title.js"
19: );
20: const grammar = fs.readFileSync(grammarPath, "utf8");
21: const parser = peggy.generate(grammar, {
22:   format: "commonjs",
23:   grammarSource: "publish-issue-title.peggy",
24:   output: "source",
25: });
26: 
27: const generatedParser = prettier.format(`/* eslint-disable */\n${parser}`, {
28:   filepath: outputPath,
29: });
30: 
31: if (process.argv.includes("--check")) {
32:   const currentParser = fs.readFileSync(outputPath, "utf8");
33:   ...
gateway · 2026-09-02 11:15:53
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/AGENTS.md</path>
<type>file</type>
<content>
1: # AGENTS.md - Coding Agent Guidelines
2: 
3: This document provides guidelines for AI coding agents working in this repository.
4: 
5: ## Project Overview
6: 
7: This is the **Sentry Publish Repository** - a GitHub Actions-based approval system for publishing releases across multiple Sentry projects using [Craft](https://github.com/getsentry/craft). It's a pure JavaScript (Node.js 24.0.0) project using CommonJS modules.
8: 
9: ## Build/Lint/Test Commands
10: 
11: ### Package Manager
12: 
13: - **Yarn 1.22.22** (classic) - Do NOT use npm
14: - Version management via Volta (pinned in package.json)
15: 
16: ### Commands
17: 
18: ```bash
19: # Install dependencies
20: yarn install
21: 
22: # Run all tests
23: yarn test
24: 
25: # Run tests in watch mode
26: yarn test:watch
27: 
28: # Run a single test file
29: yarn test src/modules/__tests__/update-issue.js
30: 
31: # Run tests ...
gateway · 2026-09-02 11:15:58
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/.github/workflows/publish.yml</path>
<type>file</type>
<content>
1: name: Publish
2: on:
3:   issues:
4:     types: [labeled]
5: 
6: concurrency:
7:   # Use the issue title (e.g. "publish: getsentry/foo@1.2.3") so duplicate
8:   # issues for the same repo@version share a concurrency group.
9:   group: ${{ github.event.issue.title }}
10:   cancel-in-progress: false
11: 
12: permissions:
13:   contents: read
14:   issues: write
15:   packages: write
16: 
17: jobs:
18:   # When accepted is added to a publish issue:
19:   #   - Add ci-pending (and remove ci-failed if retrying)
20:   #   - Enable the poller via CI_POLLER_HAS_PENDING=true
21:   #   - Comment on the issue
22:   #   - Trigger the poller immediately so we don't wait for the next cron tick
23:   # The publish job below requires ci-ready, so it will not fire until the
24:   # poller flips ci-pending → ci-ready (which also prevents publishing without
25:   # CI ...
gateway · 2026-09-02 11:16:05
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/__tests__/publish-location.js</path>
<type>file</type>
<content>
1: import { expect, test } from "vitest";
2: 
3: const {
4:   needsWorkspaceDiscovery,
5:   resolvePublishLocation,
6: } = require("../publish-location.js");
7: 
8: test.each([
9:   [{ path: "./cli" }, true],
10:   [{ path: "./packages/cli" }, false],
11:   [{ path: "." }, false],
12:   [{ path: "./cli", workspace: "cli" }, false],
13: ])("workspace discovery is %s for %j", (input, expected) => {
14:   expect(needsWorkspaceDiscovery(input)).toBe(expected);
15: });
16: 
17: test("classifies an exact one-segment workspace without normalizing it", () => {
18:   expect(
19:     resolvePublishLocation({
20:       path: "./CLI",
21:       workspaceNames: ["cli", "CLI"],
22:     })
23:   ).toStrictEqual({ path: ".", workspace: "CLI" });
24: });
25: 
26: test("keeps a non-workspace suffix as a checkout path", () => {
27:   expect(
28:     ...
gateway · 2026-09-02 11:16:10
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/__tests__/release-revision.js</path>
<type>file</type>
<content>
1: import { expect, test } from "vitest";
2: 
3: const { getReleaseRevision } = require("../release-revision.js");
4: 
5: const REVISION = "7e5ca7ed5581552de066e2a8bc295b8306be38ac";
6: 
7: test("gets the CI-approved revision for the publish repository", () => {
8:   expect(
9:     getReleaseRevision({
10:       repo: "toolkit",
11:       issueBody: `Quick links:
12: - [View check runs](https://github.com/getsentry/toolkit/commit/${REVISION}/checks/)`,
13:     })
14:   ).toBe(REVISION);
15: });
16: 
17: test("gets the CI-approved revision from a CRLF issue body", () => {
18:   expect(
19:     getReleaseRevision({
20:       repo: "toolkit",
21:       issueBody: `Quick links:\r\n- [View check runs](https://github.com/getsentry/toolkit/commit/${REVISION}/checks/)\r\n`,
22:     })
23:   ).toBe(REVISION);
24: });
25: 
26: test("rejects a check-runs link ...
gateway · 2026-09-02 11:16:15
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/details-from-context.js</path>
<type>file</type>
<content>
1: const { parse: parsePublishIssueTitle } = require("./publish-issue-title");
2: 
3: /**
4:  * Matches the entire "Targets" section of a github publish issue body.
5:  */
6: const TARGETS_SECTION_PARSER_REGEX =
7:   /^(?!### Targets$\s)(?: *- \[[ xX]\] \S+\s*$(?:\r?\n)?)+/m;
8: 
9: /**
10:  * Matches all targets of a github publish issue body in a section that was already matched and extracted with `TARGETS_PARSER_REGEX`.
11:  * The "id" of the targets is captured within a capture group.
12:  */
13: const TARGETS_PARSER_REGEX = /^\s*- \[[ x]\] (\S+)/gim;
14: 
15: /**
16:  * Matches checked targets of a github publish issue body in a section that was already matched and extracted with `TARGETS_PARSER_REGEX`.
17:  * The "id" of the targets is captured within a capture group. ...
gateway · 2026-09-02 11:16:27
result
No files found
gateway · 2026-09-02 11:16:32
result
Found 44 matches
/home/byk/Code/getsentry/publish-workspace-acceptance/src/publish/inputs.js:
  Line 3: const { detailsFromContext } = require('../modules/details-from-context');

  Line 6:     const result = await detailsFromContext({


/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/release-revision.js:
  Line 2:   /^- \[View check runs\]\(https:\/\/github\.com\/getsentry\/(?<repo>[A-Za-z0-9_.-]+)\/commit\/(?<revision>[0-9a-f]{40})\/checks\/?\)\r?$/m;

  Line 8:       `Expected a View check runs link for getsentry/${repo} in the publish issue body.`


/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/details-from-context.js:
  Line 21: async function detailsFromContext({ context }) {

  Line 90:   detailsFromContext,


/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/__tests__/release-revision.js:
  Line 11:       issueBody: `Quick links:

  Line 12: - [View check ...
gateway · 2026-09-02 11:16:39
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/.github/workflows</path>
<type>directory</type>
<entries>
auto-approve.yml
ci-poller.yml
cocoapods-keepalive.yml
publish.yml
test.yml

(5 entries)
</entries>
gateway · 2026-09-02 11:16:43
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/.github/workflows/ci-poller.yml</path>
<type>file</type>
<content>
1: name: CI Status Poller
2: 
3: on:
4:   schedule:
5:     - cron: "*/5 * * * *"
6:   workflow_dispatch:
7:     inputs:
8:       attempt:
9:         description: Self-dispatch attempt counter (internal use)
10:         required: false
11:         default: "0"
12: 
13: permissions:
14:   contents: read
15:   issues: read
16: 
17: jobs:
18:   check-ci:
19:     runs-on: ubuntu-latest
20:     environment: production
21:     # Skip entirely (no runner provisioned) when there's nothing to check.
22:     # Set to "true" by ci-pending.yml, reset to "false" here when done.
23:     # Always allow workflow_dispatch for manual recovery.
24:     if: vars.CI_POLLER_HAS_PENDING == 'true' || github.event_name == 'workflow_dispatch'
25:     concurrency:
26:       group: ci-status-poller
27:       cancel-in-progress: false
28:     steps:
29:       # sentry-internal-app token ...
gateway · 2026-09-02 11:16:52
result
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/commands/publish.ts</path>
<type>file</type>
<content>
590:   logger.info(`Running the post-release command...`);
591:   await spawnProcess(sysCommand as string, args as string[], {
592:     env: buildReleaseCommandEnv({ CRAFT_RELEASED_VERSION: newVersion }),
593:   });
594:   return true;
595: }
596: 
597: /**
598:  * Body of 'publish' command
599:  *
600:  * @param argv Command-line arguments
601:  */
602: export async function publishMain(argv: PublishOptions): Promise<any> {
603:   // Get publishing configuration
604:   const config = getConfiguration() || {};
605: 
606:   const newVersion = argv.newVersion;
607: 
608:   logger.info(`Publishing version: "${newVersion}"`);
609: 
610:   const git = await getGitClient();
611: 
612:   // Check for dirty repository state before any git operations
613:   if (argv.noGitChecks) {
614:     logger.info('Not checking the status of the local repository');
615:   } else ...
gateway · 2026-09-02 11:17:01
result
Found 17 matches
/home/byk/Code/getsentry/craft-workspace-action-propagation/src/commands/publish.ts:
  Line 630:   let checkoutTarget;

  Line 631:   let branchName;

  Line 634:     branchName = await getRevisionBranchName(git, rev);

  Line 635:     checkoutTarget = branchName || rev;

  Line 636:     logger.debug('Checking out revision', checkoutTarget);

  Line 637:     await git.checkout(checkoutTarget);

  Line 640:     branchName = `${branchPrefix}/${newVersion}`;

  Line 641:     checkoutTarget = branchName;

  Line 644:       logger.debug('Checking out release branch', branchName);

  Line 645:       await git.checkout(checkoutTarget);

  Line 653:         `Could not find the release branch "${branchName}".\n\n` +

  Line 833:   } else if (!branchName) {

  Line 847:         branchName,

  Line 858:         `Failed to merge release branch "${branchName}" into the target branch.`,

  Line 878:           `  2. Delete the release branch: git push ${argv.remote} --delete ...
gateway · 2026-09-02 11:17:05
result
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/commands/publish.ts</path>
<type>file</type>
<content>
810:     }, !argv.keepDownloads);
811: 
812:     logger.info(' ');
813:   }
814: 
815:   // Check both CLI flag and config option for noMerge
816:   const noMergeConfig = getNoMergeConfig();
817:   const noMerge = argv.noMerge || noMergeConfig.noMerge;
818: 
819:   // Warn if --merge-target was specified but noMerge is true from config
820:   if (noMergeConfig.noMerge && !argv.noMerge && argv.mergeTarget) {
821:     logger.warn(
822:       `The --merge-target option will be ignored because noMerge is enabled via ${noMergeConfig.source === 'auto-detected' ? 'auto-detection (compiled GitHub Action)' : 'config'}.`,
823:     );
824:   }
825: 
826:   if (noMerge) {
827:     const source = argv.noMerge
828:       ? 'CLI option'
829:       : noMergeConfig.source === 'auto-detected'
830:         ? ...
gateway · 2026-09-02 11:17:14
result
Found 66 matches
/home/byk/Code/getsentry/craft-workspace-action-propagation/src/utils/env.ts:
  Line 83:   sanitizeDynamicLinkerEnv,

  Line 84:   sanitizeSpawnEnv,


/home/byk/Code/getsentry/craft-workspace-action-propagation/src/utils/system.ts:
  Line 14: import { sanitizeSpawnEnv } from './dynamicLinkerEnv';

  Line 173:       // Startup already sanitises process.env, so the only way one of

  Line 177:       // propagate them. See sanitizeSpawnEnv() in ../utils/env.ts.

  Line 178:       options.env = sanitizeSpawnEnv(options.env ?? process.env);


/home/byk/Code/getsentry/craft-workspace-action-propagation/src/utils/dynamicLinkerEnv.ts:
  Line 42:  * `process.env`, {@link sanitizeDynamicLinkerEnv} and

  Line 43:  * {@link sanitizeSpawnEnv} become no-ops.

  Line 54: export function sanitizeDynamicLinkerEnv(): void {

  Line 93:  * @param env Environment variables bag to sanitise. The input is

  Line 99: export function sanitizeSpawnEnv(

  Line 108:   const sanitized: ...
gateway · 2026-09-02 11:17:18
result
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/utils/publishState.ts</path>
<type>file</type>
<content>
1: /**
2:  * Helpers for locating Craft's publish-state file in a path that is NOT
3:  * writable by the repository being published.
4:  *
5:  * Background: `craft publish` writes a small JSON file listing targets
6:  * that have completed so a resumed run can skip them. Before this module
7:  * existed, the file lived at `.craft-publish-<version>.json` in the
8:  * project's cwd. That path is inside the repository checkout, so any
9:  * committed file at the same path (or any earlier CI step) could
10:  * pre-populate the "published" set and trick Craft into silently
11:  * skipping targets.
12:  *
13:  * The file now lives under `$XDG_STATE_HOME/craft/` (falling back to
14:  * `$HOME/.local/state/craft/`). The filename is keyed on
15:  * owner, repo, a hash of cwd (to disambiguate monorepo subpaths), and
16:  * the version being published. ...
gateway · 2026-09-02 11:17:24
result
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/action.yml</path>
<type>file</type>
<content>
1: name: 'Craft Prepare Release'
2: description: 'Prepare a new release using Craft'
3: 
4: inputs:
5:   version:
6:     description: >
7:       Version to release. Can be a semver string (e.g., "1.2.3"),
8:       a bump type ("major", "minor", "patch"), or "auto" for automatic detection.
9:     required: false
10:   merge_target:
11:     description: Target branch to merge into. Uses the default branch as a fallback. ...
gateway · 2026-09-02 11:17:36
result
Found 4 matches
/home/byk/Code/getsentry/craft-workspace-action-propagation/src/config.ts:
  Line 67: export const WORKSPACES_MIN_VERSION = '2.29.0';

  Line 186:   if (!isVersionGteMinVersion(config.minVersion, WORKSPACES_MIN_VERSION)) {

  Line 188:       `Using "workspaces" requires minVersion >= ${WORKSPACES_MIN_VERSION} ` +

  Line 210:  *   enforces the `WORKSPACES_MIN_VERSION` gate.
gateway · 2026-09-02 11:17:52
result
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/config.ts</path>
<type>file</type>
<content>
40: } from './status_providers/base';
41: 
42: // TODO support multiple configuration files (one per configuration)
43: export const CONFIG_FILE_NAME = '.craft.yml';
44: 
45: /**
46:  * The default prefix for the release branch.
47:  */
48: export const DEFAULT_RELEASE_BRANCH_NAME = 'release';
49: 
50: /**
51:  * Cached path to the configuration file
52:  */
53: let _configPathCache: string;
54: 
55: /**
56:  * Cached configuration
57:  */
58: let _configCache: CraftProjectConfig;
59: 
60: /**
61:  * The minimum craft version required to use the top-level `workspaces` config.
62:  *
63:  * This is the release the workspaces feature ships in. A dev build of that
64:  * release (e.g. `2.29.0-dev.0`) satisfies it via the pre-release relaxation in
65:  * `checkMinimalConfigVersion`.
66:  */
67: export const WORKSPACES_MIN_VERSION = '2.29.0';
68: 
69: /**
70:  * The name of ...
gateway · 2026-09-02 11:17:58
result
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/package.json</path>
<type>file</type>
<content>
1: {
2:   "name": "@sentry/craft",
3:   "version": "2.31.0-dev.0",
4:   "description": "The universal sentry workflow CLI",
5:   "main": "dist/craft",
6:   "repository": "https://github.com/getsentry/craft",
7:   "author": "Sentry",
8:   "license": "MIT",
9:   "bin": {
10:     "craft": "dist/craft",
11:     "sentry-craft": "dist/craft"
12:   },
13:   "devDependencies": {
14:     "@aws-sdk/client-lambda": "^3.984.0",
15:     "@eslint/js": "^9.17.0",
16:     "@google-cloud/storage": "^7.14.0",
17:     "@octokit/plugin-retry": "^7.1.2",
18:     "@octokit/request-error": "^7.0.0",
19:     "@octokit/rest": "^21.0.2",
20:     "@sentry/esbuild-plugin": "^2.23.0",
21:     "@sentry/node": "^10.27.0",
22:     "@types/async": "^3.0.1",
23:     "@types/aws4": "^1.5.1",
24:     "@types/cli-table": "^0.3.0",
25:     "@types/git-url-parse": "^9.0.0",
26:     "@types/is-ci": "^2.0.0",
27: ...
gateway · 2026-09-02 11:18:02
result
 RUN  v4.1.8 /home/byk/Code/getsentry/craft-workspace-action-propagation


 Test Files  4 passed (4)
      Tests  81 passed (81)
   Start at  11:18:03
   Duration  2.38s (transform 1.19s, setup 0ms, import 3.72s, tests 633ms, environment 1ms)


> @sentry/craft@2.31.0-dev.0 lint /home/byk/Code/getsentry/craft-workspace-action-propagation
> eslint --cache --cache-strategy content


/home/byk/Code/getsentry/craft-workspace-action-propagation/src/commands/publish.ts
  482:14  warning  '_abortError' is defined but never used   @typescript-eslint/no-unused-vars
  499:14  warning  '_abortError' is defined but never used   @typescript-eslint/no-unused-vars
  515:16  warning  '_statusError' is defined but never used  @typescript-eslint/no-unused-vars
  521:18  warning  '_diffError' is defined but never used    @typescript-eslint/no-unused-vars
  527:16  warning  '_abortError' is defined but never used   ...
gateway · 2026-09-02 11:18:13
result
yarn run v1.22.22
$ node scripts/generate-publish-issue-title-parser.js --check
Done in 0.47s.
yarn run v1.22.22
$ /home/byk/Code/getsentry/publish-workspace-acceptance/node_modules/.bin/vitest run src/modules/__tests__/details-from-context.js src/modules/__tests__/publish-workflow.js src/modules/__tests__/publish-location.js src/modules/__tests__/release-revision.js

 RUN  v4.1.0 /home/byk/Code/getsentry/publish-workspace-acceptance


 Test Files  4 passed (4)
      Tests  32 passed (32)
   Start at  11:18:15
   Duration  571ms (transform 114ms, setup 0ms, import 222ms, tests 147ms, environment 1ms)

Done in 1.14s.
yarn run v1.22.22
$ eslint src .github --ignore-pattern '!.github'
Done in 0.99s.
gateway · 2026-09-02 11:18:43
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/pnpm-lock.yaml</path>
<type>file</type>
<content>
1: lockfileVersion: '9.0'
2: 
3: settings:
4:   autoInstallPeers: true
5:   excludeLinksFromLockfile: false
6: 
7: overrides:
8:   undici: ^6.23.0
9: 
10: importers:
11: 
12:   .:
13:     dependencies:
14:       '@actions/core':
15:         specifier: ^2.0.0
16:         version: 2.0.3
17:       '@actions/github':
18:         specifier: ^7.0.0
19:         version: 7.0.0
20:       '@sentry/node':
21:         specifier: ^10.0.0
22:         version: 10.71.0(@opentelemetry/core@2.10.0(@opentelemetry/api@1.9.1))
23:     devDependencies:
24:       eslint:
25:         specifier: ^8.9.0
26:         version: 8.57.1
27:       eslint-config-prettier:
28:         specifier: ^8.3.0
29:         version: 8.10.2(eslint@8.57.1)
30:       eslint-plugin-yml:
31:         specifier: ^0.13.0
32:         version: 0.13.0(eslint@8.57.1)
33:       peggy:
34:         specifier: 5.1.0
35:         version: ...
gateway · 2026-09-02 11:19:03

P0 — FAIL: CI poller cannot process supported legacy titles.
.github/workflows/ci-poller.yml:99 requires owner/repo, although the canonical parser accepts optional getsentry/ (src/modules/publish-issue-title.peggy:11). It also treats JSON workspace titles containing / as part of the repository. Such accepted legacy issues never reach CI approval. Add parser-backed title parsing to the poller and regression coverage.

P1 — FAIL: Untracked pnpm lockfile violates the repository’s Yarn-only lockfile contract.
pnpm-lock.yaml:1 is untracked while the workflow installs with Yarn (.github/workflows/publish.yml:131-132) and the dependency change updates yarn.lock. Remove pnpm-lock.yaml before committing.

PASS: Exact revision flows from the canonical View check runs URL (src/modules/release-revision.js:1-13) through target checkout (.github/workflows/publish.yml:159-167) and craft publish --rev (.github/workflows/publish.yml:239-249). Detached SHAs remain supported (src/commands/publish.ts:632-637,930-943).

PASS: Compact workspace resolution preserves case-sensitive identity and rejects workspace/path coexistence (src/modules/publish-location.js:5-40; action.yml:74-87). Legacy JSON workspace/path coexistence also fails (src/modules/details-from-context.js:53-59).

PASS: Publish-state filename construction matches Craft’s owner/repo, cwd hash, base64url workspace prefix, and version sanitisation contract (.github/workflows/publish.yml:217-235; src/utils/publishState.ts:51-99), with no repository-local state fallback (src/commands/publish.ts:734-746).

PASS: Generated parser is current (scripts/generate-publish-issue-title-parser.js:20-37; src/modules/publish-issue-title.js:1-4). Focused tests, generated-parser check, and YAML lint pass.

DO-NOT-MERGE

gpt-5.6-terra · 2026-09-02 11:19:03 · ~440 tokens

Distillations (1)

Gen 0 2026-09-02 11:15:35 · 333 tokens

Date: Sep 2, 2026 * 🔴 [requested-review] (11:14) User requested a strict read-only adversarial review of uncommitted compact workspace publish-contract changes in both worktrees: `/home/byk/Code/getsentry/craft-workspace-action-propagation` on branch `feat/workspace-action-propagation`, and `/home/byk/Code/getsentry/publish-workspace-acceptance` on branch `feat/workspace-acceptance`. * 🔴 [enfor…