cabloy 5.1.149 → 5.1.151

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.
Files changed (122) hide show
  1. package/.cabloy-version +1 -1
  2. package/.claude/commands/release.md +12 -1
  3. package/.claude/hooks/contract-loop-gate.ts +35 -17
  4. package/.claude/skills/cabloy-backend-scaffold/SKILL.md +4 -3
  5. package/.claude/skills/cabloy-backend-scaffold/references/follow-up-checklist.md +3 -2
  6. package/.claude/skills/cabloy-contract-loop/SKILL.md +4 -3
  7. package/.claude/skills/cabloy-domain-planning/SKILL.md +4 -3
  8. package/.claude/skills/cabloy-frontend-scaffold/SKILL.md +5 -3
  9. package/.claude/skills/cabloy-master-detail/SKILL.md +4 -3
  10. package/.claude/skills/cabloy-module-removal/SKILL.md +5 -4
  11. package/.claude/skills/cabloy-resource-field-update/SKILL.md +8 -5
  12. package/.claude/skills/cabloy-spec-execution/SKILL.md +169 -0
  13. package/.claude/skills/cabloy-spec-execution/evals/evals.json +71 -0
  14. package/.claude/skills/cabloy-spec-execution/references/execution-protocol.md +137 -0
  15. package/.claude/skills/cabloy-spec-execution/references/status-and-evidence.md +117 -0
  16. package/.claude/skills/cabloy-spec-generation/SKILL.md +227 -0
  17. package/.claude/skills/cabloy-spec-generation/evals/evals.json +83 -0
  18. package/.claude/skills/cabloy-spec-generation/references/repo-aware-discovery.md +101 -0
  19. package/.claude/skills/cabloy-spec-generation/references/repo-specs-document-set.md +267 -0
  20. package/.claude/skills/cabloy-spec-generation/references/traceability-and-status-rules.md +135 -0
  21. package/.claude/skills/cabloy-spec-generation/scripts/generate-implementation-charts.mjs +350 -0
  22. package/.claude/skills/cabloy-spec-generation/scripts/generate-implementation-charts.test.mjs +202 -0
  23. package/.claude/skills/cabloy-workflow/SKILL.md +21 -10
  24. package/.claude/skills/cabloy-workflow/evals/evals.json +8 -2
  25. package/.claude/skills/cabloy-workflow/references/edition-detection.md +5 -3
  26. package/.claude/skills/cabloy-zova-source-reading/SKILL.md +4 -3
  27. package/CHANGELOG.md +41 -0
  28. package/CLAUDE.md +12 -11
  29. package/package.json +4 -2
  30. package/repo-docs/.vitepress/config.mjs +4 -0
  31. package/repo-docs/ai/docs-skills-rules-mapping.md +6 -6
  32. package/repo-docs/ai/future-skill-roadmap.md +2 -2
  33. package/repo-docs/ai/introduction.md +5 -5
  34. package/repo-docs/ai/playbook-contract-regeneration.md +3 -9
  35. package/repo-docs/ai/repo-guidance.md +5 -4
  36. package/repo-docs/ai/rules-and-config.md +2 -2
  37. package/repo-docs/ai/virtual-decorator-guidance.md +1 -3
  38. package/repo-docs/backend/cache-guide.md +36 -0
  39. package/repo-docs/backend/dto-guide.md +7 -6
  40. package/repo-docs/backend/dto-infer-generation.md +25 -5
  41. package/repo-docs/backend/introduction.md +1 -1
  42. package/repo-docs/backend/migration-and-changes.md +27 -2
  43. package/repo-docs/backend/model-guide.md +1 -1
  44. package/repo-docs/backend/resource-field-update.md +156 -0
  45. package/repo-docs/frontend/a-model-under-the-hood.md +38 -0
  46. package/repo-docs/frontend/a-openapi-under-the-hood.md +13 -2
  47. package/repo-docs/frontend/form-layout-guide.md +26 -9
  48. package/repo-docs/frontend/model-resource-best-practices.md +2 -0
  49. package/repo-docs/frontend/model-resource-cookbook.md +7 -1
  50. package/repo-docs/frontend/router-tabs-introduction.md +2 -4
  51. package/repo-docs/frontend/use-state-data-best-practices.md +44 -0
  52. package/repo-docs/frontend/zova-form-source-reading-map.md +26 -9
  53. package/repo-docs/frontend/zova-form-under-the-hood.md +11 -0
  54. package/repo-docs/fullstack/a-pay-payment-suite.md +1 -1
  55. package/repo-docs/fullstack/contract-loop-playbook.md +4 -0
  56. package/repo-docs/fullstack/one-to-one-companion-resource-guide.md +2 -2
  57. package/repo-docs/reference/package-map.md +1 -1
  58. package/repo-e2e/specs/a-commerce.spec.ts +40 -0
  59. package/scripts/release.ts +48 -1
  60. package/scripts/upgrade.ts +18 -7
  61. package/vona/packages-cli/cli/package.json +1 -1
  62. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudStart/boilerplate/src/controller/{{resourceName}}.ts_ +2 -2
  63. package/vona/packages-cli/cli-set-api/package.json +1 -1
  64. package/vona/pnpm-lock.yaml +83 -75
  65. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/.metadata/index.ts +108 -108
  66. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/skuSelectResItem.tsx +12 -0
  67. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/service/sku.ts +19 -1
  68. package/vona/src/suite/a-commerce/modules/commerce-catalog/test/skuPresentation.test.ts +53 -4
  69. package/vona/src/suite/a-commerce/modules/commerce-trade/src/.metadata/index.ts +148 -148
  70. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/stockAdjust.tsx +37 -3
  71. package/vona/src/suite/a-training/modules/training-student/src/.metadata/index.ts +2 -2
  72. package/vona/src/suite/a-training/modules/training-student/src/dto/studentCreate.tsx +7 -6
  73. package/vona/src/suite/a-training/modules/training-student/src/dto/studentSummary.tsx +1 -1
  74. package/vona/src/suite/a-training/modules/training-student/src/dto/studentUpdate.tsx +7 -6
  75. package/vona/src/suite/a-training/modules/training-student/src/dto/studentView.tsx +10 -7
  76. package/vona/src/suite/a-training/modules/training-student/src/model/student.ts +4 -4
  77. package/vona/src/suite/a-training/modules/training-student/src/service/student.ts +39 -67
  78. package/vona/src/suite/a-training/modules/training-student/test/student.test.ts +56 -37
  79. package/zova/packages-zova/zova/package.json +2 -2
  80. package/zova/pnpm-lock.yaml +5 -5
  81. package/zova/src/suite/a-commerce/modules/commerce-trade/cli/openapi.config.ts +1 -0
  82. package/zova/src/suite/a-commerce/modules/commerce-trade/package.json +6 -1
  83. package/zova/src/suite/a-commerce/modules/commerce-trade/src/.metadata/component/tableCellActionAdjustStock.ts +34 -0
  84. package/zova/src/suite/a-commerce/modules/commerce-trade/src/.metadata/index.ts +81 -6
  85. package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/commerceTradeStockBalance.ts +32 -0
  86. package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/openapi/schemas.ts +44 -44
  87. package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/openapi/types.ts +356 -338
  88. package/zova/src/suite/a-commerce/modules/commerce-trade/src/apiSchema/commerceTradeStockBalance.ts +17 -0
  89. package/zova/src/suite/a-commerce/modules/commerce-trade/src/bean/tableCell.actionAdjustStock.tsx +35 -0
  90. package/zova/src/suite/a-commerce/modules/commerce-trade/src/component/tableCellActionAdjustStock/controller.tsx +138 -0
  91. package/zova/src/suite/a-commerce/modules/commerce-trade/src/config/locale/en-us.ts +3 -0
  92. package/zova/src/suite/a-commerce/modules/commerce-trade/src/config/locale/zh-cn.ts +3 -0
  93. package/zova/src/suite/a-commerce/modules/commerce-trade/src/model/stockBalance.ts +36 -0
  94. package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/payment/controller.tsx +4 -4
  95. package/zova/src/suite/a-training/modules/training-student/src/api/openapi/schemas.ts +8 -8
  96. package/zova/src/suite/a-training/modules/training-student/src/api/openapi/types.ts +11 -11
  97. package/zova/src/suite/a-training/modules/training-student/src/bean/tableCell.actionSummary.tsx +2 -2
  98. package/zova/src/suite/cabloy-basic/modules/basic-app/src/bean/behavior.appModal.tsx +2 -0
  99. package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/package.json +1 -1
  100. package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/model/resource.ts +2 -1
  101. package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/test/model/resource.types.ts +11 -0
  102. package/zova/src/suite-vendor/a-cabloy/package.json +2 -2
  103. package/zova/src/suite-vendor/a-zova/modules/a-form/package.json +1 -1
  104. package/zova/src/suite-vendor/a-zova/modules/a-form/src/lib/formLayout.ts +58 -9
  105. package/zova/src/suite-vendor/a-zova/modules/a-form/test/lib/formLayout.test.ts +157 -0
  106. package/zova/src/suite-vendor/a-zova/modules/a-model/package.json +1 -1
  107. package/zova/src/suite-vendor/a-zova/modules/a-model/src/bean/bean.model/bean.model.persister.ts +3 -1
  108. package/zova/src/suite-vendor/a-zova/modules/a-model/src/bean/bean.model/bean.model.useQuery.ts +11 -13
  109. package/zova/src/suite-vendor/a-zova/modules/a-model/src/bean/bean.model/bean.model.useState.ts +9 -7
  110. package/zova/src/suite-vendor/a-zova/modules/a-model/src/bean/bean.model/bean.model.useStateGeneral.ts +5 -12
  111. package/zova/src/suite-vendor/a-zova/modules/a-model/src/lib/queryPersister.ts +17 -0
  112. package/zova/src/suite-vendor/a-zova/modules/a-model/src/lib/queryRefetch.ts +34 -0
  113. package/zova/src/suite-vendor/a-zova/modules/a-model/src/types/query.ts +27 -3
  114. package/zova/src/suite-vendor/a-zova/modules/a-model/test/lib/queryPersister.test.ts +115 -0
  115. package/zova/src/suite-vendor/a-zova/modules/a-model/test/lib/queryRefetch.test.ts +84 -0
  116. package/zova/src/suite-vendor/a-zova/modules/a-openapi/package.json +1 -1
  117. package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/lib/schema.ts +27 -5
  118. package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/model/sdk.ts +2 -2
  119. package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/types/rest.ts +4 -0
  120. package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/types/schema.ts +2 -5
  121. package/zova/src/suite-vendor/a-zova/modules/a-openapi/test/lib/schema.test.ts +179 -0
  122. package/zova/src/suite-vendor/a-zova/package.json +4 -4
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: cabloy-workflow
3
- description: This skill should be used when the main Cabloy problem is workflow routing before implementation: deciding between Vona backend scaffolding, Zova frontend scaffolding, contract-loop work, or docs/AI-enablement homes such as repo-docs, repo-docs-internal, CLAUDE.md, commands, or skills, including cases where Cabloy Basic vs Cabloy Start assumptions affect that routing. Trigger on requests to route, classify, choose a workflow, choose an edition-specific path, or decide where Cabloy guidance should live. Do not use it once the task is already clearly a backend scaffold, frontend scaffold, or contract-loop job.
3
+ description: This skill should be used when the main Cabloy problem is workflow routing before implementation: deciding between Vona backend scaffolding, Zova frontend scaffolding, contract-loop work, or docs/AI-enablement homes such as repo-docs, an established internal-docs home when present, CLAUDE.md, commands, or skills, including cases where Cabloy Basic vs Cabloy Start assumptions affect that routing. Trigger on requests to route, classify, choose a workflow, choose an edition-specific path, or decide where Cabloy guidance should live. Do not use it once the task is already clearly a backend scaffold, frontend scaffold, or contract-loop job.
4
4
  ---
5
5
 
6
6
  # Cabloy Workflow
@@ -24,12 +24,21 @@ Check the repository root for these marker files:
24
24
 
25
25
  Interpretation:
26
26
 
27
- - `__CABLOY_BASIC__` present → this is Cabloy Basic
28
- - `__CABLOY_START__` present → this is Cabloy Start
29
- - neither present → inspect the repo scripts and ask the user before making a strong edition-specific assumption
27
+ - only `__CABLOY_BASIC__` present → this is Cabloy Basic
28
+ - only `__CABLOY_START__` present → this is Cabloy Start
29
+ - both markers present → treat the repository as ambiguous or invalid and stop before making edition-specific assumptions
30
+ - neither marker present → inspect the owning package scripts and nearby repository structure, then ask before making an edition-specific assumption
30
31
 
31
32
  This matters most for frontend work, UI-layer assumptions, flavor names, suite/module availability, SSR site baselines, project assets, and edition-specific AI guidance.
32
33
 
34
+ Repository-path availability is independent of edition detection:
35
+
36
+ - inspect a documentation path before recommending or reading it
37
+ - use `repo-docs-internal/` only when an established active-repository home exists
38
+ - treat edition-local internal notes as optional maintainer material, never as a prerequisite for shared workflow routing
39
+ - when an optional path is absent, continue from public docs, bundled skill references, active source, and tests
40
+ - do not create a missing documentation home unless the user explicitly asks to establish one
41
+
33
42
  ## Step 2: Identify the task layer
34
43
 
35
44
  Classify the request before proposing a workflow.
@@ -70,7 +79,7 @@ Use the frontend path when the task is about:
70
79
  Use the docs/AI path when the task is about:
71
80
 
72
81
  - `repo-docs/`
73
- - `repo-docs-internal/`
82
+ - an established `repo-docs-internal/` home when present
74
83
  - `CLAUDE.md`
75
84
  - `.claude/commands/`
76
85
  - `.claude/skills/`
@@ -85,7 +94,7 @@ Before inventing a workflow, inspect these shared surfaces:
85
94
  - `npm run zova`
86
95
  - root `CLAUDE.md` if present
87
96
  - `repo-docs/` for public guidance
88
- - `repo-docs-internal/` for maintainer rationale
97
+ - an established `repo-docs-internal/` home for optional maintainer rationale
89
98
 
90
99
  If the request spans backend and frontend, classify it as fullstack by default unless the user clearly wants only one side.
91
100
 
@@ -158,15 +167,17 @@ Use `repo-docs/` for:
158
167
  - reusable AI-facing workflow guidance
159
168
  - edition-aware public documentation
160
169
 
161
- ### Internal engineering docs
170
+ ### Optional internal engineering docs
162
171
 
163
- Use `repo-docs-internal/` for:
172
+ When an established `repo-docs-internal/` home exists, it may be used for:
164
173
 
165
174
  - ADRs
166
175
  - architecture notes
167
176
  - maintainer rationale
168
177
  - invariants and design boundaries
169
178
 
179
+ Its absence must not block routing or implementation, and it must not be assumed to exist in every checkout.
180
+
170
181
  ### Root rules and commands
171
182
 
172
183
  Use `CLAUDE.md` and `.claude/commands/` for:
@@ -197,7 +208,7 @@ When the request is about whether a backend base class belongs in `src/lib`, `sr
197
208
  For these requests:
198
209
 
199
210
  - put the durable operational explanation in `repo-docs/`
200
- - put rationale and invariants in `repo-docs-internal/`
211
+ - when an established internal-docs home exists, put rationale and invariants there; otherwise preserve the public operational explanation and ask before establishing a new maintainer-rationale home
201
212
  - keep `CLAUDE.md` short and behavioral
202
213
  - do not treat `@Service()` as a business-layer naming decision only; for B2 it is a runtime-anchor placement choice
203
214
 
@@ -276,7 +287,7 @@ Verify:
276
287
 
277
288
  - referenced paths exist
278
289
  - command names still exist
279
- - public docs, internal docs, and rules tell a consistent story
290
+ - public docs, optional internal rationale, and rules tell a consistent story
280
291
  - edition-specific notes point to the right repo assumptions
281
292
 
282
293
  ### For backend/frontend workflow changes
@@ -15,8 +15,8 @@
15
15
  },
16
16
  {
17
17
  "id": 3,
18
- "prompt": "Please help me decide whether this new AI guidance belongs in public docs, repo-docs-internal, CLAUDE.md, or a skill. The guidance is about when to use npm run zova instead of hand-written scaffolding.",
19
- "expected_output": "Routes the request to the right knowledge homes, prefers public docs plus Claude rules/skills as appropriate, and reinforces the CLI-first principle.",
18
+ "prompt": "Please help me decide whether this new AI guidance belongs in public docs, an internal-docs home when present, CLAUDE.md, or a skill. The guidance is about when to use npm run zova instead of hand-written scaffolding.",
19
+ "expected_output": "Routes shared operational guidance to public docs and Claude rules/skills as appropriate, treats an internal-docs home as optional maintainer material rather than an assumed requirement, and reinforces the CLI-first principle.",
20
20
  "files": []
21
21
  },
22
22
  {
@@ -48,6 +48,12 @@
48
48
  "prompt": "I created a linked Cabloy Basic worktree and only need backend tests. What should I do for local environment isolation?",
49
49
  "expected_output": "Keeps generic routing read-only and directs the user to the canonical guide plus explicit /cabloy-worktree-environment invocation. It explains that the invoked skill still generates the universal APP_NAME, SERVER_LISTEN_PORT, DEV_SERVER_PORT, DEV_SERVER_HMR_PORT, and derived API_BASE_URL tuple in both broad local files after confirmation; it does not provide a backend-only one-file path.",
50
50
  "files": []
51
+ },
52
+ {
53
+ "id": 9,
54
+ "prompt": "I am in a Cabloy checkout whose active repository currently has no repo-docs-internal directory. I need shared agent guidance and some maintainer rationale. Where should each part go?",
55
+ "expected_output": "Inspects the active repository path rather than making an edition-wide assumption, routes shared operational guidance to existing public docs and Claude rules or skills, and asks which established maintainer-rationale home to use rather than putting rationale into public docs automatically.",
56
+ "files": []
51
57
  }
52
58
  ]
53
59
  }
@@ -2,10 +2,12 @@
2
2
 
3
3
  ## Primary markers
4
4
 
5
- Use these root markers first:
5
+ Interpret the root markers as exactly one of these states:
6
6
 
7
- - `__CABLOY_BASIC__`
8
- - `__CABLOY_START__`
7
+ - only `__CABLOY_BASIC__` present → Cabloy Basic
8
+ - only `__CABLOY_START__` present → Cabloy Start
9
+ - both markers present → treat the checkout as invalid or ambiguous and stop before making edition-specific assumptions
10
+ - neither marker present → inspect the owning `package.json` and nearby repository structure, then ask before making an edition-specific assumption
9
11
 
10
12
  ## Why the markers matter
11
13
 
@@ -25,9 +25,10 @@ Check the repository root for these marker files:
25
25
 
26
26
  Interpretation:
27
27
 
28
- - `__CABLOY_BASIC__` present → this is Cabloy Basic
29
- - `__CABLOY_START__` present → this is Cabloy Start
30
- - neither present → inspect the repo scripts and ask before making edition-specific frontend assumptions
28
+ - only `__CABLOY_BASIC__` present → this is Cabloy Basic
29
+ - only `__CABLOY_START__` present → this is Cabloy Start
30
+ - both markers present → treat the repository as ambiguous or invalid and stop before making edition-specific assumptions
31
+ - neither marker present → inspect the owning package scripts and nearby repository structure, then ask before making an edition-specific assumption
31
32
 
32
33
  This matters most when the analysis becomes UI-sensitive, SSR-site-sensitive, flavor-sensitive, or module-set-sensitive.
33
34
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,46 @@
1
1
  # Changelog
2
2
 
3
+ ## 5.1.151
4
+
5
+ ### Features
6
+
7
+ - Add chart specifications and chart support.
8
+ - Add SSR site specifications.
9
+ - Add Cabloy specification execution.
10
+ - Add skill creation support.
11
+ - Add implementation burndown and gantt charts.
12
+
13
+ ### Bug Fixes
14
+
15
+ - Fix skill specifications.
16
+
17
+ ### Improvements
18
+
19
+ - Refactor skills and skill specification generation.
20
+ - Update dependencies.
21
+
22
+ ## 5.1.150
23
+
24
+ ### Features
25
+
26
+ - Add `bypassPersister` support.
27
+ - Update query functionality.
28
+ - Add runbook updates.
29
+ - Add schema alias support.
30
+ - Add SKU stock availability support.
31
+ - Update related functionality and resources.
32
+
33
+ ### Bug Fixes
34
+
35
+ - Fix end-to-end tests.
36
+ - Correct `bypassPersister` behavior.
37
+ - Update schema tests.
38
+
39
+ ### Improvements
40
+
41
+ - Refactor the student model and service.
42
+ - Improve documentation for `bypassPersister`.
43
+
3
44
  ## 5.1.149
4
45
 
5
46
  ### Features
package/CLAUDE.md CHANGED
@@ -2,15 +2,14 @@
2
2
 
3
3
  ## Repository identity
4
4
 
5
- This repository is **Cabloy Basic**, the public framework/reference edition, identified by the root marker file:
5
+ Detect the active edition from the repository-root marker before making edition-sensitive assumptions:
6
6
 
7
- - `__CABLOY_BASIC__`
7
+ - exactly `__CABLOY_BASIC__` present → Cabloy Basic, the public framework/reference edition
8
+ - exactly `__CABLOY_START__` present → Cabloy Start, the private commercial edition delivered as licensed source
9
+ - both markers present → treat the checkout as invalid or ambiguous and stop before giving edition-specific guidance
10
+ - neither marker present → inspect the owning `package.json` and nearby repository structure, then ask before making an edition-specific assumption
8
11
 
9
- A sibling repository named `cabloy-start` is the private commercial edition, delivered as a licensed separate source repository and identified by:
10
-
11
- - `__CABLOY_START__`
12
-
13
- Always detect the active edition before making UI-sensitive assumptions, choosing frontend examples, recommending module-specific workflows, or assuming the project creation path.
12
+ Always perform this detection before making UI-sensitive assumptions, choosing frontend examples, recommending module-specific workflows, or assuming the project creation path.
14
13
 
15
14
  ## Monorepo layout
16
15
 
@@ -18,7 +17,7 @@ Always detect the active edition before making UI-sensitive assumptions, choosin
18
17
  - `vona/` contains the backend framework, backend modules, and the Vona CLI.
19
18
  - `zova/` contains the frontend framework, frontend modules, and the Zova CLI.
20
19
  - `repo-docs/` contains the unified public documentation.
21
- - `repo-docs-internal/` contains internal engineering notes and ADRs.
20
+ - `repo-docs-internal/`, when present, contains edition-local maintainer notes and ADRs; treat it as optional supporting material, not as a shared-edition requirement.
22
21
  - `repo-specs/` contains product and business specifications, delivery plans, and suite-local ADRs.
23
22
  - `repo-e2e/` contains the end-to-end test project.
24
23
  - `repo-observability/` contains local observability infrastructure.
@@ -39,8 +38,9 @@ Before inventing a custom implementation path:
39
38
  ## Documentation boundary
40
39
 
41
40
  - Put user-facing and agent-facing guidance in `repo-docs/`.
42
- - Put maintainer rationale, architecture notes, and engineering ADRs in `repo-docs-internal/`.
43
- - Put product and business specifications, delivery plans, acceptance records, and suite-local ADRs in `repo-specs/`.
41
+ - When an established `repo-docs-internal/` home exists, use it for maintainer rationale, architecture notes, and engineering ADRs. Do not infer or create that path from edition identity alone.
42
+ - If the active repository has no established internal-documentation home, do not block the workflow or move internal rationale into public docs automatically; use existing documentation homes or ask before establishing one.
43
+ - Put product and business specifications, delivery plans, acceptance records, and suite-local ADRs in `repo-specs/` when that repository surface exists.
44
44
  - Do not mix internal rationale into public how-to pages unless a trimmed user-facing explanation is genuinely needed.
45
45
 
46
46
  ## AI development rules
@@ -65,6 +65,7 @@ Before inventing a custom implementation path:
65
65
  - In Zova page routes, any route with dynamic `params` must define `route.name`; do not rely on unnamed path-keyed routes for typed `$params`. Static routes should omit `route.name` unless a documented named-route requirement exists; use `$router.getPagePath(...)` for canonical static URL generation rather than adding a name or alias for convenience. Ordinary business routes without `locale` params should omit app-config aliases unless a documented system, compatibility, or user-facing URL exception requires one. Choose `ssrProfile` from the page's rendering contract: Web remains `public` by default, while `session` is an explicit choice for cookie-backed state, protected admission, personalized first paint, or private SSR data; the absence of a locale parameter alone does not select a profile. `requiresAuth` is independent, so anonymous routes must explicitly use `requiresAuth: false`. Regenerate page metadata after route changes.
66
66
  - For frontend async state that affects rendering or interaction across consumers, prefer model-owned `$useStateData(...)` over controller-managed fetch/cache state.
67
67
  - Default to establishing such query state during render. Use `disableSuspenseOnInit: true` only for relatively stable query-backed state when you want to skip the init-time `query.suspense()` kick; it does not prevent query creation, fetches, or hydration-time rendering. If strict readiness is needed later, wait explicitly at the interaction boundary.
68
+ - For render-driving async state, read the current query-owned reactive surface (`query.data` or a model-derived projection); an awaited `query.refetch()` result is valid only for one-shot interaction or orchestration and must not become a parallel ongoing controller/render state owner.
68
69
  - In SSR, keep server HTML and the client's hydration-time initial render equivalent. When server rendering intentionally omits private, cookie-unavailable, or browser-only state, keep the same neutral shell or placeholder through hydration and defer its query/load/render branch to an explicit post-hydration, admission, mounted, or interaction boundary.
69
70
  - Keep repo-wide AI rules in `CLAUDE.md` short and durable; put branching Zova analysis workflows in `.claude/skills/`.
70
71
  - Do not modify shared environment identity or ports merely to bypass a busy resource. For intentional parallel worktree setup, follow `repo-docs/fullstack/parallel-worktree-environment.md`; otherwise wait for the shared resource or ask the user. Create or change worktree-local environment overrides only through the explicitly invoked `cabloy-worktree-environment` skill and its confirmation phase, and only in `vona/env/.env.local` and `zova/env/.env.local`; never modify flavor-, mode-, app-mode-, or runtime-specific `.env.*.local` files. The skill derives the standard `APP_NAME`, `SERVER_LISTEN_PORT`, `DEV_SERVER_PORT`, `DEV_SERVER_HMR_PORT`, and API-derived `API_BASE_URL` tuple only from Git worktree metadata and fixed port baselines; never read or expose `.env*` content while recommending values. Admin and Web are alternative commands using this shared tuple and must not run concurrently in one worktree; use another linked worktree for concurrent use. Detect the active edition before choosing scripts, and never run `npm run init` as an automatic follow-up.
@@ -81,7 +82,7 @@ Before inventing a custom implementation path:
81
82
  - When adding a persisted field to an existing backend resource, ask the user whether `vonaModule.fileVersion` should be incremented before changing `meta.version.ts` or the module schema path. If yes, add a new migration version and bump `fileVersion`. If no, keep the current `fileVersion` and fold the schema change into the current version path. Do not assume the versioning strategy without confirmation.
82
83
  - In shared-database multitenancy, do not use `table.unique(...)` for business uniqueness. Keep ordinary indexes for lookup performance and enforce tenant-scoped uniqueness in the business layer.
83
84
  - In Vona, a tenant corresponds to an instance. Ordinary resource-model CRUD is automatically scoped to the active instance; treat records absent from that scope as absent, and do not use raw cross-instance probes merely to choose between `403` and not-found behavior. Model future multi-merchant boundaries explicitly inside an instance.
84
- - Model cross-Model query-cache dependencies as one directed, acyclic `modelsClear` / `modelsClearedBy` graph, and verify source mutations refresh warmed dependent queries; read `repo-docs-internal/architecture/vona-cross-model-query-cache-dependencies.md` before designing a nontrivial graph.
85
+ - Model cross-Model query-cache dependencies as one directed, acyclic `modelsClear` / `modelsClearedBy` graph, and verify source mutations refresh warmed dependent queries; follow [Cross-model query-cache dependencies](repo-docs/backend/cache-guide.md#cross-model-query-cache-dependencies) before designing a nontrivial graph.
85
86
  - For `@Api.field(...)` and related schemaLike composition, framework guards now preserve previously attached OpenAPI metadata across schema rebuilds, but structure-shaping schemaLike is still order-sensitive. Treat `v.object(...)`, `v.array(...)`, `v.optional()`, `v.nullable()`, `v.default(...)`, and preprocess/transform wrappers as structure-shaping; keep the final structure-defining schemaLike last and verify emitted schema/OpenAPI output after such edits.
86
87
  - `@Core.transaction(...)` defaults to `REQUIRED`: it starts a transaction only when none exists and otherwise joins the current datasource transaction without upgrading its isolation. Prefer it over manual `inTransaction` wrappers for atomic service methods; use `REQUIRES_NEW` only when an independently committed boundary is explicitly required.
87
88
  - For replay-safe transient failures, use `@Core.retryable(...)` with an explicit `errorCodes` allowlist. It retries the downstream AOP suffix, so place it closest to the method when it must wrap and retry a `@Core.transaction(...)` boundary; use `ownerOnly: true` for dual-role leaves that must not retry inside a caller-owned transaction; do not retry external side effects or infer retryability from isolation level.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cabloy",
3
- "version": "5.1.149",
3
+ "version": "5.1.151",
4
4
  "gitHead": "2c5c19284bab738e492856189acb6fad74b8a7b7",
5
5
  "description": "A Node.js fullstack framework",
6
6
  "keywords": [
@@ -23,7 +23,6 @@
23
23
  "scripts": {
24
24
  "init": "node scripts/init.ts",
25
25
  "init:test-data": "node scripts/initTestData.ts",
26
- "test:scripts": "node --test scripts/initAppName.test.ts",
27
26
  "upgrade": "node scripts/upgrade.ts",
28
27
  "upgrade:dry-run": "node scripts/upgrade.ts --dry-run",
29
28
  "vona": "node ./vona/packages-cli/cli/src/bin/vona.ts --projectPath=vona",
@@ -57,6 +56,9 @@
57
56
  "format:fix": "oxfmt --write",
58
57
  "lint": "oxlint --disable-nested-config",
59
58
  "lint:fix": "oxlint --disable-nested-config --fix",
59
+ "test:spec-charts": "node --test .claude/skills/cabloy-spec-generation/scripts/generate-implementation-charts.test.mjs",
60
+ "spec:charts": "node ./.claude/skills/cabloy-spec-generation/scripts/generate-implementation-charts.mjs",
61
+ "spec:charts:check": "node ./.claude/skills/cabloy-spec-generation/scripts/generate-implementation-charts.mjs --check",
60
62
  "docs:dev": "pnpm --dir repo-docs docs:dev",
61
63
  "docs:build": "pnpm --dir repo-docs docs:build",
62
64
  "docs:preview": "pnpm --dir repo-docs docs:preview",
@@ -292,6 +292,10 @@ export default defineConfig({
292
292
  text: 'Data & CRUD',
293
293
  items: [
294
294
  { text: 'CRUD Workflow', link: '/backend/crud-workflow' },
295
+ {
296
+ text: 'Existing Resource Field Update',
297
+ link: '/backend/resource-field-update',
298
+ },
295
299
  { text: 'Migration and Changes', link: '/backend/migration-and-changes' },
296
300
  { text: 'Field Indexes', link: '/backend/field-indexes' },
297
301
  { text: 'ORM Guide', link: '/backend/orm-guide' },
@@ -38,11 +38,11 @@ Public docs answer questions like:
38
38
  - how does Zova page or model architecture work?
39
39
  - what is different between Cabloy Basic and Cabloy Start?
40
40
 
41
- ### 2. Internal engineering docs
41
+ ### 2. Optional internal engineering docs
42
42
 
43
43
  Location:
44
44
 
45
- - `repo-docs-internal/`
45
+ - an established internal-documentation home, when the active repository provides one
46
46
 
47
47
  Use internal docs for:
48
48
 
@@ -51,7 +51,7 @@ Use internal docs for:
51
51
  - maintenance boundaries
52
52
  - “why this design exists” notes that do not belong in public user docs
53
53
 
54
- Internal docs answer questions like:
54
+ When available, internal docs answer questions like:
55
55
 
56
56
  - why were docs and internal notes separated?
57
57
  - why is AI enablement structured this way?
@@ -105,7 +105,7 @@ Skills answer questions like:
105
105
  Use this quick rule:
106
106
 
107
107
  - if people and agents both need to read and understand it, put it in **public docs**
108
- - if it is maintainer rationale or long-lived design history, put it in **internal docs**
108
+ - if it is maintainer rationale or long-lived design history, use an established internal-documentation home when one exists; otherwise ask before establishing one
109
109
  - if it is short repo-wide behavioral guidance, put it in **CLAUDE.md**
110
110
  - if it is a named repeatable operator action, put it in a **command**
111
111
  - if it is a reusable procedural workflow with branching, put it in a **skill**
@@ -128,7 +128,7 @@ Use this quick rule:
128
128
  ### Example: “How should a backend base class be placed?”
129
129
 
130
130
  - public operational explanation → [Class Placement Rule](/ai/class-placement-rule)
131
- - maintainer rationale and invariants → `repo-docs-internal/architecture/class-placement-a-b1-b2.md`
131
+ - maintainer rationale and invariants → an established internal-documentation home, when available
132
132
  - default repo-wide behavior → `CLAUDE.md`
133
133
  - procedural decision workflow → `cabloy-workflow` skill
134
134
 
@@ -153,7 +153,7 @@ Use this quick rule:
153
153
  ### Example: “How should AI remove an existing module cleanly?”
154
154
 
155
155
  - public operational explanation → [Playbook: Module Removal](/ai/playbook-module-removal)
156
- - maintainer rationale and pitfalls → `repo-docs-internal/architecture/module-removal-workflow.md`
156
+ - maintainer rationale and pitfalls → an established internal-documentation home, when available
157
157
  - avoid putting the full workflow in `CLAUDE.md` because the task needs branching, cleanup order, generated-runtime recovery, and verification
158
158
  - procedural decision workflow → `cabloy-module-removal` skill
159
159
 
@@ -85,7 +85,7 @@ Primary dependencies:
85
85
 
86
86
  - Vona entity / migration / DTO workflow knowledge
87
87
  - Zova metadata/build flows when renderer follow-up is involved
88
- - the backend resource field workflow note in `repo-docs-internal/`
88
+ - [Existing Resource Field Update](/backend/resource-field-update)
89
89
 
90
90
  ### 5. Metadata refresh skill
91
91
 
@@ -148,7 +148,7 @@ The purpose is to create a small number of high-leverage skills that directly re
148
148
 
149
149
  - `repo-docs/`
150
150
  - `CLAUDE.md`
151
- - `repo-docs-internal/`
151
+ - an established internal-documentation home, when present
152
152
  - `.claude/skills/`
153
153
  - the Vona and Zova CLIs
154
154
 
@@ -8,7 +8,7 @@ The Cabloy monorepo is a good fit for AI vibe coding because the source tree alr
8
8
  - Vona CLI source and command groups
9
9
  - Zova CLI source and command groups
10
10
  - archived docs that still capture valuable concepts
11
- - internal engineering docs for maintainers
11
+ - optional internal engineering docs for maintainers when the active repository provides them
12
12
  - Claude commands and skills
13
13
 
14
14
  ## The main design goal
@@ -20,7 +20,7 @@ The goal is to make AI **reuse the repo’s existing conventions directly**, esp
20
20
  - CLI commands
21
21
  - root scripts
22
22
  - repo markers
23
- - internal architecture notes
23
+ - optional internal architecture notes when the active repository provides them
24
24
  - shared public documentation
25
25
 
26
26
  ## How to approach AI work
@@ -29,7 +29,7 @@ For contributor and automation workflows in this repository, prefer this order:
29
29
 
30
30
  1. inspect the active edition and repo markers before making UI-sensitive or workflow-sensitive assumptions
31
31
  2. inspect root scripts, Vona CLI, and Zova CLI before inventing manual scaffolding or custom workflow steps
32
- 3. use public docs for durable user-facing guidance and `repo-docs-internal/` for maintainer rationale
32
+ 3. use public docs for durable user-facing and agent-facing guidance; consult an established internal-documentation home only when the active repository provides one for maintainer rationale
33
33
  4. encode repeatable behavior in Claude rules, commands, or skills instead of relying on unstated habits
34
34
 
35
35
  ## The knowledge layers
@@ -40,9 +40,9 @@ Use `repo-docs/` for user-facing and agent-facing guidance that should remain du
40
40
 
41
41
  For normal project usage, prefer the user-facing entry docs such as [Fullstack Quickstart](/fullstack/quickstart). This AI section focuses on repository workflows and AI vibe coding.
42
42
 
43
- ### Internal engineering docs
43
+ ### Optional internal engineering docs
44
44
 
45
- Use `repo-docs-internal/` for architecture notes, ADRs, and maintainership rationale that should not be mixed into public how-to documentation.
45
+ When an established internal-documentation home exists, use it for architecture notes, ADRs, and maintainer rationale that should not be mixed into public how-to documentation. Its absence must not block a shared workflow or cause internal rationale to be moved into public how-to documentation automatically.
46
46
 
47
47
  ### Claude rules and commands
48
48
 
@@ -52,17 +52,11 @@ Before regenerating frontend artifacts:
52
52
 
53
53
  ## Step 4: Regenerate the frontend-side contract artifacts
54
54
 
55
- Use the Zova OpenAPI and REST-generation path rather than manually updating request code first.
55
+ Use the Zova OpenAPI and REST-generation path rather than manually updating request code first. Follow the canonical [Contract Loop Playbook](/fullstack/contract-loop-playbook#forward-chain-playbook) for the active edition’s complete generation and verification sequence.
56
56
 
57
- Representative commands may include:
57
+ Do not treat `build:rest:*` as a standalone current command recipe. Resolve the active edition’s full build path from the canonical playbook and current root scripts so SSR bundle and REST output stay synchronized.
58
58
 
59
- ```bash
60
- npm run zova :openapi:generate ...
61
- cd zova && npm run build:rest:cabloyBasicAdmin
62
- cd zova && npm run build:rest:cabloyBasicWeb
63
- ```
64
-
65
- For Start, use the Start-specific flavor paths from that repo.
59
+ For Start, resolve Start-specific flavor paths from that repository.
66
60
 
67
61
  ## Step 5: Inspect affected frontend layers
68
62
 
@@ -8,10 +8,10 @@ Check the root repository signals first:
8
8
 
9
9
  - `package.json`
10
10
  - edition marker files such as `__CABLOY_BASIC__` or `__CABLOY_START__`
11
- - `repo-docs-internal/README.md`
11
+ - an established internal-documentation home, when present
12
12
  - root `.claude/` assets
13
13
 
14
- These files tell the agent which repo it is in, which scripts are canonical, and where public versus internal documentation belongs.
14
+ These surfaces tell the agent which repo it is in and which scripts are canonical. Inspect an internal-documentation home only when the active repository actually provides one.
15
15
 
16
16
  ## 2. Prefer framework entrypoints over scattered examples
17
17
 
@@ -27,10 +27,11 @@ For frontend workflows:
27
27
 
28
28
  This is more reliable than copying old file structures from examples without understanding the command surface that created them.
29
29
 
30
- ## 3. Use docs and internal notes for different purposes
30
+ ## 3. Use public docs and optional internal notes for different purposes
31
31
 
32
32
  - use `repo-docs/` to explain how people and agents should work
33
- - use `repo-docs-internal/` to explain why maintainers designed the repo a certain way
33
+ - when an established internal-documentation home exists, use it for maintainer rationale
34
+ - when it does not exist, continue from public docs, rules, skills, source, and tests; do not create a new documentation home implicitly
34
35
 
35
36
  ## 4. Treat edition detection as mandatory for UI-sensitive work
36
37
 
@@ -8,7 +8,7 @@ Use the root `CLAUDE.md` for concise, durable operational guidance such as:
8
8
 
9
9
  - how the monorepo is organized
10
10
  - where public docs live
11
- - where internal docs live
11
+ - whether an established internal-documentation home is available
12
12
  - which command entrypoints are preferred
13
13
  - why edition detection is mandatory before UI-sensitive guidance or project-creation assumptions
14
14
 
@@ -26,4 +26,4 @@ Use Claude settings for permissions and execution environment, not as the primar
26
26
 
27
27
  ## Documentation boundary
28
28
 
29
- If a rule is important for people and agents to understand, it probably belongs in public docs too. If it explains internal rationale rather than user-facing workflow, it belongs in `repo-docs-internal/`.
29
+ If a rule is important for people and agents to understand, it probably belongs in public docs too. When an established internal-documentation home exists, it may hold maintainer rationale rather than user-facing workflow. Do not infer or create such a home from edition identity alone.
@@ -201,6 +201,4 @@ Read these pages together:
201
201
  - [Global Bean Lookup](/ai/global-bean-lookup)
202
202
  - [Docs, Skills, Rules, and CLI Mapping](/ai/docs-skills-rules-mapping)
203
203
 
204
- For maintainer-level rationale, also read:
205
-
206
- - `repo-docs-internal/architecture/virtual-decorator-runtime-semantics.md`
204
+ For maintainer-level rationale, consult an established internal-documentation home when the active repository provides one. The public guidance above is the complete shared operational rule.
@@ -52,6 +52,42 @@ Representative areas include:
52
52
  - related-model cache clearing
53
53
  - custom cache-clearing logic
54
54
 
55
+ ## Cross-model query-cache dependencies
56
+
57
+ When a mutation in one Model changes the members, totals, projections, includes, or visibility of a query cached by another Model, declare an explicit cross-model dependency. Decide this from **query-result semantics**, not merely from a relation or foreign key.
58
+
59
+ ### Choose one directed declaration
60
+
61
+ Express each dependency as one source-to-target edge:
62
+
63
+ - `modelsClear` declares targets from the source Model;
64
+ - `modelsClearedBy` declares sources from the target Model.
65
+
66
+ They normalize to the same direction. Choose the form that makes local ownership clearest, but never declare both forms for the same edge.
67
+
68
+ ### Keep the graph acyclic
69
+
70
+ Keep the dependency graph directed, acyclic, and free of duplicate edges. A normal target clear can propagate transitively to its own dependent query caches, so reverse or duplicate declarations are not a way to increase reliability.
71
+
72
+ The default behavior clears affected **query caches**. It does not make a cross-Model entity cache relationship, replace a lock, enforce uniqueness, or create a transaction boundary.
73
+
74
+ ### Use custom clearing deliberately
75
+
76
+ `modelsClearedByFn` replaces the normal target-clear behavior for that dependency. When using it, explicitly own the target clear and any required downstream propagation. Do not add it as if it were an additional callback around the normal path.
77
+
78
+ Prefer normal Model or service mutation paths so source invalidation, transaction-aware re-clearing, and configured cache behavior remain active.
79
+
80
+ ### Verify a warmed dependent query
81
+
82
+ For every new dependency path, add a regression test that:
83
+
84
+ 1. warms the dependent Model query;
85
+ 2. mutates the source through the normal Model or service path;
86
+ 3. repeats the dependent query;
87
+ 4. proves that the result now reflects the mutation.
88
+
89
+ This test demonstrates business invalidation rather than relying on test-runner scheduling or cache implementation assumptions.
90
+
55
91
  ## Consistency strategy
56
92
 
57
93
  Vona also clears or compensates cache automatically when model mutation occurs.
@@ -183,7 +183,7 @@ A practical split is:
183
183
  - use inferred DTOs when the contract closely follows model structure or query shape
184
184
  - wrap inferred DTOs in a named DTO class when reuse or discoverability becomes more important
185
185
 
186
- When stable Entity, Model, relation, or query truth already exists, prefer inference first: use `$Dto.*` with `columns`, `include`, or `dtoClass` to define the projection; use `@Dto({ fields })` with `$makeMetadata(...)` for metadata-only differences or `$makeSchema(...)` for schema and validation differences; add an `@Api.field(...)` member only for a genuinely new field absent from the inferred contract. Keep an explicit DTO as a deliberate fallback when no suitable upstream truth exists or the inferred composition is less clear.
186
+ When stable Entity, Model, relation, or query truth already exists, prefer inference first: use `$Dto.*` with `columns`, `include`, or `dtoClass` to define the projection; use `@Dto({ fields })` with `$makeMetadata(...)` only for metadata-only differences on an existing inferred/projected field, or `$makeSchema(...)` for schema and validation differences. A true virtual `fields` key absent from that projection must use `$makeSchema(...)` with a final concrete `z.<type>()` schema; `fieldSource(...)` maps its binding but supplies no type. Add an `@Api.field(...)` member only for a genuinely new declared DTO property. See [Virtual fields in the DTO fields map](/backend/dto-infer-generation#virtual-fields-in-the-dto-fields-map) for the full decision rule. Keep an explicit DTO as a deliberate fallback when no suitable upstream truth exists or the inferred composition is less clear.
187
187
 
188
188
  Advanced inferred DTO shaping can also stay named and reusable through helper options such as `dtoClass`, especially for relation-aware contracts and nested DTO surfaces. `$Dto.get(...)` otherwise keeps the complete model-aware read shape by default; use `columns` or `dtoClass` for a genuine business projection, not merely to remove `iid` or `deleted`. For the canonical authoring sequence, see [Default-first three-layer DTO authoring](/backend/dto-infer-generation#default-first-three-layer-dto-authoring) and [Default read shape versus a public projection](/backend/dto-infer-generation#default-read-shape-versus-a-public-projection).
189
189
 
@@ -205,11 +205,12 @@ When creating DTOs:
205
205
 
206
206
  1. check whether an Entity, Model, relation, or query shape already provides suitable upstream contract truth
207
207
  2. define the inferred projection before redeclaring fields: choose the `$Dto.*` helper and, where needed, `columns`, `include`, or `dtoClass`
208
- 3. use `$makeMetadata(...)` for metadata-only refinement and `$makeSchema(...)` for schema or validation refinement of an inferred field
209
- 4. use `@Api.field(...)` for a genuinely new field, not as a second declaration of an inferred field
210
- 5. keep DTO validation and OpenAPI concerns aligned, and keep the final structure-defining schema last when using schema-like composition
211
- 6. decide whether the contract should remain inferred, be wrapped in a named inferred DTO, or deliberately fall back to an explicit DTO
212
- 7. treat DTO design as part of the contract between backend handlers, models, and frontend integration
208
+ 3. use `$makeMetadata(...)` for metadata-only refinement and `$makeSchema(...)` for schema or validation refinement of an inferred/projected field
209
+ 4. for a true virtual key added only through `@Dto({ fields })`, use `$makeSchema(...)` with a final concrete `z.<type>()` schema; `fieldSource(...)` supplies no missing type
210
+ 5. use `@Api.field(...)` for a genuinely new declared DTO property, not as a second declaration of an inferred field
211
+ 6. keep DTO validation and OpenAPI concerns aligned, and keep the final structure-defining schema last when using schema-like composition
212
+ 7. decide whether the contract should remain inferred, be wrapped in a named inferred DTO, or deliberately fall back to an explicit DTO
213
+ 8. treat DTO design as part of the contract between backend handlers, models, and frontend integration
213
214
 
214
215
  ## Where to read next
215
216
 
@@ -193,6 +193,25 @@ export class DtoStudentSelectReq extends $Dto.queryPage(EntityStudent, [
193
193
 
194
194
  Framework DTO composition preserves inherited OpenAPI metadata when a field schema is refined. That includes metadata such as titles, render information, and scene identity. It does **not** make structure-shaping schema-like arguments order-independent: keep the final structure-defining argument last and verify the effective schema rather than assuming a metadata merge can repair a reordered schema.
195
195
 
196
+ #### Virtual fields in the DTO fields map
197
+
198
+ The Layer 2 `$makeMetadata(...)` rule has a precondition: the field key must already be supplied by the inferred projection, whether through the `$Dto.*` base, `columns`, `include`, or `dtoClass`. It overlays metadata on that existing runtime schema.
199
+
200
+ A **true virtual DTO field** is a key added only through `@Dto({ fields })` and absent from that inherited projection. Define such a key with `$makeSchema(...)` and a final concrete Zod schema, even when its purpose is only to map a renderer to a nested source:
201
+
202
+ ```typescript
203
+ const descriptionMarkdownField = $makeSchema(
204
+ ZovaRender.fieldSource('content.descriptionMarkdown'),
205
+ ZovaRender.field('basic-markdown:formFieldMarkdown'),
206
+ v.optional(),
207
+ z.string(),
208
+ );
209
+ ```
210
+
211
+ `z.string()` establishes the virtual key's validation and emitted OpenAPI type. `fieldSource(...)` only maps the DTO-facing key to the canonical source path used by downstream schema-driven UI; it does not supply a type. `$makeMetadata(...)` alone has no inherited schema to overlay for a true virtual key, so its metadata is attached to an unconstrained fallback rather than a meaningful field schema.
212
+
213
+ Use a class-body `@Api.field(...)` member instead when the new field should be a declared, statically typed DTO property rather than a contract-only `fields`-map key.
214
+
196
215
  `@Dto({ fields })` changes the runtime contract and metadata. It does not rewrite the TypeScript property type inferred from the `$Dto.*` base class. Do not add a duplicate `declare` field or a second field decorator solely to mirror a runtime schema restriction unless a separate static contract is genuinely required and is type-compatible with the inferred base.
197
216
 
198
217
  ### Layer 3: add contract-only fields
@@ -507,10 +526,11 @@ When evaluating a return shape or input contract that closely follows model stru
507
526
  2. is the contract get/list/query/create/update/aggregate/group oriented, and which `$Dto.*` helper matches it?
508
527
  3. should `columns`, `include`, `with`, or `dtoClass` define the projection boundary?
509
528
  4. should the inferred DTO stay inline or be wrapped in a named DTO class?
510
- 5. for every local difference, is it metadata-only (`$makeMetadata(...)`) or schema-affecting (`$makeSchema(...)`)?
511
- 6. is every `@Api.field(...)` member genuinely new instead of a redeclared inferred field?
512
- 7. if `$makeSchema(...)` is used, is the structure-defining schema last and is emitted schema/OpenAPI verification planned?
513
- 8. does the resulting DTO also affect OpenAPI and frontend generation paths?
514
- 9. is CRUD generation already giving enough contract structure that another handwritten DTO would be redundant, or is an explicit DTO clearer?
529
+ 5. for every local difference, does the `fields` key already have an inferred/projected schema, or is it a true virtual key?
530
+ 6. use `$makeMetadata(...)` only for metadata-only refinement of an inferred/projected field; define every true virtual key with `$makeSchema(...)` and a final concrete `z.<type>()` schema
531
+ 7. is every `@Api.field(...)` member genuinely new instead of a redeclared inferred field?
532
+ 8. if `$makeSchema(...)` is used, is the structure-defining schema last and is emitted schema/OpenAPI verification planned?
533
+ 9. does the resulting DTO also affect OpenAPI and frontend generation paths?
534
+ 10. is CRUD generation already giving enough contract structure that another handwritten DTO would be redundant, or is an explicit DTO clearer?
515
535
 
516
536
  That helps reduce redundant type work and keeps contracts closer to the model truth.
@@ -19,7 +19,7 @@ For contributor and automation workflows in this repository, prefer this order:
19
19
  1. inspect the root `package.json` and `npm run vona` entrypoint
20
20
  2. inspect Vona CLI command families such as `create:*`, `init:*`, `tools:*`, and `bin:*`
21
21
  3. inspect the current module or suite layout before creating new files manually
22
- 4. use public docs for user-facing guidance and `repo-docs-internal/` for maintainer rationale
22
+ 4. use public docs for user-facing and agent-facing guidance; consult an established internal-documentation home only when the active repository provides one for maintainer rationale
23
23
 
24
24
  ## Backend reading paths
25
25