@reqvire-org/ads 0.3.11 → 0.3.12

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.
@@ -4,7 +4,7 @@ import ts from "typescript";
4
4
  import { isInside, sourceFiles } from "../config.mjs";
5
5
  import { projectCompilerOptions } from "../boundaries.mjs";
6
6
  import { publicApi } from "../public-api.mjs";
7
- import { projectGuideFiles } from "../project-documents.mjs";
7
+ import { projectDocumentFiles } from "../project-documents.mjs";
8
8
 
9
9
  export const PROJECT_URI = "ads://project";
10
10
  export const sourceUri = (file) => `${PROJECT_URI}/files/${file.split("/").map(encodeURIComponent).join("/")}`;
@@ -21,10 +21,10 @@ export function projectDocuments(options) {
21
21
  }
22
22
  for (const directory of new Set(files.map((file) => path.dirname(file)))) docs(directory);
23
23
  docs(dsRoot);
24
- for (const name of projectGuideFiles(root)) files.push(path.join(root, name));
24
+ for (const directory of new Set([root,dsRoot])) for (const name of projectDocumentFiles(directory)) files.push(path.join(directory, name));
25
25
  return [...new Set(files)].filter((file) => isInside(root, realpathSync(file))).sort().map((file) => {
26
26
  const relative = path.relative(root, file).replaceAll("\\", "/");
27
- return { uri: sourceUri(relative), name: relative, mimeType: file.endsWith(".md") ? "text/markdown" : file.endsWith(".json") ? "application/json" : "text/plain", file };
27
+ return { uri: sourceUri(relative), name: relative, mimeType: /\.md$/i.test(file) ? "text/markdown" : file.endsWith(".json") ? "application/json" : "text/plain", file };
28
28
  });
29
29
  }
30
30
 
@@ -65,7 +65,7 @@ function validateContent(change, unit) {
65
65
  if (change.content === null) return;
66
66
  const bytes = Buffer.from(change.content);
67
67
  if (bytes.length > mutationLimits.fileBytes) throw fail("mutation-content", "The patched file exceeds 16 MiB.", change.path);
68
- if (textFile(change.path) && (bytes.includes(0) || !Buffer.from(bytes.toString("utf8")).equals(bytes))) throw fail("mutation-content", "Text source must contain valid UTF-8 without NUL bytes.", change.path);
68
+ if ((unit === "documentation" || textFile(change.path)) && (bytes.includes(0) || !Buffer.from(bytes.toString("utf8")).equals(bytes))) throw fail("mutation-content", "Text source and documentation must contain valid UTF-8 without NUL bytes.", change.path);
69
69
  if (/\.jsonc?$/.test(change.path)) {
70
70
  const content=bytes.toString("utf8");
71
71
  if (unit === "configuration" && !["package.json","ds.config.json"].includes(path.basename(change.path))) {
@@ -260,9 +260,9 @@ export function createAdsMcp(directory, { era = "legacy", skillDirectory, pollIn
260
260
  await refresh();
261
261
  return { ...json(result), ...(!result.ok ? { isError: true } : {}) };
262
262
  } },
263
- { name: "ads_units", description: "Discover editable ADS units and their files: components/patterns with colocated previews; shared controllers; composition; tokens; foundation shared files; documentation; assets/brand, assets/fonts and asset groups; configuration with ds.config.json, package/build/lint configuration and registered project guard/compiler sources. List summaries with query, or pass an exact unit ID for its manifest. Manifests include companionFiles with permitted shared-entry or owner-only style-boundary bookkeeping; preserve peer permissions and unrelated configuration. Imported peers stay separate. New owners follow the existing colocation convention.", schema: query.extend({ unit: z.string().min(1).max(256).optional() }), call: ({ unit, query: search = "", limit }) => {
263
+ { name: "ads_units", description: "Discover editable ADS units and their files: components/patterns with colocated previews; shared controllers; composition; tokens; foundation shared files; documentation including shared credits/license notices; assets/brand, assets/fonts and asset groups; configuration with ds.config.json, package/build/lint configuration and registered project guard/compiler sources. List summaries with query, or pass an exact unit ID for its manifest. Manifests include filePolicy for supported new documentation paths and companionFiles with permitted shared-entry or owner-only style-boundary bookkeeping; preserve peer permissions and unrelated configuration. Imported peers stay separate. New owners follow the existing colocation convention.", schema: query.extend({ unit: z.string().min(1).max(256).optional() }), call: ({ unit, query: search = "", limit }) => {
264
264
  const matches = edits.units().filter(item => unit ? item.id === unit : item.id.toLowerCase().includes(search.toLowerCase()));
265
- return json({ total: matches.length, units: matches.slice(0, limit).map(item => ({ id: item.id, kind: item.kind, fileCount: item.files.length, ...(unit ? { files: item.files.slice(0, 200), filesTruncated: item.files.length > 200, ...(item.companionFiles ? { companionFiles: item.companionFiles } : {}) } : {}) })) });
265
+ return json({ total: matches.length, units: matches.slice(0, limit).map(item => ({ id: item.id, kind: item.kind, fileCount: item.files.length, ...(unit ? { files: item.files.slice(0, 200), filesTruncated: item.files.length > 200, ...(item.companionFiles ? { companionFiles: item.companionFiles } : {}), ...(item.filePolicy ? { filePolicy: item.filePolicy } : {}) } : {}) })) });
266
266
  } },
267
267
  { name: "ads_read_file", description: "Read a bounded range of ADS or registered configuration/extension source. Returns unit, full-file digest, startLine and nextOffset; default/max is 12000 UTF-16 characters. Binary assets return byte count/digest and no encoded content. Paths come from ads_units or discovery. Missing new paths return digest null. Read only relevant context before preparing a Git patch.", schema: z.object({ path: z.string().min(1).max(500), offset: z.number().int().min(0).default(0), limit: z.number().int().min(1).max(mutationLimits.readChars).default(mutationLimits.readChars) }).strict(), call: ({ path: file, ...range }) => json(edits.read(file, range)) },
268
268
  ...(mutations ? [{ name: "ads_prepare_patch", description: "Prepare a Git patch without a separate project mirror. Create copies only one owner plus its declared companions into a local draft; edit that directory with local file tools. Diff checks baseline/source freshness and owner paths, then writes a patchFile under .ds/patches. Discard removes the draft. Live source is never changed; ads_apply_patch still validates all gates. Remote clients can continue sending inline Git diffs instead.", schema:z.object({unit:z.string().min(1).max(256),action:z.enum(["create","diff","discard"]).default("create"),draft:z.string().max(100).optional()}).strict(), call:args=>json(prepareUnitPatch(options,args)) },
@@ -2,15 +2,31 @@ import { existsSync, lstatSync, readdirSync } from "node:fs";
2
2
  import path from "node:path";
3
3
 
4
4
  const rootNames = ["README.md", "ADS.md", "DS.md", "ARCHITECTURE.md", "Architecture.md", "GUIDE.md", "MCP.md", "CHANGELOG.md"];
5
+ const noticeStem = /^(?:CREDITS|LICEN[CS]ES?|NOTICES?|COPYING|COPYRIGHT)(?:[-_][A-Za-z0-9][A-Za-z0-9._-]*)?$/i;
6
+ const textExtension = /\.(?:md|txt)$/i;
7
+
8
+ export const documentationFilePolicy = "Project guides; root CREDITS, LICENSE/LICENCE, NOTICE, COPYING and COPYRIGHT notices (optional -/_ qualifiers); licenses/ collections, also under docs/ or doc/. Notices use .md, .txt, or conventional extensionless names and valid UTF-8. The same document paths may live at the ADS root. Component-local notices remain with their owner; code, configuration, hidden and generated paths are excluded.";
9
+
10
+ function noticeName(name) {
11
+ const extension = path.posix.extname(name);
12
+ return (!extension || textExtension.test(name)) && noticeStem.test(extension ? name.slice(0,-extension.length) : name);
13
+ }
14
+
15
+ function isProjectNotice(file) {
16
+ if (!file.includes("/")) return noticeName(file);
17
+ return /^(?:(?:docs|doc)\/)?licenses\/.+$/i.test(file) && (textExtension.test(file) || noticeName(path.posix.basename(file)));
18
+ }
5
19
 
6
20
  /** Recognize documentation ownership even before a new guide exists. */
7
21
  export function isProjectDocument(file) {
8
- return rootNames.includes(file) || /^(?:docs|doc)\/.+\.md$/i.test(file) && !file.split("/").some(part => part.startsWith("."));
22
+ if (file.includes("\\") || file.includes("\0") || file.split("/").some(part => !part || part.startsWith("."))) return false;
23
+ return rootNames.includes(file) || isProjectNotice(file) || /^(?:docs|doc)\/.+\.md$/i.test(file);
9
24
  }
10
25
 
11
- /** Shared guide discovery for MCP resources, workflow context and editable units. */
12
- export function projectGuideFiles(root) {
13
- const files = rootNames.filter(file => existsSync(path.join(root, file)) && lstatSync(path.join(root, file)).isFile());
26
+ /** Shared document discovery for MCP resources and editable units. */
27
+ export function projectDocumentFiles(root) {
28
+ if (!existsSync(root) || !lstatSync(root).isDirectory()) return [];
29
+ const files = [];
14
30
  function walk(relative) {
15
31
  const directory = path.join(root, relative);
16
32
  if (!existsSync(directory) || !lstatSync(directory).isDirectory()) return;
@@ -21,7 +37,14 @@ export function projectGuideFiles(root) {
21
37
  else if (entry.isFile() && isProjectDocument(file)) files.push(file);
22
38
  }
23
39
  }
24
- walk("docs");
25
- walk("doc");
40
+ for (const entry of readdirSync(root,{withFileTypes:true})) {
41
+ if (entry.isFile() && isProjectDocument(entry.name)) files.push(entry.name);
42
+ else if (entry.isDirectory() && /^(?:docs|doc|licenses)$/i.test(entry.name)) walk(entry.name);
43
+ }
26
44
  return files.sort();
27
45
  }
46
+
47
+ /** Provenance stays discoverable without loading notice inventories as workflow guides. */
48
+ export function projectGuideFiles(root) {
49
+ return projectDocumentFiles(root).filter(file => !isProjectNotice(file));
50
+ }
@@ -49,10 +49,12 @@ For owner drafts, token-sample reconciliation, coupled transactions and local
49
49
  constant namespaces, read [guarded-editing.md](references/guarded-editing.md).
50
50
 
51
51
 
52
- For parent/child `covers`, public style-helper use in scenarios, or
53
- `scenario-render` / `showcase-class` findings, read
54
- [scenario contracts](references/scenarios.md). Traced parents can cover declared
55
- public children; verified public Linaria helpers do not grant custom scenario CSS.
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
55
+ examples explain API visibility, reference baselines and state-transition checks.
56
+ Traced parents can cover declared public children; verified public Linaria
57
+ helpers do not grant custom scenario CSS.
56
58
 
57
59
  For atomic base/variant styling, helper/wrapper class composition, extracted
58
60
  custom-property arithmetic, or an
@@ -6,6 +6,16 @@ tools, request `action:"diff"`, then apply the returned patchFile. Discard the
6
6
  draft afterward. Remote clients can keep sending inline Git diffs. Neither draft
7
7
  preparation nor diff generation validates or changes live source.
8
8
 
9
+ Shared provenance uses the existing `documentation` unit. Read its `filePolicy`
10
+ from `ads_units`: one patch can create `CREDITS.md`, shared `licenses/*.txt` and
11
+ README links together. Conventional root credits/license/notice names support
12
+ UTF-8 `.md`/`.txt` or extensionless notices; `licenses/` may also sit under
13
+ `docs/`, `doc/` or the ADS root. Preserve upstream notice text exactly. Keep
14
+ component/asset-local notices with their owner; reference shared notices instead
15
+ of duplicating them across units. Do not create an asset group or bypass a guard
16
+ to add these documents. Code/configuration and hidden/generated paths remain
17
+ outside documentation ownership.
18
+
9
19
  For genuinely coupled changes, `ads_apply_transaction` accepts 2–8 distinct owner
10
20
  patches (32 distinct files and 16 MiB combined). Each patch keeps its ownership and
11
21
  companion restrictions. Patches apply in order; later shared-entry hunks match the
@@ -68,6 +68,23 @@ just to satisfy a guard. Static evidence does not establish successful mounting,
68
68
  visibility, interaction, every state or visual parity. Verify those in the built
69
69
  App and registered browser checks.
70
70
 
71
+ ## Verification pitfalls
72
+
73
+ Preserve the intended API and the reference baseline when resolving a diagnostic.
74
+ These examples describe verification mistakes, not component-specific rules:
75
+
76
+ | Situation | Do not | Do instead |
77
+ |-----------|--------|------------|
78
+ | A reference example sets `width: 15rem`, while the native popup uses its default width. | Remove the reference width and claim the original example now matches. | Keep the baseline intact. Reproduce demo sizing through the project's public review/layout pattern or supported style helper. If a different native size is intentional, document it. Label any additional normalized comparison separately. |
79
+ | Static tracing cannot prove that a public clear control renders when a value is selected. | Remove its export, drop its required coverage, or change runtime behavior merely to pass the gate. | Preserve the intended public API. Try a meaningful selected-state fixture or another real scenario. If valid rendering remains untraceable, report the tooling limitation with a small reproduction. |
80
+ | A screenshot shows the clear control in a selected state. | Treat its presence as evidence that clearing works. | Add a browser check: start selected, activate Clear, assert the value and selection are empty, verify the control's resulting visibility and documented focus behavior, then select again. |
81
+
82
+ A private helper exposed through its parent's public prop can legitimately stay
83
+ private when that is the intended API. Verify the behavior through the parent;
84
+ do not export the helper solely for a test. Public/private ownership is a product
85
+ decision, not a coverage workaround. Browser checks verify transitions but do not
86
+ replace the current static `covers` requirement; `exercises` does not waive it.
87
+
71
88
  ## Scenarios may consume verified public style helpers
72
89
 
73
90
  A deliberately public helper can expose its owner's Linaria treatment:
@@ -80,10 +80,12 @@ use the client's normal source-editing tools.
80
80
  For owner drafts, token-sample reconciliation, coupled transactions and local
81
81
  constant namespaces, read [guarded-editing.md](references/guarded-editing.md).
82
82
 
83
- For parent/child `covers`, public style-helper use in scenarios, or
84
- `scenario-render` / `showcase-class` findings, read
85
- [scenario contracts](references/scenarios.md). Traced parents can cover declared
86
- public children; verified public Linaria helpers do not grant custom scenario CSS.
83
+ For parent/child `covers`, conditional-control review, reference comparisons,
84
+ public style-helper use in scenarios, or `scenario-render` / `showcase-class`
85
+ findings, read [scenario contracts](references/scenarios.md). Its verification
86
+ examples explain API visibility, reference baselines and state-transition checks.
87
+ Traced parents can cover declared public children; verified public Linaria
88
+ helpers do not grant custom scenario CSS.
87
89
 
88
90
  For atomic base/variant styling, helper/wrapper class composition, extracted
89
91
  custom-property arithmetic, or an
@@ -6,6 +6,16 @@ tools, request `action:"diff"`, then apply the returned patchFile. Discard the
6
6
  draft afterward. Remote clients can keep sending inline Git diffs. Neither draft
7
7
  preparation nor diff generation validates or changes live source.
8
8
 
9
+ Shared provenance uses the existing `documentation` unit. Read its `filePolicy`
10
+ from `ads_units`: one patch can create `CREDITS.md`, shared `licenses/*.txt` and
11
+ README links together. Conventional root credits/license/notice names support
12
+ UTF-8 `.md`/`.txt` or extensionless notices; `licenses/` may also sit under
13
+ `docs/`, `doc/` or the ADS root. Preserve upstream notice text exactly. Keep
14
+ component/asset-local notices with their owner; reference shared notices instead
15
+ of duplicating them across units. Do not create an asset group or bypass a guard
16
+ to add these documents. Code/configuration and hidden/generated paths remain
17
+ outside documentation ownership.
18
+
9
19
  For genuinely coupled changes, `ads_apply_transaction` accepts 2–8 distinct owner
10
20
  patches (32 distinct files and 16 MiB combined). Each patch keeps its ownership and
11
21
  companion restrictions. Patches apply in order; later shared-entry hunks match the
@@ -68,6 +68,23 @@ just to satisfy a guard. Static evidence does not establish successful mounting,
68
68
  visibility, interaction, every state or visual parity. Verify those in the built
69
69
  App and registered browser checks.
70
70
 
71
+ ## Verification pitfalls
72
+
73
+ Preserve the intended API and the reference baseline when resolving a diagnostic.
74
+ These examples describe verification mistakes, not component-specific rules:
75
+
76
+ | Situation | Do not | Do instead |
77
+ |-----------|--------|------------|
78
+ | A reference example sets `width: 15rem`, while the native popup uses its default width. | Remove the reference width and claim the original example now matches. | Keep the baseline intact. Reproduce demo sizing through the project's public review/layout pattern or supported style helper. If a different native size is intentional, document it. Label any additional normalized comparison separately. |
79
+ | Static tracing cannot prove that a public clear control renders when a value is selected. | Remove its export, drop its required coverage, or change runtime behavior merely to pass the gate. | Preserve the intended public API. Try a meaningful selected-state fixture or another real scenario. If valid rendering remains untraceable, report the tooling limitation with a small reproduction. |
80
+ | A screenshot shows the clear control in a selected state. | Treat its presence as evidence that clearing works. | Add a browser check: start selected, activate Clear, assert the value and selection are empty, verify the control's resulting visibility and documented focus behavior, then select again. |
81
+
82
+ A private helper exposed through its parent's public prop can legitimately stay
83
+ private when that is the intended API. Verify the behavior through the parent;
84
+ do not export the helper solely for a test. Public/private ownership is a product
85
+ decision, not a coverage workaround. Browser checks verify transitions but do not
86
+ replace the current static `covers` requirement; `exercises` does not waive it.
87
+
71
88
  ## Scenarios may consume verified public style helpers
72
89
 
73
90
  A deliberately public helper can expose its owner's Linaria treatment:
@@ -44,10 +44,12 @@ use the client's normal source-editing tools.
44
44
  For owner drafts, token-sample reconciliation, coupled transactions and local
45
45
  constant namespaces, read [guarded-editing.md](references/guarded-editing.md).
46
46
 
47
- For parent/child `covers`, public style-helper use in scenarios, or
48
- `scenario-render` / `showcase-class` findings, read
49
- [scenario contracts](references/scenarios.md). Traced parents can cover declared
50
- public children; verified public Linaria helpers do not grant custom scenario CSS.
47
+ For parent/child `covers`, conditional-control review, reference comparisons,
48
+ public style-helper use in scenarios, or `scenario-render` / `showcase-class`
49
+ findings, read [scenario contracts](references/scenarios.md). Its verification
50
+ examples explain API visibility, reference baselines and state-transition checks.
51
+ Traced parents can cover declared public children; verified public Linaria
52
+ helpers do not grant custom scenario CSS.
51
53
 
52
54
  For atomic base/variant styling, helper/wrapper class composition, extracted
53
55
  custom-property arithmetic, or an
@@ -6,6 +6,16 @@ tools, request `action:"diff"`, then apply the returned patchFile. Discard the
6
6
  draft afterward. Remote clients can keep sending inline Git diffs. Neither draft
7
7
  preparation nor diff generation validates or changes live source.
8
8
 
9
+ Shared provenance uses the existing `documentation` unit. Read its `filePolicy`
10
+ from `ads_units`: one patch can create `CREDITS.md`, shared `licenses/*.txt` and
11
+ README links together. Conventional root credits/license/notice names support
12
+ UTF-8 `.md`/`.txt` or extensionless notices; `licenses/` may also sit under
13
+ `docs/`, `doc/` or the ADS root. Preserve upstream notice text exactly. Keep
14
+ component/asset-local notices with their owner; reference shared notices instead
15
+ of duplicating them across units. Do not create an asset group or bypass a guard
16
+ to add these documents. Code/configuration and hidden/generated paths remain
17
+ outside documentation ownership.
18
+
9
19
  For genuinely coupled changes, `ads_apply_transaction` accepts 2–8 distinct owner
10
20
  patches (32 distinct files and 16 MiB combined). Each patch keeps its ownership and
11
21
  companion restrictions. Patches apply in order; later shared-entry hunks match the
@@ -92,7 +92,9 @@ imports, setup/providers, and scope/mounting across routes where relevant.
92
92
 
93
93
  Compare the imported component or pattern with the actual source implementation
94
94
  at the recorded revision. Align content, configuration, themes, viewport, and
95
- input modality. For implementation comparisons, use matching token values when
95
+ input modality. Preserve the original comparison baseline; see the
96
+ [verification pitfalls](scenarios.md#verification-pitfalls) before changing
97
+ reference sizing or API visibility to make checks pass. For implementation comparisons, use matching token values when
96
98
  possible; also verify the item under its actual destination theme. For
97
99
  stateful/motion-heavy items, check lifecycle, focus, keyboard,
98
100
  pointer and touch, natural dimensions, transitions, interruption, reduced motion,
@@ -68,6 +68,23 @@ just to satisfy a guard. Static evidence does not establish successful mounting,
68
68
  visibility, interaction, every state or visual parity. Verify those in the built
69
69
  App and registered browser checks.
70
70
 
71
+ ## Verification pitfalls
72
+
73
+ Preserve the intended API and the reference baseline when resolving a diagnostic.
74
+ These examples describe verification mistakes, not component-specific rules:
75
+
76
+ | Situation | Do not | Do instead |
77
+ |-----------|--------|------------|
78
+ | A reference example sets `width: 15rem`, while the native popup uses its default width. | Remove the reference width and claim the original example now matches. | Keep the baseline intact. Reproduce demo sizing through the project's public review/layout pattern or supported style helper. If a different native size is intentional, document it. Label any additional normalized comparison separately. |
79
+ | Static tracing cannot prove that a public clear control renders when a value is selected. | Remove its export, drop its required coverage, or change runtime behavior merely to pass the gate. | Preserve the intended public API. Try a meaningful selected-state fixture or another real scenario. If valid rendering remains untraceable, report the tooling limitation with a small reproduction. |
80
+ | A screenshot shows the clear control in a selected state. | Treat its presence as evidence that clearing works. | Add a browser check: start selected, activate Clear, assert the value and selection are empty, verify the control's resulting visibility and documented focus behavior, then select again. |
81
+
82
+ A private helper exposed through its parent's public prop can legitimately stay
83
+ private when that is the intended API. Verify the behavior through the parent;
84
+ do not export the helper solely for a test. Public/private ownership is a product
85
+ decision, not a coverage workaround. Browser checks verify transitions but do not
86
+ replace the current static `covers` requirement; `exercises` does not waive it.
87
+
71
88
  ## Scenarios may consume verified public style helpers
72
89
 
73
90
  A deliberately public helper can expose its owner's Linaria treatment:
@@ -46,10 +46,12 @@ For owner drafts, token-sample reconciliation, coupled transactions and local
46
46
  constant namespaces, read [guarded-editing.md](references/guarded-editing.md).
47
47
 
48
48
 
49
- For parent/child `covers`, public style-helper use in scenarios, or
50
- `scenario-render` / `showcase-class` findings, read
51
- [scenario contracts](references/scenarios.md). Traced parents can cover declared
52
- public children; verified public Linaria helpers do not grant custom scenario CSS.
49
+ For parent/child `covers`, conditional-control review, reference comparisons,
50
+ public style-helper use in scenarios, or `scenario-render` / `showcase-class`
51
+ findings, read [scenario contracts](references/scenarios.md). Its verification
52
+ examples explain API visibility, reference baselines and state-transition checks.
53
+ Traced parents can cover declared public children; verified public Linaria
54
+ helpers do not grant custom scenario CSS.
53
55
 
54
56
  For atomic base/variant styling, helper/wrapper class composition, extracted
55
57
  custom-property arithmetic, or an
@@ -6,6 +6,16 @@ tools, request `action:"diff"`, then apply the returned patchFile. Discard the
6
6
  draft afterward. Remote clients can keep sending inline Git diffs. Neither draft
7
7
  preparation nor diff generation validates or changes live source.
8
8
 
9
+ Shared provenance uses the existing `documentation` unit. Read its `filePolicy`
10
+ from `ads_units`: one patch can create `CREDITS.md`, shared `licenses/*.txt` and
11
+ README links together. Conventional root credits/license/notice names support
12
+ UTF-8 `.md`/`.txt` or extensionless notices; `licenses/` may also sit under
13
+ `docs/`, `doc/` or the ADS root. Preserve upstream notice text exactly. Keep
14
+ component/asset-local notices with their owner; reference shared notices instead
15
+ of duplicating them across units. Do not create an asset group or bypass a guard
16
+ to add these documents. Code/configuration and hidden/generated paths remain
17
+ outside documentation ownership.
18
+
9
19
  For genuinely coupled changes, `ads_apply_transaction` accepts 2–8 distinct owner
10
20
  patches (32 distinct files and 16 MiB combined). Each patch keeps its ownership and
11
21
  companion restrictions. Patches apply in order; later shared-entry hunks match the
@@ -68,6 +68,23 @@ just to satisfy a guard. Static evidence does not establish successful mounting,
68
68
  visibility, interaction, every state or visual parity. Verify those in the built
69
69
  App and registered browser checks.
70
70
 
71
+ ## Verification pitfalls
72
+
73
+ Preserve the intended API and the reference baseline when resolving a diagnostic.
74
+ These examples describe verification mistakes, not component-specific rules:
75
+
76
+ | Situation | Do not | Do instead |
77
+ |-----------|--------|------------|
78
+ | A reference example sets `width: 15rem`, while the native popup uses its default width. | Remove the reference width and claim the original example now matches. | Keep the baseline intact. Reproduce demo sizing through the project's public review/layout pattern or supported style helper. If a different native size is intentional, document it. Label any additional normalized comparison separately. |
79
+ | Static tracing cannot prove that a public clear control renders when a value is selected. | Remove its export, drop its required coverage, or change runtime behavior merely to pass the gate. | Preserve the intended public API. Try a meaningful selected-state fixture or another real scenario. If valid rendering remains untraceable, report the tooling limitation with a small reproduction. |
80
+ | A screenshot shows the clear control in a selected state. | Treat its presence as evidence that clearing works. | Add a browser check: start selected, activate Clear, assert the value and selection are empty, verify the control's resulting visibility and documented focus behavior, then select again. |
81
+
82
+ A private helper exposed through its parent's public prop can legitimately stay
83
+ private when that is the intended API. Verify the behavior through the parent;
84
+ do not export the helper solely for a test. Public/private ownership is a product
85
+ decision, not a coverage workaround. Browser checks verify transitions but do not
86
+ replace the current static `covers` requirement; `exercises` does not waive it.
87
+
71
88
  ## Scenarios may consume verified public style helpers
72
89
 
73
90
  A deliberately public helper can expose its owner's Linaria treatment:
@@ -8,6 +8,11 @@ the baseline. The page frame may use native controls, but those controls must
8
8
  trigger the original component and store. Two pages importing the native component
9
9
  cannot establish upstream parity.
10
10
 
11
+ Keep example-level sizing and configuration intact too. Changing a reference to
12
+ match the native result weakens the comparison even when its component CSS is
13
+ untouched. Use the [verification pitfalls](scenarios.md#verification-pitfalls)
14
+ for concrete baseline, API-visibility and conditional-control examples.
15
+
11
16
  Use identical messages, options, counts, async delays/outcomes, action payloads,
12
17
  and viewport/input settings. Align configuration explicitly rather than relying
13
18
  on two different defaults. Compare brand/token differences separately from UX
@@ -66,10 +66,12 @@ For owner drafts, token-sample reconciliation, coupled transactions and local
66
66
  constant namespaces, read [guarded-editing.md](references/guarded-editing.md).
67
67
 
68
68
 
69
- For parent/child `covers`, public style-helper use in scenarios, or
70
- `scenario-render` / `showcase-class` findings, read
71
- [scenario contracts](references/scenarios.md). Traced parents can cover declared
72
- public children; verified public Linaria helpers do not grant custom scenario CSS.
69
+ For parent/child `covers`, conditional-control review, reference comparisons,
70
+ public style-helper use in scenarios, or `scenario-render` / `showcase-class`
71
+ findings, read [scenario contracts](references/scenarios.md). Its verification
72
+ examples explain API visibility, reference baselines and state-transition checks.
73
+ Traced parents can cover declared public children; verified public Linaria
74
+ helpers do not grant custom scenario CSS.
73
75
 
74
76
  For atomic base/variant styling, helper/wrapper class composition, extracted
75
77
  custom-property arithmetic, or an
@@ -6,6 +6,16 @@ tools, request `action:"diff"`, then apply the returned patchFile. Discard the
6
6
  draft afterward. Remote clients can keep sending inline Git diffs. Neither draft
7
7
  preparation nor diff generation validates or changes live source.
8
8
 
9
+ Shared provenance uses the existing `documentation` unit. Read its `filePolicy`
10
+ from `ads_units`: one patch can create `CREDITS.md`, shared `licenses/*.txt` and
11
+ README links together. Conventional root credits/license/notice names support
12
+ UTF-8 `.md`/`.txt` or extensionless notices; `licenses/` may also sit under
13
+ `docs/`, `doc/` or the ADS root. Preserve upstream notice text exactly. Keep
14
+ component/asset-local notices with their owner; reference shared notices instead
15
+ of duplicating them across units. Do not create an asset group or bypass a guard
16
+ to add these documents. Code/configuration and hidden/generated paths remain
17
+ outside documentation ownership.
18
+
9
19
  For genuinely coupled changes, `ads_apply_transaction` accepts 2–8 distinct owner
10
20
  patches (32 distinct files and 16 MiB combined). Each patch keeps its ownership and
11
21
  companion restrictions. Patches apply in order; later shared-entry hunks match the
@@ -68,6 +68,23 @@ just to satisfy a guard. Static evidence does not establish successful mounting,
68
68
  visibility, interaction, every state or visual parity. Verify those in the built
69
69
  App and registered browser checks.
70
70
 
71
+ ## Verification pitfalls
72
+
73
+ Preserve the intended API and the reference baseline when resolving a diagnostic.
74
+ These examples describe verification mistakes, not component-specific rules:
75
+
76
+ | Situation | Do not | Do instead |
77
+ |-----------|--------|------------|
78
+ | A reference example sets `width: 15rem`, while the native popup uses its default width. | Remove the reference width and claim the original example now matches. | Keep the baseline intact. Reproduce demo sizing through the project's public review/layout pattern or supported style helper. If a different native size is intentional, document it. Label any additional normalized comparison separately. |
79
+ | Static tracing cannot prove that a public clear control renders when a value is selected. | Remove its export, drop its required coverage, or change runtime behavior merely to pass the gate. | Preserve the intended public API. Try a meaningful selected-state fixture or another real scenario. If valid rendering remains untraceable, report the tooling limitation with a small reproduction. |
80
+ | A screenshot shows the clear control in a selected state. | Treat its presence as evidence that clearing works. | Add a browser check: start selected, activate Clear, assert the value and selection are empty, verify the control's resulting visibility and documented focus behavior, then select again. |
81
+
82
+ A private helper exposed through its parent's public prop can legitimately stay
83
+ private when that is the intended API. Verify the behavior through the parent;
84
+ do not export the helper solely for a test. Public/private ownership is a product
85
+ decision, not a coverage workaround. Browser checks verify transitions but do not
86
+ replace the current static `covers` requirement; `exercises` does not waive it.
87
+
71
88
  ## Scenarios may consume verified public style helpers
72
89
 
73
90
  A deliberately public helper can expose its owner's Linaria treatment:
package/dist/units.mjs CHANGED
@@ -4,7 +4,7 @@ import ts from "typescript";
4
4
  import postcss from "postcss";
5
5
  import { isDevelopmentFile, isInside } from "./config.mjs";
6
6
  import { importResolver } from "./boundaries.mjs";
7
- import { isProjectDocument, projectGuideFiles } from "./project-documents.mjs";
7
+ import { documentationFilePolicy, isProjectDocument, projectDocumentFiles } from "./project-documents.mjs";
8
8
  import { foundationFiles, foundationImportTarget } from "./token-policy.mjs";
9
9
 
10
10
  const source = /\.[cm]?[jt]sx?$/;
@@ -119,13 +119,13 @@ export function inspectUnits(options) {
119
119
  function owner(relative) {
120
120
  const projectFile = slash(path.relative(root, path.resolve(dsRoot, relative)));
121
121
  if (setup.has(projectFile)) return "configuration";
122
- if (isProjectDocument(projectFile)) return "documentation";
123
- if (!isInside(dsRoot, path.resolve(dsRoot, relative))) return null;
122
+ if (!isInside(dsRoot, path.resolve(dsRoot, relative))) return isProjectDocument(projectFile) ? "documentation" : null;
124
123
  if (relative === publicEntry) return null; // Controlled re-export bookkeeping.
125
124
  if (relative.startsWith(tokenDir + "/")) return "tokens";
126
125
  if (relative.startsWith("assets/")) return relative.split("/").length > 2 ? relative.split("/").slice(0, 2).join("/") : "assets";
126
+ if (isProjectDocument(relative)) return "documentation";
127
127
  if (!relative.includes("/")) return /(?:\.(?:md|txt)$|^LICENSE$)/i.test(relative) ? "documentation" : "foundation";
128
- if (!/^(?:components|patterns|controllers|composition)\//.test(relative)) return relative.split("/")[0];
128
+ if (!/^(?:components|patterns|controllers|composition)\//.test(relative)) return relative.split("/")[0] === "documentation" ? null : relative.split("/")[0];
129
129
  for (const directory of directoryUnits) if (relative.startsWith(directory + "/")) return directory;
130
130
  for (const unit of flatUnits) if (relative.startsWith(unit + "/") || relative.startsWith(unit + ".")) return unit;
131
131
  const base = path.basename(relative).split(".")[0];
@@ -136,7 +136,8 @@ export function inspectUnits(options) {
136
136
  for (const id of ["foundation", "documentation", "tokens", "assets/brand", "assets/fonts"]) units.set(id, { id, kind: id.split("/")[0], files: [] });
137
137
  units.get("tokens").companionFiles = [{ path: slash(path.relative(root, path.join(dsRoot, stylesEntry))),
138
138
  allowedChanges: "Only add/remove canonical foundation imports required by token foundation files created/deleted in this patch; preserve other imports and comments." }];
139
- units.get("documentation").files = projectGuideFiles(root);
139
+ units.get("documentation").files = projectDocumentFiles(root).filter(file => owner(slash(path.relative(dsRoot,path.resolve(root,file)))) === "documentation");
140
+ units.get("documentation").filePolicy = documentationFilePolicy;
140
141
  for (const relative of files) {
141
142
  const id = owner(relative);
142
143
  if (!id) continue;
@@ -182,7 +183,7 @@ export function checkUnitFiles(options, unit, changes, inventory = inspectUnits(
182
183
  if (unit === "tokens" && relative === inventory.stylesEntry) continue; // Controlled foundation import bookkeeping.
183
184
  if (allowNew && change.originalContent === null && (relative.startsWith(unit + "/") || relative.startsWith(unit + "."))) continue;
184
185
  const owner = inventory.owner(relative);
185
- if (owner !== unit) throw fail(`This patch targets ${unit}; ${change.path} belongs to ${owner ?? "a different ADS layer"}. Submit a separate unit patch.`, change.path);
186
+ if (owner !== unit) throw fail(`This patch targets ${unit}; ${change.path} belongs to ${owner ?? "a different ADS layer"}. Submit a separate unit patch.${unit === "documentation" ? ` ${documentationFilePolicy}` : ""}`, change.path);
186
187
  }
187
188
  return inventory;
188
189
  }
package/docs/ADS.md CHANGED
@@ -333,6 +333,10 @@ in each item's local README. Record source repository/file links, revision,
333
333
  authors, concrete influences, and integration differences. Preserve applicable
334
334
  license notices for copied/adapted source and assets. The project guide records
335
335
  local implementation choices and links to the local item guides.
336
+ Shared `CREDITS.md`, conventional root notices and text files in `licenses/` use
337
+ the `documentation` mutation unit; its `filePolicy` describes supported new paths.
338
+ They can be added with README links in one guarded patch, without duplicating a
339
+ shared license into every component. Colocated notices retain their owning unit.
336
340
 
337
341
  ## Build contract
338
342
 
@@ -373,7 +373,11 @@ the isolated candidate project. Passing checks describe
373
373
  their registered assertions, not every natural-language claim. This keeps edits
374
374
  focused without requiring entire file bodies in model context. Peer units and
375
375
  unrelated owners remain outside the selected unit's edit boundary. Shared foundation,
376
- branding and guides have their own units. Project configuration, registered guards
376
+ branding and guides have their own units. Shared credits and text license notices
377
+ belong to the documentation unit, including conventional root notices and shared
378
+ `licenses/` collections. Colocated notices remain with their component or asset
379
+ owner. Documentation paths and UTF-8 validation do not grant code/configuration
380
+ ownership. Project configuration, registered guards
377
381
  and compiler integration form an explicit configuration unit; their proposed
378
382
  settings pass the same mandatory validation. Binary assets can travel as Git patch
379
383
  artifacts without entering model context, and compiler configuration changes
package/docs/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.12
4
+
5
+ - Let the documentation unit create shared credits, conventional root license
6
+ notices and text `licenses/` collections in one guarded owner patch. Expose its
7
+ new-file policy, discover readable provenance resources without enlarging
8
+ workflow guide context, preserve verbatim UTF-8 notices and keep code/peer/path
9
+ boundaries. Verify drafts, dry runs, publication, reads and rejection atomically.
10
+ - Add generic skill examples for preserving reference baselines and intended
11
+ public APIs while resolving coverage diagnostics; verify conditional controls
12
+ through browser state transitions instead of screenshots alone.
13
+
3
14
  ## 0.3.11
4
15
 
5
16
  - Bind preview success to project input content as well as artifact bytes. Source
package/docs/MCP.md CHANGED
@@ -294,10 +294,23 @@ The same discovery covers the rest of the project ADS:
294
294
  | Unit | Scope |
295
295
  |------|-------|
296
296
  | `foundation` | Shared ADS entry styles and root helpers |
297
- | `documentation` | ADS guides/licenses and the project's README, GUIDE, MCP, Architecture and ADS Markdown guides |
297
+ | `documentation` | ADS/project guides, shared credits and license notices, and `licenses/` text collections |
298
298
  | `assets/brand`, `assets/fonts`, other `assets/*` groups | Original SVG, image, font and other asset files |
299
299
  | `configuration` | `ds.config.json`, package/TypeScript/bundler/lint configuration, registered ADS guard modules, compiler/check entrypoints and their static local dependencies |
300
300
 
301
+ The `documentation` manifest includes `filePolicy` for paths that can be created
302
+ before they exist. One documentation patch can add `CREDITS.md`,
303
+ `licenses/example.txt` and the required README links together. Conventional root
304
+ `LICENSE`/`LICENCE`, `NOTICE`, `COPYING`, `COPYRIGHT` and `CREDITS` notices accept
305
+ `.md`, `.txt`, or extensionless names, with optional `-`/`_` qualifiers. Shared
306
+ `licenses/` collections may also live under `docs/`, `doc/`, or the configured ADS
307
+ root. Their entries use `.md`/`.txt` or conventional extensionless notice names.
308
+ Content must be UTF-8 without NUL bytes; Git patches preserve exact text, Unicode,
309
+ line endings and final-newline state. Code/configuration, hidden/generated paths
310
+ and peer-owned files retain their boundaries. A component's colocated notice stays
311
+ in that component unit. Shared notices are listed as readable MCP resources, while
312
+ workflow guide discovery omits provenance inventories. No asset unit is needed.
313
+
301
314
  Configuration ownership follows the project's registrations. It does not absorb
302
315
  components merely because a guard or compiler reads them. Guard registration,
303
316
  implementation, helpers and the associated check script can change together.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reqvire-org/ads",
3
- "version": "0.3.11",
3
+ "version": "0.3.12",
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": {