Dashboard › craft › Session 1IwF6F9erLuY
1IwF6F9erLuYXPVGePerform a strict read-only final adversarial review of the CURRENT uncommitted compact workspace publish-contract changes in BOTH worktrees:
Do not modify files. Inspect complete diffs and relevant current source/tests/workflows. Validate specifically:
Return only prioritized file:line findings with PASS/FAIL and conclude MERGE or DO-NOT-MERGE. No generic summary.
<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>
<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 README.md scripts/ src/ vitest.config.js yarn.lock (15 entries) </entries>
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/ action.yml | 18 ++--- docs/src/content/docs/targets/github.md | 36 ++++++++- src/__tests__/action.test.ts | 135 ++++++++++++++++++++++++++++--- src/__tests__/config.test.ts | 136 +++++++++++++++++++++++--------- 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 | 66 +++++++++++----- 9 files changed, 389 insertions(+), 97 deletions(-) diff --git a/action.yml b/action.yml index 6344db2..b2de7f1 100644 --- ...
M .github/workflows/ci-poller.yml 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 ?? scripts/ ?? src/modules/__tests__/ci-poller-input.js ?? src/modules/__tests__/publish-location.js ?? src/modules/__tests__/release-revision.js ?? src/modules/ci-poller-input.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-ci-poller-input.js ?? src/publish/resolve-location.js ?? src/publish/resolve-release-revision.js .github/workflows/ci-poller.yml | 32 ++++++-------- .github/workflows/publish.yml | 59 +++++++++++++------------ docs/publish-issue-format.md | 62 ...
/home/byk/Code/getsentry/craft-workspace-action-propagation/src/commands/workspace.ts
/home/byk/Code/getsentry/craft-workspace-action-propagation/src/commands/workspace_cmds/__tests__/list.test.ts /home/byk/Code/getsentry/craft-workspace-action-propagation/src/commands/workspace_cmds/list.ts
/home/byk/Code/getsentry/publish-workspace-acceptance/scripts/generate-publish-issue-title-parser.js
/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/ci-poller-input.js /home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/release-revision.js /home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/publish-location.js /home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/publish-issue-title.js /home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/publish-issue-title.peggy /home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/__tests__/ci-poller-input.js /home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/__tests__/release-revision.js /home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/__tests__/publish-location.js
<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). ...
<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>
<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: ...
<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: = ...
<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: ? ...
<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: ...
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/ci-poller-input.js</path>
<type>file</type>
<content>
1: const { parse: parsePublishIssueTitle } = require("./publish-issue-title");
2: const {
3: getReleaseRevision,
4: updateReleaseRevision,
5: } = require("./release-revision");
6:
7: function getCiPollerInput({ title, issueBody, revision }) {
8: let parsedTitle;
9: try {
10: parsedTitle = parsePublishIssueTitle(title);
11: } catch {
12: throw new Error(`Invalid publish issue title: '${title}'`);
13: }
14: const { repo, version } = parsedTitle;
15: const currentRevision = getReleaseRevision({ issueBody, repo });
16:
17: return {
18: ...(revision
19: ? { issueBody: updateReleaseRevision({ issueBody, repo, revision }) }
20: : {}),
21: repo: `getsentry/${repo}`,
22: revision: currentRevision,
23: version,
24: };
25: }
26:
27: module.exports = { getCiPollerInput };
(End of file - total 27 lines)
</content>
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/release-revision.js</path>
<type>file</type>
<content>
1: const CHECK_RUNS_LINK =
2: /^Quick links:\r?\n(?:[ \t]*\r?\n)?[ \t]*- \[View changes\]\([^\r\n]+\)\r?\n[ \t]*- \[View check runs\]\(https:\/\/github\.com\/getsentry\/(?<repo>[A-Za-z0-9_.-]+)\/commit\/(?<revision>[0-9a-f]{40})\/checks\/?\)\r?$/m;
3: const CHECK_RUNS_LINK_COUNT = /^[ \t]*- \[View check runs\]\(/gm;
4:
5: function getReleaseRevision({ issueBody, repo }) {
6: if ((issueBody.match(CHECK_RUNS_LINK_COUNT) || []).length !== 1) {
7: throw new Error(
8: `Expected exactly one View check runs link in Quick links for getsentry/${repo}.`
9: );
10: }
11:
12: const match = issueBody.match(CHECK_RUNS_LINK);
13: if (!match?.groups || match.groups.repo !== repo) {
14: throw new Error(
15: `Expected a View check runs link for getsentry/${repo} in the publish issue body.`
16: );
17: }
18:
19: return ...
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/src/publish/resolve-ci-poller-input.js</path>
<type>file</type>
<content>
1: const { getCiPollerInput } = require("../modules/ci-poller-input");
2:
3: process.stdout.write(
4: JSON.stringify(
5: getCiPollerInput({
6: issueBody: process.env.PUBLISH_ISSUE_BODY || "",
7: title: process.env.PUBLISH_TITLE || "",
8: revision: process.env.PUBLISH_REVISION || "",
9: })
10: )
11: );
(End of file - total 11 lines)
</content>
<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>
<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>
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/__tests__/ci-poller-input.js</path>
<type>file</type>
<content>
1: import { readFileSync } from "fs";
2: import { join } from "path";
3:
4: import { expect, test } from "vitest";
5:
6: const { getCiPollerInput } = require("../ci-poller-input.js");
7:
8: const REVISION = "7e5ca7ed5581552de066e2a8bc295b8306be38ac";
9: const issueBody = `Quick links:
10: - [View changes](https://github.com/getsentry/toolkit/compare/1.2.2...release/1.2.3)
11: - [View check runs](https://github.com/getsentry/toolkit/commit/${REVISION}/checks/)`;
12:
13: test("parses compact and legacy workspace publish titles", () => {
14: expect(
15: getCiPollerInput({
16: issueBody,
17: title: "publish: getsentry/toolkit/cli@1.2.3",
18: })
19: ).toEqual({
20: repo: "getsentry/toolkit",
21: revision: REVISION,
22: version: "1.2.3",
23: });
24:
25: expect(
26: getCiPollerInput({
27: issueBody,
28: ...
<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 {
4: getReleaseRevision,
5: updateReleaseRevision,
6: } = require("../release-revision.js");
7:
8: const REVISION = "7e5ca7ed5581552de066e2a8bc295b8306be38ac";
9:
10: test("gets the CI-approved revision for the publish repository", () => {
11: expect(
12: getReleaseRevision({
13: repo: "toolkit",
14: issueBody: `Quick links:
15: - [View changes](https://github.com/getsentry/toolkit/compare/1.2.2...release/1.2.3)
16: - [View check runs](https://github.com/getsentry/toolkit/commit/${REVISION}/checks/)`,
17: })
18: ).toBe(REVISION);
19: });
20:
21: test("gets the CI-approved revision from a CRLF issue body", () => {
22: expect(
23: getReleaseRevision({
24: repo: "toolkit",
25: issueBody: `Quick links:\r\n- [View ...
<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: ...
<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 ...
<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 ...
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/__tests__/details-from-context.js</path>
<type>file</type>
<content>
1: import { test, expect } from "vitest";
2:
3: const { detailsFromContext } = require("../details-from-context.js");
4:
5: const inputsArgs = {
6: context: {
7: repo: { owner: "getsentry", repo: "publish" },
8: payload: {
9: issue: {
10: number: "223",
11: title: "publish: getsentry/sentry@21.3.1",
12: body: `
13: Requested by: @BYK
14:
15: Merge target: custom-branch
16:
17: Quick links:
18: - [View changes](https://github.com/getsentry/sentry/compare/21.3.0...refs/heads/releases/21.3.1)
19: - [View check runs](https://github.com/getsentry/sentry/commit/7e5ca7ed5581552de066e2a8bc295b8306be38ac/checks/)
20:
21: Assign the **accepted** label to this issue to approve the release. ...
> @sentry/craft@2.31.0-dev.0 test /home/byk/Code/getsentry/craft-workspace-action-propagation > vitest run -- --runInBand RUN v4.1.8 /home/byk/Code/getsentry/craft-workspace-action-propagation [info] [[target/github]] No previous release found [info] [[target/github]] Deleted orphaned draft release: v1.0.0 [info] [[target/github]] No previous release found [warn] [[target/github]] Failed to clean up release "v1.0.0": Error: Cleanup failed [info] [[target/github]] No previous release found [info] [[target/github]] No previous release found [info] [[target/github]] Release for tag "1.0.0" already exists and is published. Skipping GitHub release creation (likely from a previous run). [info] [[target/github]] No previous release found [info] [[target/github]] createRelease returned 422 for tag "1.0.0". Looking for a leftover draft release to clean up... [info] [[target/github]] Deleting leftover draft release (id=789) for tag "1.0.0"... ...
yarn run v1.22.22 $ yarn check:generated && vitest run $ node scripts/generate-publish-issue-title-parser.js --check [1m[46m RUN [49m[22m [36mv4.1.0 [39m[90m/home/byk/Code/getsentry/publish-workspace-acceptance[39m [2m Test Files [22m [1m[32m9 passed[39m[22m[90m (9)[39m [2m Tests [22m [1m[32m54 passed[39m[22m[90m (54)[39m [2m Start at [22m 13:21:46 [2m Duration [22m 1.73s[2m (transform 266ms, setup 0ms, import 1.28s, tests 294ms, environment 1ms)[22m Done in 2.93s.
Found 1 matches
/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/__tests__/ci-poller-input.js:
Line 13: test("parses compact and legacy workspace publish titles", () => {
Found 18 matches
/home/byk/Code/getsentry/craft-workspace-action-propagation/src/utils/publishState.ts:
Line 34: * `scripts/print-publish-state-path.ts` if present) that needs to
Line 71: * `publish-state-<owner>-<repo>-<sha1(cwd)[:12]>-<version>.json`
Line 76: * `publish-state-<sha256(cwd)[:16]>-<version>.json`
Line 90: ? `workspace-${Buffer.from(workspace).toString('base64url')}-`
Line 95: return `publish-state-${owner}-${repo}-${shortCwdHash(cwd)}-${workspacePrefix}${safeVersion}.json`;
Line 98: return `publish-state-${cwdDigest}-${workspacePrefix}${safeVersion}.json`;
/home/byk/Code/getsentry/craft-workspace-action-propagation/src/utils/__tests__/publishState.test.ts:
Line 52: /^publish-state-getsentry-craft-[0-9a-f]{12}-1\.2\.3\.json$/,
Line 84: expect(cli).toMatch(/-workspace-Y2xp-1\.2\.3\.json$/);
Line 85: expect(mcp).toMatch(/-workspace-bWNw-1\.2\.3\.json$/);
Line 107: ...
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/utils/publishState.ts</path>
<type>file</type>
<content>
60: * disambiguate monorepo subpaths so `packages/foo` and `packages/bar`
61: * get separate state files even at the same version.
62: */
63: function shortCwdHash(cwd: string): string {
64: return createHash('sha1').update(cwd).digest('hex').slice(0, 12);
65: }
66:
67: /**
68: * Builds the filename for the publish-state file.
69: *
70: * With a resolvable GitHub config:
71: * `publish-state-<owner>-<repo>-<sha1(cwd)[:12]>-<version>.json`
72: *
73: * Without GitHub config (offline / non-GitHub test harnesses) the
74: * filename falls back to a cwd-hash-only form so Craft still refuses
75: * to write into the repo itself:
76: * `publish-state-<sha256(cwd)[:16]>-<version>.json`
77: *
78: * When a release workspace is selected, its losslessly encoded name is
79: * included before the version so independent release units in the same
80: * ...
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/ src/commands/workspace.ts src/commands/workspace_cmds/__tests__/list.test.ts src/commands/workspace_cmds/list.ts action.yml docs/src/content/docs/targets/github.md src/__tests__/action.test.ts src/__tests__/config.test.ts src/commands/__tests__/publish.test.ts src/commands/publish.ts src/config.ts src/index.ts src/schemas/project_config.ts
M .github/workflows/ci-poller.yml 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 ?? scripts/ ?? src/modules/__tests__/ci-poller-input.js ?? src/modules/__tests__/publish-location.js ?? src/modules/__tests__/release-revision.js ?? src/modules/ci-poller-input.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-ci-poller-input.js ?? src/publish/resolve-location.js ?? ...
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/post-workflow-details.js</path>
<type>file</type>
<content>
1: async function postWorkflowDetails({context, octokit}) {
2: const { repo: publishRepo, runId: run_id } = context;
3: const { number: issue_number } = context.payload.issue;
4:
5: const workflowInfo = (
6: await octokit.rest.actions.getWorkflowRun({
7: ...publishRepo,
8: run_id,
9: })
10: ).data;
11:
12: return octokit.rest.issues.createComment({
13: ...publishRepo,
14: issue_number,
15: body: `Publishing: [run#${run_id}](${workflowInfo.html_url})`,
16: });
17: }
18:
19: module.exports = postWorkflowDetails;
(End of file - total 19 lines)
</content>
MUST-FIX — FAIL: Legacy JSON workspace paths are accepted by Publish but rejected by Craft. src/modules/publish-location.js:53-60 preserves workspace: "cli/v2", while Craft rejects that configured key at src/schemas/project_config.ts:221-232 and action input at action.yml:82-85. Existing legacy title requests cannot complete.
MUST-FIX — FAIL: The controller posts “Publishing” before validating the canonical CI revision. .github/workflows/publish.yml:138-149 runs post-workflow-details.js before resolve-release-revision.js; malformed or decoy Quick links cause a side effect before failure.
FAIL (commit hygiene): Unrelated newline-only changes exist in src/modules/post-workflow-details.js:18 and src/publish/inputs.js:10.
PASS: Title grammar supports optional getsentry/, compact suffixes, and legacy JSON workspace values: src/modules/publish-issue-title.peggy:10-45; exercised at src/modules/__tests__/ci-poller-input.js:13-35.
PASS: CI poller checks out controller code and uses the generated parser: .github/workflows/ci-poller.yml:51-54,100-107.
PASS: Canonical Quick links validation rejects duplicate and decoy check-runs links and requires the title repository: src/modules/release-revision.js:1-27; tests at src/modules/__tests__/release-revision.js:42-117.
PASS: The approved revision flows through checkout, discovery, resolved location, state, and craft publish --rev: .github/workflows/publish.yml:144-248; ordering test at src/modules/__tests__/publish-workflow.js:63-96.
PASS: Compact discovery rejects . and ..: src/modules/publish-location.js:35-42; regression coverage at src/modules/__tests__/publish-location.js:92-99. Craft schema/action also reject them at src/schemas/project_config.ts:221-232 and action.yml:82-85.
PASS: State parity uses a feasible resolved compact location: src/modules/__tests__/publish-workflow.js:105-123. ...
Date: Sep 2, 2026 * 🔴 [requested-read-only-review] (13:18) User requested a strict read-only final adversarial review of current uncommitted compact workspace publish-contract changes in both worktrees: `/home/byk/Code/getsentry/craft-workspace-action-propagation` and `/home/byk/Code/getsentry/publish-workspace-acceptance`; instructed not to modify files. * 🔴 (13:18) User required inspection of…