@chrisdudek/yg 2.9.0 → 2.11.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.
- package/dist/bin.js +16 -1
- package/dist/bin.js.map +1 -1
- package/dist/templates/rules.ts +13 -0
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -109,6 +109,7 @@ You are not allowed to edit or create source code without establishing graph cov
|
|
|
109
109
|
- [ ] 2. Assess blast radius: \`yg impact --node <node_path>\` \u2014 review dependents, descendants, and co-aspect nodes before changing interfaces or shared behavior
|
|
110
110
|
- [ ] 3. Modify source code
|
|
111
111
|
- [ ] 4. Sync graph artifacts \u2014 edit artifact files to reflect the changes (after each file, not batched \u2014 context is freshest immediately after the change). If the node's purpose changed, update \`description\` in \`yg-node.yaml\`.
|
|
112
|
+
- [ ] 4b. If you split, merged, or renamed a node: run \`yg flows\` and update any flow \`nodes\` lists that referenced the old node path to point to the correct child/new nodes.
|
|
112
113
|
- [ ] 5. Run \`yg validate\` \u2014 fix all errors (if unfixable after 3 attempts \u2192 stop, report to user)
|
|
113
114
|
- [ ] 6. Run \`yg drift-sync --node <node_path>\` \u2014 only after graph and code are both current
|
|
114
115
|
|
|
@@ -372,6 +373,12 @@ Test: "Does this describe what happens in the world, or only in the software?" I
|
|
|
372
373
|
|
|
373
374
|
**Warning:** Flow descriptions must describe business processes, not code sequences. "The OrderService calls PaymentGateway.charge()" is WRONG. "The system charges the customer's payment method" is CORRECT.
|
|
374
375
|
|
|
376
|
+
**Flow identification heuristic:** If a spec, conversation, or code reveals a sequence of steps toward a business goal \u2014 it IS a flow, and you MUST create one. This applies to multi-actor processes (user submits form \u2192 system notifies \u2192 admin responds) AND single-actor workflows (admin creates post \u2192 edits \u2192 publishes \u2192 system revalidates). A user performing actions on the system toward a goal is a business process, not "just CRUD." This applies equally when working from specs and when working from code. Examples: "user submits contact form \u2192 system sends notification \u2192 user receives response" (ContactInquiry), "user creates gallery \u2192 sends link \u2192 recipient views photos \u2192 user sees stats" (GalleryDelivery), "user writes blog post \u2192 publishes \u2192 system revalidates \u2192 readers see content" (BlogPublishing). Test: "Does this describe a goal-directed sequence of steps that a future agent needs to understand as a whole?" Yes \u2192 create the flow before or during implementation, never after.
|
|
377
|
+
|
|
378
|
+
**Flow verification from specs:** When working from external specifications, for EACH business process described in the specs, verify a corresponding flow exists. If it doesn't, create one. Specs are the primary source of flow discovery \u2014 they describe what happens in the world, which is exactly what flows capture. Do not wait until implementation is complete to create flows.
|
|
379
|
+
|
|
380
|
+
**Flow participant maintenance:** When splitting a node that participates in a flow (e.g., splitting \`admin-pages\` into \`admin-pages/blog\`, \`admin-pages/gallery\`, etc.), update the flow's \`nodes\` list to reference the specific child nodes that actually participate, not the parent. A flow participant must be the most specific node that performs the action. After any node restructuring (split, merge, rename), run \`yg flows\` and verify all participant references are still valid.
|
|
381
|
+
|
|
375
382
|
### Operational Rules
|
|
376
383
|
|
|
377
384
|
- **English only** for all files in \`.yggdrasil/\`. Conversation can be any language.
|
|
@@ -522,6 +529,9 @@ What matters is the ACTION you are performing, not what instructed it. If the ac
|
|
|
522
529
|
| "This is a UX detail, not architecture" | UX patterns that apply to 3+ screens ARE cross-cutting requirements. Create an aspect. |
|
|
523
530
|
| "The user just mentioned it casually, it's not a formal decision" | Casual statements ARE decisions. "We don't do studio" is a business constraint. Capture it now or lose it after context compression. |
|
|
524
531
|
| "I'll remember this from the conversation" | No you won't. Context gets compressed. The user won't repeat it. Write it to the graph now. |
|
|
532
|
+
| "Flows can wait until I understand the full system" | Flows capture business processes from specs. Create them BEFORE implementing \u2014 they are part of the specification, not an afterthought. |
|
|
533
|
+
| "I split the node but the flow still works" | Flow participants reference specific node paths. After a split, old paths are stale. Run \`yg flows\` and update. |
|
|
534
|
+
| "This is just CRUD, not a business process" | A user performing a sequence of steps toward a goal IS a business process \u2014 even single-actor workflows (publish blog, manage portfolio, fulfill order). Create a flow. |
|
|
525
535
|
|
|
526
536
|
### Failure States
|
|
527
537
|
|
|
@@ -542,6 +552,9 @@ You have broken Yggdrasil if you do any of the following:
|
|
|
542
552
|
- \u274C Implemented 3+ features sharing a pattern (autosave, version history, empty states) without extracting it to an aspect. Deferred aspect discovery = lost rationale.
|
|
543
553
|
- \u274C Left business strategy, personas, or quality targets only in external documents instead of routing them to graph artifacts. External docs are input; the graph is the persistent store.
|
|
544
554
|
- \u274C Heard the user state a business fact, constraint, or decision in conversation and did not record it in the graph. Conversations are the most volatile knowledge source \u2014 they vanish after context compression and the user will not repeat them.
|
|
555
|
+
- \u274C Split or renamed a node that participates in a flow without updating the flow's \`nodes\` list. Stale flow participants are invisible broken references.
|
|
556
|
+
- \u274C Implemented a spec that describes a goal-directed workflow (publishing content, managing portfolio, fulfilling orders, processing payments) without creating a corresponding flow. Any sequence of steps toward a business goal IS a flow \u2014 single-actor workflows included.
|
|
557
|
+
- \u274C Created flows only after all implementation was complete. Flows are part of the specification phase \u2014 they describe WHAT happens in the world, which informs HOW to implement it.
|
|
545
558
|
|
|
546
559
|
### Reverse Engineering
|
|
547
560
|
|
|
@@ -3942,6 +3955,7 @@ async function detectDrift(graph, filterNodePath) {
|
|
|
3942
3955
|
const entries = [];
|
|
3943
3956
|
for (const [nodePath, node] of graph.nodes) {
|
|
3944
3957
|
if (filterNodePath && nodePath !== filterNodePath && !nodePath.startsWith(filterNodePath + "/")) continue;
|
|
3958
|
+
if (node.meta.blackbox) continue;
|
|
3945
3959
|
const mapping = node.meta.mapping;
|
|
3946
3960
|
if (!mapping) continue;
|
|
3947
3961
|
const mappingPaths = normalizeMappingPaths(mapping);
|
|
@@ -4040,6 +4054,7 @@ async function syncDriftState(graph, nodePath) {
|
|
|
4040
4054
|
const node = graph.nodes.get(nodePath);
|
|
4041
4055
|
if (!node) throw new Error(`Node not found: ${nodePath}`);
|
|
4042
4056
|
if (!node.meta.mapping) throw new Error(`Node has no mapping: ${nodePath}`);
|
|
4057
|
+
if (node.meta.blackbox) throw new Error(`Cannot sync blackbox node: ${nodePath}`);
|
|
4043
4058
|
const trackedFiles = collectTrackedFiles(node, graph);
|
|
4044
4059
|
const excludePrefixes = getChildMappingExclusions(graph, nodePath);
|
|
4045
4060
|
const existingEntry = await readNodeDriftState(graph.rootPath, nodePath);
|
|
@@ -4225,7 +4240,7 @@ function registerDriftSyncCommand(program2) {
|
|
|
4225
4240
|
const graph = await loadGraph(process.cwd());
|
|
4226
4241
|
let nodesToSync;
|
|
4227
4242
|
if (options.all) {
|
|
4228
|
-
nodesToSync = [...graph.nodes.entries()].filter(([, n]) => normalizeMappingPaths(n.meta.mapping).length > 0).map(([p]) => p).sort();
|
|
4243
|
+
nodesToSync = [...graph.nodes.entries()].filter(([, n]) => !n.meta.blackbox && normalizeMappingPaths(n.meta.mapping).length > 0).map(([p]) => p).sort();
|
|
4229
4244
|
} else {
|
|
4230
4245
|
const nodePath = options.node.trim().replace(/^\.\//, "").replace(/\/+$/, "");
|
|
4231
4246
|
if (!graph.nodes.has(nodePath)) {
|