@agile-vibe-coding/avc 0.2.3 → 0.3.1

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 (261) hide show
  1. package/cli/agents/agent-selector.md +23 -0
  2. package/cli/agents/code-implementer.md +117 -0
  3. package/cli/agents/code-validator.md +80 -0
  4. package/cli/agents/context-reviewer-epic.md +101 -0
  5. package/cli/agents/context-reviewer-story.md +92 -0
  6. package/cli/agents/context-writer-epic.md +145 -0
  7. package/cli/agents/context-writer-story.md +111 -0
  8. package/cli/agents/doc-writer-epic.md +42 -0
  9. package/cli/agents/doc-writer-story.md +43 -0
  10. package/cli/agents/duplicate-detector.md +110 -0
  11. package/cli/agents/epic-story-decomposer.md +318 -39
  12. package/cli/agents/mission-scope-generator.md +68 -4
  13. package/cli/agents/mission-scope-validator.md +40 -6
  14. package/cli/agents/project-context-extractor.md +21 -6
  15. package/cli/agents/scaffolding-generator.md +99 -0
  16. package/cli/agents/seed-validator.md +71 -0
  17. package/cli/agents/story-scope-reviewer.md +147 -0
  18. package/cli/agents/story-splitter.md +83 -0
  19. package/cli/agents/validator-documentation.json +31 -0
  20. package/cli/agents/validator-documentation.md +3 -1
  21. package/cli/api-reference-tool.js +368 -0
  22. package/cli/checks/catalog.json +76 -0
  23. package/cli/checks/code/quality.json +26 -0
  24. package/cli/checks/code/testing.json +14 -0
  25. package/cli/checks/code/traceability.json +26 -0
  26. package/cli/checks/cross-refs/epic.json +171 -0
  27. package/cli/checks/cross-refs/story.json +149 -0
  28. package/cli/checks/epic/api.json +114 -0
  29. package/cli/checks/epic/backend.json +126 -0
  30. package/cli/checks/epic/cloud.json +126 -0
  31. package/cli/checks/epic/data.json +102 -0
  32. package/cli/checks/epic/database.json +114 -0
  33. package/cli/checks/epic/developer.json +182 -0
  34. package/cli/checks/epic/devops.json +174 -0
  35. package/cli/checks/epic/frontend.json +162 -0
  36. package/cli/checks/epic/mobile.json +102 -0
  37. package/cli/checks/epic/qa.json +90 -0
  38. package/cli/checks/epic/security.json +184 -0
  39. package/cli/checks/epic/solution-architect.json +192 -0
  40. package/cli/checks/epic/test-architect.json +90 -0
  41. package/cli/checks/epic/ui.json +102 -0
  42. package/cli/checks/epic/ux.json +90 -0
  43. package/cli/checks/fixes/epic-fix-template.md +10 -0
  44. package/cli/checks/fixes/story-fix-template.md +10 -0
  45. package/cli/checks/story/api.json +186 -0
  46. package/cli/checks/story/backend.json +102 -0
  47. package/cli/checks/story/cloud.json +102 -0
  48. package/cli/checks/story/data.json +210 -0
  49. package/cli/checks/story/database.json +102 -0
  50. package/cli/checks/story/developer.json +168 -0
  51. package/cli/checks/story/devops.json +102 -0
  52. package/cli/checks/story/frontend.json +174 -0
  53. package/cli/checks/story/mobile.json +102 -0
  54. package/cli/checks/story/qa.json +210 -0
  55. package/cli/checks/story/security.json +198 -0
  56. package/cli/checks/story/solution-architect.json +230 -0
  57. package/cli/checks/story/test-architect.json +210 -0
  58. package/cli/checks/story/ui.json +102 -0
  59. package/cli/checks/story/ux.json +102 -0
  60. package/cli/coding-order.js +401 -0
  61. package/cli/dependency-checker.js +72 -0
  62. package/cli/epic-story-validator.js +284 -799
  63. package/cli/index.js +0 -0
  64. package/cli/init-model-config.js +17 -10
  65. package/cli/init.js +514 -92
  66. package/cli/kanban-server-manager.js +1 -2
  67. package/cli/llm-claude.js +98 -31
  68. package/cli/llm-gemini.js +29 -5
  69. package/cli/llm-local.js +493 -0
  70. package/cli/llm-openai.js +262 -41
  71. package/cli/llm-provider.js +147 -8
  72. package/cli/llm-token-limits.js +113 -4
  73. package/cli/llm-verifier.js +209 -1
  74. package/cli/llm-xiaomi.js +143 -0
  75. package/cli/message-constants.js +3 -12
  76. package/cli/messaging-api.js +6 -12
  77. package/cli/micro-check-fixer.js +335 -0
  78. package/cli/micro-check-runner.js +449 -0
  79. package/cli/micro-check-scorer.js +148 -0
  80. package/cli/micro-check-validator.js +538 -0
  81. package/cli/model-pricing.js +23 -0
  82. package/cli/model-selector.js +3 -2
  83. package/cli/prompt-logger.js +57 -0
  84. package/cli/repl-ink.js +106 -346
  85. package/cli/repl-old.js +1 -2
  86. package/cli/seed-processor.js +194 -24
  87. package/cli/sprint-planning-processor.js +2638 -289
  88. package/cli/template-processor.js +50 -3
  89. package/cli/token-tracker.js +50 -23
  90. package/cli/tools/generate-story-validators.js +1 -1
  91. package/cli/validation-router.js +70 -8
  92. package/cli/worktree-runner.js +654 -0
  93. package/kanban/client/dist/assets/index-D_KC5EQT.css +1 -0
  94. package/kanban/client/dist/assets/index-DjY5zqW7.js +351 -0
  95. package/kanban/client/dist/index.html +2 -2
  96. package/kanban/client/src/App.jsx +43 -14
  97. package/kanban/client/src/components/ceremony/AskArchPopup.jsx +7 -3
  98. package/kanban/client/src/components/ceremony/AskModelPopup.jsx +23 -10
  99. package/kanban/client/src/components/ceremony/CeremonyWorkflowModal.jsx +320 -133
  100. package/kanban/client/src/components/ceremony/ProviderSwitcherButton.jsx +290 -0
  101. package/kanban/client/src/components/ceremony/SponsorCallModal.jsx +80 -13
  102. package/kanban/client/src/components/ceremony/SprintPlanningModal.jsx +156 -22
  103. package/kanban/client/src/components/ceremony/steps/ArchitectureStep.jsx +11 -11
  104. package/kanban/client/src/components/ceremony/steps/CompleteStep.jsx +3 -21
  105. package/kanban/client/src/components/ceremony/steps/ReviewAnswersStep.jsx +214 -10
  106. package/kanban/client/src/components/ceremony/steps/RunningStep.jsx +23 -2
  107. package/kanban/client/src/components/kanban/CardDetailModal.jsx +97 -10
  108. package/kanban/client/src/components/kanban/GroupingSelector.jsx +7 -1
  109. package/kanban/client/src/components/kanban/KanbanCard.jsx +23 -14
  110. package/kanban/client/src/components/kanban/RefineWorkItemPopup.jsx +9 -14
  111. package/kanban/client/src/components/kanban/RunButton.jsx +162 -0
  112. package/kanban/client/src/components/kanban/SeedButton.jsx +176 -0
  113. package/kanban/client/src/components/settings/AgentsTab.jsx +103 -75
  114. package/kanban/client/src/components/settings/ApiKeysTab.jsx +31 -2
  115. package/kanban/client/src/components/settings/CeremonyModelsTab.jsx +9 -2
  116. package/kanban/client/src/components/settings/CheckEditorPopup.jsx +507 -0
  117. package/kanban/client/src/components/settings/CostThresholdsTab.jsx +3 -2
  118. package/kanban/client/src/components/settings/ModelPricingTab.jsx +72 -7
  119. package/kanban/client/src/components/settings/OpenAIAuthSection.jsx +412 -0
  120. package/kanban/client/src/components/settings/SettingsModal.jsx +4 -4
  121. package/kanban/client/src/components/stats/CostModal.jsx +34 -3
  122. package/kanban/client/src/hooks/useGrouping.js +59 -0
  123. package/kanban/client/src/lib/api.js +118 -4
  124. package/kanban/client/src/lib/status-grouping.js +10 -0
  125. package/kanban/client/src/store/kanbanStore.js +8 -0
  126. package/kanban/server/index.js +23 -2
  127. package/kanban/server/routes/ceremony.js +153 -4
  128. package/kanban/server/routes/costs.js +9 -3
  129. package/kanban/server/routes/openai-oauth.js +366 -0
  130. package/kanban/server/routes/settings.js +447 -14
  131. package/kanban/server/routes/websocket.js +7 -2
  132. package/kanban/server/routes/work-items.js +141 -1
  133. package/kanban/server/services/CeremonyService.js +275 -24
  134. package/kanban/server/services/TaskRunnerService.js +261 -0
  135. package/kanban/server/workers/run-task-worker.js +121 -0
  136. package/kanban/server/workers/seed-worker.js +94 -0
  137. package/kanban/server/workers/sponsor-call-worker.js +14 -6
  138. package/kanban/server/workers/sprint-planning-worker.js +94 -12
  139. package/package.json +2 -3
  140. package/cli/agents/solver-epic-api.json +0 -15
  141. package/cli/agents/solver-epic-api.md +0 -39
  142. package/cli/agents/solver-epic-backend.json +0 -15
  143. package/cli/agents/solver-epic-backend.md +0 -39
  144. package/cli/agents/solver-epic-cloud.json +0 -15
  145. package/cli/agents/solver-epic-cloud.md +0 -39
  146. package/cli/agents/solver-epic-data.json +0 -15
  147. package/cli/agents/solver-epic-data.md +0 -39
  148. package/cli/agents/solver-epic-database.json +0 -15
  149. package/cli/agents/solver-epic-database.md +0 -39
  150. package/cli/agents/solver-epic-developer.json +0 -15
  151. package/cli/agents/solver-epic-developer.md +0 -39
  152. package/cli/agents/solver-epic-devops.json +0 -15
  153. package/cli/agents/solver-epic-devops.md +0 -39
  154. package/cli/agents/solver-epic-frontend.json +0 -15
  155. package/cli/agents/solver-epic-frontend.md +0 -39
  156. package/cli/agents/solver-epic-mobile.json +0 -15
  157. package/cli/agents/solver-epic-mobile.md +0 -39
  158. package/cli/agents/solver-epic-qa.json +0 -15
  159. package/cli/agents/solver-epic-qa.md +0 -39
  160. package/cli/agents/solver-epic-security.json +0 -15
  161. package/cli/agents/solver-epic-security.md +0 -39
  162. package/cli/agents/solver-epic-solution-architect.json +0 -15
  163. package/cli/agents/solver-epic-solution-architect.md +0 -39
  164. package/cli/agents/solver-epic-test-architect.json +0 -15
  165. package/cli/agents/solver-epic-test-architect.md +0 -39
  166. package/cli/agents/solver-epic-ui.json +0 -15
  167. package/cli/agents/solver-epic-ui.md +0 -39
  168. package/cli/agents/solver-epic-ux.json +0 -15
  169. package/cli/agents/solver-epic-ux.md +0 -39
  170. package/cli/agents/solver-story-api.json +0 -15
  171. package/cli/agents/solver-story-api.md +0 -39
  172. package/cli/agents/solver-story-backend.json +0 -15
  173. package/cli/agents/solver-story-backend.md +0 -39
  174. package/cli/agents/solver-story-cloud.json +0 -15
  175. package/cli/agents/solver-story-cloud.md +0 -39
  176. package/cli/agents/solver-story-data.json +0 -15
  177. package/cli/agents/solver-story-data.md +0 -39
  178. package/cli/agents/solver-story-database.json +0 -15
  179. package/cli/agents/solver-story-database.md +0 -39
  180. package/cli/agents/solver-story-developer.json +0 -15
  181. package/cli/agents/solver-story-developer.md +0 -39
  182. package/cli/agents/solver-story-devops.json +0 -15
  183. package/cli/agents/solver-story-devops.md +0 -39
  184. package/cli/agents/solver-story-frontend.json +0 -15
  185. package/cli/agents/solver-story-frontend.md +0 -39
  186. package/cli/agents/solver-story-mobile.json +0 -15
  187. package/cli/agents/solver-story-mobile.md +0 -39
  188. package/cli/agents/solver-story-qa.json +0 -15
  189. package/cli/agents/solver-story-qa.md +0 -39
  190. package/cli/agents/solver-story-security.json +0 -15
  191. package/cli/agents/solver-story-security.md +0 -39
  192. package/cli/agents/solver-story-solution-architect.json +0 -15
  193. package/cli/agents/solver-story-solution-architect.md +0 -39
  194. package/cli/agents/solver-story-test-architect.json +0 -15
  195. package/cli/agents/solver-story-test-architect.md +0 -39
  196. package/cli/agents/solver-story-ui.json +0 -15
  197. package/cli/agents/solver-story-ui.md +0 -39
  198. package/cli/agents/solver-story-ux.json +0 -15
  199. package/cli/agents/solver-story-ux.md +0 -39
  200. package/cli/agents/validator-epic-api.json +0 -93
  201. package/cli/agents/validator-epic-api.md +0 -137
  202. package/cli/agents/validator-epic-backend.json +0 -93
  203. package/cli/agents/validator-epic-backend.md +0 -130
  204. package/cli/agents/validator-epic-cloud.json +0 -93
  205. package/cli/agents/validator-epic-cloud.md +0 -137
  206. package/cli/agents/validator-epic-data.json +0 -93
  207. package/cli/agents/validator-epic-data.md +0 -130
  208. package/cli/agents/validator-epic-database.json +0 -93
  209. package/cli/agents/validator-epic-database.md +0 -137
  210. package/cli/agents/validator-epic-developer.json +0 -74
  211. package/cli/agents/validator-epic-developer.md +0 -153
  212. package/cli/agents/validator-epic-devops.json +0 -74
  213. package/cli/agents/validator-epic-devops.md +0 -153
  214. package/cli/agents/validator-epic-frontend.json +0 -74
  215. package/cli/agents/validator-epic-frontend.md +0 -153
  216. package/cli/agents/validator-epic-mobile.json +0 -93
  217. package/cli/agents/validator-epic-mobile.md +0 -130
  218. package/cli/agents/validator-epic-qa.json +0 -93
  219. package/cli/agents/validator-epic-qa.md +0 -130
  220. package/cli/agents/validator-epic-security.json +0 -74
  221. package/cli/agents/validator-epic-security.md +0 -154
  222. package/cli/agents/validator-epic-solution-architect.json +0 -74
  223. package/cli/agents/validator-epic-solution-architect.md +0 -156
  224. package/cli/agents/validator-epic-test-architect.json +0 -93
  225. package/cli/agents/validator-epic-test-architect.md +0 -130
  226. package/cli/agents/validator-epic-ui.json +0 -93
  227. package/cli/agents/validator-epic-ui.md +0 -130
  228. package/cli/agents/validator-epic-ux.json +0 -93
  229. package/cli/agents/validator-epic-ux.md +0 -130
  230. package/cli/agents/validator-story-api.json +0 -104
  231. package/cli/agents/validator-story-api.md +0 -152
  232. package/cli/agents/validator-story-backend.json +0 -104
  233. package/cli/agents/validator-story-backend.md +0 -152
  234. package/cli/agents/validator-story-cloud.json +0 -104
  235. package/cli/agents/validator-story-cloud.md +0 -152
  236. package/cli/agents/validator-story-data.json +0 -104
  237. package/cli/agents/validator-story-data.md +0 -152
  238. package/cli/agents/validator-story-database.json +0 -104
  239. package/cli/agents/validator-story-database.md +0 -152
  240. package/cli/agents/validator-story-developer.json +0 -104
  241. package/cli/agents/validator-story-developer.md +0 -152
  242. package/cli/agents/validator-story-devops.json +0 -104
  243. package/cli/agents/validator-story-devops.md +0 -152
  244. package/cli/agents/validator-story-frontend.json +0 -104
  245. package/cli/agents/validator-story-frontend.md +0 -152
  246. package/cli/agents/validator-story-mobile.json +0 -104
  247. package/cli/agents/validator-story-mobile.md +0 -152
  248. package/cli/agents/validator-story-qa.json +0 -104
  249. package/cli/agents/validator-story-qa.md +0 -152
  250. package/cli/agents/validator-story-security.json +0 -104
  251. package/cli/agents/validator-story-security.md +0 -152
  252. package/cli/agents/validator-story-solution-architect.json +0 -104
  253. package/cli/agents/validator-story-solution-architect.md +0 -152
  254. package/cli/agents/validator-story-test-architect.json +0 -104
  255. package/cli/agents/validator-story-test-architect.md +0 -152
  256. package/cli/agents/validator-story-ui.json +0 -104
  257. package/cli/agents/validator-story-ui.md +0 -152
  258. package/cli/agents/validator-story-ux.json +0 -104
  259. package/cli/agents/validator-story-ux.md +0 -152
  260. package/kanban/client/dist/assets/index-CiD8PS2e.js +0 -306
  261. package/kanban/client/dist/assets/index-nLh0m82Q.css +0 -1
@@ -10,7 +10,7 @@ import { groupItemsByColumn, getColumnStats } from '../utils/status-grouping.js'
10
10
  * @param {object} dataStore - Data store with work items
11
11
  * @returns {express.Router}
12
12
  */
13
- export function createWorkItemsRouter(dataStore, refineService) {
13
+ export function createWorkItemsRouter(dataStore, refineService, ceremonyService) {
14
14
  const router = express.Router();
15
15
 
16
16
  /**
@@ -213,6 +213,10 @@ export function createWorkItemsRouter(dataStore, refineService) {
213
213
  */
214
214
  router.put('/:id', async (req, res) => {
215
215
  try {
216
+ const cs = ceremonyService?.getStatus();
217
+ if (cs?.status === 'running' && cs?.runningType === 'sprint-planning') {
218
+ return res.status(423).json({ error: 'Work items are read-only while sprint planning is active' });
219
+ }
216
220
  if (!refineService) {
217
221
  return res.status(503).json({ error: 'Refine service not available' });
218
222
  }
@@ -247,6 +251,10 @@ export function createWorkItemsRouter(dataStore, refineService) {
247
251
  */
248
252
  router.put('/:id/doc', async (req, res) => {
249
253
  try {
254
+ const cs = ceremonyService?.getStatus();
255
+ if (cs?.status === 'running' && cs?.runningType === 'sprint-planning') {
256
+ return res.status(423).json({ error: 'Work items are read-only while sprint planning is active' });
257
+ }
250
258
  const { items } = dataStore.getHierarchy();
251
259
  const item = items.get(req.params.id);
252
260
  if (!item) return res.status(404).json({ error: 'Work item not found' });
@@ -277,6 +285,137 @@ export function createWorkItemsRouter(dataStore, refineService) {
277
285
  }
278
286
  });
279
287
 
288
+ // ---- Status update ----
289
+ const VALID_TRANSITIONS = {
290
+ 'planned': ['ready', 'implementing'],
291
+ 'ready': ['implementing'],
292
+ 'implementing': ['completed', 'failed'],
293
+ 'failed': ['implementing'],
294
+ 'completed': [],
295
+ };
296
+
297
+ router.put('/:id/status', async (req, res) => {
298
+ try {
299
+ const cs = ceremonyService?.getStatus();
300
+ if (cs?.status === 'running' && cs?.runningType === 'sprint-planning') {
301
+ return res.status(423).json({ error: 'Work items are read-only while sprint planning is active' });
302
+ }
303
+
304
+ const { items } = dataStore.getHierarchy();
305
+ const item = items.get(req.params.id);
306
+ if (!item) return res.status(404).json({ error: 'Work item not found' });
307
+
308
+ const { status } = req.body;
309
+ if (!status || typeof status !== 'string') {
310
+ return res.status(400).json({ error: 'status is required' });
311
+ }
312
+
313
+ const currentStatus = item.status || 'planned';
314
+ const allowed = VALID_TRANSITIONS[currentStatus] || [];
315
+ if (!allowed.includes(status)) {
316
+ return res.status(422).json({
317
+ error: `Invalid status transition: ${currentStatus} → ${status}`,
318
+ allowed,
319
+ });
320
+ }
321
+
322
+ // Write to work.json
323
+ const workJsonPath = path.join(item._dirPath, 'work.json');
324
+ if (fsSync.existsSync(workJsonPath)) {
325
+ const workJson = JSON.parse(fsSync.readFileSync(workJsonPath, 'utf8'));
326
+ workJson.status = status;
327
+ workJson.updated = new Date().toISOString();
328
+ fsSync.writeFileSync(workJsonPath, JSON.stringify(workJson, null, 2), 'utf8');
329
+ }
330
+
331
+ // Reload hierarchy so in-memory state reflects the change
332
+ await dataStore.reload();
333
+
334
+ // When an item is completed, cascade: promote dependents to 'ready' if all their deps are now met
335
+ if (status === 'completed') {
336
+ try {
337
+ const { checkDependenciesReady } = await import('../../../cli/dependency-checker.js');
338
+ const { items: freshItems } = dataStore.getHierarchy();
339
+
340
+ // Build lookup from fresh hierarchy
341
+ const lookup = {};
342
+ for (const [id, wi] of freshItems) {
343
+ lookup[id] = {
344
+ id: wi.id, name: wi.name, type: wi._type || wi.type,
345
+ status: wi.status || 'planned', dependencies: wi.dependencies || [],
346
+ };
347
+ }
348
+
349
+ // Find items that depend on the completed item and are still 'planned'
350
+ let promoted = 0;
351
+ for (const [id, wi] of freshItems) {
352
+ if (wi.status !== 'planned') continue;
353
+ const deps = wi.dependencies || [];
354
+ if (!deps.includes(req.params.id)) continue;
355
+
356
+ // Check if ALL dependencies are now met
357
+ const result = checkDependenciesReady(id, lookup);
358
+ if (result.ready) {
359
+ const depWorkJsonPath = path.join(wi._dirPath, 'work.json');
360
+ if (fsSync.existsSync(depWorkJsonPath)) {
361
+ const wj = JSON.parse(fsSync.readFileSync(depWorkJsonPath, 'utf8'));
362
+ wj.status = 'ready';
363
+ wj.updated = new Date().toISOString();
364
+ fsSync.writeFileSync(depWorkJsonPath, JSON.stringify(wj, null, 2), 'utf8');
365
+ promoted++;
366
+ }
367
+ }
368
+ }
369
+
370
+ if (promoted > 0) {
371
+ await dataStore.reload();
372
+ console.log(`[status-cascade] ${promoted} item(s) promoted to 'ready' after ${req.params.id} completed`);
373
+ }
374
+ } catch (cascadeErr) {
375
+ console.error('Status cascade error (non-critical):', cascadeErr.message);
376
+ }
377
+ }
378
+
379
+ res.json({ status: 'ok', item: cleanWorkItem(item) });
380
+ } catch (error) {
381
+ console.error(`Error updating status for ${req.params.id}:`, error);
382
+ res.status(500).json({ error: 'Failed to update status' });
383
+ }
384
+ });
385
+
386
+ // ---- Dependency status check ----
387
+ router.get('/:id/dependency-status', (req, res) => {
388
+ try {
389
+ const { items } = dataStore.getHierarchy();
390
+ const item = items.get(req.params.id);
391
+ if (!item) return res.status(404).json({ error: 'Work item not found' });
392
+
393
+ // Build a plain lookup object from the items Map
394
+ const lookup = {};
395
+ for (const [id, wi] of items) {
396
+ lookup[id] = {
397
+ id: wi.id,
398
+ name: wi.name,
399
+ type: wi._type || wi.type,
400
+ status: wi.status || 'planned',
401
+ dependencies: wi.dependencies || [],
402
+ };
403
+ }
404
+
405
+ // Dynamic import to keep the route file sync-compatible
406
+ import('../../../cli/dependency-checker.js').then(({ checkDependenciesReady }) => {
407
+ const result = checkDependenciesReady(req.params.id, lookup);
408
+ res.json(result);
409
+ }).catch(err => {
410
+ console.error(`Error checking dependencies for ${req.params.id}:`, err);
411
+ res.status(500).json({ error: 'Failed to check dependencies' });
412
+ });
413
+ } catch (error) {
414
+ console.error(`Error checking dependencies for ${req.params.id}:`, error);
415
+ res.status(500).json({ error: 'Failed to check dependencies' });
416
+ }
417
+ });
418
+
280
419
  return router;
281
420
  }
282
421
 
@@ -303,6 +442,7 @@ function cleanWorkItem(item, includeFullDetails = false) {
303
442
  acceptance: item.acceptance, // stories
304
443
  userType: item.userType, // stories
305
444
  domain: item.domain, // epics
445
+ functions: item.functions, // code traceability registry
306
446
  };
307
447
 
308
448
  // Add parent reference (ID only, not full object)