velloo 0.2.0 → 0.3.0
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.
- package/README.md +1 -1
- package/canvas/assets/index-CqXW6xA_.js +29 -0
- package/canvas/assets/index-gB0StCrx.css +2 -0
- package/canvas/assets/lucide-all-C_CNpsMs.js +1 -0
- package/canvas/assets/{radix-C3HaOB-d.js → radix-gmpYzWRH.js} +1 -1
- package/canvas/index.html +3 -3
- package/chunk-0zen7bzb.js +3 -0
- package/{chunk-er1fxb7d.js → chunk-1jzhw3p4.js} +1 -1
- package/{chunk-j11fyeqh.js → chunk-1n5kmsxb.js} +1 -1
- package/{chunk-08sv3k41.js → chunk-2fgfex9b.js} +1 -1
- package/{chunk-hcb68zt7.js → chunk-3g3dqej3.js} +1 -1
- package/{chunk-vdkrbzh1.js → chunk-3tmsrvaj.js} +1 -1
- package/chunk-49cgk5s2.js +2 -0
- package/{chunk-ek71z2fv.js → chunk-4nqr089t.js} +1 -1
- package/{chunk-sn3x2m0m.js → chunk-52hxv18g.js} +1 -1
- package/chunk-5ezzc1h2.js +688 -0
- package/{chunk-0fe83yzt.js → chunk-5wv5a52y.js} +1 -1
- package/chunk-6nzqhfqq.js +5 -0
- package/{chunk-bwnvcncx.js → chunk-6zz9kfbd.js} +1 -1
- package/chunk-788t8y5x.js +2 -0
- package/{chunk-x4f4k9pp.js → chunk-7bvvbsqy.js} +7 -7
- package/{chunk-xt5ayg7g.js → chunk-7k7dpj5y.js} +1 -1
- package/{chunk-dy41n60j.js → chunk-7njj1qmq.js} +5 -5
- package/{chunk-1h55s5he.js → chunk-9f22qnge.js} +1 -1
- package/{chunk-mnapdp1y.js → chunk-9g4tr0r6.js} +1 -1
- package/{chunk-vgmr98cv.js → chunk-9nhw49vv.js} +1 -1
- package/{chunk-pp86v6m6.js → chunk-as08hzp3.js} +1 -1
- package/{chunk-ngnymg2q.js → chunk-bhx8k09w.js} +1 -1
- package/{chunk-dgwjpbp9.js → chunk-bpeezw7w.js} +1 -1
- package/{chunk-jr0ss0mm.js → chunk-bvmtq0vn.js} +2 -2
- package/{chunk-3e8vez4d.js → chunk-c4fym47a.js} +63 -19
- package/{chunk-jb21jkp1.js → chunk-c6hywdvq.js} +1 -1
- package/{chunk-zb6hc1y0.js → chunk-cxzkkn12.js} +1 -1
- package/{chunk-fsbsksga.js → chunk-d9p6s05n.js} +1 -1
- package/{chunk-2c7jbx46.js → chunk-dsks52m7.js} +1 -1
- package/{chunk-80r93t2e.js → chunk-hfzg98c8.js} +1 -1
- package/{chunk-jfx9xjmr.js → chunk-js6mz7h1.js} +1 -1
- package/{chunk-7eq7nx37.js → chunk-jx11jvq8.js} +1 -1
- package/{chunk-v40fn08f.js → chunk-k6n249vb.js} +2 -2
- package/{chunk-4dn75m6t.js → chunk-k7sehkm8.js} +1 -1
- package/{chunk-sjgqnykd.js → chunk-k9219kmj.js} +1 -1
- package/{chunk-dg6z4vdd.js → chunk-kz4423th.js} +1 -1
- package/{chunk-a84n72m2.js → chunk-m3czg1tt.js} +1 -1
- package/{chunk-ccszg02q.js → chunk-maz6z7tz.js} +1 -1
- package/{chunk-ydhwv29b.js → chunk-n9kcxaj7.js} +2 -2
- package/chunk-n9t36h0q.js +2 -0
- package/{chunk-mh2pr7cq.js → chunk-nr3ej3qf.js} +1 -1
- package/{chunk-40xgcth8.js → chunk-nte0t7v3.js} +2 -2
- package/{chunk-ayrb3qnm.js → chunk-nycs0z7h.js} +1 -1
- package/{chunk-4fj5tahv.js → chunk-qdnb2t6a.js} +1 -1
- package/{chunk-735ezz23.js → chunk-qgwhd4n6.js} +2 -2
- package/{chunk-avns4dbf.js → chunk-sn9vg42q.js} +1 -1
- package/{chunk-rpwpeph5.js → chunk-t5bb30zy.js} +1 -1
- package/{chunk-7eyb8yrf.js → chunk-tbmkq7wy.js} +1 -1
- package/{chunk-jv0xggh0.js → chunk-tc4mzzfw.js} +1 -1
- package/chunk-td5z2sm4.js +6 -0
- package/{chunk-r22epxz2.js → chunk-wa6qamwh.js} +1 -1
- package/{chunk-6w6ch4ce.js → chunk-wcqqx6tz.js} +1 -1
- package/{chunk-ampmdzz4.js → chunk-wzngjjeb.js} +1 -1
- package/chunk-xyfed1j0.js +2 -0
- package/{chunk-n9gs6yx9.js → chunk-y5r2w2z3.js} +1 -1
- package/{chunk-6nqghjda.js → chunk-yeh9gb5w.js} +1 -1
- package/cli.js +1 -1
- package/package.json +1 -1
- package/pkgs/helpers/src/descriptors.ts +7 -1
- package/pkgs/provider-antd/src/index.ts +1 -0
- package/pkgs/provider-chakra/src/index.ts +1 -0
- package/pkgs/provider-mui/src/index.ts +1 -0
- package/pkgs/provider-none/src/index.ts +42 -1
- package/pkgs/provider-none/src/intro.ts +2 -2
- package/pkgs/schema/src/config.ts +19 -0
- package/pkgs/schema/src/extension.ts +26 -0
- package/pkgs/schema/src/index.ts +10 -0
- package/pkgs/schema/src/node.ts +99 -0
- package/pkgs/schema/src/screen.ts +7 -0
- package/pkgs/shadcn-snapshot/dist/manifest.json +9 -1
- package/skills/velloo-setup/SKILL.md +70 -48
- package/canvas/assets/index-BCvDZiBo.css +0 -2
- package/canvas/assets/index-ClaBqcaS.js +0 -28
- package/canvas/assets/lucide-all-iIF-pmzN.js +0 -1
- package/chunk-308ynsxd.js +0 -2
- package/chunk-9vg3yafz.js +0 -3
- package/chunk-eyr8hrzf.js +0 -2
- package/chunk-k17gfwq3.js +0 -2
- package/chunk-rgasy862.js +0 -5
- package/chunk-t448rrfr.js +0 -2
- package/chunk-tdsk5wxa.js +0 -451
- package/chunk-vsv8z729.js +0 -6
package/pkgs/schema/src/node.ts
CHANGED
|
@@ -47,6 +47,37 @@ export type ComponentNode = {
|
|
|
47
47
|
* capture → design → emit. Absent ⇒ the node emits as itself.
|
|
48
48
|
*/
|
|
49
49
|
$emitAs?: { name: string; importPath: string } | undefined;
|
|
50
|
+
/**
|
|
51
|
+
* Repository component identity: this node IS a component the host app
|
|
52
|
+
* imports (a package export such as Mantine's `Tabs`, or the app's own
|
|
53
|
+
* `StatCard`), not a library component. `$ref` stays the JSX name codegen
|
|
54
|
+
* prints; the identity decides rendering and imports. Takes precedence over
|
|
55
|
+
* any provider component or extension of the same name, so shadowing is
|
|
56
|
+
* explicit on the node rather than a registry-order accident.
|
|
57
|
+
*/
|
|
58
|
+
$repo?: RepoComponentRef | undefined;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Where a repository component comes from. The import form is kept exactly as
|
|
63
|
+
* code generation must print it; the resolved file is runtime cache data and
|
|
64
|
+
* never persisted.
|
|
65
|
+
*/
|
|
66
|
+
export type RepoComponentRef = {
|
|
67
|
+
/**
|
|
68
|
+
* Module specifier. Bare (`@mantine/core`) and aliased (`@/components/card`)
|
|
69
|
+
* specifiers are kept as the app writes them; a `./`-relative one is relative
|
|
70
|
+
* to the host app root, since the importing file varies per call site.
|
|
71
|
+
*/
|
|
72
|
+
importPath: string;
|
|
73
|
+
/** The export binding, or `"default"` for a default export. */
|
|
74
|
+
exportName: string;
|
|
75
|
+
/** Static member path of a compound part: `"List"` for `Tabs.List`. */
|
|
76
|
+
member?: string | undefined;
|
|
77
|
+
/** `config.hostApps` key in a monorepo; absent ⇒ the default host app. */
|
|
78
|
+
app?: string | undefined;
|
|
79
|
+
/** Snippet id drawn in the component's place when it can't render for real. */
|
|
80
|
+
proxy?: string | undefined;
|
|
50
81
|
};
|
|
51
82
|
|
|
52
83
|
export type SnippetInstance = {
|
|
@@ -126,6 +157,42 @@ const EmitAsSchema = z.object({
|
|
|
126
157
|
importPath: z.string().min(1),
|
|
127
158
|
});
|
|
128
159
|
|
|
160
|
+
/**
|
|
161
|
+
* A specifier codegen may print verbatim inside `import … from "…"` and the
|
|
162
|
+
* bundler may resolve against the host app. Conservative charset (no quotes,
|
|
163
|
+
* spaces, semicolons), and no absolute or `..` paths: a design folder is data a
|
|
164
|
+
* cloned repo supplies, and it must not be able to reach outside the app.
|
|
165
|
+
*/
|
|
166
|
+
export function repoImportIssue(importPath: string): string | null {
|
|
167
|
+
if (!/^[\w@./~-]+$/.test(importPath)) return "has characters an import specifier can't carry";
|
|
168
|
+
if (importPath.startsWith("/")) return "must not be an absolute path";
|
|
169
|
+
if (importPath.split("/").includes("..")) return "must not climb out of the host app with ..";
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const IDENTIFIER = /^[A-Za-z_$][\w$]*$/;
|
|
174
|
+
|
|
175
|
+
export const RepoComponentRefSchema = z.object({
|
|
176
|
+
importPath: z
|
|
177
|
+
.string()
|
|
178
|
+
.min(1)
|
|
179
|
+
.superRefine((value, ctx) => {
|
|
180
|
+
const issue = repoImportIssue(value);
|
|
181
|
+
if (issue) ctx.addIssue({ code: "custom", message: `importPath ${issue}` });
|
|
182
|
+
}),
|
|
183
|
+
exportName: z
|
|
184
|
+
.string()
|
|
185
|
+
.regex(IDENTIFIER, { message: 'exportName must be an identifier or "default"' }),
|
|
186
|
+
member: z
|
|
187
|
+
.string()
|
|
188
|
+
.regex(/^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*$/, {
|
|
189
|
+
message: 'member must be a dotted identifier path like "List"',
|
|
190
|
+
})
|
|
191
|
+
.optional(),
|
|
192
|
+
app: z.string().min(1).optional(),
|
|
193
|
+
proxy: z.string().min(1).optional(),
|
|
194
|
+
});
|
|
195
|
+
|
|
129
196
|
const ComponentNodeSchema: z.ZodType<ComponentNode> = z.lazy(() =>
|
|
130
197
|
z.object({
|
|
131
198
|
$ref: z.string().min(1),
|
|
@@ -136,9 +203,41 @@ const ComponentNodeSchema: z.ZodType<ComponentNode> = z.lazy(() =>
|
|
|
136
203
|
.transform((items) => items.map(wrapScalarChild))
|
|
137
204
|
.optional(),
|
|
138
205
|
$emitAs: EmitAsSchema.optional(),
|
|
206
|
+
$repo: RepoComponentRefSchema.optional(),
|
|
139
207
|
}),
|
|
140
208
|
);
|
|
141
209
|
|
|
210
|
+
/** True when the node is a repository component (see ComponentNode.$repo). */
|
|
211
|
+
export function isRepoNode(n: Node): n is ComponentNode & { $repo: RepoComponentRef } {
|
|
212
|
+
return isComponentNode(n) && n.$repo !== undefined;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* The runtime key a repository component registers under — identity only, so
|
|
217
|
+
* two apps' `Button`s (or Mantine's vs the provider's) never collide.
|
|
218
|
+
*/
|
|
219
|
+
export function repoKey(ref: RepoComponentRef): string {
|
|
220
|
+
const member = ref.member ? `.${ref.member}` : "";
|
|
221
|
+
return `repo:${encodeURIComponent(ref.app ?? "")}:${ref.importPath}#${ref.exportName}${member}`;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Invert {@link repoKey}. A bundle URL carries only keys, so the runtime can
|
|
226
|
+
* resolve a screen's components from identity alone — no catalog lookup, which
|
|
227
|
+
* keeps a design renderable while discovery is cold or the app has moved on.
|
|
228
|
+
*/
|
|
229
|
+
export function parseRepoKey(key: string): RepoComponentRef | null {
|
|
230
|
+
const match = /^repo:([^:]*):([^#]+)#([A-Za-z_$][\w$]*)(?:\.(.+))?$/.exec(key);
|
|
231
|
+
if (!match) return null;
|
|
232
|
+
const parsed = RepoComponentRefSchema.safeParse({
|
|
233
|
+
importPath: match[2],
|
|
234
|
+
exportName: match[3],
|
|
235
|
+
...(match[4] ? { member: match[4] } : {}),
|
|
236
|
+
...(match[1] ? { app: decodeURIComponent(match[1]) } : {}),
|
|
237
|
+
});
|
|
238
|
+
return parsed.success ? parsed.data : null;
|
|
239
|
+
}
|
|
240
|
+
|
|
142
241
|
const SnippetInstanceSchema: z.ZodType<SnippetInstance> = z.object({
|
|
143
242
|
$snippet: z.string().min(1),
|
|
144
243
|
$id: NodeIdSchema.optional(),
|
|
@@ -24,6 +24,13 @@ export const ScreenSchema = z.object({
|
|
|
24
24
|
* components and extensions resolve against this library's registry.
|
|
25
25
|
*/
|
|
26
26
|
library: z.string().min(1).optional(),
|
|
27
|
+
/**
|
|
28
|
+
* The app route this screen stands for ("/", "/settings/account"). Set by
|
|
29
|
+
* the route scan `init` runs, and editable per screen. The canvas mount
|
|
30
|
+
* hands it to the host framework's router contexts, so a repository nav
|
|
31
|
+
* lights the item the real page would.
|
|
32
|
+
*/
|
|
33
|
+
route: z.string().min(1).optional(),
|
|
27
34
|
tree: NodeSchema,
|
|
28
35
|
});
|
|
29
36
|
|
|
@@ -460,7 +460,15 @@
|
|
|
460
460
|
"group": "layout",
|
|
461
461
|
"family": "Box",
|
|
462
462
|
"source": "velloo",
|
|
463
|
-
"props": [
|
|
463
|
+
"props": [
|
|
464
|
+
{
|
|
465
|
+
"name": "as",
|
|
466
|
+
"type": "string",
|
|
467
|
+
"optional": true,
|
|
468
|
+
"control": "string"
|
|
469
|
+
}
|
|
470
|
+
],
|
|
471
|
+
"designModeNotes": "A plain div by default; `as` renders a lowercase HTML tag instead — \"span\" for an inline run inside a sentence, \"ul\"/\"li\", \"section\". Anything else falls back to div.",
|
|
464
472
|
"example": {
|
|
465
473
|
"className": "flex flex-col gap-6 px-8 py-12"
|
|
466
474
|
}
|
|
@@ -11,18 +11,41 @@ description: >-
|
|
|
11
11
|
|
|
12
12
|
# Calibrating Velloo to an existing app
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
The canvas renders the app's own components — whatever library they come from
|
|
15
|
+
(Mantine, a private design system, a hand-rolled `components/` directory) —
|
|
16
|
+
as real, nested, editable nodes. `list_components` lists them on **Repo**
|
|
17
|
+
shelves, found from what the app's routes actually render. For shadcn folders
|
|
18
|
+
the configured `components/ui` files additionally back the library itself.
|
|
19
|
+
None of that is a promise that arbitrary application React runs inside a
|
|
20
|
+
design iframe: the components need the context the app gives them (providers,
|
|
21
|
+
global CSS), portal-heavy families use adaptations, and a component that can't
|
|
22
|
+
build or render falls back on its own. Fidelity is observable through
|
|
23
|
+
`component_status`; never infer it from a component merely appearing on screen.
|
|
21
24
|
|
|
22
25
|
Your job here is to close that gap **before** you start designing, and to say
|
|
23
26
|
honestly what's left open. Do this once per design folder. Skip it only for a
|
|
24
27
|
greenfield folder with no app to match.
|
|
25
28
|
|
|
29
|
+
## 0. The preview entry — when the app has components
|
|
30
|
+
|
|
31
|
+
Call `preview_status` first. It reports `state` (`absent` / `valid` /
|
|
32
|
+
`failing`), the providers and stylesheets the app's own entry uses
|
|
33
|
+
(`appWrappers`, `appStylesheets`), and mounts one real component to prove the
|
|
34
|
+
setup works — a missing provider or an unstyled render shows up here, not
|
|
35
|
+
halfway through a design.
|
|
36
|
+
|
|
37
|
+
- **`valid` with a recipe** (Mantine and friends): a built-in wrapper is doing
|
|
38
|
+
the work, themed from Velloo's tokens. Good enough to design with; write your
|
|
39
|
+
own entry only when the app's theme, router or data providers matter.
|
|
40
|
+
- **`absent` / `failing`**: adapt `suggestedPreviewEntry` — it is lifted from
|
|
41
|
+
the app's entry — and call `set_preview_entry { source }`. Keep the app's
|
|
42
|
+
global CSS imports, swap network-backed providers for fixtures (a
|
|
43
|
+
`QueryClient` with seeded data, a memory router), never pass credentials. The
|
|
44
|
+
tool re-probes and answers with the new state; iterate until `valid`.
|
|
45
|
+
|
|
46
|
+
A snippet can't do this job: it is node data, so it can't import CSS, build a
|
|
47
|
+
router or wrap the whole screen. Snippets are for step 4 below.
|
|
48
|
+
|
|
26
49
|
## 1. Theme first — it buys the most
|
|
27
50
|
|
|
28
51
|
`import_theme { cssPath, apply: true }` against the app's stylesheet. This is
|
|
@@ -78,26 +101,28 @@ live data legitimately differ.
|
|
|
78
101
|
|
|
79
102
|
Only after theme parity, call `component_status { screen: "<id>" }` for each
|
|
80
103
|
screen you're about to design or verify (or `{ ids: [...] }` before a screen
|
|
81
|
-
exists
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
- **`exact`** —
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
- **`adapted`** — the real
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
- **`
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
(`
|
|
104
|
+
exists — repo catalog ids work too). For library components, check `mounted`
|
|
105
|
+
first: that mount is all-or-nothing, so a single `unavailable` library
|
|
106
|
+
component keeps the whole screen on Velloo's bundled components. A screen with
|
|
107
|
+
the app's own components always mounts, and each of those falls back alone.
|
|
108
|
+
Treat the statuses as part of the design brief:
|
|
109
|
+
|
|
110
|
+
- **`exact`** — the app's own source (or package export) renders in the canvas
|
|
111
|
+
mount. Custom CVA variants and ordinary explicit props are also reflected
|
|
112
|
+
into discovery when their syntax is recognizable.
|
|
113
|
+
- **`adapted`** — the real component renders through a design-time wrapper
|
|
114
|
+
(an overlay kept inside the frame, focus trapping off). Preserve its identity
|
|
115
|
+
and props, but do not claim pixel-identical behavior.
|
|
116
|
+
- **`unstyled`** — it rendered, but its stylesheet never loaded: import the
|
|
117
|
+
library's CSS in the preview entry.
|
|
118
|
+
- **`fallback`** — a bundled provider component or Velloo helper is rendering
|
|
119
|
+
instead of the app's file. Read the returned note/errors.
|
|
120
|
+
- **`proxy`** — the app's component can't render here, and the node's proxy
|
|
121
|
+
snippet stands in for it; emitted code still imports the real one.
|
|
122
|
+
- **`unavailable`** — nothing renders it; read its `code` and `remedy`
|
|
123
|
+
(`missing-provider`, `resolve-failed`, `compile-failed`, `server-only`,
|
|
124
|
+
`render-threw`, `missing-export`). A resolution failure usually means the
|
|
125
|
+
recorded app root is wrong (`velloo design set-app-root`).
|
|
101
126
|
|
|
102
127
|
Host-source edits invalidate the canvas bundle automatically. After changing a
|
|
103
128
|
component, wait for the frame to reload and call `component_status` again; do
|
|
@@ -106,25 +131,22 @@ not restart the daemon merely to pick up a normal source edit.
|
|
|
106
131
|
## 4. Close only the important remaining gaps
|
|
107
132
|
|
|
108
133
|
If an on-screen component is not `exact` and the difference is load-bearing,
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
- **
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
mount is visual-only, and it breaks whenever the host file doesn't compile.
|
|
126
|
-
Never the default for library components, and never use it to work around a
|
|
127
|
-
compound component with children.
|
|
134
|
+
choose the smallest honest adaptation:
|
|
135
|
+
|
|
136
|
+
- **Fix the context** first: most `unavailable` app components are missing a
|
|
137
|
+
provider or fixture the preview entry can supply.
|
|
138
|
+
- **A proxy snippet** for a component that genuinely can't render in a static
|
|
139
|
+
canvas (it needs live data, a server, a browser API). `add_snippet` composing
|
|
140
|
+
primitives to match its appearance, then point the node at it — `update_props`
|
|
141
|
+
can't set identity, so place it with `add_node { repo: { importPath,
|
|
142
|
+
exportName }, … }` and a `proxy`, or record `"proxy": "<snippet-id>"` for it in
|
|
143
|
+
the design folder's `repo-components.json`. The snippet draws on the canvas;
|
|
144
|
+
`emit_code` still imports the real component with the design's props.
|
|
145
|
+
- **A snippet** (`add_snippet`) for a composition that isn't a component in the
|
|
146
|
+
app at all. `render_snippet` immediately after defining one.
|
|
147
|
+
- **A live extension** (`add_extension` with `render: "live"`) only for a
|
|
148
|
+
dynamic leaf the preview entry can't make render as a normal node. Its
|
|
149
|
+
children are stripped and the mount is visual-only.
|
|
128
150
|
|
|
129
151
|
Do not replace an `adapted` overlay merely because its status is not `exact`;
|
|
130
152
|
the adaptation is what keeps dialogs, menus, popovers, and similar components
|
|
@@ -138,8 +160,8 @@ session — and the user — knows where things stand. Three headings, honest:
|
|
|
138
160
|
|
|
139
161
|
- **Exact** — theme imported from `<path>`, fonts, and the components reported
|
|
140
162
|
`exact` by `component_status`.
|
|
141
|
-
- **Adapted / fallback** — the status, reason, and any
|
|
142
|
-
decision made to close a load-bearing difference.
|
|
163
|
+
- **Adapted / fallback / proxy** — the status, reason, and any preview-entry,
|
|
164
|
+
proxy-snippet or live decision made to close a load-bearing difference.
|
|
143
165
|
- **Unverified** — screens behind auth you couldn't reach, pages whose dev
|
|
144
166
|
server wouldn't start, tokens the stylesheet didn't declare.
|
|
145
167
|
|