chati-dev 4.3.0 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/README.md +18 -13
  2. package/bin/chati.js +32 -4
  3. package/framework/agents/build/dev.md +9 -5
  4. package/framework/agents/discover/brief.md +2 -0
  5. package/framework/agents/discover/brownfield-wu.md +2 -0
  6. package/framework/agents/discover/greenfield-wu.md +18 -1
  7. package/framework/agents/plan/detail.md +2 -0
  8. package/framework/agents/plan/tasks.md +31 -0
  9. package/framework/agents/plan/ux-brand-architect.md +21 -2
  10. package/framework/agents/plan/ux-component-engineer.md +10 -0
  11. package/framework/agents/quality/qa-implementation.md +1 -1
  12. package/framework/agents/quality/qa-planning.md +1 -1
  13. package/framework/agents/quality/qa-visual.md +33 -21
  14. package/framework/config.yaml +5 -4
  15. package/framework/constitution.md +58 -11
  16. package/framework/context/governance.md +12 -10
  17. package/framework/context/root.md +2 -2
  18. package/framework/data/entity-registry.yaml +12 -4
  19. package/framework/data/qa-rubrics.yaml +335 -0
  20. package/framework/domains/constitution.yaml +3 -3
  21. package/framework/executors/json-validate.js +80 -0
  22. package/framework/executors/npm-script.js +72 -0
  23. package/framework/executors/path-check.js +67 -0
  24. package/framework/executors/registry.yaml +36 -0
  25. package/framework/hooks/advance-trigger.js +47 -3
  26. package/framework/hooks/constitution-guard.js +9 -4
  27. package/framework/hooks/git-push-authority.js +113 -0
  28. package/framework/hooks/license-guard.js +59 -9
  29. package/framework/hooks/model-governance.js +40 -17
  30. package/framework/hooks/prism-engine.js +78 -11
  31. package/framework/hooks/session-digest.js +12 -3
  32. package/framework/hooks/settings.json +7 -3
  33. package/framework/hooks/style-guard.js +52 -3
  34. package/framework/hooks/team-quality-gate.js +43 -5
  35. package/framework/i18n/en.yaml +3 -3
  36. package/framework/i18n/es.yaml +3 -3
  37. package/framework/i18n/fr.yaml +3 -3
  38. package/framework/i18n/pt.yaml +3 -3
  39. package/framework/intelligence/confidence.yaml +85 -6
  40. package/framework/intelligence/context-engine.md +9 -5
  41. package/framework/intelligence/decision-engine.md +1 -1
  42. package/framework/orchestrator/chati-router.js +59 -5
  43. package/framework/orchestrator/chati-update.md +19 -3
  44. package/framework/orchestrator/chati.md +20 -1
  45. package/framework/quality-gates/planning-gate.md +2 -0
  46. package/framework/rules/human-writing-style.md +47 -0
  47. package/framework/scaffold/motion-premium/README.md +12 -2
  48. package/framework/scaffold/motion-premium/lib/animations/tokens.ts.template +1 -1
  49. package/framework/scaffold/motion-premium/scaffold.yaml +6 -1
  50. package/framework/scaffold/motion-premium-3d/README.md +10 -0
  51. package/framework/scaffold/motion-premium-3d/components/webgl/WebGLContext.tsx.template +1 -1
  52. package/framework/scaffold/motion-premium-3d/scaffold.yaml +3 -0
  53. package/framework/scaffold/saas-dashboard/README.md +58 -0
  54. package/framework/scaffold/saas-dashboard/app/dashboard/page.tsx.template +546 -0
  55. package/framework/scaffold/saas-dashboard/app/globals.css.template +746 -0
  56. package/framework/scaffold/saas-dashboard/app/layout.tsx.template +192 -0
  57. package/framework/scaffold/saas-dashboard/app/shell.css.template +1070 -0
  58. package/framework/scaffold/saas-dashboard/components/data/Chart.tsx.template +725 -0
  59. package/framework/scaffold/saas-dashboard/components/data/DataTable.tsx.template +623 -0
  60. package/framework/scaffold/saas-dashboard/components/data/DataTable.types.ts.template +104 -0
  61. package/framework/scaffold/saas-dashboard/components/data/DataTablePagination.tsx.template +234 -0
  62. package/framework/scaffold/saas-dashboard/components/data/SkeletonBlock.tsx.template +111 -0
  63. package/framework/scaffold/saas-dashboard/components/data/StatCard.tsx.template +393 -0
  64. package/framework/scaffold/saas-dashboard/components/data/StatCardGrid.tsx.template +121 -0
  65. package/framework/scaffold/saas-dashboard/components/feedback/EmptyState.tsx.template +281 -0
  66. package/framework/scaffold/saas-dashboard/components/interaction/CommandPalette.tsx.template +767 -0
  67. package/framework/scaffold/saas-dashboard/components/interaction/Field.tsx.template +351 -0
  68. package/framework/scaffold/saas-dashboard/components/interaction/Form.tsx.template +424 -0
  69. package/framework/scaffold/saas-dashboard/components/primitives/Badge.tsx.template +193 -0
  70. package/framework/scaffold/saas-dashboard/components/primitives/Button.tsx.template +261 -0
  71. package/framework/scaffold/saas-dashboard/components/primitives/Card.tsx.template +287 -0
  72. package/framework/scaffold/saas-dashboard/components/primitives/Input.tsx.template +310 -0
  73. package/framework/scaffold/saas-dashboard/components/primitives/Spinner.tsx.template +135 -0
  74. package/framework/scaffold/saas-dashboard/components/primitives/index.ts.template +60 -0
  75. package/framework/scaffold/saas-dashboard/components/shell/AppShell.tsx.template +174 -0
  76. package/framework/scaffold/saas-dashboard/components/shell/Breadcrumb.tsx.template +186 -0
  77. package/framework/scaffold/saas-dashboard/components/shell/Container.tsx.template +86 -0
  78. package/framework/scaffold/saas-dashboard/components/shell/NavItem.tsx.template +147 -0
  79. package/framework/scaffold/saas-dashboard/components/shell/Sidebar.tsx.template +378 -0
  80. package/framework/scaffold/saas-dashboard/components/shell/SidebarContext.tsx.template +169 -0
  81. package/framework/scaffold/saas-dashboard/components/shell/ThemeToggle.tsx.template +128 -0
  82. package/framework/scaffold/saas-dashboard/components/shell/Topbar.tsx.template +301 -0
  83. package/framework/scaffold/saas-dashboard/lib/brand.ts.template +324 -0
  84. package/framework/scaffold/saas-dashboard/scaffold.yaml +225 -0
  85. package/framework/schemas/session.schema.json +5 -0
  86. package/framework/schemas/task.schema.json +9 -0
  87. package/framework/scripts/visual-qa.js +101 -3
  88. package/framework/tasks/orchestrator-health.md +4 -4
  89. package/framework/tasks/qa-impl-verdict.md +11 -5
  90. package/framework/templates/brandbook-html-tmpl.md +1 -1
  91. package/framework/templates/qa-gate-tmpl.yaml +24 -11
  92. package/package.json +4 -3
  93. package/src/config/context-file-generator.js +0 -6
  94. package/src/dashboard/renderer.js +0 -36
  95. package/src/executors/runner.js +204 -0
  96. package/src/installer/core.js +13 -3
  97. package/src/installer/templates.js +5 -6
  98. package/src/intelligence/registry-manager.js +1 -1
  99. package/src/license/client.js +9 -3
  100. package/src/license/commands.js +12 -2
  101. package/src/license/machine-id.js +42 -1
  102. package/src/memory/gotchas.js +58 -40
  103. package/src/memory/magic-docs.js +1 -1
  104. package/src/memory/session-digest.js +9 -4
  105. package/src/orchestrator/cli.js +186 -15
  106. package/src/orchestrator/doctor.js +98 -16
  107. package/src/orchestrator/pipeline-manager.js +44 -22
  108. package/src/orchestrator/session-manager.js +64 -8
  109. package/src/telemetry/sender.js +7 -19
  110. package/src/terminal/run-team.js +3 -3
  111. package/src/upgrade/tracked-files-detector.js +34 -16
  112. package/src/utils/feature-flags.js +1 -1
  113. package/src/utils/flatten-entities.js +4 -40
  114. package/src/utils/schema-validator.js +0 -14
  115. package/src/wizard/i18n.js +3 -3
  116. package/src/api/index.js +0 -120
  117. package/src/autonomy/autonomous-gate.js +0 -294
  118. package/src/autonomy/build-loop.js +0 -281
  119. package/src/autonomy/build-state.js +0 -286
  120. package/src/autonomy/cause-analyzer.js +0 -177
  121. package/src/autonomy/escalation.js +0 -214
  122. package/src/autonomy/index.js +0 -51
  123. package/src/autonomy/mode-manager.js +0 -225
  124. package/src/autonomy/mode-suggester.js +0 -283
  125. package/src/autonomy/progress-reporter.js +0 -275
  126. package/src/autonomy/safety-net.js +0 -370
  127. package/src/config/agent-customizer.js +0 -231
  128. package/src/decision/analyzer.js +0 -291
  129. package/src/decision/engine.js +0 -250
  130. package/src/decision/index.js +0 -38
  131. package/src/decision/registry-healer.js +0 -468
  132. package/src/decision/registry-updater.js +0 -339
  133. package/src/extensions/loader.js +0 -145
  134. package/src/extensions/registry.js +0 -134
  135. package/src/gates/circuit-breaker.js +0 -151
  136. package/src/gates/g1-planning-complete.js +0 -154
  137. package/src/gates/g2-qa-planning.js +0 -156
  138. package/src/gates/g3-implementation.js +0 -215
  139. package/src/gates/g4-qa-implementation.js +0 -240
  140. package/src/gates/g5-deploy-ready.js +0 -181
  141. package/src/gates/gate-base.js +0 -185
  142. package/src/gates/index.js +0 -46
  143. package/src/health/auto-fix.js +0 -216
  144. package/src/health/engine.js +0 -246
  145. package/src/merger/semantic-merger.js +0 -292
  146. package/src/preview/detector.js +0 -238
  147. package/src/preview/index.js +0 -20
  148. package/src/preview/launcher.js +0 -235
  149. package/src/preview/log-buffer.js +0 -103
  150. package/src/quality/metrics-collector.js +0 -281
  151. package/src/quality/test-runner.js +0 -366
  152. package/src/tasks/executor.js +0 -195
  153. package/src/tasks/index.js +0 -4
  154. package/src/tasks/loader.js +0 -210
  155. package/src/tasks/router.js +0 -182
  156. package/src/utils/event-bus.js +0 -126
@@ -0,0 +1,225 @@
1
+ # Scaffold Premium - saas-dashboard v1.0.0
2
+ #
3
+ # Declarative manifest for the saas-dashboard scaffold preset. Consumed by
4
+ # the scaffold-applier at apply time to resolve placeholders and emit files
5
+ # into the target project. App-shell category: a premium SaaS dashboard with
6
+ # a sidebar, top bar, sortable data tables, KPI cards, an SVG chart, forms,
7
+ # and a Cmd+K command palette. Distinct from the motion-premium presets,
8
+ # which target animated showcase sites.
9
+ #
10
+ # Contract: this schema is STABLE within v1.x. Additions only.
11
+
12
+ id: saas-dashboard
13
+ version: 1.0.0
14
+ description: "Premium SaaS dashboard and app-shell: sidebar nav, top bar, sortable data tables, KPI stat cards, a self-contained SVG chart, accessible forms, and a Cmd+K command palette. Calibrated dark palette, modular type scale, fully token-driven, WCAG AA. Opinionated for Next.js / React 18+ / Tailwind v4."
15
+
16
+ framework:
17
+ chati_dev: ">=4.3.0"
18
+
19
+ stack:
20
+ build_tools: ["nextjs"]
21
+ tailwind: ">=4.0.0"
22
+ typescript: ">=5.0.0"
23
+ node: ">=18.0.0"
24
+ react: ">=18.0.0"
25
+ next: ">=13.0.0"
26
+ # TypeScript dev types. create-next-app --typescript installs these; declared
27
+ # here so a hand-rolled Next.js project knows to add them before applying.
28
+ "@types/react": ">=18.0.0"
29
+ "@types/react-dom": ">=18.0.0"
30
+ # Runtime peer deps imported directly by templates. The chart and command
31
+ # palette are hand-rolled (no chart or cmdk dependency) to keep the footprint small.
32
+ lucide-react: ">=0.400.0"
33
+ "framer-motion": "^11.0.0"
34
+ # Playwright powers the QA-Visual screenshot gate. Without it, visual-qa.js
35
+ # falls back to source analysis (gateway: WEAK).
36
+ playwright: "^1.44.0"
37
+
38
+ # Brandable accent (role 1 interactive affordance). The neutral and semantic
39
+ # scales are the designed system and are not parameterized.
40
+ placeholders:
41
+ ACCENT_HEX:
42
+ source: brand.colors.accent
43
+ default: "#7c5af8"
44
+ type: hex
45
+ ACCENT_HOVER_HEX:
46
+ source: brand.colors.accentHover
47
+ default: "#9070ff"
48
+ type: hex
49
+
50
+ brand_sources:
51
+ - path: lib/brand.ts
52
+ type: typescript
53
+ description: "Existing brand tokens (brownfield or post-install)"
54
+ - path: artifacts/4-UX/brandbook.md
55
+ type: markdown
56
+ description: "UX-authored brandbook (greenfield, post-UX phase)"
57
+ - type: interactive
58
+ prompt: true
59
+ description: "Fallback: ask the user for the accent with default hints"
60
+
61
+ # Files shipped by this scaffold (30 templates).
62
+ files:
63
+ - source: app/dashboard/page.tsx.template
64
+ target: app/dashboard/page.tsx
65
+ phase: sample
66
+ override: full
67
+ notes: "Composed sample dashboard demonstrating the preset. User replaces with real pages."
68
+ - source: app/globals.css.template
69
+ target: app/globals.css
70
+ phase: foundation
71
+ override: partial
72
+ notes: "Design tokens (CSS custom properties). Accent vars synced from brand source; the calibrated neutral and semantic scales are the designed system, user-editable."
73
+ - source: app/shell.css.template
74
+ target: app/shell.css
75
+ phase: shell
76
+ override: partial
77
+ notes: "BEM styles for the app-shell layer (sidebar, topbar, breadcrumb, theme toggle). References the globals.css tokens; imported once by app/layout.tsx."
78
+ - source: app/layout.tsx.template
79
+ target: app/layout.tsx
80
+ phase: shell
81
+ override: partial
82
+ notes: "Ships the shell + providers + fonts. User fills metadata, analytics, chrome."
83
+ - source: components/data/Chart.tsx.template
84
+ target: components/data/Chart.tsx
85
+ phase: data
86
+ override: none
87
+ notes: "Data-display component (table, stat card, chart). Scaffold-owned."
88
+ - source: components/data/DataTable.tsx.template
89
+ target: components/data/DataTable.tsx
90
+ phase: data
91
+ override: none
92
+ notes: "Data-display component (table, stat card, chart). Scaffold-owned."
93
+ - source: components/data/DataTable.types.ts.template
94
+ target: components/data/DataTable.types.ts
95
+ phase: data
96
+ override: none
97
+ notes: "Data-display component (table, stat card, chart). Scaffold-owned."
98
+ - source: components/data/DataTablePagination.tsx.template
99
+ target: components/data/DataTablePagination.tsx
100
+ phase: data
101
+ override: none
102
+ notes: "Data-display component (table, stat card, chart). Scaffold-owned."
103
+ - source: components/data/SkeletonBlock.tsx.template
104
+ target: components/data/SkeletonBlock.tsx
105
+ phase: data
106
+ override: none
107
+ notes: "Data-display component (table, stat card, chart). Scaffold-owned."
108
+ - source: components/data/StatCard.tsx.template
109
+ target: components/data/StatCard.tsx
110
+ phase: data
111
+ override: none
112
+ notes: "Data-display component (table, stat card, chart). Scaffold-owned."
113
+ - source: components/data/StatCardGrid.tsx.template
114
+ target: components/data/StatCardGrid.tsx
115
+ phase: data
116
+ override: none
117
+ notes: "Data-display component (table, stat card, chart). Scaffold-owned."
118
+ - source: components/feedback/EmptyState.tsx.template
119
+ target: components/feedback/EmptyState.tsx
120
+ phase: feedback
121
+ override: partial
122
+ notes: "Feedback component (empty state). User supplies copy and slots."
123
+ - source: components/interaction/CommandPalette.tsx.template
124
+ target: components/interaction/CommandPalette.tsx
125
+ phase: interaction
126
+ override: none
127
+ notes: "Interaction component (command palette, form fields). Scaffold-owned."
128
+ - source: components/interaction/Field.tsx.template
129
+ target: components/interaction/Field.tsx
130
+ phase: interaction
131
+ override: none
132
+ notes: "Interaction component (command palette, form fields). Scaffold-owned."
133
+ - source: components/interaction/Form.tsx.template
134
+ target: components/interaction/Form.tsx
135
+ phase: interaction
136
+ override: none
137
+ notes: "Interaction component (command palette, form fields). Scaffold-owned."
138
+ - source: components/primitives/Badge.tsx.template
139
+ target: components/primitives/Badge.tsx
140
+ phase: primitives
141
+ override: none
142
+ notes: "Shared primitive with full resting/hover/active/disabled/focus states. Scaffold-owned."
143
+ - source: components/primitives/Button.tsx.template
144
+ target: components/primitives/Button.tsx
145
+ phase: primitives
146
+ override: none
147
+ notes: "Shared primitive with full resting/hover/active/disabled/focus states. Scaffold-owned."
148
+ - source: components/primitives/Card.tsx.template
149
+ target: components/primitives/Card.tsx
150
+ phase: primitives
151
+ override: none
152
+ notes: "Shared primitive with full resting/hover/active/disabled/focus states. Scaffold-owned."
153
+ - source: components/primitives/Input.tsx.template
154
+ target: components/primitives/Input.tsx
155
+ phase: primitives
156
+ override: none
157
+ notes: "Shared primitive with full resting/hover/active/disabled/focus states. Scaffold-owned."
158
+ - source: components/primitives/Spinner.tsx.template
159
+ target: components/primitives/Spinner.tsx
160
+ phase: primitives
161
+ override: none
162
+ notes: "Shared primitive with full resting/hover/active/disabled/focus states. Scaffold-owned."
163
+ - source: components/primitives/index.ts.template
164
+ target: components/primitives/index.ts
165
+ phase: primitives
166
+ override: none
167
+ notes: "Shared primitive with full resting/hover/active/disabled/focus states. Scaffold-owned."
168
+ - source: components/shell/AppShell.tsx.template
169
+ target: components/shell/AppShell.tsx
170
+ phase: shell
171
+ override: none
172
+ notes: "App-shell component (sidebar, top bar, nav). Scaffold-owned."
173
+ - source: components/shell/Breadcrumb.tsx.template
174
+ target: components/shell/Breadcrumb.tsx
175
+ phase: shell
176
+ override: none
177
+ notes: "App-shell component (sidebar, top bar, nav). Scaffold-owned."
178
+ - source: components/shell/Container.tsx.template
179
+ target: components/shell/Container.tsx
180
+ phase: foundation
181
+ override: none
182
+ notes: "Single authority for max-width + horizontal padding. Never edit."
183
+ - source: components/shell/NavItem.tsx.template
184
+ target: components/shell/NavItem.tsx
185
+ phase: shell
186
+ override: none
187
+ notes: "App-shell component (sidebar, top bar, nav). Scaffold-owned."
188
+ - source: components/shell/Sidebar.tsx.template
189
+ target: components/shell/Sidebar.tsx
190
+ phase: shell
191
+ override: none
192
+ notes: "App-shell component (sidebar, top bar, nav). Scaffold-owned."
193
+ - source: components/shell/SidebarContext.tsx.template
194
+ target: components/shell/SidebarContext.tsx
195
+ phase: shell
196
+ override: none
197
+ notes: "App-shell component (sidebar, top bar, nav). Scaffold-owned."
198
+ - source: components/shell/ThemeToggle.tsx.template
199
+ target: components/shell/ThemeToggle.tsx
200
+ phase: shell
201
+ override: none
202
+ notes: "App-shell component (sidebar, top bar, nav). Scaffold-owned."
203
+ - source: components/shell/Topbar.tsx.template
204
+ target: components/shell/Topbar.tsx
205
+ phase: shell
206
+ override: none
207
+ notes: "App-shell component (sidebar, top bar, nav). Scaffold-owned."
208
+ - source: lib/brand.ts.template
209
+ target: lib/brand.ts
210
+ phase: foundation
211
+ override: full
212
+ notes: "User-owned typed brand tokens. Protected from upgrades."
213
+
214
+ # Principles this scaffold encodes. Violating any breaks the premium guarantees.
215
+ principles:
216
+ - "Tokens over values: every color, size, radius, shadow, and duration referenced in a component file must be a CSS custom property or a typed constant from lib/brand.ts. Raw hex strings, raw pixel numbers, and bare ease keywords are linting violations."
217
+ - "Semantic layering: the neutral scale provides raw steps; the semantic layer (--color-bg-*, --color-text-*, --color-border-*) is what components consume. Adding a new theme requires only overriding the semantic layer, never touching component files."
218
+ - "Container is the sole layout authority: max-width and horizontal page padding exist only in Container.tsx. No other component may set max-width or page-level horizontal padding."
219
+ - "Motion must be purposeful: every transition must specify exactly which property it transitions (never transition:all), an explicit duration token, and an explicit easing token. The easing must match the spatial metaphor: ease-out for entering, ease-in for leaving, ease-in-out for toggling."
220
+ - "Accessibility is structural, not an afterthought: semantic HTML elements (<table>, <nav>, <main>, <dialog>, <label>) are used for their meaning. ARIA attributes supplement but never replace semantic HTML. Focus management (trap in modals, restore on close) is implemented, not skipped."
221
+ - "Reduced-motion is first-class: every animation is authored assuming motion is allowed, then a separate @media (prefers-reduced-motion: reduce) block collapses all durations to 0ms or 80ms and removes transform-based animations. This is done in globals.css, not per-component."
222
+ - "Placeholder is never the only label: every input has a real <label> element. Placeholder text may clarify format but the field is fully understandable without it. The Field primitive enforces this structurally."
223
+ - "Performance budget on animation: only transform and opacity are animated. Width, height, top, left, padding, and margin transitions are forbidden. Layout shift is prevented by reserving space for loading and empty states before content arrives."
224
+ - "Dark palette is designed, not inverted: the dark theme is built from a calibrated neutral scale with its own shadow, surface layering, and reduced-contrast accent values. It is not produced by CSS filter or by simply swapping light and dark values."
225
+ - "Primitives are the contract boundary: Button, Card, Input/Field, and Badge are the shared language across all builders. New components compose primitives; they do not reimplement base patterns. Any change to a primitive propagates correctly to all consumers."
@@ -14,6 +14,11 @@
14
14
  "type": "string",
15
15
  "description": "Legacy framework-version marker on the session object (distinct from schema_version). Kept for backwards compatibility."
16
16
  },
17
+ "model_at_last_audit": {
18
+ "type": ["string", "null"],
19
+ "default": null,
20
+ "description": "Normalized active_model recorded when /chati-update last completed. Article XXIV: when active_model differs from this, the orchestrator advises a harness re-audit. The advisory is driven entirely by this comparison; there is no separate flag."
21
+ },
17
22
  "mode": {
18
23
  "enum": ["discover", "plan", "build", "validate", "deploy", "completed"],
19
24
  "default": "discover",
@@ -66,6 +66,15 @@
66
66
  "completed_at": {
67
67
  "type": ["string", "null"],
68
68
  "format": "date-time"
69
+ },
70
+ "execution_kind": {
71
+ "enum": ["agent", "script", "specialist", "human"],
72
+ "default": "agent",
73
+ "description": "How this task executes. 'agent' (default): an LLM agent implements it. 'script': a deterministic zero-LLM executor runs it (see execution_ref). 'specialist': an agent carrying an embedded methodology. 'human': a human decision gate. Omitting the field means 'agent', so existing tasks are unaffected."
74
+ },
75
+ "execution_ref": {
76
+ "type": ["string", "null"],
77
+ "description": "Resolves the executor for non-agent kinds. For 'script': an executor id from chati.dev/executors/registry.yaml, optionally with a colon-suffixed argument (e.g. 'npm-script:lint'). For 'specialist': the methodology id. For 'human': a short description of the decision required. Null or omitted for 'agent'."
69
78
  }
70
79
  }
71
80
  }
@@ -92,6 +92,43 @@ export function computeReducedMotionViolations(report, reducedMotionMode, primar
92
92
  }));
93
93
  }
94
94
 
95
+ /**
96
+ * Spring-motion veto: derive visual errors from each page's motion_quality scan.
97
+ * Linear easing on a state transition and transition-property: all are amateur
98
+ * motion tells. ERROR severity so the qa-visual gate factors them into APPROVED
99
+ * (routed to dev via Fault Vector Protocol); not a hard crash.
100
+ *
101
+ * @param {{pages: Array<{path:string, js_checks?:object}>}} report
102
+ * @returns {Array<{severity:string, type:string, page:string, detail:string, samples:object[]}>}
103
+ */
104
+ export function computeMotionErrors(report) {
105
+ const pages = Array.isArray(report?.pages) ? report.pages : [];
106
+ const errors = [];
107
+ for (const p of pages) {
108
+ const m = p?.js_checks?.motion_quality;
109
+ if (!m) continue;
110
+ if (m.transition_all > 0) {
111
+ errors.push({
112
+ severity: 'error',
113
+ type: 'transition_all',
114
+ page: p.path,
115
+ detail: `${m.transition_all} visible element(s) use transition-property: all, which animates layout properties and janks. Transition specific compositor properties (transform, opacity) instead.`,
116
+ samples: (m.samples || []).filter(s => s.issue && s.issue.includes('all')).slice(0, 3),
117
+ });
118
+ }
119
+ if (m.linear_transitions > 0) {
120
+ errors.push({
121
+ severity: 'error',
122
+ type: 'linear_easing',
123
+ page: p.path,
124
+ detail: `${m.linear_transitions} visible element(s) use linear easing on a state transition, which feels robotic. Use ease-out, a cubic-bezier, or a spring.`,
125
+ samples: (m.samples || []).filter(s => s.issue && s.issue.includes('linear')).slice(0, 3),
126
+ });
127
+ }
128
+ }
129
+ return errors;
130
+ }
131
+
95
132
  // ---------------------------------------------------------------------------
96
133
  // Args
97
134
  // ---------------------------------------------------------------------------
@@ -370,8 +407,20 @@ async function main() {
370
407
  if (chromium) break;
371
408
  } catch { /* try next */ }
372
409
  }
373
- if (!chromium) throw new Error('Playwright not installed. Run: npx playwright install chromium');
374
- const browser = await chromium.launch({ headless: true });
410
+ if (!chromium) {
411
+ // v4.3.1+ G17: disambiguate npm-package-missing from binary-missing for actionable hints
412
+ throw new Error('Playwright npm package missing. Run: npm install playwright');
413
+ }
414
+ let browser;
415
+ try {
416
+ browser = await chromium.launch({ headless: true });
417
+ } catch (e) {
418
+ if (e.message.includes("Executable doesn't exist")
419
+ || e.message.includes('browserType.launch')) {
420
+ throw new Error('Chromium binary missing. Run: npx playwright install chromium');
421
+ }
422
+ throw e;
423
+ }
375
424
  const report = { pages: [], summary: {} };
376
425
 
377
426
  for (const pagePath of pages) {
@@ -539,6 +588,45 @@ async function main() {
539
588
  }
540
589
  checks.custom_properties_count = count;
541
590
 
591
+ // Motion quality (spring-motion veto). Premium motion uses spring or
592
+ // cubic-bezier easing on specific compositor properties. Linear easing
593
+ // on a state transition feels robotic, and transition-property: all
594
+ // animates layout and janks. Both are strong amateur-motion tells. Scan
595
+ // visible elements that actually declare a transition.
596
+ // Linear easing is a robotic tell for discrete state transitions
597
+ // (transform, opacity, color), but it is the correct, physical choice for
598
+ // continuous or progress motion (a progress bar width, an SVG stroke
599
+ // draw, a parallax offset). Exempt those properties, plus an explicit
600
+ // data-linear-ok opt-out, so a legitimate loader is never falsely flagged.
601
+ const SAFE_LINEAR_PROPS = ['width', 'height', 'max-width', 'max-height', 'min-width', 'min-height', 'background-position', 'background-size', 'stroke-dashoffset', 'stroke-dasharray', 'clip-path', 'left', 'right', 'top', 'bottom'];
602
+ const motion = { linear_transitions: 0, transition_all: 0, samples: [] };
603
+ for (const el of document.querySelectorAll('body *')) {
604
+ const cs = getComputedStyle(el);
605
+ const dur = cs.transitionDuration || '0s';
606
+ if (!dur.split(',').some(d => parseFloat(d) > 0)) continue; // no real transition
607
+ const rect = el.getBoundingClientRect();
608
+ if (rect.width < 4 || rect.height < 4) continue; // not visible
609
+ const prop = (cs.transitionProperty || '').split(',').map(s => s.trim());
610
+ const tf = cs.transitionTimingFunction || '';
611
+ let issue = null;
612
+ if (prop.includes('all')) { motion.transition_all++; issue = 'transition-property: all'; }
613
+ else if (/\blinear\b(?!\s*\()/.test(tf)) {
614
+ const allSafe = prop.length > 0 && prop.every(p => SAFE_LINEAR_PROPS.includes(p));
615
+ if (!allSafe && !el.hasAttribute('data-linear-ok')) { motion.linear_transitions++; issue = 'linear easing'; }
616
+ }
617
+ if (issue && motion.samples.length < 8) {
618
+ motion.samples.push({
619
+ tag: el.tagName.toLowerCase(),
620
+ cls: [...el.classList].slice(0, 4).join(' '),
621
+ issue,
622
+ timing: tf,
623
+ property: cs.transitionProperty,
624
+ duration: dur,
625
+ });
626
+ }
627
+ }
628
+ checks.motion_quality = motion;
629
+
542
630
  // 3D scaffold signals (motion-premium-3d workstream P7). Detects
543
631
  // whether the page rendered a Canvas or fell back to SceneFallback.
544
632
  // The data-* attributes come from the CanvasProvider + SceneFallback
@@ -610,6 +698,7 @@ async function main() {
610
698
  const reducedMotionViolations = computeReducedMotionViolations(
611
699
  report, reducedMotionMode, viewports[0]
612
700
  );
701
+ const motionErrors = computeMotionErrors(report);
613
702
 
614
703
  report.summary = {
615
704
  total_pages: report.pages.length,
@@ -630,6 +719,8 @@ async function main() {
630
719
  viewport_profiles: viewports.map(v => v.checkKey),
631
720
  layout_errors: allLayoutErrors,
632
721
  layout_error_count: allLayoutErrors.filter(e => e.severity === 'error').length,
722
+ motion_errors: motionErrors,
723
+ motion_error_count: motionErrors.length,
633
724
  };
634
725
 
635
726
  // 6. Write report
@@ -648,7 +739,14 @@ async function main() {
648
739
  }
649
740
  }
650
741
 
651
- if (!report.summary.lenis_active_all || !report.summary.gsap_loaded_all || report.summary.em_dashes_detected || report.summary.layout_error_count > 0) {
742
+ if (report.summary.motion_error_count > 0) {
743
+ console.log(`\nMotion errors (spring-motion veto): ${report.summary.motion_error_count}`);
744
+ for (const err of report.summary.motion_errors.slice(0, 6)) {
745
+ console.log(` [${err.type}] ${err.page || ''}: ${err.detail}`);
746
+ }
747
+ }
748
+
749
+ if (!report.summary.lenis_active_all || !report.summary.gsap_loaded_all || report.summary.em_dashes_detected || report.summary.layout_error_count > 0 || report.summary.motion_error_count > 0) {
652
750
  exitCode = 1;
653
751
  }
654
752
 
@@ -29,7 +29,7 @@ Validate the chati.dev framework installation, check system dependencies, verify
29
29
 
30
30
  ### 1. Check Core Framework Files
31
31
  Verify essential framework files exist and are valid:
32
- - `chati.dev/constitution.md` (Article I through XI)
32
+ - `chati.dev/constitution.md` (Article I through XXV)
33
33
  - `chati.dev/config.yaml` (framework configuration)
34
34
  - `chati.dev/installer/install.js` (installer script)
35
35
  - `.chati/` directory structure
@@ -192,7 +192,7 @@ health_report:
192
192
  - file: "chati.dev/constitution.md"
193
193
  status: "ok"
194
194
  size_kb: 45
195
- articles_count: 11
195
+ articles_count: 25
196
196
  - file: "chati.dev/config.yaml"
197
197
  status: "ok"
198
198
  valid_yaml: true
@@ -280,7 +280,7 @@ health_report:
280
280
 
281
281
  constitution_validation:
282
282
  status: "healthy"
283
- articles_present: 11
283
+ articles_present: 25
284
284
  article_xi_valid: true
285
285
  mode_definitions: ["planning", "build", "deploy"]
286
286
  transition_rules_defined: true
@@ -308,7 +308,7 @@ health_report:
308
308
  ✓ Framework Health: HEALTHY
309
309
 
310
310
  All core components validated successfully:
311
- - Constitution with 11 articles
311
+ - Constitution with 25 articles
312
312
  - 12 agent definitions
313
313
  - 35 task definitions
314
314
  - 8 schema files
@@ -62,11 +62,17 @@ Issue the final QA verdict by synthesizing all QA implementation results (tests,
62
62
  - Document gate outcome with rationale
63
63
 
64
64
  6. **Calculate Overall Quality Score**
65
- - **Test Results**: 25 points (pass rate, coverage)
66
- - **SAST**: 25 points (vulnerability severity, count)
67
- - **Regressions**: 25 points (regression count, severity)
68
- - **Performance**: 25 points (threshold compliance, degradation)
69
- - Total: 100 points maximum
65
+ - Use the canonical weighted scoring table from `docs/architecture/quality-gates.md` (single source of truth). Weights:
66
+ - **Tests**: 0.20
67
+ - **Security (SAST)**: 0.20
68
+ - **Adversarial Review**: 0.15
69
+ - **Visual Review**: 0.15
70
+ - **Code Quality**: 0.10
71
+ - **Coverage**: 0.10
72
+ - **Acceptance Criteria**: 0.10
73
+ - Each dimension is scored 0-100; the weighted sum is the overall score (0-100).
74
+ - Verdict thresholds: **>= 95%** APPROVED | **90–94%** NEEDS_REVISION | **< 90%** BLOCKED.
75
+ - Note: the legacy 4-gate 25-point equal-weight table (Tests/SAST/Regressions/Performance = 25/25/25/25) is DEPRECATED — `qa-gate-tmpl.yaml` and `docs/architecture/quality-gates.md` both use the weighted scheme above.
70
76
 
71
77
  7. **Apply Gate Logic**
72
78
  - **ALL gates PASS**: Overall verdict = PASS
@@ -103,5 +103,5 @@ sections must exist and what each must contain.
103
103
 
104
104
  ## Reference
105
105
 
106
- See `/Users/ogabrielalonso/code/focus-ai/ping/docs/brand/brandbook.html` for a production
106
+ See `<your-project>/docs/brand/brandbook.html` for a production
107
107
  example with 14 sections, sticky nav, dark mode toggle, and complete token rendering.
@@ -46,28 +46,41 @@ sections:
46
46
  description: "Each agent defined rigorous, binary criteria"
47
47
  penalty_on_fail: -10
48
48
 
49
+ # Implementation gate weights — single source of truth:
50
+ # `docs/architecture/quality-gates.md` § Weighted Scoring. The legacy 30/20/25/15/10
51
+ # (Test/Coverage/SAST/Review/AC) table was deprecated 2026-05; consumers
52
+ # SHALL use the 7-dimension table below. Verdict thresholds:
53
+ # >= 95% APPROVED | 90-94% NEEDS_REVISION | < 90% BLOCKED.
49
54
  - id: implementation_gate
50
55
  applicable_to: implementation
51
56
  checks:
52
- - name: "Test Execution"
57
+ - name: "Tests"
53
58
  description: "All tests pass"
54
- weight: 0.30
55
- threshold: "100% pass rate"
56
-
57
- - name: "Code Coverage"
58
- description: "Line and branch coverage"
59
59
  weight: 0.20
60
- threshold: ">= 80%"
60
+ threshold: "100% pass rate"
61
61
 
62
- - name: "Security Scan (SAST)"
62
+ - name: "Security (SAST)"
63
63
  description: "No critical or high vulnerabilities"
64
- weight: 0.25
64
+ weight: 0.20
65
65
  threshold: "0 critical, 0 high"
66
66
 
67
- - name: "Code Review"
68
- description: "Architecture adherence, patterns, quality"
67
+ - name: "Adversarial Review"
68
+ description: "Devil's-advocate cross-review of risky changes"
69
+ weight: 0.15
70
+
71
+ - name: "Visual Review"
72
+ description: "Playwright screenshots + brandbook token compliance"
69
73
  weight: 0.15
70
74
 
75
+ - name: "Code Quality"
76
+ description: "Architecture adherence, patterns, style"
77
+ weight: 0.10
78
+
79
+ - name: "Coverage"
80
+ description: "Line and branch coverage"
81
+ weight: 0.10
82
+ threshold: ">= 80%"
83
+
71
84
  - name: "Acceptance Criteria"
72
85
  description: "All Given-When-Then criteria verified"
73
86
  weight: 0.10
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chati-dev",
3
- "version": "4.3.0",
3
+ "version": "4.4.0",
4
4
  "description": "AI-Powered Multi-Agent Orchestration System - Structured vibe coding for Full Stack Development",
5
5
  "type": "module",
6
6
  "bin": {
@@ -10,7 +10,6 @@
10
10
  "main": "src/wizard/index.js",
11
11
  "exports": {
12
12
  ".": "./src/wizard/index.js",
13
- "./api": "./src/api/index.js",
14
13
  "./installer": "./src/installer/core.js",
15
14
  "./dashboard": "./src/dashboard/renderer.js",
16
15
  "./upgrade": "./src/upgrade/checker.js"
@@ -32,7 +31,9 @@
32
31
  "prepublishOnly": "node scripts/sync-framework.js && node scripts/scan-stale.js && node scripts/validate-package.js && node scripts/sign-manifest.js",
33
32
  "test": "node --test test/**/*.test.js",
34
33
  "lint": "eslint src/ bin/",
35
- "lint:fix": "eslint src/ bin/ --fix"
34
+ "lint:fix": "eslint src/ bin/ --fix",
35
+ "verify-v431": "npm test && node scripts/scan-stale.js && npm run sync && node scripts/validate-package.js && node test/fixtures/manual-smoke-v430-upgrade.mjs",
36
+ "smoke:scaffold-build": "node test/fixtures/manual-smoke-scaffold-build.mjs"
36
37
  },
37
38
  "keywords": [
38
39
  "ai",
@@ -72,12 +72,6 @@ function buildCodexReplacements(frameworkDir = 'chati.dev') {
72
72
  ];
73
73
  }
74
74
 
75
- /**
76
- * Text replacements for Codex CLI context file (legacy constant using default 'chati.dev/' prefix).
77
- * @deprecated Use buildCodexReplacements(frameworkDir) for correct path resolution.
78
- */
79
- const CODEX_REPLACEMENTS = buildCodexReplacements();
80
-
81
75
  // ---------------------------------------------------------------------------
82
76
  // Generators
83
77
  // ---------------------------------------------------------------------------
@@ -69,39 +69,3 @@ export async function renderDashboardWatch(targetDir, intervalMs = 5000) {
69
69
 
70
70
  return timer;
71
71
  }
72
-
73
- /**
74
- * Render plain text fallback (for terminals without TUI support)
75
- */
76
- export async function renderPlainDashboard(targetDir) {
77
- const data = await readDashboardData(targetDir);
78
-
79
- if (!data.session) {
80
- console.log('No chati.dev session found. Run `npx chati-dev init` first.');
81
- return;
82
- }
83
-
84
- const session = data.session;
85
- const project = session.project || {};
86
-
87
- console.log();
88
- console.log('=== chati.dev Dashboard ===');
89
- console.log();
90
- console.log(`Project: ${project.name || 'unknown'}`);
91
- console.log(`Type: ${project.type || 'unknown'}`);
92
- console.log(`Phase: ${project.state || 'unknown'}`);
93
- console.log(`Mode: ${session.execution_mode || 'interactive'}`);
94
- console.log(`Language: ${session.language || 'en'}`);
95
- console.log();
96
-
97
- console.log('--- Agent Scores ---');
98
- for (const [name, info] of Object.entries(data.agentScores)) {
99
- const status = info.status === 'pending' ? '--' : info.status === 'in_progress' ? '...' : String(info.score);
100
- console.log(` ${name.padEnd(20)} ${status}`);
101
- }
102
-
103
- console.log();
104
- console.log(`Blockers: ${data.blockers.length || 'None'}`);
105
- console.log(`Gotchas: ${data.gotchas.length} patterns`);
106
- console.log();
107
- }