diff --git a/dashboards/tracker-web/src/app/dashboard/fleet/jobs/[id]/page.tsx b/dashboards/tracker-web/src/app/dashboard/fleet/jobs/[id]/page.tsx
index 01957990..1f0c9268 100644
--- a/dashboards/tracker-web/src/app/dashboard/fleet/jobs/[id]/page.tsx
+++ b/dashboards/tracker-web/src/app/dashboard/fleet/jobs/[id]/page.tsx
@@ -404,15 +404,28 @@ export default function FleetJobDetailPage() {
{r.prUrl ? (
-
- PR ↗
-
+
+
+ PR ↗
+
+ {r.prState && (
+
+ {r.prState}
+
+ )}
+
) : (
'—'
)}
diff --git a/dashboards/tracker-web/src/lib/fleet-client.ts b/dashboards/tracker-web/src/lib/fleet-client.ts
index dd009f16..5e041b57 100644
--- a/dashboards/tracker-web/src/lib/fleet-client.ts
+++ b/dashboards/tracker-web/src/lib/fleet-client.ts
@@ -65,6 +65,7 @@ export interface FleetRun {
insights: FleetRunInsights;
prUrl?: string;
branch?: string;
+ prState?: 'open' | 'merged';
}
export interface FleetEvent {
diff --git a/services/platform-service/src/modules/fleet/coordinator.ts b/services/platform-service/src/modules/fleet/coordinator.ts
index 46765df5..6bc0d692 100644
--- a/services/platform-service/src/modules/fleet/coordinator.ts
+++ b/services/platform-service/src/modules/fleet/coordinator.ts
@@ -895,6 +895,7 @@ export async function releaseLease(
result?: FleetRunDoc['result'];
prUrl?: string;
branch?: string;
+ prState?: FleetRunDoc['prState'];
}
): Promise> {
const job = await repo.getJob(jobId, productId);
@@ -906,13 +907,14 @@ export async function releaseLease(
if (!res.ok) return { ok: false, reason: 'conflict' };
if (stage) await repo.revUpdateJob(jobId, productId, job.rev, { stage });
// Record the factory's reported metrics + outcome + PR deliverable on the run.
- if (report?.insights || report?.result || report?.prUrl || report?.branch) {
+ if (report?.insights || report?.result || report?.prUrl || report?.branch || report?.prState) {
const runId = `${jobId}:run:${job.attempts}`;
await repo.updateRun(runId, jobId, {
...(report.insights ? { insights: report.insights } : {}),
...(report.result ? { result: report.result } : {}),
...(report.prUrl ? { prUrl: report.prUrl } : {}),
...(report.branch ? { branch: report.branch } : {}),
+ ...(report.prState ? { prState: report.prState } : {}),
endedAt: new Date().toISOString(),
});
}
diff --git a/services/platform-service/src/modules/fleet/routes.ts b/services/platform-service/src/modules/fleet/routes.ts
index a9576afd..c26fe1f7 100644
--- a/services/platform-service/src/modules/fleet/routes.ts
+++ b/services/platform-service/src/modules/fleet/routes.ts
@@ -263,6 +263,7 @@ export async function fleetRoutes(app: FastifyInstance) {
result: parsed.data.result,
prUrl: parsed.data.prUrl,
branch: parsed.data.branch,
+ prState: parsed.data.prState,
});
if (!res.ok) {
if (res.reason === 'not_found') throw new NotFoundError('Job or lease not found');
diff --git a/services/platform-service/src/modules/fleet/types.ts b/services/platform-service/src/modules/fleet/types.ts
index f84add31..62332dba 100644
--- a/services/platform-service/src/modules/fleet/types.ts
+++ b/services/platform-service/src/modules/fleet/types.ts
@@ -227,6 +227,7 @@ export const FleetRunDocSchema = z.object({
/** PR deliverable produced by this run (§PR mode). */
prUrl: z.string().optional(),
branch: z.string().optional(),
+ prState: z.enum(['open', 'merged']).optional(),
});
export type FleetRunDoc = z.infer;
@@ -432,9 +433,10 @@ export const ReleaseLeaseSchema = z.object({
// releases the lease at the end of a work unit. Recorded on the current run.
insights: InsightsSchema.optional(),
result: z.enum(RUN_RESULTS).optional(),
- // PR deliverable (§PR mode): the pull request the run opened + its branch.
+ // PR deliverable (§PR mode): the pull request the run opened + its branch + state.
prUrl: z.string().optional(),
branch: z.string().optional(),
+ prState: z.enum(['open', 'merged']).optional(),
});
export type ReleaseLeaseInput = z.infer;
|