project-tiny-context-harness 0.8.8 → 0.8.11
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 +149 -123
- package/assets/README.md +279 -251
- package/assets/README.zh-CN.md +172 -144
- package/assets/skills/design-resource-authoring/SKILL.md +12 -12
- package/assets/skills/design-resource-authoring/references/downstream-handoff.md +57 -48
- package/dist/commands/design-resource.js +62 -2
- package/dist/lib/design-resource-fact-manifest-validation.d.ts +3 -1
- package/dist/lib/design-resource-fact-manifest-validation.js +23 -18
- package/dist/lib/design-resource-fact-universe-catalog.js +18 -8
- package/dist/lib/design-resource-fact-universe-helpers.js +9 -5
- package/dist/lib/design-resource-handoff-bundle-draft.d.ts +11 -0
- package/dist/lib/design-resource-handoff-bundle-draft.js +38 -0
- package/dist/lib/design-resource-handoff-bundle.d.ts +31 -0
- package/dist/lib/design-resource-handoff-bundle.js +147 -0
- package/dist/lib/design-resource-handoff-file-validation.d.ts +1 -1
- package/dist/lib/design-resource-handoff-file-validation.js +1 -9
- package/dist/lib/design-resource-handoff-input-types.d.ts +11 -0
- package/dist/lib/design-resource-handoff-input-types.js +1 -0
- package/dist/lib/design-resource-handoff-manifest-projection.d.ts +4 -0
- package/dist/lib/design-resource-handoff-manifest-projection.js +37 -0
- package/dist/lib/design-resource-handoff-parser.d.ts +7 -2
- package/dist/lib/design-resource-handoff-parser.js +32 -12
- package/dist/lib/design-resource-handoff-set-integrity.d.ts +8 -0
- package/dist/lib/design-resource-handoff-set-integrity.js +93 -0
- package/dist/lib/design-resource-handoff-shape.d.ts +2 -0
- package/dist/lib/design-resource-handoff-shape.js +62 -0
- package/dist/lib/design-resource-handoff-snapshot.d.ts +6 -0
- package/dist/lib/design-resource-handoff-snapshot.js +21 -0
- package/dist/lib/design-resource-handoff-types.d.ts +13 -1
- package/dist/lib/design-resource-handoff-validation.d.ts +2 -0
- package/dist/lib/design-resource-handoff-validation.js +45 -22
- package/dist/lib/long-task-design-resource-handoff.d.ts +15 -0
- package/dist/lib/long-task-design-resource-handoff.js +63 -173
- package/dist/lib/long-task-design-resource-method-binding.d.ts +8 -0
- package/dist/lib/long-task-design-resource-method-binding.js +135 -0
- package/dist/lib/long-task-source-item-parser.d.ts +8 -0
- package/dist/lib/long-task-source-item-parser.js +29 -107
- package/dist/lib/long-task-source-owned-sections.d.ts +29 -0
- package/dist/lib/long-task-source-owned-sections.js +90 -0
- package/dist/lib/source-line-scanner.d.ts +3 -0
- package/dist/lib/source-line-scanner.js +42 -0
- package/package.json +84 -84
|
@@ -5,7 +5,7 @@ description: Use when the user explicitly asks to generate, author, plan, commis
|
|
|
5
5
|
|
|
6
6
|
# Design Resource Authoring
|
|
7
7
|
|
|
8
|
-
Commission the smallest sufficient set of design resources for the explicitly requested output or development scope from live Open Design capabilities. “Smallest” governs artifact count and surrounding scope, never information granularity. For a formal selected Web/App implementation handoff, first derive the complete material in-scope Expected Fact Universe from requirements, product semantics, adopted design system, target platforms and observable conditions; then require canonical resources to express it and a frozen Inspector to enumerate it. The default identity is one atomic Fact Cell—not a Product Control, page, screenshot, broad dimension row or provider summary—and exact targets additionally require condition-specific full-target layout and pixel facts. This Skill is a thin task-local planner, provider adapter, iteration guide, final proposal reconciler and handoff layer; Open Design owns generation logic and Tiny Context owns neither its prompts nor runtime.
|
|
8
|
+
Commission the smallest sufficient set of design resources for the explicitly requested output or development scope from live Open Design capabilities. “Smallest” governs artifact count and surrounding scope, never information granularity. For a formal selected Web/App implementation handoff, first derive the complete material in-scope Expected Fact Universe from requirements, product semantics, adopted design system, target platforms and observable conditions; then require canonical resources to express it and a frozen Inspector to enumerate it. The default identity is one atomic Fact Cell—not a Product Control, page, screenshot, broad dimension row or provider summary—and exact targets additionally require condition-specific full-target layout and pixel facts. This Skill is a thin task-local planner, provider adapter, iteration guide, final proposal reconciler and handoff layer; Open Design owns generation logic and Tiny Context owns neither its prompts nor runtime.
|
|
9
9
|
|
|
10
10
|
## Hard boundaries
|
|
11
11
|
|
|
@@ -14,10 +14,10 @@ Commission the smallest sufficient set of design resources for the explicitly re
|
|
|
14
14
|
- Proposal reconciliation changes only the initial proposal: never mutate `project_context/**`, `DESIGN.md`, a Source Plan, Delivery Contract, production code or tests as a design-resource side effect.
|
|
15
15
|
- Never make a prototype, wireframe, high-fidelity candidate, design-system slice, provider-native file, variant count or directory layout universally mandatory.
|
|
16
16
|
- Treat the user's explicit output/development scope as the hard ceiling. Include only the surrounding context needed to design that slice.
|
|
17
|
-
- Never require one artifact per control. Reuse selected component sources and group repeated controls by family; commission a dedicated study only for unique or complex uncovered meaning.
|
|
18
|
-
- Do not confuse Product Control granularity with design-fact granularity. An image, text run, icon, component part, smaller visual primitive, layout relation, geometry/style/token/content/state/behavior fact remains independently material when the selected resource expresses it.
|
|
19
|
-
- For a formal selected Web/App handoff, do not let initially generated output define its own obligation universe. Derive that universe before commissioning from scoped subjects, target conditions, subject-local variations and the atomic property catalog. A label such as `all-states`, one default page, representative screenshots, pairwise sampling or an Inspector `complete` Boolean cannot stand in for enumerated identities.
|
|
20
|
-
- Artifact grouping and exact-value ownership remain separate: one HTML/CSS/JS/JSON/SVG source set may carry thousands of atomic facts. Exact values stay in that canonical source; the manifest, residual handoff and downstream Contract preserve typed locators, digests, comparison authority and Fact identities rather than copying CSS into a second value owner.
|
|
17
|
+
- Never require one artifact per control. Reuse selected component sources and group repeated controls by family; commission a dedicated study only for unique or complex uncovered meaning.
|
|
18
|
+
- Do not confuse Product Control granularity with design-fact granularity. An image, text run, icon, component part, smaller visual primitive, layout relation, geometry/style/token/content/state/behavior fact remains independently material when the selected resource expresses it.
|
|
19
|
+
- For a formal selected Web/App handoff, do not let initially generated output define its own obligation universe. Derive that universe before commissioning from scoped subjects, target conditions, subject-local variations and the atomic property catalog. A label such as `all-states`, one default page, representative screenshots, pairwise sampling or an Inspector `complete` Boolean cannot stand in for enumerated identities.
|
|
20
|
+
- Artifact grouping and exact-value ownership remain separate: one HTML/CSS/JS/JSON/SVG source set may carry thousands of atomic facts. Exact values stay in that canonical source; the manifest, residual handoff and downstream Contract preserve typed locators, digests, comparison authority and Fact identities rather than copying CSS into a second value owner.
|
|
21
21
|
- Never infer that a page frame or prototype covers states, responsiveness, accessibility or interaction it does not explicitly specify or demonstrate.
|
|
22
22
|
- Exploration and unselected previews stay schema-free. Only a final selected implementation handoff requires the shared strict Markdown adapter; this is input preparation, not a resource pack or acceptance result.
|
|
23
23
|
- Design resources may express user-visible interaction and presentation, but must not invent or become sole owner of business, data, permission or algorithmic rules.
|
|
@@ -37,15 +37,15 @@ Commission the smallest sufficient set of design resources for the explicitly re
|
|
|
37
37
|
2. **Inventory inputs.** Accept initial proposals, notes, product/technical plans, visual briefs, screenshots, references and existing resources. Preserve each role as exact target, constraint, inspiration, current-implementation evidence or background; report unreadable/unused material.
|
|
38
38
|
3. **Classify visual-style dependency.** Mark the commission `style-bearing` when it materially expresses visual fidelity, brand, typography/color/density, component visual treatment or a production-style prototype. Mark it `non-fidelity` for IA/flow topology, low-fidelity structure, semantics-only behavior/state studies or an explicitly non-fidelity prototype. Mixed work is style-bearing unless split into an independent non-fidelity commission.
|
|
39
39
|
4. **Apply the conditional Design Authority gate.** For style-bearing work, read `DESIGN.md` and its token source. If authority is unconfigured, stop before project/run creation and tell the user to explicitly invoke `$design-system-authoring`; do not invoke it automatically. A combined explicit request authorizes running that Skill first and then resuming this one. Non-fidelity work remains allowed.
|
|
40
|
-
5. **Derive the authoring obligation universe before generation.** For a formal selected Web/App handoff, start from requested Surfaces/flows, product semantics, adopted design-system snapshot and target platforms—not from whatever a first render happens to contain. Enumerate stable subjects and hierarchy for every Surface, region, overlay/system UI, component family and instance, Control, Anatomy Part/slot, primitive, text, icon, media, asset and typed multi-subject relation. Explicitly disposition every standard condition axis—platform/OS/device/form factor, exact viewport, orientation, density, Safe Area, window/fold/display/color modes, locale/language/script/direction/pseudo-localization, content/data stress, text scale, input/assistive technology, motion/transparency/contrast/bold text/button shapes, system UI/IME, permission/capability/connectivity/lifecycle—plus scoped custom axes. For each subject enumerate `variant × state × interaction_phase × presence_phase × instance_case`, including compound precedence, conditional/lazy/virtualized/portal population and exact exclusions. Apply the standard atomic property catalog across geometry, layout/scroll, typography/color/decoration/content/icon/media, interaction/navigation/motion/feedback, responsive, accessibility, assets/system and relations; add inspector-declared custom properties without weakening the standard set. The Expected Fact Universe is the exact applicable `subject × target × condition × variation × property` cell set. Every cell is covered or has an exact source/basis-backed `not_applicable`/`excluded_by_scope`; `decision_required`/`unavailable` remains blocking. Continuous widths, text pressure and animation expose breakpoints/ranges/interpolation/reflow/timeline rules rather than only sampled snapshots. Never truncate, sample, summarize the remainder or let aggregate strings such as `all-states` impersonate atomic identities.
|
|
40
|
+
5. **Derive the authoring obligation universe before generation.** For a formal selected Web/App handoff, start from requested Surfaces/flows, product semantics, adopted design-system snapshot and target platforms—not from whatever a first render happens to contain. Enumerate stable subjects and hierarchy for every Surface, region, overlay/system UI, component family and instance, Control, Anatomy Part/slot, primitive, text, icon, media, asset and typed multi-subject relation. Explicitly disposition every standard condition axis—platform/OS/device/form factor, exact viewport, orientation, density, Safe Area, window/fold/display/color modes, locale/language/script/direction/pseudo-localization, content/data stress, text scale, input/assistive technology, motion/transparency/contrast/bold text/button shapes, system UI/IME, permission/capability/connectivity/lifecycle—plus scoped custom axes. For each subject enumerate `variant × state × interaction_phase × presence_phase × instance_case`, including compound precedence, conditional/lazy/virtualized/portal population and exact exclusions. Apply the standard atomic property catalog across geometry, layout/scroll, typography/color/decoration/content/icon/media, interaction/navigation/motion/feedback, responsive, accessibility, assets/system and relations; add inspector-declared custom properties without weakening the standard set. The Expected Fact Universe is the exact applicable `subject × target × condition × variation × property` cell set. Every cell is covered or has an exact source/basis-backed `not_applicable`/`excluded_by_scope`; `decision_required`/`unavailable` remains blocking. Continuous widths, text pressure and animation expose breakpoints/ranges/interpolation/reflow/timeline rules rather than only sampled snapshots. Never truncate, sample, summarize the remainder or let aggregate strings such as `all-states` impersonate atomic identities.
|
|
41
41
|
6. **Discover live capabilities.** Inspect the current Open Design agent/model, skills, templates, design systems, plugins and export paths. Treat absent/non-enumerable capabilities honestly.
|
|
42
42
|
7. **Choose the minimum sufficient commission.** Give each considered resource `selected`, `optional`, `not-needed`, `unavailable` or `decision-required` with one reason. Ask only when a missing preference materially changes the commission.
|
|
43
|
-
8. **Bind and commission through Open Design.** For style-bearing work, create or verify the Open Design project with the adopted design-system ID and require `get_project.designSystemId` to match. Send the bounded product commission and the derived obligation universe through structured MCP: require the canonical implementation source to encode every applicable atomic value/behavior and require explicit dispositions for non-applicable, excluded or unresolved cells. Use documented fallbacks only when required; if the live provider cannot emit/read a required fact family, preserve that gap as blocking rather than silently narrowing the commission.
|
|
44
|
-
9. **Acquire complete canonical source and its independent Fact manifest.** For Web/App implementation handoff, require Open Design to emit a canonical machine-readable entry, the full locally resolvable dependency set and one `design-resource-observable-fact-manifest-v1` inside that closure—not only a screenshot, preview or prose spec. The manifest freezes the design-system snapshot; exact Inspector identity/version/digest or named external TCB, capabilities, input paths/digests, complete enumeration and dynamic-discovery policy; addressable resource/node/declaration/token/asset/relation/variant/state/interaction/dynamic-population Census; all condition and variation axes/combinations; subject hierarchy; property catalog; Fact Cells/Facts; value and design-system lineage; evidence; Fact × required-method proof obligations; comparator/tolerance/mask, Oracle and render-environment authority; asset bindings; blockers; and non-sampling/non-truncating collection counts/digests. Enumerate and retrieve every selected file without truncation, preserve exact bytes/digests, record one `implementation_web` or `implementation_app` source profile with `acquisition: complete`, and make all local source, token, SVG, font, image, media, worker and asset dependencies resolve inside that frozen set. Non-Web resources use the bounded `reference` profile and are not forced into HTML.
|
|
45
|
-
10. **Inspect, compare and iterate to exact closure.** Run the frozen Inspector over the frozen canonical entry/dependencies. Require every Census item to map to Facts/Fact Cells or a source/basis-backed `non_material` disposition, and require the manifest Fact universe to equal the precommission Expected Fact Universe. Exercise every required verification method with its method-compatible evidence, comparator, Oracle and environment; preserve design-system token/override/conflict lineage and exact asset consumers. Iterate the provider until `Expected Fact Universe = Canonical Resource Facts = Handoff Indexed Facts` can hold. Keep provider execution, artifact readiness and design suitability separate, and keep proposal effects only in the delta buffer while candidates remain unsettled.
|
|
43
|
+
8. **Bind and commission through Open Design.** For style-bearing work, create or verify the Open Design project with the adopted design-system ID and require `get_project.designSystemId` to match. Send the bounded product commission and the derived obligation universe through structured MCP: require the canonical implementation source to encode every applicable atomic value/behavior and require explicit dispositions for non-applicable, excluded or unresolved cells. Use documented fallbacks only when required; if the live provider cannot emit/read a required fact family, preserve that gap as blocking rather than silently narrowing the commission.
|
|
44
|
+
9. **Acquire complete canonical source and its independent Fact manifest.** For Web/App implementation handoff, require Open Design to emit a canonical machine-readable entry, the full locally resolvable dependency set and one `design-resource-observable-fact-manifest-v1` inside that closure—not only a screenshot, preview or prose spec. The manifest freezes the design-system snapshot; exact Inspector identity/version/digest or named external TCB, capabilities, input paths/digests, complete enumeration and dynamic-discovery policy; addressable resource/node/declaration/token/asset/relation/variant/state/interaction/dynamic-population Census; all condition and variation axes/combinations; subject hierarchy; property catalog; Fact Cells/Facts; value and design-system lineage; evidence; Fact × required-method proof obligations; comparator/tolerance/mask, Oracle and render-environment authority; asset bindings; blockers; and non-sampling/non-truncating collection counts/digests. Enumerate and retrieve every selected file without truncation, preserve exact bytes/digests, record one `implementation_web` or `implementation_app` source profile with `acquisition: complete`, and make all local source, token, SVG, font, image, media, worker and asset dependencies resolve inside that frozen set. Non-Web resources use the bounded `reference` profile and are not forced into HTML.
|
|
45
|
+
10. **Inspect, compare and iterate to exact closure.** Run the frozen Inspector over the frozen canonical entry/dependencies. Require every Census item to map to Facts/Fact Cells or a source/basis-backed `non_material` disposition, and require the manifest Fact universe to equal the precommission Expected Fact Universe. Exercise every required verification method with its method-compatible evidence, comparator, Oracle and environment; preserve design-system token/override/conflict lineage and exact asset consumers. Iterate the provider until `Expected Fact Universe = Canonical Resource Facts = Handoff Indexed Facts` can hold. Keep provider execution, artifact readiness and design suitability separate, and keep proposal effects only in the delta buffer while candidates remain unsettled.
|
|
46
46
|
11. **Finalize selection and reconcile once.** After explicit human selection or explicit delegated selection, preserve immutable identity and consolidate accepted, rejected and unresolved effects. Apply only accepted decisions once to a writable initial-proposal file; if it exists only in conversation, return one complete revised proposal. Preserve original intent/provenance and make reruns idempotent. Do not write unresolved or rejected choices as requirements.
|
|
47
|
-
12. **Compile the residual implementation handoff when requested.**
|
|
48
|
-
13. **Return an intent-sized result.** Exploration shows the artifact promptly. An implementation handoff returns the
|
|
47
|
+
12. **Compile the residual implementation handoff when requested.** Keep each canonical per-target `design-resource-observable-fact-manifest-v1` as the sole complete index for Inspector inputs/Census, axes and exclusions, conditions, subjects and variations, properties and lineage, Fact Cells/Facts, evidence/proofs, Oracles/environments, assets and blockers. Do not copy those collections into handoff YAML. For each target, author one small project-native Markdown draft with readable, target-attributed `ty-source-item` facts and exactly one fenced `design-resource-handoff-v1` block whose `representation` is `manifest_backed`. The block contains only residual scope/provenance, resource identities, that one target/profile, resource-fact closure, coverage and proposal binding. Shared meaning is atomized into uniquely keyed target-attributed Source facts without dropping its original predicate or provenance. Freeze the explicit canonical manifest path set and choose an actual UTF-8 byte ceiling before draft generation. Ensure the authorized output parent already exists, then call `ty-context design-resource bundle <draft-dir> <new-output-dir> --manifest <facts.json> [...] --max-handoff-bytes <bytes>`. The command rejects embedded/full-array drafts, multi-target drafts, over-budget descriptors, missing/extra/duplicate targets, manifest path/SHA drift, invalid collection count/identity digests, any normalized preflight failure and any existing final directory; it processes one target at a time in a same-volume temporary directory and publishes the complete target set with one atomic directory rename. Validation is an invariant check on the already compact representation, never a post-hoc splitting pass. On failure only the command-owned temporary directory is removed; drafts and existing/adopted handoffs remain unchanged. Do not author the older embedded V1 representation; it remains readable only for compatibility. Preflight hydrates the omitted collections directly from the declared canonical manifest snapshot and runs the same full semantic validator, so `Expected Fact Universe = Canonical Resource Facts = Handoff Indexed Facts` remains exact without duplicate YAML. File/model/parser/memory pressure never permits pruning, sampling, truncation, coarser Facts, implicit defaults or broader exclusions. If the truthful residual descriptor cannot meet the declared byte ceiling, treat the ceiling as incompatible and fail closed; never split a semantic target. Do not create these files for exploration.
|
|
48
|
+
13. **Return an intent-sized result.** Exploration shows the artifact promptly. An implementation handoff returns the atomically published handoff directory and every target/path mapping, selected immutable resources, stable-key coverage, manifest path/SHA plus collection count/identity-digest conservation, provenance, binding, limitations and successful bundle/preflight result. Include the reconciled initial proposal or its updated path when final selection occurred.
|
|
49
49
|
|
|
50
50
|
## Conditional Design Authority gate
|
|
51
51
|
|
|
@@ -85,4 +85,4 @@ Small requests may complete generation, selection and reconciliation in one turn
|
|
|
85
85
|
|
|
86
86
|
## Completion response
|
|
87
87
|
|
|
88
|
-
Report scope, necessary context/exclusions, style dependency and gate result; selected/omitted/unavailable resources; visible artifacts/typed locators; provider, project/run and design-system binding status; review and selection basis; immutable provenance; implementation source profile, entry/dependency closure and acquisition completeness when applicable; material applicability/coverage and unresolved decisions; proposal reconciliation status/path; and forbidden inferences. For implementation intent, report the
|
|
88
|
+
Report scope, necessary context/exclusions, style dependency and gate result; selected/omitted/unavailable resources; visible artifacts/typed locators; provider, project/run and design-system binding status; review and selection basis; immutable provenance; implementation source profile, entry/dependency closure and acquisition completeness when applicable; material applicability/coverage and unresolved decisions; proposal reconciliation status/path; and forbidden inferences. For implementation intent, report the published directory, every target-to-handoff mapping, canonical manifest path/SHA and collection count/identity-digest conservation, and successful bundle/preflight result; never call a failing, unresolved or incomplete target set ready.
|
|
@@ -16,15 +16,15 @@ For every material in-scope surface/flow/region/component/control condition, rec
|
|
|
16
16
|
|
|
17
17
|
Design resources may show user-visible triggers, transitions, states, feedback and product-rule presentation. Business, data, permission and algorithmic rules remain owned by product/technical Source and must not be invented by visuals.
|
|
18
18
|
|
|
19
|
-
Canonical implementation resources own exact code-expressible layout, visual, content, state, interaction, adaptation, motion, semantic and asset values. The
|
|
20
|
-
|
|
21
|
-
```text
|
|
22
|
-
Expected Fact Universe
|
|
23
|
-
= Canonical Resource Facts enumerated by the frozen Inspector
|
|
24
|
-
= Handoff Indexed Facts
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
The Expected Universe is derived before generation from scoped requirements, product semantics, the adopted design system, target environments, stable subjects, condition axes, subject-local variation axes and the atomic property catalog. It is not whatever an initially generated default page happens to expose.
|
|
19
|
+
Canonical implementation resources own exact code-expressible layout, visual, content, state, interaction, adaptation, motion, semantic and asset values. The canonical per-target observable-Fact manifest is the sole complete index of every Fact Cell, Fact and proof. The Markdown handoff is only the residual semantic and binding layer for scope, resources, target profile, resource closure, coverage, Source and proposal identity; preflight hydrates a normalized full handoff from the immutable manifest snapshot. Product Controls remain semantic interaction units and do not cap Fact granularity; addressable images, text, icons, component instances and Anatomy Parts, smaller primitives, relations, geometry/style/token/content/state/behavior facts remain independently queryable. For a formal selected Web/App target, completeness is:
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
Expected Fact Universe
|
|
23
|
+
= Canonical Resource Facts enumerated by the frozen Inspector
|
|
24
|
+
= Handoff Indexed Facts
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The Expected Universe is derived before generation from scoped requirements, product semantics, the adopted design system, target environments, stable subjects, condition axes, subject-local variation axes and the atomic property catalog. It is not whatever an initially generated default page happens to expose.
|
|
28
28
|
|
|
29
29
|
## Final proposal reconciliation
|
|
30
30
|
|
|
@@ -72,52 +72,61 @@ Return scope/intent, visible candidates, resource dispositions, obvious limitati
|
|
|
72
72
|
|
|
73
73
|
### Implementation handoff
|
|
74
74
|
|
|
75
|
-
After final selection for implementation, add one project-native Markdown Source at
|
|
75
|
+
After final selection for implementation, add one or more project-native Markdown Source files at authorized repository paths. They are ordinary Source, not a pack or Authority. Frozen canonical resources carry addressable implementation facts, while the residual handoff files close scope, applicability, uncovered meaning, product/technical semantics, blockers and downstream bindings. Each physical file contains readable `ty-source-item:start/end` facts plus exactly one:
|
|
76
76
|
|
|
77
77
|
````markdown
|
|
78
78
|
```yaml design-resource-handoff-v1
|
|
79
|
-
|
|
79
|
+
schema_version: design-resource-handoff-v1
|
|
80
|
+
representation: manifest_backed
|
|
81
|
+
# residual scope/resource/target/closure/coverage/proposal fields only
|
|
80
82
|
```
|
|
81
83
|
````
|
|
82
84
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
-
|
|
88
|
-
-
|
|
89
|
-
-
|
|
90
|
-
-
|
|
91
|
-
-
|
|
92
|
-
-
|
|
93
|
-
-
|
|
94
|
-
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
-
|
|
99
|
-
-
|
|
100
|
-
-
|
|
101
|
-
-
|
|
102
|
-
-
|
|
103
|
-
-
|
|
104
|
-
-
|
|
105
|
-
-
|
|
106
|
-
- exactly one `
|
|
107
|
-
-
|
|
108
|
-
- for every
|
|
109
|
-
-
|
|
110
|
-
-
|
|
111
|
-
-
|
|
112
|
-
-
|
|
113
|
-
|
|
114
|
-
|
|
85
|
+
Freeze the explicit canonical manifest path set and its target/scope identities, file SHA-256 values, and exact per-collection counts/identity digests before generating Markdown. Choose a truthful UTF-8 ceiling, then author one small draft per target. Each block keeps the shipped `design-resource-handoff-v1` marker and adds `representation: manifest_backed`; it does not repeat the manifest-owned arrays. Keep shared meaning as uniquely keyed, target-attributed Source facts without weakening the original predicate or provenance. Ensure the authorized output parent already exists, then run one bundle command over the complete draft and manifest sets. It rejects any embedded/full-array or multi-target draft, over-budget descriptor, missing/extra/duplicate target, stale manifest identity, invalid generation digest or normalized preflight failure; processes targets sequentially in a same-volume command-owned temporary directory; and atomically renames the complete set to a previously nonexistent final directory. Failure removes only that temporary directory. Drafts and existing/adopted handoffs are never overwritten, split or rewritten. The byte check is a guard on the already compact representation, not a post-hoc split. If truthful residual Source/scope/resource/closure/coverage/proposal data cannot meet the selected ceiling, the ceiling is incompatible and publication fails closed; a semantic target is never divided. File size, parser capacity, model output or memory pressure never permits sampling, truncation, Fact coarsening, implicit defaults or broader N/A/exclusions.
|
|
86
|
+
|
|
87
|
+
Each strict YAML block includes only:
|
|
88
|
+
|
|
89
|
+
- output/development scope, necessary context and exclusions;
|
|
90
|
+
- stable resource and exactly one target identity;
|
|
91
|
+
- selected exact-target/constraint/supporting classification; candidates and inspiration do not enter covered implementation rows;
|
|
92
|
+
- provider version, project/run, capability/template, agent/model and live design-system binding;
|
|
93
|
+
- each repository-local immutable resource path, media type and exact SHA-256;
|
|
94
|
+
- for implementation Web/App targets, a canonical entry, complete locally resolvable dependency set, one canonical `design-resource-observable-fact-manifest-v1` inside that set and `acquisition: complete`; non-Web resources use `reference` and are not forced into HTML;
|
|
95
|
+
- editable upstream owner, locator and update/export method, or an explicit manual/external-update boundary when unavailable;
|
|
96
|
+
- exactly one `resource_fact_closure` entry per resource, roll-up coverage with exact manifest-owned references, proposal reconciliation identity and readable target-attributed Source Items.
|
|
97
|
+
|
|
98
|
+
The referenced canonical manifest plus this residual block normalize to the complete handoff and therefore additionally include:
|
|
99
|
+
|
|
100
|
+
- a frozen Inspector identity/version/digest or named external TCB; exact capabilities, canonical entry, all input resource paths/digests, `complete_enumeration`, fully enumerated dynamic discovery and an addressable Census of every material resource/node/declaration/token/asset/relation/custom property/variant/state/interaction phase/dynamic population item;
|
|
101
|
+
- each Census row bound to exact Fact/Fact Cell sets or a source/basis-backed `non_material` rationale. An Inspector `complete` Boolean, resource count or provider statement does not replace the Census;
|
|
102
|
+
- all 33 standard target-condition axes—platform, OS, device profile, form factor, exact viewport width/height, orientation, density/pixel ratio, Safe Area insets, window/fold/display/color modes, locale/language/script/direction/pseudo-localization, content/data stress, text scale/multiplier, input/assistive technology, motion/transparency/contrast/bold text/button shapes, system UI/IME, permission/capability/connectivity/lifecycle—plus scoped custom axes. Each has an explicit applicable/not-applicable disposition and stable values; reuse of one viewport/density/Safe-Area/text-scale key with conflicting geometry is invalid;
|
|
103
|
+
- the complete target-condition Cartesian universe, with every applicable combination present and every omitted combination carrying an exact source/basis-backed exclusion. Continuous viewport/text-pressure behavior additionally exposes exact breakpoints, ranges, interpolation and reflow rules;
|
|
104
|
+
- stable subjects for every in-scope Surface, flow, region, overlay/system UI, component family and instance, Control, Anatomy Part/slot, primitive, text, icon, media, asset and typed multi-subject relation; exact parent/instance/family/override/slot/portal/presence/population/Census lineage prevents a family or one rendered instance from hiding internal or repeated subjects;
|
|
105
|
+
- for every subject, explicit `variant`, `state`, `interaction_phase`, `presence_phase` and `instance_case` axis dispositions plus the complete compound variation universe and exact exclusions. Labels such as `all-21-state-catalog` cannot impersonate 21 atomic states;
|
|
106
|
+
- the complete standard atomic property catalog plus justified inspector-declared custom properties. Properties carry stable key, family, UI/UX dimension, typed value kind, required verification methods, Inspector capabilities and Census lineage. The eight dimensions—`surface_flow`, `visual_content`, `component_control`, `state_interaction`, `motion`, `adaptation_input`, `accessibility`, `assets`—remain reporting roll-ups, not the Fact ceiling;
|
|
107
|
+
- one explicit Fact Cell for every applicable `subject × target × condition × variation × property` identity. Every cell is `covered`, source/basis-backed `not_applicable`/`excluded_by_scope`, or blocking `decision_required`/`unavailable`; sampling, pairwise coverage, summaries and implicit defaults are forbidden;
|
|
108
|
+
- one atomic Fact for every covered cell, carrying exactly one subject/target/condition/variation/property, dimension, `subject|full_target` observation scope, `plain|protected` sensitivity, typed value kind, canonical value located digest, same-target/condition evidence, Source-item lineage and effective design-system lineage. Exact token/alias/platform/mode/state/instance overrides and resolved conflicts remain traceable;
|
|
109
|
+
- typed, locally resolvable value/evidence locators for HTML/CSS/JS/JSON/Markdown/SVG or bounded binary whole-resource identity. Critical values cannot live only in a bitmap, preview or prose. Exact values stay in canonical resources; the handoff preserves locator/digest identity rather than copying CSS;
|
|
110
|
+
- separate `proof_obligations` for every Fact × property-required verification method. Each names method-compatible evidence, comparator, exact/tolerance mode, canonical parameter/tolerance and optional narrow mask located digests, one frozen executable or named external Oracle with method capability, and one frozen render environment. A Fact needing token and pixel proof keeps both;
|
|
111
|
+
- exact asset bindings to asset subjects, immutable resources, target/condition Facts and consumer subjects, including density/platform/theme/mode/locale variants, crop/focal/mask/placeholder/error/decode/fallback behavior;
|
|
112
|
+
- generation metadata proving `complete_explicit`, `sampling: forbidden`, `truncation: forbidden`, contiguous chunk indexes, and exact count plus identity digest for every Inspector input/Census, axis, condition, subject, variation, property, lineage, Fact Cell/Fact, evidence/proof, Oracle/environment, asset and blocker collection;
|
|
113
|
+
- hydration from the declared manifest bytes for every manifest-owned collection, so the residual handoff cannot restate or certify a narrower universe;
|
|
114
|
+
- roll-up coverage whose subject/target/condition/variation/property/Fact Cell/Fact/proof/evidence/Source/method sets exactly equal their indexed unions; every Fact Cell, Fact and proof appears exactly once in coverage;
|
|
115
|
+
- for every `exact_target` condition, one `full_target` `layout_geometry` fact and one `full_target` `visual_pixel` fact backed by exact-target evidence; if complete visible fidelity cannot be extracted/compared, keep the resource a `constraint` or unresolved;
|
|
116
|
+
- source/Inspector-backed rationales for every non-applicable/excluded cell; unresolved rows remain visible and make preflight fail;
|
|
117
|
+
- target-local acceptance blockers with exact target/subject/dimension/Source-item/verification-method lineage and a non-empty `required_capabilities` set; use the narrowest truthful capability such as physical device, sensor, camera, orientation, haptic, screen reader, pixel-density, safe-area, input or production runtime rather than weakening it to an available proxy;
|
|
118
|
+
- selection basis, proposal reconciliation path/status and known limitations;
|
|
119
|
+
- outer review and separate provider/artifact/design qualifiers.
|
|
120
|
+
|
|
121
|
+
Unknown fields fail closed. Every resource must be inspected; a material resource cannot be hidden as `supporting_only`, and unsupported/unreadable extraction remains blocking inside the named Inspector/Oracle TCB. All `decision_required`, `unavailable` and acceptance blockers prevent a `ready` result. A static frame may support only visible layout/visual/component Facts for its shown condition; pixel evidence cannot cover unseen interaction, motion, adaptation/input or accessibility. Protected Facts retain canonical-source ownership while downstream observations use attributable digest-only or redacted representations and never persist raw sensitive values. Publish the complete set:
|
|
115
122
|
|
|
116
123
|
```text
|
|
117
|
-
ty-context design-resource
|
|
124
|
+
ty-context design-resource bundle <draft-dir> <new-output-dir> \
|
|
125
|
+
--manifest <facts.json> [--manifest <facts.json> ...] \
|
|
126
|
+
--max-handoff-bytes <bytes>
|
|
118
127
|
```
|
|
119
128
|
|
|
120
|
-
Do not call the handoff ready until
|
|
129
|
+
`ty-context design-resource preflight <handoff.md>` remains available for one-file inspection and for older embedded V1 read compatibility, but new DSA authoring uses `bundle`. Do not call the handoff set ready until bundle publication succeeds. Passing proves acquisition, integrity and exact declared-universe closure relative to the frozen Inspector/Oracle TCB; it does not prove production implementation conformance. Exploration, candidates and unselected previews still require no file, schema, hash sequence or validator. There is no fixed directory, one-file-per-Control or one-file-per-Fact requirement.
|
|
121
130
|
|
|
122
131
|
## Recommended downstream routing
|
|
123
132
|
|
|
@@ -127,7 +136,7 @@ initial proposal
|
|
|
127
136
|
-> selected immutable resources
|
|
128
137
|
+ complete canonical implementation resources
|
|
129
138
|
+ reconciled initial proposal
|
|
130
|
-
-> validated
|
|
139
|
+
-> validated manifest-backed design-resource-handoff-v1 target file(s)
|
|
131
140
|
-> long-task-workflow (explicit long delivery)
|
|
132
141
|
OR current native Goal + default Workflow Contract (non-long delivery)
|
|
133
142
|
```
|
|
@@ -136,11 +145,11 @@ initial proposal
|
|
|
136
145
|
|
|
137
146
|
### Default Workflow consumption
|
|
138
147
|
|
|
139
|
-
The consuming Goal brings the revised proposal, selected resources and residual handoff as ordinary Source. It reruns shared preflight before UI Authority Closure, opens affected exact/constraint resources before deciding, classifies coverage, decides `Context Delta`, and makes every adopted decision-relevant target Context-reachable through existing owners. It keeps one ephemeral exact accounting of every Fact Cell, Fact and Fact × method obligation; routes each through the production owner and real-entry check; compares the current candidate with the frozen expected locator/digest using the declared comparator/tolerance/mask, Oracle and environment; and retains an attributable per-Fact actual observation and pass/fail verdict. Any unread, unsupported, unmapped, unimplemented, unverified, stale, failed or indistinguishable applicable Fact blocks the complete claim. A later update creates a new immutable version rather than overwriting the adopted baseline.
|
|
148
|
+
The consuming Goal brings the revised proposal, selected resources and every residual handoff file as ordinary Source. It reruns shared preflight per file, proves the exact target set before UI Authority Closure, opens affected exact/constraint resources before deciding, classifies coverage, decides `Context Delta`, and makes every adopted decision-relevant target Context-reachable through existing owners. It keeps one ephemeral exact accounting of every Fact Cell, Fact and Fact × method obligation; routes each through the production owner and real-entry check; compares the current candidate with the frozen expected locator/digest using the declared comparator/tolerance/mask, Oracle and environment; and retains an attributable per-Fact actual observation and pass/fail verdict. Any unread, unsupported, unmapped, unimplemented, unverified, stale, failed or indistinguishable applicable Fact blocks the complete claim. A later update creates a new immutable version rather than overwriting the adopted baseline.
|
|
140
149
|
|
|
141
150
|
### Long-Task consumption
|
|
142
151
|
|
|
143
|
-
The same revised proposal, selected resources and validated residual handoff enter `long-task-workflow`'s Source-bound Contract Draft loop immediately.
|
|
152
|
+
The same revised proposal, selected resources and all validated residual handoff files enter `long-task-workflow`'s Source-bound Contract Draft loop immediately. Every marked handoff is in `task.source_paths`; each Contract design target's frozen `source_paths` and Check `verification_inputs` equal its owning handoff plus every declared resource path and condition. Preflight hydrates one target at a time from its canonical manifest; Compile rejects missing, extra or duplicate targets and conflicting repeated residual shared rows while retaining only compact cross-file indexes. This adapter seam preserves the existing Contract, Authority, Outcome, deterministic fail-closed diagnostic precedence and Final Gate. Covered Source Items map through `source_claims` to the root conformance Assertion. Every verification method maps to an independently failing Assertion carrying its relevant Source Claims; each method × condition evidence cell carries exact handoff `fact_refs` plus canonical `fact_expectations` for subject/variation/property, sensitivity, expected located digest, comparator/parameters/tolerance/mask, Oracle and environment. Their exact union equals the target Fact set and all property-required Fact × method obligations. Current typed `design_method` evidence repeats the exact Fact set and supplies one `fact_results` row per Fact: attributable actual observation and actual environment, comparison record, exact authority identities and pass/fail verdict. Protected observations are digest-only/redacted according to the frozen sensitivity policy. Missing, extra, duplicate, stale, failed, authority-drifted or reused/indistinguishable rows fail the Assertion. Every blocker preserves its Source-item/method/required-capability lineage into a machine Claim proved on the exact capability-qualified target or a target-blocking External Confirmation. Authority Lock, Authority Revision and Final Gate remain the sole lifecycle and Final Gate source-recompiles/reruns the whole current snapshot. This Skill creates no Contract Draft, Outcome, Receipt, Check result or Gate.
|
|
144
153
|
|
|
145
154
|
## Forbidden inferences
|
|
146
155
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { publishDesignResourceHandoffBundle } from "../lib/design-resource-handoff-bundle.js";
|
|
1
2
|
import { preflightDesignResourceHandoff } from "../lib/design-resource-handoff-validation.js";
|
|
2
|
-
import { normalizeRepositoryFile } from "../lib/long-task-paths.js";
|
|
3
|
+
import { normalizeRepositoryCwd, normalizeRepositoryFile, } from "../lib/long-task-paths.js";
|
|
3
4
|
import { canonicalJson } from "../lib/strict-codec.js";
|
|
4
5
|
export async function designResource(args) {
|
|
5
6
|
const [subcommand = "help", ...rest] = args;
|
|
@@ -7,6 +8,10 @@ export async function designResource(args) {
|
|
|
7
8
|
help();
|
|
8
9
|
return;
|
|
9
10
|
}
|
|
11
|
+
if (subcommand === "bundle") {
|
|
12
|
+
await bundle(rest);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
10
15
|
if (subcommand !== "preflight")
|
|
11
16
|
throw new Error(`Unknown design-resource subcommand: ${subcommand}`);
|
|
12
17
|
const json = rest.includes("--json");
|
|
@@ -25,8 +30,63 @@ export async function designResource(args) {
|
|
|
25
30
|
console.log(`Coverage: ${result.counts.subjects} subjects x 8 dimensions (${result.counts.coverage} grouped rows)`);
|
|
26
31
|
console.log(`Acceptance blockers: ${result.counts.acceptance_blockers}`);
|
|
27
32
|
}
|
|
33
|
+
async function bundle(args) {
|
|
34
|
+
const positional = [];
|
|
35
|
+
const manifests = [];
|
|
36
|
+
let maxHandoffBytes = null;
|
|
37
|
+
let json = false;
|
|
38
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
39
|
+
const item = args[index];
|
|
40
|
+
if (item === "--json") {
|
|
41
|
+
json = true;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (item === "--manifest") {
|
|
45
|
+
const value = args[index + 1];
|
|
46
|
+
if (!value)
|
|
47
|
+
throw new Error("--manifest requires a path");
|
|
48
|
+
manifests.push(normalizeRepositoryFile(value, "design_resource_bundle_manifest"));
|
|
49
|
+
index += 1;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (item === "--max-handoff-bytes") {
|
|
53
|
+
const value = args[index + 1];
|
|
54
|
+
if (!value)
|
|
55
|
+
throw new Error("--max-handoff-bytes requires an integer");
|
|
56
|
+
maxHandoffBytes = Number(value);
|
|
57
|
+
index += 1;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (item.startsWith("--"))
|
|
61
|
+
throw new Error(`Unknown design-resource bundle option: ${item}`);
|
|
62
|
+
positional.push(item);
|
|
63
|
+
}
|
|
64
|
+
if (positional.length !== 2 ||
|
|
65
|
+
manifests.length === 0 ||
|
|
66
|
+
maxHandoffBytes === null)
|
|
67
|
+
throw new Error("usage: ty-context design-resource bundle <draft-dir> <new-output-dir> --manifest <facts.json> [--manifest <facts.json> ...] --max-handoff-bytes <bytes> [--json]");
|
|
68
|
+
const result = await publishDesignResourceHandoffBundle({
|
|
69
|
+
repository: process.cwd(),
|
|
70
|
+
draft_directory: normalizeRepositoryCwd(positional[0], "design_resource_bundle_draft_directory"),
|
|
71
|
+
output_directory: normalizeRepositoryCwd(positional[1], "design_resource_bundle_output_directory"),
|
|
72
|
+
manifest_paths: manifests,
|
|
73
|
+
max_handoff_bytes: maxHandoffBytes,
|
|
74
|
+
});
|
|
75
|
+
if (json) {
|
|
76
|
+
process.stdout.write(canonicalJson(result));
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
console.log(`Design resource handoff bundle published: ${result.output_directory}`);
|
|
80
|
+
console.log(`Handoffs: ${result.handoffs.length}`);
|
|
81
|
+
console.log(`Targets: ${result.handoffs.map((item) => item.target_key).join(", ")}`);
|
|
82
|
+
}
|
|
28
83
|
function help() {
|
|
29
84
|
console.log(`ty-context design-resource commands:
|
|
30
85
|
preflight <handoff.md> [--json]
|
|
31
|
-
Validate one selected implementation handoff
|
|
86
|
+
Validate one selected implementation handoff
|
|
87
|
+
bundle <draft-dir> <new-output-dir> --manifest <facts.json> [...]
|
|
88
|
+
--max-handoff-bytes <bytes> [--json]
|
|
89
|
+
Validate manifest-backed one-target handoffs and
|
|
90
|
+
atomically publish the complete target set; the
|
|
91
|
+
output parent directory must already exist`);
|
|
32
92
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import type { DesignResourceObservableFactManifestV1 } from "./design-resource-fact-manifest-types.js";
|
|
2
2
|
import type { ParsedDesignResourceHandoffV1 } from "./design-resource-handoff-types.js";
|
|
3
|
-
|
|
3
|
+
import type { ParsedDesignResourceHandoffInputV1 } from "./design-resource-handoff-input-types.js";
|
|
4
|
+
export declare function parseDesignResourceFactManifests(parsed: ParsedDesignResourceHandoffInputV1, contents: Map<string, Buffer>): Map<string, DesignResourceObservableFactManifestV1>;
|
|
5
|
+
export declare function validateDesignResourceFactManifests(parsed: ParsedDesignResourceHandoffV1, contents: Map<string, Buffer>, manifests: Map<string, DesignResourceObservableFactManifestV1>, validateProjection: boolean): void;
|
|
@@ -1,18 +1,9 @@
|
|
|
1
|
-
import { readFile } from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
1
|
import { parseDesignResourceFactManifestJson } from "./design-resource-fact-manifest-shape.js";
|
|
4
2
|
import { validateDesignResourceFactManifestUniverse } from "./design-resource-fact-manifest-universe.js";
|
|
5
3
|
import { invalidDesignResourceHandoff } from "./design-resource-handoff-validation-primitives.js";
|
|
6
|
-
|
|
7
|
-
export async function loadAndValidateDesignResourceFactManifests(repository, parsed) {
|
|
4
|
+
export function parseDesignResourceFactManifests(parsed, contents) {
|
|
8
5
|
const resources = new Map(parsed.handoff.resources.map((resource) => [resource.key, resource]));
|
|
9
|
-
const contents = new Map();
|
|
10
|
-
for (const resource of parsed.handoff.resources) {
|
|
11
|
-
const file = await assertProtectedRepositoryFile(repository, path.resolve(repository, ...resource.path.split("/")), `design_resource:${resource.key}`);
|
|
12
|
-
contents.set(resource.key, await readFile(file));
|
|
13
|
-
}
|
|
14
6
|
const manifests = new Map();
|
|
15
|
-
const sourceItems = new Map(Object.entries(parsed.source_item_kinds));
|
|
16
7
|
for (const target of parsed.handoff.targets) {
|
|
17
8
|
const manifestRef = target.source_profile.fact_manifest_resource_ref;
|
|
18
9
|
const manifestResource = resources.get(manifestRef);
|
|
@@ -32,13 +23,23 @@ export async function loadAndValidateDesignResourceFactManifests(repository, par
|
|
|
32
23
|
if (manifest.target_key !== target.key ||
|
|
33
24
|
manifest.scope_key !== parsed.handoff.scope.key)
|
|
34
25
|
invalid("fact_manifest_identity_mismatch", `${target.key}:${manifest.scope_key}:${manifest.target_key}`);
|
|
35
|
-
validateDesignResourceFactManifestUniverse(manifest, parsed.handoff, target, resources, contents, sourceItems);
|
|
36
|
-
validateManifestProjection(parsed.handoff, target.key, manifest);
|
|
37
26
|
manifests.set(target.key, manifest);
|
|
38
27
|
}
|
|
39
28
|
sameSet([...manifests.keys()], parsed.handoff.targets.map((target) => target.key), "fact_manifest_target_set_mismatch", "handoff");
|
|
40
29
|
return manifests;
|
|
41
30
|
}
|
|
31
|
+
export function validateDesignResourceFactManifests(parsed, contents, manifests, validateProjection) {
|
|
32
|
+
const resources = new Map(parsed.handoff.resources.map((resource) => [resource.key, resource]));
|
|
33
|
+
const sourceItems = new Map(Object.entries(parsed.source_item_kinds));
|
|
34
|
+
for (const target of parsed.handoff.targets) {
|
|
35
|
+
const manifest = manifests.get(target.key);
|
|
36
|
+
if (!manifest)
|
|
37
|
+
invalid("fact_manifest_target_missing", target.key);
|
|
38
|
+
validateDesignResourceFactManifestUniverse(manifest, parsed.handoff, target, resources, contents, sourceItems);
|
|
39
|
+
if (validateProjection)
|
|
40
|
+
validateManifestProjection(parsed.handoff, target.key, manifest);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
42
43
|
function validateManifestProjection(handoff, targetKey, manifest) {
|
|
43
44
|
const target = handoff.targets.find((item) => item.key === targetKey);
|
|
44
45
|
const targetConditions = new Set(target.condition_refs);
|
|
@@ -77,12 +78,16 @@ function validateManifestProjection(handoff, targetKey, manifest) {
|
|
|
77
78
|
exactRows(handoff.acceptance_blockers.filter((row) => row.target_refs.includes(targetKey)), manifest.acceptance_blockers, "acceptance_blockers", targetKey);
|
|
78
79
|
}
|
|
79
80
|
function exactRows(handoffRows, manifestRows, collection, targetKey) {
|
|
80
|
-
const handoff = new Map(handoffRows.map((row) => [row.key,
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
for (const
|
|
84
|
-
|
|
85
|
-
|
|
81
|
+
const handoff = new Map(handoffRows.map((row) => [row.key, row]));
|
|
82
|
+
if (handoff.size !== manifestRows.length)
|
|
83
|
+
invalid(`manifest_handoff_${collection}_set_mismatch`, `${targetKey}:count:${handoff.size}:${manifestRows.length}`);
|
|
84
|
+
for (const manifestRow of manifestRows) {
|
|
85
|
+
const handoffRow = handoff.get(manifestRow.key);
|
|
86
|
+
if (!handoffRow)
|
|
87
|
+
invalid(`manifest_handoff_${collection}_set_mismatch`, `${targetKey}:missing:${manifestRow.key}`);
|
|
88
|
+
if (canonicalJson(handoffRow) !== canonicalJson(manifestRow))
|
|
89
|
+
invalid(`manifest_handoff_${collection}_row_mismatch`, `${targetKey}:${manifestRow.key}`);
|
|
90
|
+
}
|
|
86
91
|
}
|
|
87
92
|
function canonicalJson(value) {
|
|
88
93
|
if (Array.isArray(value))
|
|
@@ -101,7 +101,7 @@ export function validateManifestFactCells(manifest, sourceItems, census) {
|
|
|
101
101
|
actual.set(fingerprint, cell.key);
|
|
102
102
|
validateFactCellDisposition(cell, coveredFacts);
|
|
103
103
|
}
|
|
104
|
-
|
|
104
|
+
assertExpectedFactCellFingerprints(manifest, actual);
|
|
105
105
|
unique(coveredFacts, "manifest_fact_ref_reused_by_cells");
|
|
106
106
|
sameSet(coveredFacts, manifest.facts.map((fact) => fact.key), "manifest_expected_canonical_fact_set_mismatch", manifest.target_key);
|
|
107
107
|
}
|
|
@@ -134,18 +134,28 @@ function validateFactCellDisposition(cell, coveredFacts) {
|
|
|
134
134
|
cell.disposition === "unavailable")
|
|
135
135
|
invalid("manifest_fact_cell_unresolved", cell.key);
|
|
136
136
|
}
|
|
137
|
-
function
|
|
138
|
-
const
|
|
137
|
+
function assertExpectedFactCellFingerprints(manifest, actual) {
|
|
138
|
+
const variationsBySubject = new Map();
|
|
139
|
+
for (const variation of manifest.variations) {
|
|
140
|
+
const rows = variationsBySubject.get(variation.subject_ref) ?? [];
|
|
141
|
+
rows.push(variation.key);
|
|
142
|
+
variationsBySubject.set(variation.subject_ref, rows);
|
|
143
|
+
}
|
|
144
|
+
let expectedCount = 0;
|
|
139
145
|
for (const subject of manifest.subjects)
|
|
140
146
|
for (const condition of manifest.conditions)
|
|
141
|
-
for (const
|
|
147
|
+
for (const variationRef of variationsBySubject.get(subject.key) ?? [])
|
|
142
148
|
for (const property of manifest.properties)
|
|
143
|
-
|
|
149
|
+
if (!actual.has(factCellFingerprint({
|
|
144
150
|
subject_ref: subject.key,
|
|
145
151
|
target_ref: manifest.target_key,
|
|
146
152
|
condition_ref: condition.key,
|
|
147
|
-
variation_ref:
|
|
153
|
+
variation_ref: variationRef,
|
|
148
154
|
property_ref: property.key,
|
|
149
|
-
}))
|
|
150
|
-
|
|
155
|
+
})))
|
|
156
|
+
invalid("manifest_expected_fact_cell_universe_mismatch", `${manifest.target_key}:missing:${subject.key}:${condition.key}:${variationRef}:${property.key}`);
|
|
157
|
+
else
|
|
158
|
+
expectedCount += 1;
|
|
159
|
+
if (actual.size !== expectedCount)
|
|
160
|
+
invalid("manifest_expected_fact_cell_universe_mismatch", `${manifest.target_key}:count:${actual.size}:${expectedCount}`);
|
|
151
161
|
}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
1
2
|
import { DESIGN_RESOURCE_STANDARD_CONDITION_AXES, } from "./design-resource-fact-manifest-types.js";
|
|
2
3
|
import { invalidDesignResourceHandoff } from "./design-resource-handoff-validation-primitives.js";
|
|
3
|
-
import { sha256Hex } from "./strict-codec.js";
|
|
4
4
|
export function manifestIdentityDigest(rows) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
const hash = createHash("sha256");
|
|
6
|
+
const identities = rows.map((row) => stableJson(row)).sort();
|
|
7
|
+
for (let index = 0; index < identities.length; index += 1) {
|
|
8
|
+
if (index > 0)
|
|
9
|
+
hash.update("\n");
|
|
10
|
+
hash.update(identities[index]);
|
|
11
|
+
}
|
|
12
|
+
return hash.digest("hex");
|
|
9
13
|
}
|
|
10
14
|
export function manifestCollectionRows(manifest) {
|
|
11
15
|
return new Map([
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ParsedDesignResourceHandoffInputV1 } from "./design-resource-handoff-input-types.js";
|
|
2
|
+
import type { DesignResourceHandoffResourceV1, DesignResourceHandoffTargetV1 } from "./design-resource-handoff-types.js";
|
|
3
|
+
type BundleFailure = (code: string, detail: string) => never;
|
|
4
|
+
export interface StagedDesignResourceHandoffDraft {
|
|
5
|
+
bytes: Buffer;
|
|
6
|
+
parsed: ParsedDesignResourceHandoffInputV1;
|
|
7
|
+
target: DesignResourceHandoffTargetV1;
|
|
8
|
+
manifest_resource: DesignResourceHandoffResourceV1;
|
|
9
|
+
}
|
|
10
|
+
export declare function stageDesignResourceHandoffDraft(repository: string, draftDirectory: string, temporaryDirectory: string, entryName: string, maxBytes: number, fail: BundleFailure): Promise<StagedDesignResourceHandoffDraft>;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { lstat, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { parseDesignResourceHandoffMarkdown } from "./design-resource-handoff-parser.js";
|
|
4
|
+
import { repoRelative } from "./long-task-workspace.js";
|
|
5
|
+
export async function stageDesignResourceHandoffDraft(repository, draftDirectory, temporaryDirectory, entryName, maxBytes, fail) {
|
|
6
|
+
const draftFile = path.join(draftDirectory, entryName);
|
|
7
|
+
const info = await lstat(draftFile);
|
|
8
|
+
if (typeof info.nlink === "number" && info.nlink > 1)
|
|
9
|
+
fail("draft_hardlink_not_allowed", entryName);
|
|
10
|
+
assertByteLimit(entryName, info.size, maxBytes, fail);
|
|
11
|
+
const bytes = await readFile(draftFile);
|
|
12
|
+
assertByteLimit(entryName, bytes.length, maxBytes, fail);
|
|
13
|
+
const content = bytes.toString("utf8");
|
|
14
|
+
if (!Buffer.from(content, "utf8").equals(bytes))
|
|
15
|
+
fail("handoff_utf8_invalid", entryName);
|
|
16
|
+
const stagedFile = path.join(temporaryDirectory, entryName);
|
|
17
|
+
await writeFile(stagedFile, bytes, { flag: "wx" });
|
|
18
|
+
const stagedPath = repoRelative(repository, stagedFile);
|
|
19
|
+
const parsed = parseDesignResourceHandoffMarkdown(stagedPath, content);
|
|
20
|
+
if (!("representation" in parsed.handoff))
|
|
21
|
+
fail("manifest_backed_representation_required", entryName);
|
|
22
|
+
if (parsed.handoff.targets.length !== 1)
|
|
23
|
+
fail("one_target_per_handoff_required", `${entryName}:${parsed.handoff.targets.length}`);
|
|
24
|
+
const target = parsed.handoff.targets[0];
|
|
25
|
+
const manifestResource = parsed.handoff.resources.find((resource) => resource.key === target.source_profile.fact_manifest_resource_ref);
|
|
26
|
+
if (!manifestResource)
|
|
27
|
+
fail("target_manifest_resource_missing", target.key);
|
|
28
|
+
return {
|
|
29
|
+
bytes,
|
|
30
|
+
parsed,
|
|
31
|
+
target,
|
|
32
|
+
manifest_resource: manifestResource,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function assertByteLimit(entryName, actual, maximum, fail) {
|
|
36
|
+
if (actual > maximum)
|
|
37
|
+
fail("handoff_byte_limit_exceeded", `${entryName}:${actual}:${maximum}`);
|
|
38
|
+
}
|