@reqvire-org/ads 0.3.14 → 0.3.16

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.
@@ -0,0 +1,37 @@
1
+ const retryDelays = [200, 800];
2
+ const networkFailure = error => error?.name === "TypeError" && /^(Failed to fetch|fetch failed|Load failed|NetworkError when attempting to fetch resource\.)$/.test(error.message);
3
+
4
+ function pause(milliseconds, signal) {
5
+ return new Promise((resolve, reject) => {
6
+ signal?.throwIfAborted();
7
+ const finish = () => { signal?.removeEventListener("abort", abort); resolve(); };
8
+ const timer = setTimeout(finish, milliseconds);
9
+ const abort = () => { clearTimeout(timer); signal.removeEventListener("abort", abort); reject(signal.reason); };
10
+ signal?.addEventListener("abort", abort, { once: true });
11
+ });
12
+ }
13
+
14
+ /** Only resources/read is repeatable here; never wrap tool calls or assertions. */
15
+ export function resourceReader(read, { signal, onDiagnostic, wait = pause } = {}) {
16
+ return async input => {
17
+ for (let attempt = 1; ; attempt++) {
18
+ signal?.throwIfAborted();
19
+ try {
20
+ const response = await read(input);
21
+ signal?.throwIfAborted();
22
+ if (attempt > 1) onDiagnostic?.({ state: "recovered", uri: input.uri, attempt });
23
+ return response;
24
+ } catch (error) {
25
+ signal?.throwIfAborted();
26
+ if (!networkFailure(error)) throw error;
27
+ if (attempt > retryDelays.length) {
28
+ onDiagnostic?.({ state: "exhausted", uri: input.uri, attempt, message: error.message });
29
+ throw Object.assign(new Error(`MCP resource transport failed for ${input.uri} after ${attempt} attempts: ${error.message}. Inspect the host connection and browser network diagnostics; this resource-loading error does not establish a component assertion failure.`, { cause: error }), { code: "ADS_RESOURCE_TRANSPORT" });
30
+ }
31
+ const delayMs = retryDelays[attempt - 1];
32
+ onDiagnostic?.({ state: "retry", uri: input.uri, attempt, nextAttempt: attempt + 1, delayMs, message: error.message });
33
+ await wait(delayMs, signal);
34
+ }
35
+ }
36
+ };
37
+ }
@@ -0,0 +1 @@
1
+ function c(e,t){let n=new DOMParser().parseFromString(e,"text/html"),r=n.createElement("meta");if(r.httpEquiv="Content-Security-Policy",r.content=t,n.head.prepend(r),!n.querySelector("base[href]")){let i=n.querySelector("base")??n.createElement("base");i.setAttribute("href","about:srcdoc"),r.after(i)}return"<!doctype html>"+n.documentElement.outerHTML}var a=new URL(location.href).searchParams.get("parent"),o;function s(e=[]){return e.filter(t=>/^(?:https?:\/\/[a-z0-9.*:[\]-]+(?::\d+)?|data:|blob:|about:)$/i.test(t)).join(" ")}function d(e={}){let t=s(e.resourceDomains);return`default-src 'none';script-src 'unsafe-inline' ${t};style-src 'unsafe-inline' ${t};img-src data: ${t};font-src ${t||"'none'"};media-src ${t||"'none'"};worker-src ${t||"'none'"};connect-src ${s(e.connectDomains)||"'none'"};frame-src ${s(e.frameDomains)||"'none'"};base-uri about: ${s(e.baseUriDomains)};object-src 'none'`}window.addEventListener("message",e=>{if(e.source===parent&&e.origin===a){let t=e.data;if(t?.method==="ui/notifications/sandbox-resource-ready"){let{html:n,csp:r}=t.params??{};if(typeof n!="string")return;o?.remove(),o=window.document.createElement("iframe"),o.title="Design-system App",o.setAttribute("sandbox","allow-scripts"),window.document.body.append(o),o.srcdoc=c(n,d(r))}else t?.jsonrpc==="2.0"&&!t.method?.startsWith("ui/notifications/sandbox-")&&o?.contentWindow.postMessage(t,"*")}else e.source===o?.contentWindow&&e.data?.jsonrpc==="2.0"&&!e.data.method?.startsWith("ui/notifications/sandbox-")&&parent.postMessage(e.data,a)});parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-ready",params:{}},a);
@@ -55,8 +55,8 @@ For on-demand current/candidate screenshots and visual dry-run review, read
55
55
 
56
56
 
57
57
  For parent/child `covers`, conditional-control review, reference comparisons,
58
- public style-helper use in scenarios, or `scenario-render` / `showcase-class`
59
- findings, read [scenario contracts](references/scenarios.md). Its verification
58
+ public style-helper use, fragment-link navigation, or `scenario-render` /
59
+ `showcase-class` findings, read [scenario contracts](references/scenarios.md). Its verification
60
60
  examples explain API visibility, reference baselines and state-transition checks.
61
61
  Traced parents can cover declared public children; verified public Linaria
62
62
  helpers do not grant custom scenario CSS.
@@ -51,6 +51,18 @@ blanket sleeps. Fake clocks suit timer-only guarantees; keep real time for actua
51
51
  gesture/motion/layout guarantees. Project settings belong in guarded configuration
52
52
  changes; ADS does not silently raise budgets or override the worker count.
53
53
 
54
+ If a check cannot load its MCP preview, preserve the draft and inspect the exact
55
+ resource URI and failed browser requests before changing component code. The ADS
56
+ showcase retries a fetch transport failure on `resources/read` at most twice
57
+ (200/800 ms backoff); recovered startup reads remain visible in
58
+ `startupDiagnostics`. It never retries tool calls, assertions or complete checks,
59
+ and persistent failures still block application. HTTP/protocol/content errors,
60
+ integrity failures and cancellation do not retry. External hosts own their
61
+ transport behavior. Chrome's `ERR_NETWORK_CHANGED` does not prove an ADS restart
62
+ or identify Docker/VPN churn: correlate failure timestamps with live interface
63
+ events, Chrome network logs and server availability. Do not weaken checks or
64
+ rewrite a valid API to hide infrastructure failures.
65
+
54
66
  Named barrel imports can narrow affected checks when the project accurately
55
67
  declares package `sideEffects`; retain CSS/global effects in that policy. Missing
56
68
  or unsupported policies and dynamic/wildcard dependencies stay conservative.
@@ -23,6 +23,17 @@ on-demand element screenshots. It grants no render/behavior coverage and no extr
23
23
  styling permission. Use [captures.md](captures.md) for current/candidate review,
24
24
  target selection, resource reads and storage lifecycle.
25
25
 
26
+ ## Fragment links inside Apps
27
+
28
+ Keep intended `href="#"` and named fragments in the project API and fixtures.
29
+ ADS's inline-document loader supplies an `about:srcdoc` base when the App has no
30
+ explicit base, preserving native scrolling, events and state. If a fragment
31
+ replaces the App with a sandbox URL or browser error, inspect `location.href`,
32
+ `document.baseURI` and the resolved anchor URL. Report a host loading defect;
33
+ do not add scenario `preventDefault` handlers merely to hide it. Explicit App
34
+ bases retain their declared behavior and CSP requirements; external hosts own
35
+ their document-loading policy. Verify link activation as well as rendering.
36
+
26
37
  ## Owner-local token previews load their own definitions
27
38
 
28
39
  Keep the registered token sheet imported by its runtime owner for product use.
@@ -86,8 +86,8 @@ For on-demand current/candidate screenshots and visual dry-run review, read
86
86
  [captures.md](references/captures.md).
87
87
 
88
88
  For parent/child `covers`, conditional-control review, reference comparisons,
89
- public style-helper use in scenarios, or `scenario-render` / `showcase-class`
90
- findings, read [scenario contracts](references/scenarios.md). Its verification
89
+ public style-helper use, fragment-link navigation, or `scenario-render` /
90
+ `showcase-class` findings, read [scenario contracts](references/scenarios.md). Its verification
91
91
  examples explain API visibility, reference baselines and state-transition checks.
92
92
  Traced parents can cover declared public children; verified public Linaria
93
93
  helpers do not grant custom scenario CSS.
@@ -51,6 +51,18 @@ blanket sleeps. Fake clocks suit timer-only guarantees; keep real time for actua
51
51
  gesture/motion/layout guarantees. Project settings belong in guarded configuration
52
52
  changes; ADS does not silently raise budgets or override the worker count.
53
53
 
54
+ If a check cannot load its MCP preview, preserve the draft and inspect the exact
55
+ resource URI and failed browser requests before changing component code. The ADS
56
+ showcase retries a fetch transport failure on `resources/read` at most twice
57
+ (200/800 ms backoff); recovered startup reads remain visible in
58
+ `startupDiagnostics`. It never retries tool calls, assertions or complete checks,
59
+ and persistent failures still block application. HTTP/protocol/content errors,
60
+ integrity failures and cancellation do not retry. External hosts own their
61
+ transport behavior. Chrome's `ERR_NETWORK_CHANGED` does not prove an ADS restart
62
+ or identify Docker/VPN churn: correlate failure timestamps with live interface
63
+ events, Chrome network logs and server availability. Do not weaken checks or
64
+ rewrite a valid API to hide infrastructure failures.
65
+
54
66
  Named barrel imports can narrow affected checks when the project accurately
55
67
  declares package `sideEffects`; retain CSS/global effects in that policy. Missing
56
68
  or unsupported policies and dynamic/wildcard dependencies stay conservative.
@@ -23,6 +23,17 @@ on-demand element screenshots. It grants no render/behavior coverage and no extr
23
23
  styling permission. Use [captures.md](captures.md) for current/candidate review,
24
24
  target selection, resource reads and storage lifecycle.
25
25
 
26
+ ## Fragment links inside Apps
27
+
28
+ Keep intended `href="#"` and named fragments in the project API and fixtures.
29
+ ADS's inline-document loader supplies an `about:srcdoc` base when the App has no
30
+ explicit base, preserving native scrolling, events and state. If a fragment
31
+ replaces the App with a sandbox URL or browser error, inspect `location.href`,
32
+ `document.baseURI` and the resolved anchor URL. Report a host loading defect;
33
+ do not add scenario `preventDefault` handlers merely to hide it. Explicit App
34
+ bases retain their declared behavior and CSP requirements; external hosts own
35
+ their document-loading policy. Verify link activation as well as rendering.
36
+
26
37
  ## Owner-local token previews load their own definitions
27
38
 
28
39
  Keep the registered token sheet imported by its runtime owner for product use.
@@ -50,8 +50,8 @@ For on-demand current/candidate screenshots and visual dry-run review, read
50
50
  [captures.md](references/captures.md).
51
51
 
52
52
  For parent/child `covers`, conditional-control review, reference comparisons,
53
- public style-helper use in scenarios, or `scenario-render` / `showcase-class`
54
- findings, read [scenario contracts](references/scenarios.md). Its verification
53
+ public style-helper use, fragment-link navigation, or `scenario-render` /
54
+ `showcase-class` findings, read [scenario contracts](references/scenarios.md). Its verification
55
55
  examples explain API visibility, reference baselines and state-transition checks.
56
56
  Traced parents can cover declared public children; verified public Linaria
57
57
  helpers do not grant custom scenario CSS.
@@ -51,6 +51,18 @@ blanket sleeps. Fake clocks suit timer-only guarantees; keep real time for actua
51
51
  gesture/motion/layout guarantees. Project settings belong in guarded configuration
52
52
  changes; ADS does not silently raise budgets or override the worker count.
53
53
 
54
+ If a check cannot load its MCP preview, preserve the draft and inspect the exact
55
+ resource URI and failed browser requests before changing component code. The ADS
56
+ showcase retries a fetch transport failure on `resources/read` at most twice
57
+ (200/800 ms backoff); recovered startup reads remain visible in
58
+ `startupDiagnostics`. It never retries tool calls, assertions or complete checks,
59
+ and persistent failures still block application. HTTP/protocol/content errors,
60
+ integrity failures and cancellation do not retry. External hosts own their
61
+ transport behavior. Chrome's `ERR_NETWORK_CHANGED` does not prove an ADS restart
62
+ or identify Docker/VPN churn: correlate failure timestamps with live interface
63
+ events, Chrome network logs and server availability. Do not weaken checks or
64
+ rewrite a valid API to hide infrastructure failures.
65
+
54
66
  Named barrel imports can narrow affected checks when the project accurately
55
67
  declares package `sideEffects`; retain CSS/global effects in that policy. Missing
56
68
  or unsupported policies and dynamic/wildcard dependencies stay conservative.
@@ -23,6 +23,17 @@ on-demand element screenshots. It grants no render/behavior coverage and no extr
23
23
  styling permission. Use [captures.md](captures.md) for current/candidate review,
24
24
  target selection, resource reads and storage lifecycle.
25
25
 
26
+ ## Fragment links inside Apps
27
+
28
+ Keep intended `href="#"` and named fragments in the project API and fixtures.
29
+ ADS's inline-document loader supplies an `about:srcdoc` base when the App has no
30
+ explicit base, preserving native scrolling, events and state. If a fragment
31
+ replaces the App with a sandbox URL or browser error, inspect `location.href`,
32
+ `document.baseURI` and the resolved anchor URL. Report a host loading defect;
33
+ do not add scenario `preventDefault` handlers merely to hide it. Explicit App
34
+ bases retain their declared behavior and CSP requirements; external hosts own
35
+ their document-loading policy. Verify link activation as well as rendering.
36
+
26
37
  ## Owner-local token previews load their own definitions
27
38
 
28
39
  Keep the registered token sheet imported by its runtime owner for product use.
@@ -52,8 +52,8 @@ For on-demand current/candidate screenshots and visual dry-run review, read
52
52
 
53
53
 
54
54
  For parent/child `covers`, conditional-control review, reference comparisons,
55
- public style-helper use in scenarios, or `scenario-render` / `showcase-class`
56
- findings, read [scenario contracts](references/scenarios.md). Its verification
55
+ public style-helper use, fragment-link navigation, or `scenario-render` /
56
+ `showcase-class` findings, read [scenario contracts](references/scenarios.md). Its verification
57
57
  examples explain API visibility, reference baselines and state-transition checks.
58
58
  Traced parents can cover declared public children; verified public Linaria
59
59
  helpers do not grant custom scenario CSS.
@@ -51,6 +51,18 @@ blanket sleeps. Fake clocks suit timer-only guarantees; keep real time for actua
51
51
  gesture/motion/layout guarantees. Project settings belong in guarded configuration
52
52
  changes; ADS does not silently raise budgets or override the worker count.
53
53
 
54
+ If a check cannot load its MCP preview, preserve the draft and inspect the exact
55
+ resource URI and failed browser requests before changing component code. The ADS
56
+ showcase retries a fetch transport failure on `resources/read` at most twice
57
+ (200/800 ms backoff); recovered startup reads remain visible in
58
+ `startupDiagnostics`. It never retries tool calls, assertions or complete checks,
59
+ and persistent failures still block application. HTTP/protocol/content errors,
60
+ integrity failures and cancellation do not retry. External hosts own their
61
+ transport behavior. Chrome's `ERR_NETWORK_CHANGED` does not prove an ADS restart
62
+ or identify Docker/VPN churn: correlate failure timestamps with live interface
63
+ events, Chrome network logs and server availability. Do not weaken checks or
64
+ rewrite a valid API to hide infrastructure failures.
65
+
54
66
  Named barrel imports can narrow affected checks when the project accurately
55
67
  declares package `sideEffects`; retain CSS/global effects in that policy. Missing
56
68
  or unsupported policies and dynamic/wildcard dependencies stay conservative.
@@ -23,6 +23,17 @@ on-demand element screenshots. It grants no render/behavior coverage and no extr
23
23
  styling permission. Use [captures.md](captures.md) for current/candidate review,
24
24
  target selection, resource reads and storage lifecycle.
25
25
 
26
+ ## Fragment links inside Apps
27
+
28
+ Keep intended `href="#"` and named fragments in the project API and fixtures.
29
+ ADS's inline-document loader supplies an `about:srcdoc` base when the App has no
30
+ explicit base, preserving native scrolling, events and state. If a fragment
31
+ replaces the App with a sandbox URL or browser error, inspect `location.href`,
32
+ `document.baseURI` and the resolved anchor URL. Report a host loading defect;
33
+ do not add scenario `preventDefault` handlers merely to hide it. Explicit App
34
+ bases retain their declared behavior and CSP requirements; external hosts own
35
+ their document-loading policy. Verify link activation as well as rendering.
36
+
26
37
  ## Owner-local token previews load their own definitions
27
38
 
28
39
  Keep the registered token sheet imported by its runtime owner for product use.
@@ -72,8 +72,8 @@ For on-demand current/candidate screenshots and visual dry-run review, read
72
72
 
73
73
 
74
74
  For parent/child `covers`, conditional-control review, reference comparisons,
75
- public style-helper use in scenarios, or `scenario-render` / `showcase-class`
76
- findings, read [scenario contracts](references/scenarios.md). Its verification
75
+ public style-helper use, fragment-link navigation, or `scenario-render` /
76
+ `showcase-class` findings, read [scenario contracts](references/scenarios.md). Its verification
77
77
  examples explain API visibility, reference baselines and state-transition checks.
78
78
  Traced parents can cover declared public children; verified public Linaria
79
79
  helpers do not grant custom scenario CSS.
@@ -51,6 +51,18 @@ blanket sleeps. Fake clocks suit timer-only guarantees; keep real time for actua
51
51
  gesture/motion/layout guarantees. Project settings belong in guarded configuration
52
52
  changes; ADS does not silently raise budgets or override the worker count.
53
53
 
54
+ If a check cannot load its MCP preview, preserve the draft and inspect the exact
55
+ resource URI and failed browser requests before changing component code. The ADS
56
+ showcase retries a fetch transport failure on `resources/read` at most twice
57
+ (200/800 ms backoff); recovered startup reads remain visible in
58
+ `startupDiagnostics`. It never retries tool calls, assertions or complete checks,
59
+ and persistent failures still block application. HTTP/protocol/content errors,
60
+ integrity failures and cancellation do not retry. External hosts own their
61
+ transport behavior. Chrome's `ERR_NETWORK_CHANGED` does not prove an ADS restart
62
+ or identify Docker/VPN churn: correlate failure timestamps with live interface
63
+ events, Chrome network logs and server availability. Do not weaken checks or
64
+ rewrite a valid API to hide infrastructure failures.
65
+
54
66
  Named barrel imports can narrow affected checks when the project accurately
55
67
  declares package `sideEffects`; retain CSS/global effects in that policy. Missing
56
68
  or unsupported policies and dynamic/wildcard dependencies stay conservative.
@@ -23,6 +23,17 @@ on-demand element screenshots. It grants no render/behavior coverage and no extr
23
23
  styling permission. Use [captures.md](captures.md) for current/candidate review,
24
24
  target selection, resource reads and storage lifecycle.
25
25
 
26
+ ## Fragment links inside Apps
27
+
28
+ Keep intended `href="#"` and named fragments in the project API and fixtures.
29
+ ADS's inline-document loader supplies an `about:srcdoc` base when the App has no
30
+ explicit base, preserving native scrolling, events and state. If a fragment
31
+ replaces the App with a sandbox URL or browser error, inspect `location.href`,
32
+ `document.baseURI` and the resolved anchor URL. Report a host loading defect;
33
+ do not add scenario `preventDefault` handlers merely to hide it. Explicit App
34
+ bases retain their declared behavior and CSP requirements; external hosts own
35
+ their document-loading policy. Verify link activation as well as rendering.
36
+
26
37
  ## Owner-local token previews load their own definitions
27
38
 
28
39
  Keep the registered token sheet imported by its runtime owner for product use.
@@ -27,7 +27,11 @@ export async function openPreviewScenario(page, url, scenario, { timeout = 30000
27
27
  while (Date.now() < end) {
28
28
  for (const frame of page.frames().filter(frame => frame !== page.mainFrame())) {
29
29
  const state = await frame.evaluate(() => ({ state: document.documentElement.dataset.adsPreviewState, id: document.documentElement.dataset.adsScenario, message: document.getElementById("ads-preview-status")?.textContent })).catch(() => ({}));
30
- if (state.id === scenario && state.state === "ready") return frame;
30
+ if (state.id === scenario && state.state === "ready") {
31
+ const retries = await page.evaluate(() => Number(document.documentElement.dataset.adsResourceRetries ?? 0)).catch(() => 0);
32
+ if (retries > 0) console.warn(JSON.stringify({ adsPreviewDiagnostic: { kind: "resource-read-recovery", scenario, retries, failedRequests: failures } }));
33
+ return frame;
34
+ }
31
35
  if (state.id === scenario && state.state === "error") throw new Error(state.message || "The MCP App failed before verification.");
32
36
  }
33
37
  const error = await page.evaluate(() => document.querySelector('#status[data-error="true"]')?.textContent).catch(() => null);
@@ -8,6 +8,8 @@ module.exports = class AdsBehaviorReporter {
8
8
  this.cases = [];
9
9
  this.errors = [];
10
10
  this.active = new Map();
11
+ this.diagnostics = new Map();
12
+ this.diagnosticBuffers = new Map();
11
13
  this.startedAt = Date.now();
12
14
  this.totalTests = 0;
13
15
  }
@@ -22,9 +24,27 @@ module.exports = class AdsBehaviorReporter {
22
24
  }
23
25
  onTestEnd(test, result) {
24
26
  this.active.delete(test.id);
25
- for (const entry of this.entries(test)) this.cases.push({ ...entry, status: result.status === "passed" && test.expectedStatus === "passed" ? "passed" : ["skipped", "interrupted"].includes(result.status) ? "skipped" : "failed", durationMs: result.duration, workerIndex: result.workerIndex, retry: result.retry, completedAt: new Date().toISOString(), message: result.errors?.map(error => error.message || error.stack || error.value || "The browser runner reported an error without details.").join("\n").slice(0, 1000) });
27
+ const diagnostics = this.diagnostics.get(test.id);
28
+ for (const entry of this.entries(test)) this.cases.push({ ...entry, status: result.status === "passed" && test.expectedStatus === "passed" ? "passed" : ["skipped", "interrupted"].includes(result.status) ? "skipped" : "failed", durationMs: result.duration, workerIndex: result.workerIndex, retry: result.retry, completedAt: new Date().toISOString(), ...(diagnostics?.length ? { diagnostics } : {}), message: result.errors?.map(error => error.message || error.stack || error.value || "The browser runner reported an error without details.").join("\n").slice(0, 1000) });
29
+ this.diagnostics.delete(test.id);
30
+ this.diagnosticBuffers.delete(test.id);
26
31
  this.publish();
27
32
  }
33
+ onStdErr(chunk, test) {
34
+ if (!test) return;
35
+ const lines = ((this.diagnosticBuffers.get(test.id) ?? "") + String(chunk)).split("\n");
36
+ this.diagnosticBuffers.set(test.id, lines.pop().slice(-4000));
37
+ for (const line of lines) {
38
+ if (line.length > 4000) continue;
39
+ try {
40
+ const diagnostic = JSON.parse(line).adsPreviewDiagnostic;
41
+ if (diagnostic?.kind !== "resource-read-recovery" || typeof diagnostic.scenario !== "string" || !Number.isSafeInteger(diagnostic.retries) || diagnostic.retries < 1) continue;
42
+ const collected = this.diagnostics.get(test.id) ?? [];
43
+ if (collected.length < 5) collected.push({ kind: diagnostic.kind, scenario: diagnostic.scenario.slice(0, 300), retries: diagnostic.retries, failedRequests: (Array.isArray(diagnostic.failedRequests) ? diagnostic.failedRequests : []).slice(0, 5).map(value => String(value).slice(0, 500)) });
44
+ this.diagnostics.set(test.id, collected);
45
+ } catch { /* Ordinary test output is not an ADS startup diagnostic. */ }
46
+ }
47
+ }
28
48
  onError(error) {
29
49
  if (this.errors.length < 5) this.errors.push(String(error.message || error.stack || error.value || "The browser runner reported a suite error without details.").slice(0, 4000));
30
50
  this.publish();
@@ -310,6 +310,7 @@ export function createVerificationController(root, { reportRoot = root, onProgre
310
310
  results.push({ unit: check.unit, check: check.id, file: check.file, case: check.case, profile: profileName, status, current, revision: check.inputRevision, runId, completedAt: new Date().toISOString(),
311
311
  previewRevision: profile.mode === "browser" ? host?.previewRevision() ?? readPreviewManifest(options)?.revision ?? null : null,
312
312
  ...(matches.length ? { reportedStatus, durationMs: matches.reduce((sum, item) => sum + (Number.isFinite(item.durationMs) ? Math.max(0, item.durationMs) : 0), 0) } : {}),
313
+ ...(matches.some(item => item.diagnostics?.length) ? { startupDiagnostics: matches.flatMap(item => Array.isArray(item.diagnostics) ? item.diagnostics.slice(0, 5) : []).slice(0, 10) } : {}),
313
314
  ...(runnerFailure ? { runnerExitCode: run.code } : {}),
314
315
  execution: progress.cases.find(item => item.unit === check.unit && item.check === check.id)?.state,
315
316
  message: [matches.filter(item => item.status !== "passed").map(item => String(item.message || `Case reported ${item.status} without a diagnostic.`).slice(0, 2000)).join("\n"), runnerError ? `${runnerError.message} This check ${matches.length ? `reported ${reportedStatus}` : `was ${progress.cases.find(item => item.unit === check.unit && item.check === check.id)?.state ?? "not reported"}`}; the complete run did not pass.` : !matches.length ? "The selected case did not execute/report. Missing and skipped cases do not pass." : runnerFailure ? `This case reported ${reportedStatus}, but the complete run did not pass. ${runnerFailure}` : ""].filter(Boolean).join("\n"), report: slash(path.relative(reportRoot, report)) });
@@ -213,6 +213,13 @@ Project JavaScript, styles, fonts and UI run only inside that App; the outer
213
213
  shell forwards resource bytes without applying project styles or executing its
214
214
  runtime. This keeps the host neutral while compositions retain their full skin.
215
215
 
216
+ The ADS host gives inline App documents an `about:srcdoc` base when the App
217
+ provides no explicit base URL. Fragment links then stay inside their own document
218
+ with native scrolling, history and events. The sandbox permits this local base;
219
+ external bases still require declared CSP origins. This belongs to document
220
+ loading and changes no project link or scenario handler. External hosts control
221
+ their own document-loading and CSP behavior.
222
+
216
223
  The project compiler publishes a versioned dependency graph: shared runtime and
217
224
  foundation assets, plus independently addressable scenario modules. Inside the
218
225
  App, a resource loader obtains the selected dependency closure through MCP,
@@ -222,6 +229,15 @@ scenarios unmounts the previous view while keeping unchanged dependencies cached
222
229
  Persistence is a host lifecycle choice; a new external widget loads the same
223
230
  resources independently. Resource sharing is scoped to an App instance.
224
231
 
232
+ The showcase's resource bridge can recover a transient fetch failure with at most
233
+ three read attempts and bounded backoff. This applies only to `resources/read`;
234
+ tool calls, assertions and whole checks are never replayed. Cancellation,
235
+ HTTP/protocol/content errors and integrity failures remain failures. Browser
236
+ diagnostics record retries, and verification retains recovered startup reads in
237
+ its case results. Persistent transport failures still block a mutation. External
238
+ hosts own their transport recovery; the reusable App's integrity checks remain
239
+ the same.
240
+
225
241
  Managed graph builders publish into a private session directory beside the
226
242
  configured manifest. Logical scenario IDs and resource URIs stay unchanged;
227
243
  standalone builds retain the configured output and cannot overwrite a live
package/docs/BEHAVIORS.md CHANGED
@@ -169,8 +169,23 @@ pass, even if all reported cases claim success. Results retain `reportedStatus`
169
169
  and `runnerExitCode` and explain the overall failure. Suite-level browser errors and
170
170
  bounded runner output appear in diagnostics. `openBehaviorScenario` includes the
171
171
  scenario ID and failed browser requests in startup failures; App resource errors
172
- identify the resource URI. Failed assertions and startup errors are not retried
173
- automatically. Fix or investigate the failure before explicitly verifying again.
172
+ identify the resource URI. The ADS showcase retries only `resources/read` fetch
173
+ transport failures, with at most three attempts and 200/800 ms backoff. Recovered
174
+ startup reads appear in `startupDiagnostics` with retry counts and failed browser
175
+ requests; each retry is also logged in the browser console. This does not retry a
176
+ tool call, assertion, check or complete startup. HTTP/protocol/content errors,
177
+ integrity failures and cancellations do not retry. Persistent loading failures
178
+ still fail the check and block mutations. External hosts control their own
179
+ transport recovery.
180
+
181
+ `net::ERR_NETWORK_CHANGED` reports Chrome's network-change error, not proof that
182
+ the MCP endpoint restarted or that a particular interface changed. To investigate
183
+ an intermittent failure, correlate the saved case timestamps with Chrome's
184
+ network log, server availability and live interface monitoring (for example,
185
+ `ip -ts monitor link address route` on Linux). Interfaces being present, or stable
186
+ after a failure, does not establish the cause. Preserve the draft and original
187
+ diagnostic; do not change a component API, reference example or verification
188
+ policy to compensate for a resource-loading failure.
174
189
 
175
190
  The reporter atomically publishes partial snapshots at test start/end. While a
176
191
  run is active, `ads_status.behaviors.progress` exposes the profile, runner budget,
package/docs/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.16
4
+
5
+ - Recover transient showcase MCP resource fetch failures with bounded read-only
6
+ retries. Keep tool calls, assertions, checks and non-transport failures outside
7
+ recovery; expose recovered startup reads in verification diagnostics and keep
8
+ persistent loading failures blocking. Verify interrupted resource delivery and
9
+ failed delivery against a dummy App, without changing project verification policy.
10
+
11
+ ## 0.3.15
12
+
13
+ - Keep fragment links inside inline preview documents by supplying a local
14
+ `about:srcdoc` base in the sandbox host and legacy nested widget. Preserve
15
+ explicit App bases, native link events and opaque origins; retain CSP gates
16
+ for external bases. Verify scrolling, state and bridge continuity in browsers.
17
+
3
18
  ## 0.3.14
4
19
 
5
20
  - Preserve independent passing behavior outcomes in complete runs with failed
package/docs/MCP.md CHANGED
@@ -593,6 +593,13 @@ origin hosts the sandbox proxy; that proxy creates an opaque inner App iframe
593
593
  and forwards the standard Apps bridge messages. The diagnostic explorer follows
594
594
  the same sandbox model. Only the App materializes and executes project resources.
595
595
 
596
+ For inline documents without an explicit App base URL, ADS supplies
597
+ `<base href="about:srcdoc">` and permits the local `about:` base scheme in CSP.
598
+ Bare and named fragment links retain native in-document navigation and state.
599
+ Explicit App bases remain subject to declared CSP origins. The legacy nested
600
+ widget uses the same document preparation. External hosts own this behavior in
601
+ their loaders; adding scenario click handlers would conceal a host defect.
602
+
596
603
  Hosts need Apps support, server resource forwarding, native ESM/import maps and
597
604
  a CSP permitting declared `blob:` script/style/font/worker resources. Project
598
605
  previews declare no network connections. The host may enforce stricter policy;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reqvire-org/ads",
3
- "version": "0.3.14",
3
+ "version": "0.3.16",
4
4
  "type": "module",
5
5
  "description": "A design system your agent can see and shape. Your components. Your look. Your code.",
6
6
  "repository": {
@@ -1,30 +0,0 @@
1
- const parentOrigin = new URL(location.href).searchParams.get("parent");
2
- let view;
3
- function domains(values = []) {
4
- return values.filter(value => /^(?:https?:\/\/[a-z0-9.*:[\]-]+(?::\d+)?|data:|blob:|about:)$/i.test(value)).join(" ");
5
- }
6
- function policy(csp = {}) {
7
- const resources = domains(csp.resourceDomains);
8
- return `default-src 'none';script-src 'unsafe-inline' ${resources};style-src 'unsafe-inline' ${resources};img-src data: ${resources};font-src ${resources || "'none'"};media-src ${resources || "'none'"};worker-src ${resources || "'none'"};connect-src ${domains(csp.connectDomains) || "'none'"};frame-src ${domains(csp.frameDomains) || "'none'"};base-uri ${domains(csp.baseUriDomains) || "'none'"};object-src 'none'`;
9
- }
10
- window.addEventListener("message", event => {
11
- if (event.source === parent && event.origin === parentOrigin) {
12
- const message = event.data;
13
- if (message?.method === "ui/notifications/sandbox-resource-ready") {
14
- const { html, csp } = message.params ?? {};
15
- if (typeof html !== "string") return;
16
- const document = new DOMParser().parseFromString(html, "text/html");
17
- const meta = document.createElement("meta");
18
- meta.httpEquiv = "Content-Security-Policy";
19
- meta.content = policy(csp);
20
- document.head.prepend(meta);
21
- view?.remove();
22
- view = window.document.createElement("iframe");
23
- view.title = "Design-system App";
24
- view.setAttribute("sandbox", "allow-scripts");
25
- window.document.body.append(view);
26
- view.srcdoc = "<!doctype html>" + document.documentElement.outerHTML;
27
- } else if (message?.jsonrpc === "2.0" && !message.method?.startsWith("ui/notifications/sandbox-")) view?.contentWindow.postMessage(message, "*");
28
- } else if (event.source === view?.contentWindow && event.data?.jsonrpc === "2.0" && !event.data.method?.startsWith("ui/notifications/sandbox-")) parent.postMessage(event.data, parentOrigin);
29
- });
30
- parent.postMessage({ jsonrpc: "2.0", method: "ui/notifications/sandbox-proxy-ready", params: {} }, parentOrigin);