fix(page-data): deliver WeChat surveys when agent pre-binds pages
Memind CI / Test, build, and release guards (push) Failing after 5s

Include already_bound auto-bind skips and request-scoped relative paths
when building Page Data delivery artifacts, so pre-bound survey pages are
verified and linked instead of failing the finish guard.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-08-02 21:10:38 +08:00
parent 599f23521f
commit 762453852f
3 changed files with 71 additions and 3 deletions
+31 -3
View File
@@ -108,16 +108,44 @@ export function rewritePageDataDeliveryLinks(text, artifacts = []) {
}); });
} }
export function buildPageDataDeliveryArtifactsFromBindResult(autoBind, publishDir, options = {}) { function collectPageDataDeliveryRelativePaths(autoBind, relevantRelativePaths = null) {
const deliveryPaths = new Set();
for (const item of autoBind?.bound ?? []) {
if (item?.relativePath) deliveryPaths.add(item.relativePath);
}
for (const item of autoBind?.skipped ?? []) {
if (item?.reason === 'already_bound' && item?.relativePath) {
deliveryPaths.add(item.relativePath);
}
}
if (Array.isArray(relevantRelativePaths)) {
for (const relativePath of relevantRelativePaths) {
if (relativePath) deliveryPaths.add(relativePath);
}
}
return deliveryPaths;
}
export function buildPageDataDeliveryArtifactsFromBindResult(
autoBind,
publishDir,
options = {},
relevantRelativePaths = null,
) {
const boundUrls = new Map( const boundUrls = new Map(
(autoBind?.bound ?? []) (autoBind?.bound ?? [])
.filter((item) => item?.relativePath && item?.workspaceUrl) .filter((item) => item?.relativePath && item?.workspaceUrl)
.map((item) => [item.relativePath, item.workspaceUrl]), .map((item) => [item.relativePath, item.workspaceUrl]),
); );
// Only verify/deliver pages bound in this auto-bind pass. Scanning the whole const deliveryPaths = collectPageDataDeliveryRelativePaths(
autoBind,
relevantRelativePaths,
);
// Limit verification/delivery to this request's bound pages. Scanning the whole
// workspace lets one stale historical Page Data page fail delivery for a new survey. // workspace lets one stale historical Page Data page fail delivery for a new survey.
if (deliveryPaths.size === 0) return [];
return collectPageDataDeliveryArtifacts(publishDir, options) return collectPageDataDeliveryArtifacts(publishDir, options)
.filter((artifact) => boundUrls.has(artifact.relativePath)) .filter((artifact) => deliveryPaths.has(artifact.relativePath))
.map((artifact) => ({ .map((artifact) => ({
...artifact, ...artifact,
url: boundUrls.get(artifact.relativePath) ?? artifact.url, url: boundUrls.get(artifact.relativePath) ?? artifact.url,
+29
View File
@@ -6,6 +6,7 @@ import test from 'node:test';
import { import {
buildPageDataCollectFailureText, buildPageDataCollectFailureText,
buildPageDataCollectRepairPrompt, buildPageDataCollectRepairPrompt,
buildPageDataDeliveryArtifactsFromBindResult,
collectPageDataDeliveryArtifacts, collectPageDataDeliveryArtifacts,
evaluatePageDataFinishGuard, evaluatePageDataFinishGuard,
evaluatePageDataFinishGuardAsync, evaluatePageDataFinishGuardAsync,
@@ -306,6 +307,34 @@ test('evaluatePageDataFinishGuard flags html when dataset is not registered', as
} }
}); });
test('buildPageDataDeliveryArtifactsFromBindResult includes already_bound pages for this request only', () => {
const publishDir = fs.mkdtempSync(path.join(os.tmpdir(), 'page-data-guard-bind-result-'));
const previousBase = process.env.H5_PUBLIC_BASE_URL;
process.env.H5_PUBLIC_BASE_URL = 'https://m.tkmind.cn';
try {
fs.mkdirSync(path.join(publishDir, 'public'), { recursive: true });
fs.writeFileSync(path.join(publishDir, 'public', 'new-survey.html'), SURVEY_HTML, 'utf8');
fs.writeFileSync(path.join(publishDir, 'public', 'stale-survey.html'), SURVEY_HTML, 'utf8');
const autoBind = {
bound: [],
skipped: [{ relativePath: 'public/new-survey.html', reason: 'already_bound' }],
errors: [],
};
const artifacts = buildPageDataDeliveryArtifactsFromBindResult(
autoBind,
publishDir,
{},
['public/new-survey.html'],
);
assert.equal(artifacts.length, 1);
assert.equal(artifacts[0].relativePath, 'public/new-survey.html');
} finally {
if (previousBase == null) delete process.env.H5_PUBLIC_BASE_URL;
else process.env.H5_PUBLIC_BASE_URL = previousBase;
fs.rmSync(publishDir, { recursive: true, force: true });
}
});
test('collectPageDataDeliveryArtifacts uses Portal base when H5_PUBLIC_BASE_URL points at Vite', () => { test('collectPageDataDeliveryArtifacts uses Portal base when H5_PUBLIC_BASE_URL points at Vite', () => {
const publishDir = fs.mkdtempSync(path.join(os.tmpdir(), 'page-data-guard-portal-url-')); const publishDir = fs.mkdtempSync(path.join(os.tmpdir(), 'page-data-guard-portal-url-'));
const previousBase = process.env.H5_PUBLIC_BASE_URL; const previousBase = process.env.H5_PUBLIC_BASE_URL;
+11
View File
@@ -283,6 +283,9 @@ export function createMindSpacePublicFinishService({
pageService.findPageByRelativePath.bind( pageService.findPageByRelativePath.bind(
pageService, pageService,
); );
const relevantRelativePaths = (outcome?.evaluation?.relevantFiles ?? [])
.map((file) => file?.relativePath)
.filter(Boolean);
autoBind = autoBind =
await maybeAutoBindPageDataHtmlPagesFn({ await maybeAutoBindPageDataHtmlPagesFn({
pool, pool,
@@ -291,6 +294,10 @@ export function createMindSpacePublicFinishService({
h5Root, h5Root,
storageRoot, storageRoot,
findPageByRelativePath, findPageByRelativePath,
onlyRelativePaths:
relevantRelativePaths.length > 0
? relevantRelativePaths
: null,
}); });
outcome = outcome =
await resolvePageDataCollectOutcomeAsyncFn({ await resolvePageDataCollectOutcomeAsyncFn({
@@ -308,11 +315,15 @@ export function createMindSpacePublicFinishService({
let deliveryCheck = null; let deliveryCheck = null;
let rewrittenText = normalizedReply.text; let rewrittenText = normalizedReply.text;
if (outcome?.action === 'send') { if (outcome?.action === 'send') {
const deliveryRelativePaths = (outcome?.evaluation?.relevantFiles ?? [])
.map((file) => file?.relativePath)
.filter(Boolean);
deliveryArtifacts = deliveryArtifacts =
buildPageDataDeliveryArtifactsFromBindResultFn( buildPageDataDeliveryArtifactsFromBindResultFn(
autoBind, autoBind,
publishDir, publishDir,
{ publicBaseUrl }, { publicBaseUrl },
deliveryRelativePaths,
); );
if (deliveryArtifacts.length > 0) { if (deliveryArtifacts.length > 0) {
deliveryCheck = deliveryCheck =