@cat-factory/server 0.227.0 → 0.228.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"resolveRepoTarget.d.ts","sourceRoot":"","sources":["../../src/agents/resolveRepoTarget.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,4BAA4B,EACjC,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,wBAAwB,EAC7B,KAAK,iBAAiB,EACvB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AAMhF,MAAM,WAAW,6BAA6B;IAC5C,sBAAsB,EAAE,IAAI,CAAC,4BAA4B,EAAE,gBAAgB,CAAC,CAAA;IAC5E,wBAAwB,EAAE,IAAI,CAAC,wBAAwB,EAAE,MAAM,CAAC,CAAA;IAChE,eAAe,EAAE,IAAI,CAAC,eAAe,EAAE,KAAK,CAAC,CAAA;IAC7C;;;;OAIG;IACH,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,EAAE,iBAAiB,CAAC,CAAA;IAC7D;;;;;;;;OAQG;IACH,mBAAmB,CAAC,EAAE,gBAAgB,CAAC,UAAU,EAAE,CAAC,CAAA;CACrD;AAuED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,6BAA6B,GAAG,iBAAiB,CA6B7F;AAID;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,UAAU,CAAA;IAClB,mFAAmF;IACnF,OAAO,EAAE,OAAO,CAAA;IAChB;;;;;OAKG;IACH,QAAQ,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAC3D;AAED,yDAAyD;AACzD,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,YAAY,EAAE,CAAA;CAC1B;AAED,MAAM,MAAM,kBAAkB,GAAG,CAC/B,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,MAAM,EACtB,gBAAgB,EAAE,MAAM,EAAE;AAC1B;;;;;;GAMG;AACH,aAAa,CAAC,EAAE,UAAU,KACvB,OAAO,CAAC,mBAAmB,CAAC,CAAA;AAEjC,MAAM,WAAW,8BAA+B,SAAQ,6BAA6B;IACnF;;;;;OAKG;IACH,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,EAAE,iBAAiB,GAAG,mBAAmB,CAAC,CAAA;CACpF;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,8BAA8B,GAAG,kBAAkB,CAoFhG"}
1
+ {"version":3,"file":"resolveRepoTarget.d.ts","sourceRoot":"","sources":["../../src/agents/resolveRepoTarget.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,4BAA4B,EACjC,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,wBAAwB,EAC7B,KAAK,iBAAiB,EACvB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AAMhF,MAAM,WAAW,6BAA6B;IAC5C,sBAAsB,EAAE,IAAI,CAAC,4BAA4B,EAAE,gBAAgB,CAAC,CAAA;IAC5E,wBAAwB,EAAE,IAAI,CAAC,wBAAwB,EAAE,MAAM,CAAC,CAAA;IAChE,eAAe,EAAE,IAAI,CAAC,eAAe,EAAE,KAAK,CAAC,CAAA;IAC7C;;;;OAIG;IACH,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,EAAE,iBAAiB,CAAC,CAAA;IAC7D;;;;;;;;OAQG;IACH,mBAAmB,CAAC,EAAE,gBAAgB,CAAC,UAAU,EAAE,CAAC,CAAA;CACrD;AA6FD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,6BAA6B,GAAG,iBAAiB,CAqB7F;AAID;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,UAAU,CAAA;IAClB,mFAAmF;IACnF,OAAO,EAAE,OAAO,CAAA;IAChB;;;;;OAKG;IACH,QAAQ,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAC3D;AAED,yDAAyD;AACzD,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,YAAY,EAAE,CAAA;CAC1B;AAED,MAAM,MAAM,kBAAkB,GAAG,CAC/B,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,MAAM,EACtB,gBAAgB,EAAE,MAAM,EAAE;AAC1B;;;;;;GAMG;AACH,aAAa,CAAC,EAAE,UAAU,KACvB,OAAO,CAAC,mBAAmB,CAAC,CAAA;AAEjC,MAAM,WAAW,8BAA+B,SAAQ,6BAA6B;IACnF;;;;;OAKG;IACH,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,EAAE,iBAAiB,GAAG,mBAAmB,CAAC,CAAA;CACpF;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,8BAA8B,GAAG,kBAAkB,CAoFhG"}
@@ -49,6 +49,22 @@ function toRepoTarget(installationId, resolved) {
49
49
  ...(serviceDirectory ? { serviceDirectory } : {}),
50
50
  };
51
51
  }
52
+ /**
53
+ * The workspace's whole repo projection, read through the per-workspace cache when one is
54
+ * wired.
55
+ *
56
+ * Shared by BOTH builders below rather than open-coded in each: this is the hot, unbounded read
57
+ * on every dispatch, poll tick and report publish, and a resolver that misses the cache costs a
58
+ * full re-list every time while looking identical at the call site. The installation lookup and
59
+ * the ancestry walk stay live (both cheap / tree-depth-bounded), so a reparent or a service
60
+ * repo-link change needs no invalidation; only the projection's own writes do.
61
+ */
62
+ async function listProjection(deps, workspaceId) {
63
+ const { repoProjectionRepository, repoProjectionCache } = deps;
64
+ return repoProjectionCache
65
+ ? await repoProjectionCache.get(workspaceId, workspaceId, () => repoProjectionRepository.list(workspaceId))
66
+ : await repoProjectionRepository.list(workspaceId);
67
+ }
52
68
  /**
53
69
  * Resolve the repo linked to a running block's enclosing service, shared verbatim by
54
70
  * both runtime facades (Worker D1 + Node Drizzle/Postgres). Repos are linked at the
@@ -67,18 +83,12 @@ function toRepoTarget(installationId, resolved) {
67
83
  * because each wires its own resolver).
68
84
  */
69
85
  export function buildResolveRepoTarget(deps) {
70
- const { installationRepository, repoProjectionRepository, repoProjectionCache } = deps;
86
+ const { installationRepository } = deps;
71
87
  return async (workspaceId, blockId) => {
72
88
  const installation = await installationRepository.getByWorkspace(workspaceId);
73
89
  if (!installation)
74
90
  return null;
75
- // The whole-projection re-list is the hot, unbounded read here — cache it per
76
- // workspace. The installation lookup above and the block ancestry walk below stay
77
- // live (both cheap / tree-depth-bounded), so a reparent or service repo-link
78
- // change needs no cache invalidation; only the projection's own writes do.
79
- const repos = repoProjectionCache
80
- ? await repoProjectionCache.get(workspaceId, workspaceId, () => repoProjectionRepository.list(workspaceId))
81
- : await repoProjectionRepository.list(workspaceId);
91
+ const repos = await listProjection(deps, workspaceId);
82
92
  if (repos.length === 0)
83
93
  return null;
84
94
  const resolved = await walkToRepo(deps, workspaceId, blockId, indexRepos(repos));
@@ -109,7 +119,7 @@ export function buildResolveRepoTarget(deps) {
109
119
  * primary must resolve or we throw, exactly like the singular resolver.
110
120
  */
111
121
  export function buildResolveRepoTargets(deps) {
112
- const { installationRepository, repoProjectionRepository, serviceRepository } = deps;
122
+ const { installationRepository, serviceRepository } = deps;
113
123
  return async (workspaceId, primaryBlockId, involvedFrameIds, primaryTarget) => {
114
124
  // The installation id: reuse the pre-resolved primary target's when provided (skips a second
115
125
  // installation read), else read it here.
@@ -125,7 +135,7 @@ export function buildResolveRepoTargets(deps) {
125
135
  }
126
136
  installationId = installation.installationId;
127
137
  }
128
- const repos = await repoProjectionRepository.list(workspaceId);
138
+ const repos = await listProjection(deps, workspaceId);
129
139
  const index = indexRepos(repos);
130
140
  // The primary checkout: reuse the caller's already-resolved target when given (no ancestry
131
141
  // walk), else walk the primary block's ancestry from scratch.
@@ -1 +1 @@
1
- {"version":3,"file":"resolveRepoTarget.js","sourceRoot":"","sources":["../../src/agents/resolveRepoTarget.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"resolveRepoTarget.js","sourceRoot":"","sources":["../../src/agents/resolveRepoTarget.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
- import type { BlockRepository, GitHubClient, PrReportPublishResult, PrReportTarget, PrVerificationReportPublisher } from '@cat-factory/kernel';
1
+ import type { BlockRepository, GitHubClient, Logger, PrReportPublishResult, PrReportTarget, PrVerificationReportPublisher } from '@cat-factory/kernel';
2
2
  import type { ResolveRepoOrigin, ResolveRepoTarget } from '../agents/ContainerAgentExecutor.js';
3
+ import type { ResolveRepoTargets } from '../agents/resolveRepoTarget.js';
3
4
  export interface GitHubPrReportPublisherDependencies {
4
5
  /**
5
6
  * The ENGINE VCS client (`githubClient ?? gitlabEngineClient` in every facade), so a
@@ -9,8 +10,16 @@ export interface GitHubPrReportPublisherDependencies {
9
10
  githubClient: GitHubClient;
10
11
  /** Resolves the repo (connection + owner/name) the block's work targets. */
11
12
  resolveRepoTarget: ResolveRepoTarget;
12
- /** Reads the block's recorded PR ref (number). */
13
+ /** Reads the block's recorded PR refs (own-service + peers). */
13
14
  blockRepository: BlockRepository;
15
+ /**
16
+ * Resolves EVERY repo a multi-repo run touches, in one call, so a peer PR's report can be
17
+ * addressed (its repo's connection is what the write needs). Optional and absent-tolerant:
18
+ * a deployment with the involved-services coding fan-out switched off never opens a peer PR
19
+ * in the first place, so "no peers resolvable" and "no peers" coincide rather than hiding a
20
+ * report that was owed.
21
+ */
22
+ resolveRepoTargets?: ResolveRepoTargets;
14
23
  /**
15
24
  * Maps a resolved repo to its origin, whose `provider` the report states. Optional, and
16
25
  * defaulted the same way every other clone/dispatch path defaults it (`githubRepoOrigin`), so
@@ -18,10 +27,16 @@ export interface GitHubPrReportPublisherDependencies {
18
27
  * rather than this adapter hard-coding `'github'` behind the engine's back.
19
28
  */
20
29
  resolveRepoOrigin?: ResolveRepoOrigin;
30
+ /**
31
+ * Optional logger for the one best-effort path here: PEER target resolution, which is
32
+ * swallowed so a broken peer linkage cannot cost the own-service report. Wire it, or that
33
+ * swallow leaves no trace and the peers simply stop getting reports.
34
+ */
35
+ logger?: Logger;
21
36
  }
22
37
  /**
23
- * Upserts the engine's verification report onto a block's pull request as a marker-delimited
24
- * section of the PR description (see `docs/initiatives/pr-verification-report.md`, decision
38
+ * Upserts the engine's verification report onto a block's pull requests as a marker-delimited
39
+ * section of each PR description (see `docs/initiatives/pr-verification-report.md`, decision
25
40
  * D1: the markers ARE the section's identity, so the write is idempotent across re-runs,
26
41
  * retries and replayed durable steps with no persisted state at all).
27
42
  *
@@ -29,16 +44,53 @@ export interface GitHubPrReportPublisherDependencies {
29
44
  * as it is right now, so a human who edited the description while the run was in flight keeps
30
45
  * their edit. An unchanged body short-circuits before the remote write.
31
46
  *
32
- * Scoped to the block's OWN-service pull request. A multi-repo task's peer PRs are a phase-2
33
- * item on the initiative tracker reporting the own-service run's evidence onto a peer repo's
34
- * PR without per-repo composition would be misleading, so it is deliberately not done here.
47
+ * On a MULTI-REPO run (service-connections phase 3) the task opens one PR per repo it changed,
48
+ * and every one of them is a target: a reviewer on a connected service's PR is looking at part
49
+ * of this change and is as entitled to the run's evidence as one on the own-service PR. The
50
+ * engine composes a distinct report per target — the own-service-only sections are withheld
51
+ * from a peer's copy rather than copied onto it.
52
+ *
53
+ * **All addressing happens in {@link resolveTargets}, once.** Each target it returns carries the
54
+ * connection and repo its write needs, so `publish` reads no repository and a run with N pull
55
+ * requests costs one resolution per settlement rather than N. That also removes the question
56
+ * `publish` would otherwise have to answer on every call ("is this still the block's PR?") on a
57
+ * hook that fires on every settled step.
35
58
  */
36
59
  export declare class GitHubPrReportPublisher implements PrVerificationReportPublisher {
37
60
  private readonly deps;
38
61
  constructor(deps: GitHubPrReportPublisherDependencies);
39
- resolveTarget(workspaceId: string, blockId: string): Promise<PrReportTarget | null>;
40
- /** The PR number + repo a block's report targets, or null when either is unresolved. */
41
- private resolve;
42
- publish(workspaceId: string, blockId: string, section: string): Promise<PrReportPublishResult>;
62
+ /**
63
+ * Every pull request of the block's run, own-service first, each addressed for writing.
64
+ *
65
+ * ONE block read and ONE repo resolution for the whole set: the own-service target is
66
+ * resolved first (it is needed regardless, and lets the multi-repo resolver skip re-walking
67
+ * the block's ancestry), then a single `resolveRepoTargets` call covers every peer. Resolving
68
+ * per recorded peer PR would be the N+1 this codebase bans.
69
+ */
70
+ resolveTargets(workspaceId: string, blockId: string): Promise<PrReportTarget[]>;
71
+ /**
72
+ * The run's PEER pull requests, addressed through the multi-repo repo resolution.
73
+ *
74
+ * A recorded peer PR is only targetable when two things line up: it carries a `number` (the
75
+ * unit the description write addresses, absent on a ref that was only ever a URL) and its
76
+ * repo is in the resolved checkout set (which is what supplies the connection to write
77
+ * through, and is the platform's own answer about which repos this run touched). A peer that
78
+ * satisfies neither is skipped rather than guessed at — the repo name on a recorded peer PR
79
+ * is harness-reported, and writing a report onto a pull request we cannot confirm the identity
80
+ * of is the one failure mode worse than not writing it.
81
+ */
82
+ private peerTargets;
83
+ /**
84
+ * A resolved repo + PR number as a self-describing target: which PR, in which repo, on which
85
+ * provider, through which connection.
86
+ *
87
+ * The connection names the DEPLOYMENT'S provider, not this class's name: a GitLab deployment
88
+ * reaches this adapter through `vcsBackedGitHubClient`, and a target that claimed `github`
89
+ * would mis-route the day a native GitLab publisher selects its adapter from it. Both providers
90
+ * ride the same numeric connection id, because a GitLab workspace's PAT connect reuses the
91
+ * `github_installations` row this id comes from.
92
+ */
93
+ private describe;
94
+ publish(_workspaceId: string, target: PrReportTarget, section: string): Promise<PrReportPublishResult>;
43
95
  }
44
96
  //# sourceMappingURL=GitHubPrReportPublisher.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"GitHubPrReportPublisher.d.ts","sourceRoot":"","sources":["../../src/github/GitHubPrReportPublisher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACZ,qBAAqB,EACrB,cAAc,EACd,6BAA6B,EAC9B,MAAM,qBAAqB,CAAA;AAE5B,OAAO,KAAK,EAEV,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,qCAAqC,CAAA;AAG5C,MAAM,WAAW,mCAAmC;IAClD;;;;OAIG;IACH,YAAY,EAAE,YAAY,CAAA;IAC1B,4EAA4E;IAC5E,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,kDAAkD;IAClD,eAAe,EAAE,eAAe,CAAA;IAChC;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;CACtC;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,uBAAwB,YAAW,6BAA6B;IAC/D,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAjC,YAA6B,IAAI,EAAE,mCAAmC,EAAI;IAEpE,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAMxF;IAED,wFAAwF;YAC1E,OAAO;IAWf,OAAO,CACX,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,qBAAqB,CAAC,CAoBhC;CACF"}
1
+ {"version":3,"file":"GitHubPrReportPublisher.d.ts","sourceRoot":"","sources":["../../src/github/GitHubPrReportPublisher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,eAAe,EACf,YAAY,EACZ,MAAM,EACN,qBAAqB,EACrB,cAAc,EACd,6BAA6B,EAE9B,MAAM,qBAAqB,CAAA;AAG5B,OAAO,KAAK,EAEV,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,qCAAqC,CAAA;AAC5C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AAIxE,MAAM,WAAW,mCAAmC;IAClD;;;;OAIG;IACH,YAAY,EAAE,YAAY,CAAA;IAC1B,4EAA4E;IAC5E,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,gEAAgE;IAChE,eAAe,EAAE,eAAe,CAAA;IAChC;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,kBAAkB,CAAA;IACvC;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;IACrC;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAwBD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,uBAAwB,YAAW,6BAA6B;IAC/D,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAjC,YAA6B,IAAI,EAAE,mCAAmC,EAAI;IAE1E;;;;;;;OAOG;IACG,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAiCpF;IAED;;;;;;;;;;OAUG;YACW,WAAW;IAuCzB;;;;;;;;;OASG;IACH,OAAO,CAAC,QAAQ;IAiBV,OAAO,CACX,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,qBAAqB,CAAC,CAehC;CACF"}
@@ -1,8 +1,26 @@
1
- import { spliceManagedSection } from '@cat-factory/kernel';
1
+ import { noopLogger, runBestEffort, spliceManagedSection } from '@cat-factory/kernel';
2
+ import { allPullRequests } from '@cat-factory/contracts';
2
3
  import { githubRepoOrigin } from '../agents/containerAgentBody.js';
4
+ import { splitRepo } from './repoFullName.js';
3
5
  /**
4
- * Upserts the engine's verification report onto a block's pull request as a marker-delimited
5
- * section of the PR description (see `docs/initiatives/pr-verification-report.md`, decision
6
+ * The numeric connection handle the engine VCS client takes, recovered from a target's neutral
7
+ * {@link VcsConnectionRef}.
8
+ *
9
+ * Not kernel's `githubInstallationId`, which refuses a non-GitHub connection: this adapter serves
10
+ * a GitLab deployment too (through `vcsBackedGitHubClient`), and there the same numeric id is the
11
+ * workspace's `github_installations` row that holds its PAT. A non-numeric id is a wiring bug and
12
+ * throws, which the engine records as a failed publish rather than a run failure.
13
+ */
14
+ function connectionId(connection) {
15
+ const id = Number(connection.connectionId);
16
+ if (!Number.isInteger(id)) {
17
+ throw new Error(`PR report target carries an unusable connection id "${connection.connectionId}".`);
18
+ }
19
+ return id;
20
+ }
21
+ /**
22
+ * Upserts the engine's verification report onto a block's pull requests as a marker-delimited
23
+ * section of each PR description (see `docs/initiatives/pr-verification-report.md`, decision
6
24
  * D1: the markers ARE the section's identity, so the write is idempotent across re-runs,
7
25
  * retries and replayed durable steps with no persisted state at all).
8
26
  *
@@ -10,51 +28,135 @@ import { githubRepoOrigin } from '../agents/containerAgentBody.js';
10
28
  * as it is right now, so a human who edited the description while the run was in flight keeps
11
29
  * their edit. An unchanged body short-circuits before the remote write.
12
30
  *
13
- * Scoped to the block's OWN-service pull request. A multi-repo task's peer PRs are a phase-2
14
- * item on the initiative tracker reporting the own-service run's evidence onto a peer repo's
15
- * PR without per-repo composition would be misleading, so it is deliberately not done here.
31
+ * On a MULTI-REPO run (service-connections phase 3) the task opens one PR per repo it changed,
32
+ * and every one of them is a target: a reviewer on a connected service's PR is looking at part
33
+ * of this change and is as entitled to the run's evidence as one on the own-service PR. The
34
+ * engine composes a distinct report per target — the own-service-only sections are withheld
35
+ * from a peer's copy rather than copied onto it.
36
+ *
37
+ * **All addressing happens in {@link resolveTargets}, once.** Each target it returns carries the
38
+ * connection and repo its write needs, so `publish` reads no repository and a run with N pull
39
+ * requests costs one resolution per settlement rather than N. That also removes the question
40
+ * `publish` would otherwise have to answer on every call ("is this still the block's PR?") on a
41
+ * hook that fires on every settled step.
16
42
  */
17
43
  export class GitHubPrReportPublisher {
18
44
  deps;
19
45
  constructor(deps) {
20
46
  this.deps = deps;
21
47
  }
22
- async resolveTarget(workspaceId, blockId) {
23
- const resolved = await this.resolve(workspaceId, blockId);
24
- if (!resolved)
25
- return null;
26
- const { number, repo } = resolved;
27
- const origin = (this.deps.resolveRepoOrigin ?? githubRepoOrigin)(repo);
28
- return { prNumber: number, repo: `${repo.owner}/${repo.name}`, provider: origin.provider };
29
- }
30
- /** The PR number + repo a block's report targets, or null when either is unresolved. */
31
- async resolve(workspaceId, blockId) {
48
+ /**
49
+ * Every pull request of the block's run, own-service first, each addressed for writing.
50
+ *
51
+ * ONE block read and ONE repo resolution for the whole set: the own-service target is
52
+ * resolved first (it is needed regardless, and lets the multi-repo resolver skip re-walking
53
+ * the block's ancestry), then a single `resolveRepoTargets` call covers every peer. Resolving
54
+ * per recorded peer PR would be the N+1 this codebase bans.
55
+ */
56
+ async resolveTargets(workspaceId, blockId) {
32
57
  const block = await this.deps.blockRepository.get(workspaceId, blockId);
33
- const number = block?.pullRequest?.number;
34
- if (number == null)
35
- return null;
36
- const repo = await this.deps.resolveRepoTarget(workspaceId, blockId);
37
- return repo ? { number, repo } : null;
58
+ if (!block)
59
+ return [];
60
+ // `allPullRequests` is the single source of truth for "every PR this task opened", own
61
+ // first then peers — the same enumeration the CI gate aggregates over. The own-service
62
+ // entry is the one carrying no `repo` (its repo is the task's own service).
63
+ const prs = allPullRequests(block);
64
+ if (prs.length === 0)
65
+ return [];
66
+ const targets = [];
67
+ // The own-service PR FIRST when it exists: the engine reads the peer reports' back-pointer
68
+ // off the head of this list rather than re-resolving it. Matched on an ABSENT `repo` rather
69
+ // than a falsy one, and only when the block records an own PR at all: a peer whose recorded
70
+ // repo is the empty string is unaddressable, not the own-service one.
71
+ const own = block.pullRequest ? prs.find((pr) => pr.repo === undefined) : undefined;
72
+ const ownRepo = own ? await this.deps.resolveRepoTarget(workspaceId, blockId) : null;
73
+ if (own?.ref.number != null && ownRepo) {
74
+ targets.push(this.describe(ownRepo, own.ref.number, { role: 'own', url: own.ref.url }));
75
+ }
76
+ // BEST-EFFORT, and deliberately so: the multi-repo resolver THROWS on a workspace with no
77
+ // installation or an involved frame that lost its repo linkage, and letting that propagate
78
+ // would mean one broken peer linkage costs the OWN-SERVICE report too — the one a reviewer is
79
+ // most likely reading. The same "a failure on one target does not cost the others" rule the
80
+ // engine applies when publishing, applied one step earlier where the targets are found.
81
+ const peers = await runBestEffort(this.deps.logger ?? noopLogger, 'pr-report peer target resolution', () => this.peerTargets(workspaceId, blockId, block, prs, ownRepo), { workspaceId, blockId });
82
+ targets.push(...(peers ?? []));
83
+ return targets;
38
84
  }
39
- async publish(workspaceId, blockId, section) {
40
- // Resolved through the SAME helper as `resolveTarget`, so the two can never disagree about
41
- // which PR is "the block's". `publish` re-resolves rather than trusting a target handed in:
42
- // it is a port method other callers may reach directly, and the write must be self-contained.
43
- const block = await this.deps.blockRepository.get(workspaceId, blockId);
44
- const number = block?.pullRequest?.number;
45
- if (number == null)
46
- return { published: false, skipped: 'no_pull_request' };
47
- const repo = await this.deps.resolveRepoTarget(workspaceId, blockId);
48
- if (!repo)
49
- return { published: false, skipped: 'no_repo', prNumber: number };
50
- const ref = { owner: repo.owner, repo: repo.name };
85
+ /**
86
+ * The run's PEER pull requests, addressed through the multi-repo repo resolution.
87
+ *
88
+ * A recorded peer PR is only targetable when two things line up: it carries a `number` (the
89
+ * unit the description write addresses, absent on a ref that was only ever a URL) and its
90
+ * repo is in the resolved checkout set (which is what supplies the connection to write
91
+ * through, and is the platform's own answer about which repos this run touched). A peer that
92
+ * satisfies neither is skipped rather than guessed at — the repo name on a recorded peer PR
93
+ * is harness-reported, and writing a report onto a pull request we cannot confirm the identity
94
+ * of is the one failure mode worse than not writing it.
95
+ */
96
+ async peerTargets(workspaceId, blockId, block, prs, ownRepo) {
97
+ // Every entry that names a repo: the complement of the own-service one above.
98
+ const peers = prs.filter((pr) => pr.repo !== undefined);
99
+ const resolveAll = this.deps.resolveRepoTargets;
100
+ if (!peers.length || !resolveAll)
101
+ return [];
102
+ // The frames to resolve: the task's declared involved services, plus any frame a recorded
103
+ // peer PR attributes itself to. The union rather than either alone, because the declared
104
+ // list is what the run fanned out over while the recorded PRs are what it actually opened,
105
+ // and a peer whose frame left the task's involved list still has an open PR owed a report.
106
+ const frameIds = [
107
+ ...new Set([
108
+ ...(block.involvedServiceIds ?? []),
109
+ ...peers.map((p) => p.frameId).filter((id) => !!id),
110
+ ]),
111
+ ];
112
+ const resolved = await resolveAll(workspaceId, blockId, frameIds, ownRepo ?? undefined);
113
+ const byRepo = new Map(resolved.checkouts.map((c) => [`${c.target.owner}/${c.target.name}`, c.target]));
114
+ const out = [];
115
+ for (const peer of peers) {
116
+ const number = peer.ref.number;
117
+ const repo = peer.repo ? byRepo.get(peer.repo) : undefined;
118
+ if (number == null || !repo)
119
+ continue;
120
+ out.push(this.describe(repo, number, { role: 'peer', frameId: peer.frameId, url: peer.ref.url }));
121
+ }
122
+ return out;
123
+ }
124
+ /**
125
+ * A resolved repo + PR number as a self-describing target: which PR, in which repo, on which
126
+ * provider, through which connection.
127
+ *
128
+ * The connection names the DEPLOYMENT'S provider, not this class's name: a GitLab deployment
129
+ * reaches this adapter through `vcsBackedGitHubClient`, and a target that claimed `github`
130
+ * would mis-route the day a native GitLab publisher selects its adapter from it. Both providers
131
+ * ride the same numeric connection id, because a GitLab workspace's PAT connect reuses the
132
+ * `github_installations` row this id comes from.
133
+ */
134
+ describe(repo, prNumber, scope) {
135
+ const origin = (this.deps.resolveRepoOrigin ?? githubRepoOrigin)(repo);
136
+ return {
137
+ prNumber,
138
+ repo: `${repo.owner}/${repo.name}`,
139
+ provider: origin.provider,
140
+ connection: { provider: origin.provider, connectionId: String(repo.installationId) },
141
+ role: scope.role,
142
+ frameId: scope.frameId ?? null,
143
+ url: scope.url ?? null,
144
+ };
145
+ }
146
+ async publish(_workspaceId, target, section) {
147
+ // No resolution here at all: the target names its own pull request, repo and connection,
148
+ // and the caller composed `section` for exactly that. See the class doc.
149
+ const installationId = connectionId(target.connection);
150
+ const [owner, name] = splitRepo(target.repo);
151
+ const ref = { owner, repo: name };
152
+ const number = target.prNumber;
51
153
  const gh = this.deps.githubClient;
52
- const current = await gh.getPullRequestBody(repo.installationId, ref, number);
154
+ const current = await gh.getPullRequestBody(installationId, ref, number);
53
155
  const next = spliceManagedSection(current, section);
54
156
  if (next === (current ?? '')) {
55
157
  return { published: false, skipped: 'unchanged', prNumber: number };
56
158
  }
57
- await gh.updatePullRequest(repo.installationId, ref, number, { body: next });
159
+ await gh.updatePullRequest(installationId, ref, number, { body: next });
58
160
  return { published: true, prNumber: number };
59
161
  }
60
162
  }
@@ -1 +1 @@
1
- {"version":3,"file":"GitHubPrReportPublisher.js","sourceRoot":"","sources":["../../src/github/GitHubPrReportPublisher.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAM1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAA;AAsBlE;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,uBAAuB;IACL,IAAI;IAAjC,YAA6B,IAAyC;oBAAzC,IAAI;IAAwC,CAAC;IAE1E,KAAK,CAAC,aAAa,CAAC,WAAmB,EAAE,OAAe;QACtD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;QACzD,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAA;QAC1B,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAA;QACjC,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,IAAI,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAA;QACtE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAA;IAC5F,CAAC;IAED,wFAAwF;IAChF,KAAK,CAAC,OAAO,CACnB,WAAmB,EACnB,OAAe;QAEf,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;QACvE,MAAM,MAAM,GAAG,KAAK,EAAE,WAAW,EAAE,MAAM,CAAA;QACzC,IAAI,MAAM,IAAI,IAAI;YAAE,OAAO,IAAI,CAAA;QAC/B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;QACpE,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;IACvC,CAAC;IAED,KAAK,CAAC,OAAO,CACX,WAAmB,EACnB,OAAe,EACf,OAAe;QAEf,2FAA2F;QAC3F,4FAA4F;QAC5F,8FAA8F;QAC9F,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;QACvE,MAAM,MAAM,GAAG,KAAK,EAAE,WAAW,EAAE,MAAM,CAAA;QACzC,IAAI,MAAM,IAAI,IAAI;YAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAA;QAE3E,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;QACpE,IAAI,CAAC,IAAI;YAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAA;QAE5E,MAAM,GAAG,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAA;QAClD,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,CAAA;QACjC,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC,cAAc,EAAE,GAAG,EAAE,MAAM,CAAC,CAAA;QAC7E,MAAM,IAAI,GAAG,oBAAoB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;QACnD,IAAI,IAAI,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,CAAC;YAC7B,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAA;QACrE,CAAC;QACD,MAAM,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,cAAc,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;QAC5E,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAA;IAC9C,CAAC;CACF"}
1
+ {"version":3,"file":"GitHubPrReportPublisher.js","sourceRoot":"","sources":["../../src/github/GitHubPrReportPublisher.ts"],"names":[],"mappings":"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"}