Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 16 additions & 11 deletions app/image/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -604,9 +604,23 @@ export default function ImageStudioPage() {
);
}

/**
* AIT-576 residual chrome + AIT-622 leave-wait: owner deep-link or plain list.
* Lab / missing / non-private stay plain /library (never invent ?job=).
*/
const imageLibraryHref = libraryWorkbenchHandoffHref({
demo,
privateResult: lastPrivateResult,
requestId: lastRequestId,
});
const imageLibraryHandoffKind = imageLibraryHref.includes("job=")
? "request-id"
: "list";

/**
* Stop waiting on Image Studio without aborting the original still POST or
* inventing a refund restore. User can open Library while the same request finishes.
* AIT-622: owner-safe deep-link via imageLibraryHref (same helper as residual chrome).
*/
function leaveWaitingKeepBackground() {
const plan = planGenerateWaitLeave("detach");
Expand All @@ -622,7 +636,8 @@ export default function ImageStudioPage() {
setError(null);
clearFailGate();
// Soft client navigation keeps the original fetch alive in this document.
router.push("/library");
// Reuse residual chrome helper inputs (lastPrivateResult + lastRequestId).
router.push(imageLibraryHref);
}

async function generate(opts?: { prompt?: string; aspect?: string }) {
Expand Down Expand Up @@ -814,16 +829,6 @@ export default function ImageStudioPage() {
),
});

/** AIT-576: residual Library chrome — owner deep-link or plain list. */
const imageLibraryHref = libraryWorkbenchHandoffHref({
demo,
privateResult: lastPrivateResult,
requestId: lastRequestId,
});
const imageLibraryHandoffKind = imageLibraryHref.includes("job=")
? "request-id"
: "list";

return (
<div>
<Suspense
Expand Down
7 changes: 5 additions & 2 deletions scripts/generate-wait-honesty-regression.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,9 @@ const read = (rel) => readFileSync(join(root, rel), "utf8");
assert.match(imagePage, /data-generate-leave="cancel"/);
assert.match(imagePage, /data-image-leave="detach"/);
assert.match(imagePage, /Open Library · keep generating/);
assert.match(imagePage, /router\.push\(["']\/library["']\)/);
// AIT-622: owner-safe Library deep-link via imageLibraryHref (not bare /library)
assert.match(imagePage, /router\.push\(\s*imageLibraryHref\s*\)/);
assert.match(imagePage, /imageLibraryHref/);
// Detach function never aborts primary, cancels ledger, or invents restore.
{
const leaveFn = imagePage.match(
Expand All @@ -553,7 +555,8 @@ const read = (rel) => readFileSync(join(root, rel), "utf8");
assert.match(leaveFn, /planGenerateWaitLeave\("detach"\)/);
assert.match(leaveFn, /abortRef\.current = null/);
assert.match(leaveFn, /detachedWaitRef\.current = true/);
assert.match(leaveFn, /router\.push\(["']\/library["']\)/);
assert.match(leaveFn, /router\.push\(\s*imageLibraryHref\s*\)/);
assert.doesNotMatch(leaveFn, /router\.push\(\s*["']\/library["']\s*\)/);
assert.doesNotMatch(leaveFn, /\.abort\s*\(/);
assert.doesNotMatch(leaveFn, /cancelSessionStill|DELETE/);
assert.doesNotMatch(leaveFn, /setFailCreditState/);
Expand Down
35 changes: 33 additions & 2 deletions scripts/library-workbench-deeplink-smoke.mjs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#!/usr/bin/env node
/**
* AIT-529 / AIT-392 / AIT-546 / AIT-568 / AIT-576 / AIT-558: Workbench +
* AIT-529 / AIT-392 / AIT-546 / AIT-568 / AIT-576 / AIT-558 / AIT-622: Workbench +
* AfterPath + WaitStage + residual CreateStudio chips + Image residual Library
* chrome + BatchStudio/Seller Pack done → requestId deep-link (owner-safe).
* chrome + Image leave-wait keep-background + BatchStudio/Seller Pack done →
* requestId deep-link (owner-safe).
*
* Source + pure-logic contract:
* - libraryWorkbenchHandoffHref only deep-links live private + UUID requestId
Expand All @@ -14,6 +15,7 @@
* - GenerateAfterPath Library chips use helper (fail-closed)
* - GenerateWaitStage leave exposes libraryHref / handoff markers
* - Image Studio residual Library chrome uses helper; Lab/missing fail-closed
* - Image leaveWaitingKeepBackground reuses imageLibraryHref (not bare /library)
* - BatchStudio / Seller Pack post-pack Library CTAs reuse same helper
* - LibraryGrid matches deep-link by id or requestId; missing/foreign → not-your-toy
*
Expand Down Expand Up @@ -360,6 +362,35 @@ assert.match(
/href=\{imageLibraryHref\}/,
"Image residual Library chrome must bind imageLibraryHref"
);
assert.match(
imageStudio,
/router\.push\(\s*imageLibraryHref\s*\)/,
"Image leave-wait keep-background must hand off owner-safe Library href"
);
{
const leaveFn = imageStudio.match(
/function leaveWaitingKeepBackground\(\) \{[\s\S]*?\n \}/
)?.[0];
assert.ok(
leaveFn,
"leaveWaitingKeepBackground must exist on Image Studio"
);
assert.match(
leaveFn,
/router\.push\(\s*imageLibraryHref\s*\)/,
"leaveWaitingKeepBackground must push imageLibraryHref (not bare /library)"
);
assert.doesNotMatch(
leaveFn,
/router\.push\(\s*["']\/library["']\s*\)/,
"leaveWaitingKeepBackground must not hardcode plain /library"
);
assert.doesNotMatch(
leaveFn,
/\/library\?job=/,
"leaveWaitingKeepBackground must never invent hardcoded ?job="
);
}
assert.match(
imageStudio,
/data-library-handoff=/,
Expand Down
Loading