sad-mcp 1.1.7 → 1.1.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sad-mcp",
3
- "version": "1.1.7",
3
+ "version": "1.1.8",
4
4
  "description": "MCP server for Software Analysis and Design course materials at BGU",
5
5
  "type": "module",
6
6
  "bin": {
@@ -87,11 +87,29 @@ The shared files prepended to this prompt define the layout recipes, model shape
87
87
 
88
88
  ---
89
89
 
90
- ## 4. Include and Extend — Mandatory Justification Gate
90
+ ## 4. Relationship Gates — Mandatory Justifications
91
91
 
92
- **Default to zero.** Treat every «include» and «extend» as guilty until proven innocent. Before drawing ANY such relationship, write the relevant block below in your planning text. **If you cannot fill it in truthfully, the relationship does not exist do not draw it.**
92
+ Every relationship in the diagram — actor-UC associations, «include», and «extend» must pass a written justification block BEFORE it is drawn. **If you cannot fill the block in truthfully, the relationship does not exist.** Write these blocks in your planning text (not in the final HTML).
93
93
 
94
- ### «include» justification block
94
+ ### 4.1 Association justification (actor ↔ UC)
95
+
96
+ ```
97
+ Association: [actor id] ↔ [UC id]
98
+ Actor role: initiator / participant / recipient / supplier
99
+ Does this actor TRIGGER / INITIATE the UC? yes / no
100
+ One-line justification: "The actor ___ in order to ___"
101
+ Description shown on click (Hebrew): ___________________
102
+
103
+ → If the actor has no meaningful interaction with the UC → DELETE the association.
104
+ → Every UC MUST have ≥1 association where "initiates = yes". A UC with no initiator is orphaned — fix it or delete the UC.
105
+ → A human actor connected only as "recipient" of a notification is usually wrong — the initiator of the notification-sending UC is who you want (see CRITICAL RULE #10, no send-only UCs).
106
+ ```
107
+
108
+ The "Description shown on click" is the text surfaced in the HTML by the `showAssocDesc` popup — see §8. Store it on the connection object under `description`.
109
+
110
+ ### 4.2 «include» justification
111
+
112
+ **Default to zero.** Treat every «include» as guilty until proven innocent.
95
113
 
96
114
  ```
97
115
  «include» candidate: __________________________________
@@ -109,7 +127,7 @@ Semantics: «include» means the target runs **every single time** the base runs
109
127
 
110
128
  Arrow: dashed, open arrowhead, `Base UC → Included UC`.
111
129
 
112
- ### «extend» justification block
130
+ ### 4.3 «extend» justification
113
131
 
114
132
  ```
115
133
  «extend» candidate: __________________________________
@@ -414,9 +432,9 @@ If neither trigger fires, produce a single tab. Do not split on gut feeling.
414
432
 
415
433
  ---
416
434
 
417
- ## 8. Clickable Descriptions for UCs and Actors (Always Include)
435
+ ## 8. Clickable Descriptions for UCs, Actors, and Associations (Always Include)
418
436
 
419
- Every UC ellipse **and** every actor must be clickable — click shows a floating panel with name + description. One `showDesc(id, type, event)` function handles both.
437
+ Every UC ellipse, every actor, **and every association line** must be clickable — click shows a floating panel with name + description. One `showDesc(id, type, event)` function handles all three.
420
438
 
421
439
  ```javascript
422
440
  const useCaseDescriptions = {
@@ -427,10 +445,18 @@ const actorDescriptions = {
427
445
  'customer': { name: 'לקוח', desc: 'לקוח הרשום במערכת. יוזם הזמנות ועוקב אחר סטטוס.' },
428
446
  // ... one entry per actor
429
447
  };
448
+ const assocDescriptions = {
449
+ // keyed by connection id; name = actor-name ↔ UC-name (auto-composed is fine)
450
+ 'a1': { name: 'לקוח ↔ פתיחת הזמנה', desc: 'הלקוח יוזם את פתיחת ההזמנה. תפקיד: Initiator.' },
451
+ // ... one entry per association line you want described
452
+ };
430
453
 
431
454
  function showDesc(id, type, event) {
432
455
  hideDesc();
433
- const data = type === 'uc' ? useCaseDescriptions[id] : actorDescriptions[id];
456
+ const data = type === 'uc' ? useCaseDescriptions[id]
457
+ : type === 'actor' ? actorDescriptions[id]
458
+ : type === 'assoc' ? assocDescriptions[id]
459
+ : null;
434
460
  if (!data) return;
435
461
  const panel = document.createElement('div');
436
462
  panel.id = 'desc-panel';
@@ -454,13 +480,50 @@ function showDesc(id, type, event) {
454
480
  }
455
481
  function hideDesc() { document.getElementById('desc-panel')?.remove(); }
456
482
  document.addEventListener('click', e => {
457
- if (!e.target.closest('[data-uc-id]') && !e.target.closest('[data-actor-id]')) hideDesc();
483
+ if (!e.target.closest('[data-uc-id]') &&
484
+ !e.target.closest('[data-actor-id]') &&
485
+ !e.target.closest('[data-conn-id]')) hideDesc();
458
486
  });
459
487
  ```
460
488
 
461
489
  UC group: `<g id="uc-uc1" data-uc-id="uc1" onclick="showDesc('uc1','uc',event)" style="cursor:pointer">`
462
490
  Actor group: `<g id="actor-student" data-actor-id="student" onclick="showDesc('student','actor',event)" style="cursor:pointer">`
463
491
 
492
+ ### Clickable association lines (required)
493
+
494
+ A 1.8px line is nearly impossible to click. Every associatable line gets **two** line elements: a visible thin line (the one `fixLayout` already updates via `data-conn-from` / `data-conn-to`) and a transparent thick hitbox on top.
495
+
496
+ ```html
497
+ <!-- Visible line — fixLayout writes x1/y1/x2/y2 here -->
498
+ <line data-conn-from="worker" data-conn-to="uc-receive"
499
+ x1="0" y1="0" x2="0" y2="0"
500
+ stroke="#334155" stroke-width="1.8"/>
501
+
502
+ <!-- Click hitbox — invisible, tracks the same endpoints, carries the id -->
503
+ <line class="conn-hitbox" data-conn-id="a1"
504
+ data-hitbox-from="worker" data-hitbox-to="uc-receive"
505
+ x1="0" y1="0" x2="0" y2="0"
506
+ stroke="transparent" stroke-width="14"
507
+ style="cursor:pointer"
508
+ onclick="showDesc('a1','assoc',event)"/>
509
+ ```
510
+
511
+ Inside `fixLayout` Step 8, copy the endpoints from each visible line to its matching hitbox so the clickable region tracks the visible line exactly:
512
+
513
+ ```javascript
514
+ // After writing x1/y1/x2/y2 on the visible line:
515
+ const hitbox = svg.querySelector(
516
+ `.conn-hitbox[data-hitbox-from="${fId}"][data-hitbox-to="${tId}"]`);
517
+ if (hitbox) {
518
+ hitbox.setAttribute('x1', x1); hitbox.setAttribute('y1', y1);
519
+ hitbox.setAttribute('x2', x2); hitbox.setAttribute('y2', y2);
520
+ }
521
+ ```
522
+
523
+ Draw order: visible line first, hitbox second, ellipses/actors last. The hitbox stays under the ellipses and actors but above the thin visible line so clicks on or near the line hit it.
524
+
525
+ Associations without a meaningful description (e.g., auto-generated from trivially obvious actor-UC pairs) may omit the hitbox and the `assocDescriptions` entry, but they still need to pass the §4.1 justification gate.
526
+
464
527
  ### Timing labels on cron/time-actor associations (required)
465
528
 
466
529
  When a connection carries a `timing` field (every connection from a system-time actor MUST have one — see §2), inject the label at the line midpoint **after** `fixLayout` has written the endpoints. The helper below is idempotent: it removes any existing `.timing-label` group before re-rendering, so calling it again after another `fixLayout` pass is safe.
@@ -514,6 +577,21 @@ The `connections` entry for a timed link looks like:
514
577
 
515
578
  Define this variable in every generated HTML `<script>` block, following the `model-shape.md` spec for `kind: 'use-case'`. Every actor, use case, and relationship must be represented. The Visual Paradigm exporter walks this variable.
516
579
 
580
+ ### Assumptions and open questions
581
+
582
+ Both `diagramModel` and `diagramLayout` carry two parallel string arrays, matching the BPMN skill's shape:
583
+
584
+ ```javascript
585
+ {
586
+ // ...
587
+ assumptions: [ 'המערכת מזהה כל עובד מחסן דרך מזהה משתמש יחיד.',
588
+ 'ייבוא נתונים מה-ERP של הספק מתבצע באמצעות API ולא קובץ.' ],
589
+ openQuestions: [ 'האם נדרש אישור נוסף על ידי מנהל לכל שינוי רמות מלאי?' ]
590
+ }
591
+ ```
592
+
593
+ Render them in a panel at the bottom of the page — see §11. Only render if at least one of the arrays is non-empty. Do NOT hide the panel; a reader reviewing the diagram needs to see which statements in the diagram rest on assumptions.
594
+
517
595
  ---
518
596
 
519
597
  ## 10. Styling
@@ -529,9 +607,25 @@ Association line: #334155, 1.8px, no arrowhead
529
607
  Include/extend: #7c3aed, 1.6px, dasharray 6 4, open arrowhead, label 9.5px
530
608
  Generalization: #334155, 1.8px, hollow triangle (fill white)
531
609
  System title: white on #1e40af, 14px bold
610
+ Assumptions panel: white bg, border #cbd5e1 (1px), rx=8, padding 16px, margin-top 20px
611
+ Assumptions h3: #1e40af, 13px, weight 600, margin-bottom 6px
612
+ Assumptions li: #334155, 12px, line-height 1.6, list-style disc inside
532
613
  Fonts: 'Noto Sans Hebrew' + 'IBM Plex Mono' from Google Fonts
533
614
  ```
534
615
 
616
+ The assumptions panel CSS must be included in the HTML `<style>` block:
617
+
618
+ ```css
619
+ .assumptions-panel { display: flex; gap: 24px; max-width: 1000px;
620
+ margin: 20px auto; padding: 16px 20px; background: #fff;
621
+ border: 1px solid #cbd5e1; border-radius: 8px; direction: rtl; }
622
+ .assumptions-col { flex: 1; min-width: 0; }
623
+ .assumptions-col h3 { margin: 0 0 6px; font-size: 13px; font-weight: 600;
624
+ color: #1e40af; }
625
+ .assumptions-col ul { margin: 0; padding-right: 18px; }
626
+ .assumptions-col li { color: #334155; font-size: 12px; line-height: 1.6; }
627
+ ```
628
+
535
629
  ---
536
630
 
537
631
  ## 11. HTML File Structure
@@ -571,6 +665,18 @@ Fonts: 'Noto Sans Hebrew' + 'IBM Plex Mono' from Google Fonts
571
665
  <svg id="diagram-svg-1" viewBox="0 0 1100 900" xmlns="http://www.w3.org/2000/svg">...</svg>
572
666
  </div>
573
667
 
668
+ <!-- Assumptions / open-questions panel (render only if at least one non-empty) -->
669
+ <div id="assumptions-panel" class="assumptions-panel" hidden>
670
+ <div class="assumptions-col" id="assumptions-col">
671
+ <h3>הנחות</h3>
672
+ <ul id="assumptions-list"></ul>
673
+ </div>
674
+ <div class="assumptions-col" id="open-questions-col">
675
+ <h3>שאלות פתוחות</h3>
676
+ <ul id="open-questions-list"></ul>
677
+ </div>
678
+ </div>
679
+
574
680
  <!-- VP export button -->
575
681
  <button class="vp-export-btn" onclick="exportXMI()">Download .xmi (Visual Paradigm)</button>
576
682
 
@@ -595,8 +701,31 @@ Fonts: 'Noto Sans Hebrew' + 'IBM Plex Mono' from Google Fonts
595
701
  function xmiBody(elements, rels) { /* export-buttons.md */ }
596
702
  function exportXMI() { /* export-buttons.md */ }
597
703
 
704
+ function renderAssumptions() {
705
+ const a = (diagramModel && diagramModel.assumptions) || [];
706
+ const q = (diagramModel && diagramModel.openQuestions) || [];
707
+ const panel = document.getElementById('assumptions-panel');
708
+ if (!panel) return;
709
+ if (!a.length && !q.length) { panel.hidden = true; return; }
710
+ panel.hidden = false;
711
+ const ul = id => document.getElementById(id);
712
+ const fill = (listEl, items) => {
713
+ listEl.innerHTML = '';
714
+ items.forEach(s => {
715
+ const li = document.createElement('li');
716
+ li.textContent = s;
717
+ listEl.appendChild(li);
718
+ });
719
+ };
720
+ fill(ul('assumptions-list'), a);
721
+ fill(ul('open-questions-list'), q);
722
+ document.getElementById('assumptions-col').hidden = !a.length;
723
+ document.getElementById('open-questions-col').hidden = !q.length;
724
+ }
725
+
598
726
  document.addEventListener('DOMContentLoaded', () => {
599
727
  diagramLayouts.forEach(l => fixLayout(l));
728
+ renderAssumptions();
600
729
  });
601
730
  </script>
602
731
  </body>
@@ -616,6 +745,9 @@ Fonts: 'Noto Sans Hebrew' + 'IBM Plex Mono' from Google Fonts
616
745
 
617
746
  ## 13. Pre-Delivery Checklist
618
747
 
748
+ - [ ] Every actor-UC association has a written §4.1 justification block (role, initiates? one-line "why"); every UC has ≥1 association with `initiates = yes`.
749
+ - [ ] Every association line carries a transparent click-hitbox (stroke-width ≥12, `data-conn-id`) wired to `showDesc(id,'assoc',event)`; `assocDescriptions` entry exists for each id.
750
+ - [ ] `assumptions` and `openQuestions` arrays are present in `diagramModel`; the HTML renders the bottom panel whenever either is non-empty.
619
751
  - [ ] Every «include» and «extend» has a written §4 justification block; any that cannot be filled in has been deleted.
620
752
  - [ ] No «include» with exactly one incoming arrow — every include target has ≥2 bases AND zero actor associations.
621
753
  - [ ] No generic "ניהול הגדרות מערכת" or combined-entity UCs; each entity has its own UC.