From 42bc97c193b5baf80aa6ec90955f3643b60fac7b Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 8 Sep 2026 22:52:54 +0000
Subject: [PATCH 1/2] Initial plan
From 7a86e9761447f5de941bf43731590d15455d428c Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 8 Sep 2026 23:24:51 +0000
Subject: [PATCH 2/2] fix: ground studio stack checks in pack tools
Co-authored-by: groupthinking <154503486+groupthinking@users.noreply.github.com>
---
apps/web/src/components/OneLoopStudio.tsx | 23 ++++++--------
.../__tests__/studio-pipeline-status.test.ts | 31 +++++++++++++++++++
.../uvai-surface-unification.test.ts | 2 +-
apps/web/src/lib/studio-pipeline-status.ts | 14 ++++++++-
4 files changed, 55 insertions(+), 15 deletions(-)
diff --git a/apps/web/src/components/OneLoopStudio.tsx b/apps/web/src/components/OneLoopStudio.tsx
index f8e92fe98..745909017 100644
--- a/apps/web/src/components/OneLoopStudio.tsx
+++ b/apps/web/src/components/OneLoopStudio.tsx
@@ -39,6 +39,7 @@ import {
studioEventsEmptyMessage,
studioExportFilename,
studioExportToastMessage,
+ studioFormationSupplementalEntities,
studioInvalidHandoffMessage,
studioPackCitation,
studioPackFormation,
@@ -273,6 +274,11 @@ export default function OneLoopStudio() {
packTools,
);
}, [selected, packFormation.tools]);
+ const stackChecks = packFormation.checks;
+ const supplementalEntities = studioFormationSupplementalEntities(
+ packFormation.tools,
+ linkedSop?.entities,
+ );
useEffect(() => {
setCompletedChecks([]);
@@ -905,7 +911,7 @@ export default function OneLoopStudio() {
- {linkedSop.entities.length === 0 && packFormation.tools.length === 0 && (
+ {supplementalEntities.length === 0 && packFormation.tools.length === 0 && (
No catalogued tools in this transcript.
)}
{packFormation.tools.map((tool) => (
@@ -916,14 +922,7 @@ export default function OneLoopStudio() {
{tool.name}
))}
- {linkedSop.entities
- .filter(
- (entity) =>
- !packFormation.tools.some(
- (tool) => tool.name.toLowerCase() === entity.name.toLowerCase(),
- ),
- )
- .map((entity) => (
+ {supplementalEntities.map((entity) => (
- {linkedSop.checklist.some((item) => item.source === 'stack') && (
+ {stackChecks.length > 0 && (
<>
@@ -999,9 +998,7 @@ export default function OneLoopStudio() {
- {linkedSop.checklist
- .filter((item) => item.source === 'stack')
- .map((item) => {
+ {stackChecks.map((item) => {
const checked = completedChecks.includes(item.id);
const status = stackCheckStatus(item, completedChecks, 'anonymous');
return (
diff --git a/apps/web/src/lib/__tests__/studio-pipeline-status.test.ts b/apps/web/src/lib/__tests__/studio-pipeline-status.test.ts
index 0afe3e3de..17107cb92 100644
--- a/apps/web/src/lib/__tests__/studio-pipeline-status.test.ts
+++ b/apps/web/src/lib/__tests__/studio-pipeline-status.test.ts
@@ -17,6 +17,7 @@ import {
studioVerifiedLiveUrl,
studioInvalidHandoffMessage,
studioPackCitation,
+ studioFormationSupplementalEntities,
studioPackFormation,
studioPasteOutcomeMessage,
studioPlayerOverlay,
@@ -155,9 +156,39 @@ describe('studio-pipeline-status', () => {
expect(studio).toContain('studioPackFormation');
expect(studio).toContain('data-testid="pack-architecture"');
expect(studio).toContain('data-testid="pack-artifacts"');
+ expect(studio).toContain('packFormation.checks');
expect(studio).not.toMatch(/router\.(push|replace)\(['"]\/dashboard/);
});
+ it('suppresses transcript-only tool chips when pack.stack.tools are grounded', () => {
+ expect(
+ studioFormationSupplementalEntities(
+ [{ name: 'Cloudflare' }, { name: 'x402' }],
+ [
+ {
+ name: 'Shopify',
+ kind: 'platform',
+ officialUrl: 'https://shopify.dev',
+ docsUrl: 'https://shopify.dev/docs',
+ timestamps: [],
+ },
+ ],
+ ),
+ ).toEqual([]);
+
+ expect(
+ studioFormationSupplementalEntities([], [
+ {
+ name: 'Shopify',
+ kind: 'platform',
+ officialUrl: 'https://shopify.dev',
+ docsUrl: 'https://shopify.dev/docs',
+ timestamps: [],
+ },
+ ]).map((entity) => entity.name),
+ ).toEqual(['Shopify']);
+ });
+
it('tells the truth when events[] is empty after a completed run', () => {
expect(
studioEventsEmptyMessage({
diff --git a/apps/web/src/lib/__tests__/uvai-surface-unification.test.ts b/apps/web/src/lib/__tests__/uvai-surface-unification.test.ts
index 05a8e60b3..de54397b9 100644
--- a/apps/web/src/lib/__tests__/uvai-surface-unification.test.ts
+++ b/apps/web/src/lib/__tests__/uvai-surface-unification.test.ts
@@ -63,7 +63,7 @@ describe('UVAI is one product surface', () => {
it('keeps stack-check unlock on the same OneLoopStudio page', () => {
const studio = readSource('components/OneLoopStudio.tsx');
- expect(studio).toContain("item.source === 'stack'");
+ expect(studio).toContain('packFormation.checks');
expect(studio).toContain('setCompletedChecks');
expect(studio).not.toMatch(/window\.location\.(href|assign).*dashboard/);
expect(studio).not.toMatch(/router\.push\(['"`]\/dashboard/);
diff --git a/apps/web/src/lib/studio-pipeline-status.ts b/apps/web/src/lib/studio-pipeline-status.ts
index 87db998c0..bf6d95420 100644
--- a/apps/web/src/lib/studio-pipeline-status.ts
+++ b/apps/web/src/lib/studio-pipeline-status.ts
@@ -1,5 +1,9 @@
import type { VideoPackCitation } from '@/lib/emit-video-pack';
-import { stackChecksFromPackTools, type ChecklistItem } from '@/lib/linked-sop';
+import {
+ stackChecksFromPackTools,
+ type ChecklistItem,
+ type LinkedEntity,
+} from '@/lib/linked-sop';
import type {
VideoPackArchitecture,
VideoPackArtifact,
@@ -86,6 +90,14 @@ export function studioPackFormation(pack: VideoPackCitation | null | undefined):
};
}
+export function studioFormationSupplementalEntities(
+ tools: VideoPackStackTool[] | null | undefined,
+ entities: LinkedEntity[] | null | undefined,
+): LinkedEntity[] {
+ if ((tools?.length ?? 0) > 0) return [];
+ return entities ?? [];
+}
+
export function studioEventsEmptyMessage(input: {
busy: boolean;
hasCompletedRun: boolean;