sad-mcp 2.3.3 → 2.3.5
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/usecase/validate.js
CHANGED
|
@@ -348,7 +348,7 @@ export function validateModel(model) {
|
|
|
348
348
|
const isHuman = !pa || pa.actorType !== "system";
|
|
349
349
|
const wfMissing = typeof wf !== "string" || wf.trim() === "";
|
|
350
350
|
if (isHuman && wfMissing) {
|
|
351
|
-
|
|
351
|
+
err("wireframe-missing", `${path}.wireframe`, `UC "${id}" has a human primary actor ("${primaryActor}") but no wireframe. Wireframes are mandatory for every human-initiated UC (§WF) — add one.`);
|
|
352
352
|
}
|
|
353
353
|
}
|
|
354
354
|
if (typeof wf === "string" && wf.length > 0) {
|
package/package.json
CHANGED
|
@@ -207,10 +207,10 @@ Font: 'IBM Plex Mono', monospace (Google Fonts import)
|
|
|
207
207
|
|
|
208
208
|
## 7. Legend Bar
|
|
209
209
|
|
|
210
|
-
Include at the bottom of every SVG:
|
|
210
|
+
Include at the bottom of every SVG (no dependency entry — dependencies are not used, §3):
|
|
211
211
|
```
|
|
212
|
-
── Association ◇── Aggregation ◆── Composition ──▷ Generalization
|
|
213
|
-
Multiplicity at both ends | italic = operations
|
|
212
|
+
── Association ◇── Aggregation ◆── Composition ──▷ Generalization
|
|
213
|
+
Multiplicity at both ends (rendered outside both boxes) | italic = operations
|
|
214
214
|
```
|
|
215
215
|
|
|
216
216
|
---
|
|
@@ -385,13 +385,18 @@ function svgRel(rel) {
|
|
|
385
385
|
// 'assoc': no markers — plain line
|
|
386
386
|
|
|
387
387
|
let s = `<polyline points="${pts}" fill="none" stroke="#334155" stroke-width="1.8" ${dash} ${mS} ${mE}/>`;
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
388
|
+
// Multiplicity labels — placed just OUTSIDE each box, offset along the line
|
|
389
|
+
// (away from the box) and beside it, so BOTH ends are always legible.
|
|
390
|
+
const multLabel = (end, adj, txt) => {
|
|
391
|
+
const dx = adj[0] - end[0], dy = adj[1] - end[1];
|
|
392
|
+
const L = Math.hypot(dx, dy) || 1, ux = dx / L, uy = dy / L;
|
|
393
|
+
const x = end[0] + ux * 16 - uy * 9, y = end[1] + uy * 16 + ux * 9 + 3;
|
|
394
|
+
return `<text x="${x}" y="${y}" text-anchor="middle" fill="#64748b" font-size="9.5" ${FM}>${escXml(txt)}</text>`;
|
|
395
|
+
};
|
|
396
|
+
if (rel.fromMult) s += multLabel(rel.points[0], rel.points[1], rel.fromMult);
|
|
392
397
|
if (rel.toMult) {
|
|
393
|
-
const
|
|
394
|
-
s +=
|
|
398
|
+
const n = rel.points.length;
|
|
399
|
+
s += multLabel(rel.points[n - 1], rel.points[n - 2], rel.toMult);
|
|
395
400
|
}
|
|
396
401
|
if (rel.label) {
|
|
397
402
|
const mid = rel.points[Math.floor(rel.points.length / 2)];
|
|
@@ -435,7 +440,7 @@ function render() {
|
|
|
435
440
|
const rels = RELS.map(svgRel).join('');
|
|
436
441
|
const boxes = CLASSES.map(svgBox).join('');
|
|
437
442
|
// Legend is placed at totalHeight - 60 so it always lands inside the viewBox.
|
|
438
|
-
const legend = `<text x="16" y="${totalHeight - 60}" fill="#64748b" font-size="9" ${FM}>── Association ◇── Aggregation ◆── Composition ──▷ Generalization
|
|
443
|
+
const legend = `<text x="16" y="${totalHeight - 60}" fill="#64748b" font-size="9" ${FM}>── Association ◇── Aggregation ◆── Composition ──▷ Generalization | קרדינליות בשני קצות הקשר</text>`;
|
|
439
444
|
|
|
440
445
|
const svg = document.getElementById('diagram-svg');
|
|
441
446
|
svg.setAttribute('width', totalWidth);
|
|
@@ -200,7 +200,7 @@ UC documentation: [uc-id]
|
|
|
200
200
|
- בתור [תפקיד שונה או אותו תפקיד עם מטרה שונה], אני רוצה [...], כדי ש[...].
|
|
201
201
|
- ... (keep adding until every user-facing goal tied to this UC is represented)
|
|
202
202
|
|
|
203
|
-
wireframe
|
|
203
|
+
wireframe: (REQUIRED for every human-initiated UC; omit only for system/cron primary actors and include-targets — see §WF)
|
|
204
204
|
```
|
|
205
205
|
|
|
206
206
|
**Gates enforced before publishing:**
|
|
@@ -652,15 +652,13 @@ Every connection from a system-time actor MUST carry a `timing` field:
|
|
|
652
652
|
|
|
653
653
|
---
|
|
654
654
|
|
|
655
|
-
## §WF. Wireframe Authoring (
|
|
655
|
+
## §WF. Wireframe Authoring (Always On)
|
|
656
656
|
|
|
657
|
-
**
|
|
658
|
-
|
|
659
|
-
When wireframes are requested, generate them only for UCs whose `primaryActor.actorType === 'human'`. Skip wireframes for:
|
|
657
|
+
**Generate a wireframe for every human-initiated UC — always.** This course wants a UI mock on every human-facing screen; author them as part of normal generation, not on request. Generate a wireframe for every UC whose `primaryActor.actorType === 'human'`. Skip wireframes ONLY for:
|
|
660
658
|
- UCs whose primary actor is a system or cron (`actorType: 'system'`) — no human sees a screen.
|
|
661
659
|
- Pure include-target UCs (sub-behaviors with no actor association).
|
|
662
660
|
|
|
663
|
-
|
|
661
|
+
Emit each wireframe as an inline HTML fragment and attach it to `useCaseDocs[ucId].wireframe` (and thus to the derived `diagramModel` useCase element). The modal renderer (§8a) injects the fragment after passing a safety check (see `wireframeSafe()` in §8a). A missing wireframe on a human-initiated UC is a validation ERROR (§12).
|
|
664
662
|
|
|
665
663
|
Claude authors the wireframe using its own UI-generation judgment — there is no DSL. But the skill enforces a consistent look and safe sandbox via a scoped CSS theme and a set of forbidden patterns.
|
|
666
664
|
|
|
@@ -903,7 +901,8 @@ The validator runs locally (no API cost) and catches what the §4 and CR gates c
|
|
|
903
901
|
- Extensions referencing invalid step numbers → ERROR
|
|
904
902
|
- Narrative text missing Hebrew characters (description, preconditions, postconditions, flow/extension text, user stories, assumptions, openQuestions) → ERROR
|
|
905
903
|
- Unsafe wireframe HTML (script / on*= / iframe / external URL / @import / inline style) → ERROR
|
|
906
|
-
-
|
|
904
|
+
- Missing wireframe on a human-initiated UC (§WF — wireframes are mandatory) → ERROR
|
|
905
|
+
- Warnings: fewer than 2 user stories on a UC, no preconditions/postconditions, overall >2 include+extend relationships
|
|
907
906
|
|
|
908
907
|
If the response is `✗ Model invalid`, fix every listed error and call the validator again. **Do not write the HTML file until the validator returns `✓ Model valid`.**
|
|
909
908
|
|
|
@@ -921,7 +920,7 @@ Briefly report: actor count, use case count, include/extend count, whether split
|
|
|
921
920
|
- [ ] Every `primaryActor` id exists in `actors[]` AND has an association with `role: 'initiator'` on that UC (aligning §4.1 with §4.4).
|
|
922
921
|
- [ ] Every flow step of `kind: 'actor'` references a real actor id; every `kind: 'include'` references a real UC id; every `extension.at` references a valid step number in its scenario's flow.
|
|
923
922
|
- [ ] Clicking a UC on the diagram opens the full-screen modal (§8a); Esc / backdrop click closes it. Step actor/UC references are clickable. Actor popup + association popup (§8b) still work for non-UC clicks.
|
|
924
|
-
- [ ] Wireframes generated
|
|
923
|
+
- [ ] Wireframes generated for EVERY human-initiated UC (§WF — mandatory); system/cron primary actors and include-targets omitted.
|
|
925
924
|
- [ ] Any `wireframe` HTML passes `wireframeSafe()` (no `<script>`, no `on*=`, no `<iframe>`, no external URLs, no `@import`, no inline `<style>`); all classes are `wf-*` only; visible text is in Hebrew.
|
|
926
925
|
- [ ] Every actor-UC association has a written §4.1 justification block (role, initiates? one-line "why"); every UC has ≥1 association with `initiates = yes`.
|
|
927
926
|
- [ ] 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.
|