@aisdlc/core 1.3.0 → 1.3.2
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/index.cjs +317 -44
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +317 -44
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -722,6 +722,12 @@ function walkMdFiles(dir, fileList = [], excludeDirs = [
|
|
|
722
722
|
"node_modules",
|
|
723
723
|
".git",
|
|
724
724
|
"dist",
|
|
725
|
+
"bin",
|
|
726
|
+
"obj",
|
|
727
|
+
"build",
|
|
728
|
+
"out",
|
|
729
|
+
"target",
|
|
730
|
+
"coverage",
|
|
725
731
|
".changeset",
|
|
726
732
|
"scratch",
|
|
727
733
|
"test-scaffold",
|
|
@@ -733,7 +739,9 @@ function walkMdFiles(dir, fileList = [], excludeDirs = [
|
|
|
733
739
|
".claude",
|
|
734
740
|
".cursor",
|
|
735
741
|
".github",
|
|
736
|
-
".vscode"
|
|
742
|
+
".vscode",
|
|
743
|
+
".vs",
|
|
744
|
+
".idea"
|
|
737
745
|
]) {
|
|
738
746
|
try {
|
|
739
747
|
if (!fs6.existsSync(dir)) return fileList;
|
|
@@ -2052,6 +2060,7 @@ var TYPE_TO_SCHEMA_MAP = {
|
|
|
2052
2060
|
"security-requirement": "schemas/security/security-req.schema.json",
|
|
2053
2061
|
"threat-actor": "schemas/security/threat-actor.schema.json",
|
|
2054
2062
|
// Architecture
|
|
2063
|
+
"architecture-introduction": "schemas/architecture/introduction-and-goals.schema.json",
|
|
2055
2064
|
"architecture-decision-record": "schemas/architecture/adr.schema.json",
|
|
2056
2065
|
component: "schemas/architecture/component.schema.json",
|
|
2057
2066
|
// Safety
|
|
@@ -2095,6 +2104,7 @@ var PREFIX_TAXONOMY = [
|
|
|
2095
2104
|
["HAZ-", "hazard"],
|
|
2096
2105
|
["SAF-REQ-", "safety-requirement"],
|
|
2097
2106
|
["SAF-", "safety-requirement"],
|
|
2107
|
+
["ARCH-INTRO-", "architecture-introduction"],
|
|
2098
2108
|
["ADR-", "architecture-decision-record"],
|
|
2099
2109
|
["CMP-", "component"],
|
|
2100
2110
|
["MAN-USER-", "user-manual"],
|
|
@@ -3284,10 +3294,18 @@ var SKIPPED_DIR_NAMES = /* @__PURE__ */ new Set([
|
|
|
3284
3294
|
"node_modules",
|
|
3285
3295
|
".git",
|
|
3286
3296
|
"dist",
|
|
3297
|
+
"bin",
|
|
3298
|
+
"obj",
|
|
3299
|
+
"build",
|
|
3300
|
+
"out",
|
|
3301
|
+
"target",
|
|
3302
|
+
"coverage",
|
|
3287
3303
|
"scratch",
|
|
3288
3304
|
"fixtures",
|
|
3289
3305
|
"templates",
|
|
3290
|
-
"examples"
|
|
3306
|
+
"examples",
|
|
3307
|
+
".vs",
|
|
3308
|
+
".idea"
|
|
3291
3309
|
]);
|
|
3292
3310
|
function shouldSkipDir(name) {
|
|
3293
3311
|
return SKIPPED_DIR_NAMES.has(name) || name.startsWith("temp-");
|
|
@@ -3389,8 +3407,14 @@ function verifyTraceability(options = {}) {
|
|
|
3389
3407
|
});
|
|
3390
3408
|
}
|
|
3391
3409
|
}
|
|
3392
|
-
|
|
3393
|
-
|
|
3410
|
+
const isArchIntro = frontmatter.type === "architecture-introduction" || frontmatter.id !== void 0 && String(frontmatter.id).trim().startsWith("ARCH-INTRO-");
|
|
3411
|
+
if (!isArchIntro && (relFile.includes("architecture/") || relFile.includes("06_runtime_view") || relFile.includes("08_security_concept") || relFile.includes("09_decisions"))) {
|
|
3412
|
+
architectureViews.push({
|
|
3413
|
+
file: relFile,
|
|
3414
|
+
id: frontmatter.id ? String(frontmatter.id).trim() : void 0,
|
|
3415
|
+
type: typeof frontmatter.type === "string" ? frontmatter.type.trim() : void 0,
|
|
3416
|
+
content
|
|
3417
|
+
});
|
|
3394
3418
|
}
|
|
3395
3419
|
} catch {
|
|
3396
3420
|
}
|
|
@@ -3473,6 +3497,14 @@ function verifyTraceability(options = {}) {
|
|
|
3473
3497
|
productTraces.push(...associatedHandoff.subgraph.abuseCases);
|
|
3474
3498
|
}
|
|
3475
3499
|
}
|
|
3500
|
+
for (const [artId, artEntry] of artifactMap.entries()) {
|
|
3501
|
+
if (artEntry.type === "architecture-introduction" || artId.startsWith("ARCH-INTRO-")) {
|
|
3502
|
+
const citedGoals = artEntry.frontmatter["cites-quality-goals"];
|
|
3503
|
+
if (Array.isArray(citedGoals) && citedGoals.includes(reqId)) {
|
|
3504
|
+
productTraces.push(artId);
|
|
3505
|
+
}
|
|
3506
|
+
}
|
|
3507
|
+
}
|
|
3476
3508
|
const validProductTraces = Array.from(
|
|
3477
3509
|
new Set(productTraces.filter((id) => artifactMap.has(id)))
|
|
3478
3510
|
);
|
|
@@ -3493,8 +3525,9 @@ function verifyTraceability(options = {}) {
|
|
|
3493
3525
|
}
|
|
3494
3526
|
for (const view of architectureViews) {
|
|
3495
3527
|
if (view.content.includes(reqId)) {
|
|
3496
|
-
const
|
|
3497
|
-
|
|
3528
|
+
const isEntityWithId = view.type === "component" || view.type === "adr" || view.type === "architecture-decision-record" || view.type === "security-enclave" || view.id !== void 0 && (view.id.startsWith("CMP-") || view.id.startsWith("ADR-") || view.id.startsWith("SEC-ENC-"));
|
|
3529
|
+
const viewIdentifier = isEntityWithId && view.id ? view.id : path8.basename(view.file);
|
|
3530
|
+
if (!archTraces.includes(viewIdentifier)) archTraces.push(viewIdentifier);
|
|
3498
3531
|
}
|
|
3499
3532
|
}
|
|
3500
3533
|
const uniqueArchTraces = Array.from(new Set(archTraces));
|
|
@@ -3831,7 +3864,7 @@ function scanAllTestArtifacts(rootDir) {
|
|
|
3831
3864
|
for (const e of entries) {
|
|
3832
3865
|
const fullPath = path8.join(dir, e.name);
|
|
3833
3866
|
if (e.isDirectory()) {
|
|
3834
|
-
if (!["node_modules", ".git", "dist", ".changeset", "scratch", "fixtures", "templates", "examples"].includes(e.name)) {
|
|
3867
|
+
if (!["node_modules", ".git", "dist", "bin", "obj", "build", "out", "target", "coverage", ".changeset", "scratch", "fixtures", "templates", "examples", ".vs", ".idea"].includes(e.name)) {
|
|
3835
3868
|
walk(fullPath);
|
|
3836
3869
|
}
|
|
3837
3870
|
} else {
|
|
@@ -7136,7 +7169,31 @@ function buildGraphElements(rootDir = process.cwd()) {
|
|
|
7136
7169
|
for (const n of pdac.drifts) {
|
|
7137
7170
|
driftTargets.add(n.targetId);
|
|
7138
7171
|
}
|
|
7172
|
+
const NON_GRAPH_TYPES = /* @__PURE__ */ new Set([
|
|
7173
|
+
"term",
|
|
7174
|
+
"handoff",
|
|
7175
|
+
"agent-handoff",
|
|
7176
|
+
"tasks",
|
|
7177
|
+
"task-plan",
|
|
7178
|
+
"spec-change-proposal",
|
|
7179
|
+
"proposal",
|
|
7180
|
+
"spec-design",
|
|
7181
|
+
"spec-change-design",
|
|
7182
|
+
"design",
|
|
7183
|
+
"delivery-spec",
|
|
7184
|
+
"spec",
|
|
7185
|
+
"pre-merge-audit-report",
|
|
7186
|
+
"user-design-feedback",
|
|
7187
|
+
"release-kpis",
|
|
7188
|
+
"session-telemetry",
|
|
7189
|
+
"license-manifest",
|
|
7190
|
+
"mcp-config",
|
|
7191
|
+
"user-manual",
|
|
7192
|
+
"production-manual",
|
|
7193
|
+
"architecture-glossary"
|
|
7194
|
+
]);
|
|
7139
7195
|
const scannedArtifactsMap = /* @__PURE__ */ new Map();
|
|
7196
|
+
const archViewByBasename = /* @__PURE__ */ new Map();
|
|
7140
7197
|
const artifactDirs = ["product", "architecture", "specs", "security"];
|
|
7141
7198
|
for (const dirName of artifactDirs) {
|
|
7142
7199
|
const fullDirPath = path8.join(rootDir, dirName);
|
|
@@ -7146,6 +7203,7 @@ function buildGraphElements(rootDir = process.cwd()) {
|
|
|
7146
7203
|
try {
|
|
7147
7204
|
const fileContent = fs6.readFileSync(f, "utf-8");
|
|
7148
7205
|
const relPath = path8.relative(rootDir, f).replace(/\\/g, "/");
|
|
7206
|
+
if (relPath.includes("/changes/") || relPath.startsWith("changes/")) continue;
|
|
7149
7207
|
const match = fileContent.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
7150
7208
|
if (!match) continue;
|
|
7151
7209
|
let fm = {};
|
|
@@ -7157,8 +7215,14 @@ function buildGraphElements(rootDir = process.cwd()) {
|
|
|
7157
7215
|
const id = typeof fm.id === "string" ? fm.id.trim() : void 0;
|
|
7158
7216
|
if (!id) continue;
|
|
7159
7217
|
let type = typeof fm.type === "string" ? fm.type.trim() : "";
|
|
7218
|
+
if (NON_GRAPH_TYPES.has(type) || id.startsWith("TERM-") || id.startsWith("HOF-") || id.startsWith("AHOF-") || id.startsWith("CHG-") || id.startsWith("DSG-") || id.startsWith("SPEC-") || id.startsWith("TSK-") || id.startsWith("UDF-") || id.startsWith("AUDIT-")) {
|
|
7219
|
+
continue;
|
|
7220
|
+
}
|
|
7160
7221
|
let layer = "product";
|
|
7161
|
-
if (id.startsWith("
|
|
7222
|
+
if (id.startsWith("ARCH-INTRO-") || type === "architecture-introduction") {
|
|
7223
|
+
type = "architecture-introduction";
|
|
7224
|
+
layer = "product";
|
|
7225
|
+
} else if (id.startsWith("JRN-") || type === "journey") {
|
|
7162
7226
|
type = "journey";
|
|
7163
7227
|
layer = "product";
|
|
7164
7228
|
} else if (id.startsWith("ACT-THREAT-") || type === "threat-actor") {
|
|
@@ -7191,16 +7255,19 @@ function buildGraphElements(rootDir = process.cwd()) {
|
|
|
7191
7255
|
} else if (id.startsWith("SEC-REQ-") || type === "security-requirement") {
|
|
7192
7256
|
type = "security-requirement";
|
|
7193
7257
|
layer = "requirement";
|
|
7194
|
-
} else if (id.startsWith("FR-") || id.startsWith("QR-") || id.startsWith("CON-") || type === "requirement") {
|
|
7258
|
+
} else if (id.startsWith("FR-") || id.startsWith("QR-") || id.startsWith("CON-") || type === "requirement" || type === "functional-requirement" || type === "quality-requirement") {
|
|
7195
7259
|
type = "requirement";
|
|
7196
7260
|
layer = "requirement";
|
|
7261
|
+
} else if (id.startsWith("ARCH-") || relPath.includes("architecture/")) {
|
|
7262
|
+
type = "architecture";
|
|
7263
|
+
layer = "architecture";
|
|
7197
7264
|
} else {
|
|
7198
7265
|
type = type || "product";
|
|
7199
7266
|
layer = "product";
|
|
7200
7267
|
}
|
|
7201
7268
|
const title = typeof fm.title === "string" ? fm.title.trim() : id;
|
|
7202
7269
|
const content = fileContent.replace(/^---\r?\n[\s\S]*?\r?\n---/, "").trim();
|
|
7203
|
-
|
|
7270
|
+
const scannedArt = {
|
|
7204
7271
|
id,
|
|
7205
7272
|
type,
|
|
7206
7273
|
title,
|
|
@@ -7208,7 +7275,12 @@ function buildGraphElements(rootDir = process.cwd()) {
|
|
|
7208
7275
|
filePath: relPath,
|
|
7209
7276
|
content,
|
|
7210
7277
|
frontmatter: fm
|
|
7211
|
-
}
|
|
7278
|
+
};
|
|
7279
|
+
if (layer === "architecture" && type === "architecture") {
|
|
7280
|
+
archViewByBasename.set(path8.basename(relPath), scannedArt);
|
|
7281
|
+
} else {
|
|
7282
|
+
scannedArtifactsMap.set(id, scannedArt);
|
|
7283
|
+
}
|
|
7212
7284
|
} catch {
|
|
7213
7285
|
}
|
|
7214
7286
|
}
|
|
@@ -7217,7 +7289,7 @@ function buildGraphElements(rootDir = process.cwd()) {
|
|
|
7217
7289
|
for (const r of trace.rows) {
|
|
7218
7290
|
const isOk = (r.productStatus === "COMPLIANT" || r.productStatus === "CONFORME") && (r.archStatus === "COMPLIANT" || r.archStatus === "CONFORME") && (r.testStatus === "COMPLIANT" || r.testStatus === "CONFORME");
|
|
7219
7291
|
const status = isOk ? "COMPLIANT" : "ORPHAN";
|
|
7220
|
-
const reqType = r.id.startsWith("SEC-REQ-") ? "security-requirement" :
|
|
7292
|
+
const reqType = r.id.startsWith("SEC-REQ-") ? "security-requirement" : "requirement";
|
|
7221
7293
|
nodeMap.set(r.id, {
|
|
7222
7294
|
id: r.id,
|
|
7223
7295
|
label: r.id,
|
|
@@ -7243,16 +7315,18 @@ function buildGraphElements(rootDir = process.cwd()) {
|
|
|
7243
7315
|
const u = up.trim();
|
|
7244
7316
|
if (u && u !== "NINGUNO" && u !== "NONE") {
|
|
7245
7317
|
const isAbuse = u.startsWith("ABUSE-");
|
|
7318
|
+
const isArchIntro = u.startsWith("ARCH-INTRO-");
|
|
7319
|
+
const rel = isAbuse ? "mitigated-by" : isArchIntro ? "defines-goal" : "derives-from";
|
|
7246
7320
|
addEdge({
|
|
7247
7321
|
id: `edge-${u}-${r.id}`,
|
|
7248
7322
|
source: u,
|
|
7249
7323
|
target: r.id,
|
|
7250
|
-
label:
|
|
7251
|
-
relation:
|
|
7324
|
+
label: rel,
|
|
7325
|
+
relation: rel,
|
|
7252
7326
|
status
|
|
7253
7327
|
});
|
|
7254
7328
|
if (!nodeMap.has(u)) {
|
|
7255
|
-
const upType = u.startsWith("ACT-") ? "actor" : u.startsWith("UC-") ? "use-case" : u.startsWith("BR-") ? "business-rule" : u.startsWith("ABUSE-") ? "abuse-case" : "product";
|
|
7329
|
+
const upType = u.startsWith("ARCH-INTRO-") ? "architecture-introduction" : u.startsWith("ACT-") ? "actor" : u.startsWith("UC-") ? "use-case" : u.startsWith("BR-") ? "business-rule" : u.startsWith("ABUSE-") ? "abuse-case" : "product";
|
|
7256
7330
|
nodeMap.set(u, {
|
|
7257
7331
|
id: u,
|
|
7258
7332
|
label: u,
|
|
@@ -7277,13 +7351,16 @@ function buildGraphElements(rootDir = process.cwd()) {
|
|
|
7277
7351
|
});
|
|
7278
7352
|
if (!nodeMap.has(a)) {
|
|
7279
7353
|
const aType = a.startsWith("CMP-") ? "component" : a.startsWith("ADR-") ? "adr" : a.startsWith("SEC-ENC-") ? "security-enclave" : "architecture";
|
|
7354
|
+
const viewArt = archViewByBasename.get(a);
|
|
7280
7355
|
nodeMap.set(a, {
|
|
7281
7356
|
id: a,
|
|
7282
7357
|
label: a,
|
|
7283
|
-
title: a,
|
|
7358
|
+
title: viewArt?.title || a,
|
|
7284
7359
|
type: aType,
|
|
7285
7360
|
layer: "architecture",
|
|
7286
|
-
status: "COMPLIANT"
|
|
7361
|
+
status: "COMPLIANT",
|
|
7362
|
+
filePath: viewArt?.filePath,
|
|
7363
|
+
content: viewArt?.content
|
|
7287
7364
|
});
|
|
7288
7365
|
}
|
|
7289
7366
|
}
|
|
@@ -7347,7 +7424,80 @@ function buildGraphElements(rootDir = process.cwd()) {
|
|
|
7347
7424
|
}
|
|
7348
7425
|
for (const art of scannedArtifactsMap.values()) {
|
|
7349
7426
|
const fm = art.frontmatter;
|
|
7350
|
-
if (art.type === "
|
|
7427
|
+
if (art.type === "architecture-introduction") {
|
|
7428
|
+
const citedActors = Array.isArray(fm["cites-product-actors"]) ? fm["cites-product-actors"] : [];
|
|
7429
|
+
for (const actId of citedActors) {
|
|
7430
|
+
if (typeof actId === "string" && actId.trim()) {
|
|
7431
|
+
const a = actId.trim();
|
|
7432
|
+
if (!nodeMap.has(a)) {
|
|
7433
|
+
nodeMap.set(a, {
|
|
7434
|
+
id: a,
|
|
7435
|
+
label: a,
|
|
7436
|
+
title: a,
|
|
7437
|
+
type: "actor",
|
|
7438
|
+
layer: "product",
|
|
7439
|
+
status: "COMPLIANT"
|
|
7440
|
+
});
|
|
7441
|
+
}
|
|
7442
|
+
addEdge({
|
|
7443
|
+
id: `edge-${art.id}-${a}`,
|
|
7444
|
+
source: art.id,
|
|
7445
|
+
target: a,
|
|
7446
|
+
label: "identifies",
|
|
7447
|
+
relation: "identifies",
|
|
7448
|
+
status: "COMPLIANT"
|
|
7449
|
+
});
|
|
7450
|
+
}
|
|
7451
|
+
}
|
|
7452
|
+
const citedUcs = Array.isArray(fm["cites-use-cases"]) ? fm["cites-use-cases"] : [];
|
|
7453
|
+
for (const ucId of citedUcs) {
|
|
7454
|
+
if (typeof ucId === "string" && ucId.trim()) {
|
|
7455
|
+
const u = ucId.trim();
|
|
7456
|
+
if (!nodeMap.has(u)) {
|
|
7457
|
+
nodeMap.set(u, {
|
|
7458
|
+
id: u,
|
|
7459
|
+
label: u,
|
|
7460
|
+
title: u,
|
|
7461
|
+
type: "use-case",
|
|
7462
|
+
layer: "product",
|
|
7463
|
+
status: "COMPLIANT"
|
|
7464
|
+
});
|
|
7465
|
+
}
|
|
7466
|
+
addEdge({
|
|
7467
|
+
id: `edge-${art.id}-${u}`,
|
|
7468
|
+
source: art.id,
|
|
7469
|
+
target: u,
|
|
7470
|
+
label: "envisions",
|
|
7471
|
+
relation: "envisions",
|
|
7472
|
+
status: "COMPLIANT"
|
|
7473
|
+
});
|
|
7474
|
+
}
|
|
7475
|
+
}
|
|
7476
|
+
const citedGoals = Array.isArray(fm["cites-quality-goals"]) ? fm["cites-quality-goals"] : [];
|
|
7477
|
+
for (const qrId of citedGoals) {
|
|
7478
|
+
if (typeof qrId === "string" && qrId.trim()) {
|
|
7479
|
+
const q = qrId.trim();
|
|
7480
|
+
if (!nodeMap.has(q)) {
|
|
7481
|
+
nodeMap.set(q, {
|
|
7482
|
+
id: q,
|
|
7483
|
+
label: q,
|
|
7484
|
+
title: q,
|
|
7485
|
+
type: q.startsWith("SEC-REQ-") ? "security-requirement" : "requirement",
|
|
7486
|
+
layer: "requirement",
|
|
7487
|
+
status: "COMPLIANT"
|
|
7488
|
+
});
|
|
7489
|
+
}
|
|
7490
|
+
addEdge({
|
|
7491
|
+
id: `edge-${art.id}-${q}`,
|
|
7492
|
+
source: art.id,
|
|
7493
|
+
target: q,
|
|
7494
|
+
label: "defines-goal",
|
|
7495
|
+
relation: "defines-goal",
|
|
7496
|
+
status: "COMPLIANT"
|
|
7497
|
+
});
|
|
7498
|
+
}
|
|
7499
|
+
}
|
|
7500
|
+
} else if (art.type === "journey") {
|
|
7351
7501
|
const persona = typeof fm.persona === "string" ? fm.persona : typeof fm.actor === "string" ? fm.actor : void 0;
|
|
7352
7502
|
if (persona) {
|
|
7353
7503
|
if (!nodeMap.has(persona)) {
|
|
@@ -7415,7 +7565,31 @@ function buildGraphElements(rootDir = process.cwd()) {
|
|
|
7415
7565
|
status: "COMPLIANT"
|
|
7416
7566
|
});
|
|
7417
7567
|
}
|
|
7418
|
-
const
|
|
7568
|
+
const supportingActors = Array.isArray(fm["supporting-actors"]) ? fm["supporting-actors"] : Array.isArray(fm["secondary-actors"]) ? fm["secondary-actors"] : [];
|
|
7569
|
+
for (const actorId of supportingActors) {
|
|
7570
|
+
if (typeof actorId === "string" && actorId.trim()) {
|
|
7571
|
+
const a = actorId.trim();
|
|
7572
|
+
if (!nodeMap.has(a)) {
|
|
7573
|
+
nodeMap.set(a, {
|
|
7574
|
+
id: a,
|
|
7575
|
+
label: a,
|
|
7576
|
+
title: a,
|
|
7577
|
+
type: "actor",
|
|
7578
|
+
layer: "product",
|
|
7579
|
+
status: "COMPLIANT"
|
|
7580
|
+
});
|
|
7581
|
+
}
|
|
7582
|
+
addEdge({
|
|
7583
|
+
id: `edge-${a}-${art.id}`,
|
|
7584
|
+
source: a,
|
|
7585
|
+
target: art.id,
|
|
7586
|
+
label: "initiates",
|
|
7587
|
+
relation: "initiates",
|
|
7588
|
+
status: "COMPLIANT"
|
|
7589
|
+
});
|
|
7590
|
+
}
|
|
7591
|
+
}
|
|
7592
|
+
const governedBy = Array.isArray(fm["governed-by"]) ? fm["governed-by"] : Array.isArray(fm["business-rules"]) ? fm["business-rules"] : [];
|
|
7419
7593
|
for (const ruleId of governedBy) {
|
|
7420
7594
|
if (typeof ruleId === "string" && ruleId.trim()) {
|
|
7421
7595
|
const r = ruleId.trim();
|
|
@@ -7476,7 +7650,31 @@ function buildGraphElements(rootDir = process.cwd()) {
|
|
|
7476
7650
|
status: "COMPLIANT"
|
|
7477
7651
|
});
|
|
7478
7652
|
}
|
|
7479
|
-
const
|
|
7653
|
+
const secondaryThreatActors = Array.isArray(fm["secondary-actors"]) ? fm["secondary-actors"] : Array.isArray(fm["supporting-actors"]) ? fm["supporting-actors"] : [];
|
|
7654
|
+
for (const secActor of secondaryThreatActors) {
|
|
7655
|
+
if (typeof secActor === "string" && secActor.trim()) {
|
|
7656
|
+
const sa = secActor.trim();
|
|
7657
|
+
if (!nodeMap.has(sa)) {
|
|
7658
|
+
nodeMap.set(sa, {
|
|
7659
|
+
id: sa,
|
|
7660
|
+
label: sa,
|
|
7661
|
+
title: sa,
|
|
7662
|
+
type: sa.startsWith("ACT-THREAT-") ? "threat-actor" : "actor",
|
|
7663
|
+
layer: "product",
|
|
7664
|
+
status: "COMPLIANT"
|
|
7665
|
+
});
|
|
7666
|
+
}
|
|
7667
|
+
addEdge({
|
|
7668
|
+
id: `edge-${sa}-${art.id}`,
|
|
7669
|
+
source: sa,
|
|
7670
|
+
target: art.id,
|
|
7671
|
+
label: "threatens",
|
|
7672
|
+
relation: "threatens",
|
|
7673
|
+
status: "COMPLIANT"
|
|
7674
|
+
});
|
|
7675
|
+
}
|
|
7676
|
+
}
|
|
7677
|
+
const rawTargets = Array.isArray(fm["targets-use-case"]) ? fm["targets-use-case"] : typeof fm["targets-use-case"] === "string" ? [fm["targets-use-case"]] : Array.isArray(fm["targets-use-cases"]) ? fm["targets-use-cases"] : Array.isArray(fm["targets"]) ? fm["targets"] : [];
|
|
7480
7678
|
for (const tgt of rawTargets) {
|
|
7481
7679
|
if (typeof tgt === "string" && tgt.trim()) {
|
|
7482
7680
|
const t = tgt.trim();
|
|
@@ -7541,6 +7739,40 @@ function buildGraphElements(rootDir = process.cwd()) {
|
|
|
7541
7739
|
});
|
|
7542
7740
|
}
|
|
7543
7741
|
}
|
|
7742
|
+
} else if (art.type === "adr") {
|
|
7743
|
+
const affectedComponents = Array.isArray(fm["affects-components"]) ? fm["affects-components"] : typeof fm["affects-components"] === "string" ? [fm["affects-components"]] : [];
|
|
7744
|
+
for (const cmpId of affectedComponents) {
|
|
7745
|
+
if (typeof cmpId === "string" && cmpId.trim()) {
|
|
7746
|
+
const c = cmpId.trim();
|
|
7747
|
+
if (nodeMap.has(c)) {
|
|
7748
|
+
addEdge({
|
|
7749
|
+
id: `edge-${art.id}-${c}`,
|
|
7750
|
+
source: art.id,
|
|
7751
|
+
target: c,
|
|
7752
|
+
label: "governs",
|
|
7753
|
+
relation: "governs",
|
|
7754
|
+
status: "COMPLIANT"
|
|
7755
|
+
});
|
|
7756
|
+
}
|
|
7757
|
+
}
|
|
7758
|
+
}
|
|
7759
|
+
} else if (art.type === "security-enclave") {
|
|
7760
|
+
const enforcedBy = Array.isArray(fm["enforced-by"]) ? fm["enforced-by"] : typeof fm["enforced-by"] === "string" ? [fm["enforced-by"]] : [];
|
|
7761
|
+
for (const secReq of enforcedBy) {
|
|
7762
|
+
if (typeof secReq === "string" && secReq.trim()) {
|
|
7763
|
+
const s = secReq.trim();
|
|
7764
|
+
if (nodeMap.has(s)) {
|
|
7765
|
+
addEdge({
|
|
7766
|
+
id: `edge-${s}-${art.id}`,
|
|
7767
|
+
source: s,
|
|
7768
|
+
target: art.id,
|
|
7769
|
+
label: "satisfies",
|
|
7770
|
+
relation: "satisfies",
|
|
7771
|
+
status: "COMPLIANT"
|
|
7772
|
+
});
|
|
7773
|
+
}
|
|
7774
|
+
}
|
|
7775
|
+
}
|
|
7544
7776
|
}
|
|
7545
7777
|
}
|
|
7546
7778
|
for (const [id, node] of nodeMap.entries()) {
|
|
@@ -7690,6 +7922,9 @@ function collectDashboardMetrics(rootDir) {
|
|
|
7690
7922
|
function escapeHtml(str) {
|
|
7691
7923
|
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
7692
7924
|
}
|
|
7925
|
+
function safeJsonForScript(data) {
|
|
7926
|
+
return JSON.stringify(data).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
7927
|
+
}
|
|
7693
7928
|
function renderAutonomyModeSection(mode, statusIcon, count, roleDescription, allTasks = []) {
|
|
7694
7929
|
const modeTasks = (allTasks || []).filter(
|
|
7695
7930
|
(t) => (t.task?.autonomyMode || "").toUpperCase() === mode
|
|
@@ -7801,14 +8036,14 @@ function renderAutonomyModeSection(mode, statusIcon, count, roleDescription, all
|
|
|
7801
8036
|
}
|
|
7802
8037
|
function renderDashboardHtml(graphData, metricsData, title = "AI-SDLC: Dashboard Interactivo de Trazabilidad y Calidad") {
|
|
7803
8038
|
const cytoscapeScript = getCytoscapeScript();
|
|
7804
|
-
const elementsJson =
|
|
8039
|
+
const elementsJson = safeJsonForScript(graphData.elements);
|
|
7805
8040
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7806
8041
|
return `<!DOCTYPE html>
|
|
7807
8042
|
<html lang="es">
|
|
7808
8043
|
<head>
|
|
7809
8044
|
<meta charset="UTF-8">
|
|
7810
8045
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7811
|
-
<title>${title}</title>
|
|
8046
|
+
<title>${escapeHtml(title)}</title>
|
|
7812
8047
|
<style>
|
|
7813
8048
|
:root {
|
|
7814
8049
|
--bg-dark: #0f172a;
|
|
@@ -8111,6 +8346,7 @@ function renderDashboardHtml(graphData, metricsData, title = "AI-SDLC: Dashboard
|
|
|
8111
8346
|
<div class="tool-row">
|
|
8112
8347
|
<select id="type-filter" class="tool-select" onchange="filterType(this.value)">
|
|
8113
8348
|
<option value="all">All Typologies</option>
|
|
8349
|
+
<option value="architecture-introduction">Vision & Goals (ARCH-INTRO)</option>
|
|
8114
8350
|
<option value="journey">Journeys (JRN)</option>
|
|
8115
8351
|
<option value="actor">Actors (ACT)</option>
|
|
8116
8352
|
<option value="use-case">Use Cases (UC)</option>
|
|
@@ -8145,6 +8381,7 @@ function renderDashboardHtml(graphData, metricsData, title = "AI-SDLC: Dashboard
|
|
|
8145
8381
|
<div class="graph-legend">
|
|
8146
8382
|
<div class="legend-header">Node Typologies</div>
|
|
8147
8383
|
<div class="legend-items">
|
|
8384
|
+
<div class="legend-item"><span class="legend-dot" style="background:#0f766e; border:2px solid #2dd4bf;"></span><strong>Vision / Goals</strong> (ARCH-INTRO)</div>
|
|
8148
8385
|
<div class="legend-item"><span class="legend-dot" style="background:#581c87; border:2px solid #c084fc;"></span><strong>Journey</strong> (JRN)</div>
|
|
8149
8386
|
<div class="legend-item"><span class="legend-dot" style="background:#065f46; border:2px solid #34d399; border-radius:50%;"></span><strong>Actor</strong> (ACT)</div>
|
|
8150
8387
|
<div class="legend-item"><span class="legend-dot" style="background:#0369a1; border:2px solid #38bdf8;"></span><strong>Use Case</strong> (UC)</div>
|
|
@@ -8183,12 +8420,12 @@ function renderDashboardHtml(graphData, metricsData, title = "AI-SDLC: Dashboard
|
|
|
8183
8420
|
${metricsData.trace.rows.map((r) => {
|
|
8184
8421
|
const isRowOk = (r.productStatus === "COMPLIANT" || r.productStatus === "CONFORME") && (r.archStatus === "COMPLIANT" || r.archStatus === "CONFORME") && (r.testStatus === "COMPLIANT" || r.testStatus === "CONFORME");
|
|
8185
8422
|
return `
|
|
8186
|
-
<tr onclick="focusNode('${r.id}')" onmouseenter="startRowTooltip(event, '${r.id}')" onmouseleave="cancelRowTooltip()" onmousemove="updateRowTooltipPos(event)" style="cursor: pointer;">
|
|
8187
|
-
<td><strong><code>${r.id}</code></strong></td>
|
|
8188
|
-
<td>${r.title}</td>
|
|
8189
|
-
<td><code>${r.productTraces}</code></td>
|
|
8190
|
-
<td><code>${r.archTraces}</code></td>
|
|
8191
|
-
<td><code>${r.testTraces}</code></td>
|
|
8423
|
+
<tr onclick="focusNode('${escapeHtml(String(r.id || ""))}')" onmouseenter="startRowTooltip(event, '${escapeHtml(String(r.id || ""))}')" onmouseleave="cancelRowTooltip()" onmousemove="updateRowTooltipPos(event)" style="cursor: pointer;">
|
|
8424
|
+
<td><strong><code>${escapeHtml(String(r.id || ""))}</code></strong></td>
|
|
8425
|
+
<td>${escapeHtml(String(r.title || ""))}</td>
|
|
8426
|
+
<td><code>${escapeHtml(String(r.productTraces || ""))}</code></td>
|
|
8427
|
+
<td><code>${escapeHtml(String(r.archTraces || ""))}</code></td>
|
|
8428
|
+
<td><code>${escapeHtml(String(r.testTraces || ""))}</code></td>
|
|
8192
8429
|
<td><span class="badge ${isRowOk ? "badge-green" : "badge-amber"}">${isRowOk ? "COMPLIANT" : "ORPHAN"}</span></td>
|
|
8193
8430
|
</tr>
|
|
8194
8431
|
`;
|
|
@@ -8401,7 +8638,7 @@ function renderDashboardHtml(graphData, metricsData, title = "AI-SDLC: Dashboard
|
|
|
8401
8638
|
</script>
|
|
8402
8639
|
<script>
|
|
8403
8640
|
var elements = ${elementsJson};
|
|
8404
|
-
var govTasks = ${
|
|
8641
|
+
var govTasks = ${safeJsonForScript(metricsData.gov.tasks || [])};
|
|
8405
8642
|
var cy = null;
|
|
8406
8643
|
|
|
8407
8644
|
var reqHoverTimer = null;
|
|
@@ -8564,6 +8801,19 @@ function renderDashboardHtml(graphData, metricsData, title = "AI-SDLC: Dashboard
|
|
|
8564
8801
|
}
|
|
8565
8802
|
},
|
|
8566
8803
|
// Typology Styles
|
|
8804
|
+
{
|
|
8805
|
+
selector: 'node.type-architecture-introduction',
|
|
8806
|
+
style: {
|
|
8807
|
+
'shape': 'round-rectangle',
|
|
8808
|
+
'background-color': '#0f766e',
|
|
8809
|
+
'border-color': '#2dd4bf',
|
|
8810
|
+
'border-width': 3,
|
|
8811
|
+
'width': 92,
|
|
8812
|
+
'height': 44,
|
|
8813
|
+
'font-weight': 'bold',
|
|
8814
|
+
'text-max-width': '86px'
|
|
8815
|
+
}
|
|
8816
|
+
},
|
|
8567
8817
|
{
|
|
8568
8818
|
selector: 'node.type-journey',
|
|
8569
8819
|
style: {
|
|
@@ -8680,7 +8930,7 @@ function renderDashboardHtml(graphData, metricsData, title = "AI-SDLC: Dashboard
|
|
|
8680
8930
|
},
|
|
8681
8931
|
// Fallback Layer styles if type is missing
|
|
8682
8932
|
{
|
|
8683
|
-
selector: 'node.layer-product:not(.type-journey):not(.type-actor):not(.type-use-case):not(.type-usecase):not(.type-business-rule):not(.type-rule):not(.type-abuse-case):not(.type-threat-actor)',
|
|
8933
|
+
selector: 'node.layer-product:not(.type-architecture-introduction):not(.type-journey):not(.type-actor):not(.type-use-case):not(.type-usecase):not(.type-business-rule):not(.type-rule):not(.type-abuse-case):not(.type-threat-actor)',
|
|
8684
8934
|
style: { 'shape': 'diamond', 'background-color': '#0e7490', 'border-color': '#38bdf8', 'width': 50, 'height': 50 }
|
|
8685
8935
|
},
|
|
8686
8936
|
{
|
|
@@ -8709,6 +8959,10 @@ function renderDashboardHtml(graphData, metricsData, title = "AI-SDLC: Dashboard
|
|
|
8709
8959
|
}
|
|
8710
8960
|
},
|
|
8711
8961
|
// Semantic Edge Relations
|
|
8962
|
+
{
|
|
8963
|
+
selector: 'edge.relation-identifies, edge.relation-envisions, edge.relation-defines-goal',
|
|
8964
|
+
style: { 'line-color': '#2dd4bf', 'target-arrow-color': '#2dd4bf', 'width': 2 }
|
|
8965
|
+
},
|
|
8712
8966
|
{
|
|
8713
8967
|
selector: 'edge.relation-pursues',
|
|
8714
8968
|
style: { 'line-color': '#c084fc', 'target-arrow-color': '#c084fc', 'width': 2 }
|
|
@@ -8849,7 +9103,10 @@ function renderDashboardHtml(graphData, metricsData, title = "AI-SDLC: Dashboard
|
|
|
8849
9103
|
var typeName = (data.type || data.layer || 'node').toLowerCase();
|
|
8850
9104
|
var typeBadgeColor = '#334155';
|
|
8851
9105
|
var typeTitle = (data.type || data.layer || 'NODE').toUpperCase();
|
|
8852
|
-
if (typeName === '
|
|
9106
|
+
if (typeName === 'architecture-introduction') {
|
|
9107
|
+
typeBadgeColor = '#0f766e';
|
|
9108
|
+
typeTitle = 'VISION & GOALS (ARCH-INTRO)';
|
|
9109
|
+
} else if (typeName === 'journey') {
|
|
8853
9110
|
typeBadgeColor = '#581c87';
|
|
8854
9111
|
typeTitle = 'JOURNEY (JRN)';
|
|
8855
9112
|
} else if (typeName === 'actor') {
|
|
@@ -8915,6 +9172,11 @@ function renderDashboardHtml(graphData, metricsData, title = "AI-SDLC: Dashboard
|
|
|
8915
9172
|
if (!cy) return;
|
|
8916
9173
|
if (type === 'all') {
|
|
8917
9174
|
cy.elements().show();
|
|
9175
|
+
} else if (type === 'architecture-introduction') {
|
|
9176
|
+
cy.elements().hide();
|
|
9177
|
+
var nodes = cy.nodes('.type-architecture-introduction');
|
|
9178
|
+
nodes.show();
|
|
9179
|
+
nodes.connectedEdges().show();
|
|
8918
9180
|
} else if (type === 'journey') {
|
|
8919
9181
|
cy.elements().hide();
|
|
8920
9182
|
var nodes = cy.nodes('.type-journey');
|
|
@@ -9034,9 +9296,10 @@ function renderDashboardHtml(graphData, metricsData, title = "AI-SDLC: Dashboard
|
|
|
9034
9296
|
|
|
9035
9297
|
function switchTab(name) {
|
|
9036
9298
|
hideTooltip();
|
|
9037
|
-
document.querySelectorAll('.tab-btn').forEach(function(b) {
|
|
9299
|
+
document.querySelectorAll('.tab-btn').forEach(function(b) {
|
|
9300
|
+
b.classList.toggle('active', b.getAttribute('onclick') === "switchTab('" + name + "')");
|
|
9301
|
+
});
|
|
9038
9302
|
document.querySelectorAll('.tab-panel').forEach(function(p) { p.classList.remove('active'); });
|
|
9039
|
-
event.target?.classList?.add('active');
|
|
9040
9303
|
var p = document.getElementById('tab-' + name);
|
|
9041
9304
|
if (p) p.classList.add('active');
|
|
9042
9305
|
if (name === 'graph' && cy) {
|
|
@@ -9250,14 +9513,20 @@ var SPECIALIZED_AGENT_TEMPLATES = [
|
|
|
9250
9513
|
{
|
|
9251
9514
|
id: "agent-product-analyst",
|
|
9252
9515
|
title: "Product Analyst / Scribe",
|
|
9253
|
-
description: "Assist the human Product Owner in exploring, modeling, and refining product definition using ProductShape (ACT-*, UC-*, FR-*, QR-*, BR-*).",
|
|
9254
|
-
globs: "product/**, specs/product/**, templates/product
|
|
9516
|
+
description: "Assist the human Product Owner in exploring, modeling, and refining product definition using NAF v4 Enterprise & Capability Vision (ARCH-INTRO-*) and ProductShape (ACT-*, UC-*, FR-*, QR-*, BR-*).",
|
|
9517
|
+
globs: "product/**, specs/product/**, templates/product/**, templates/architecture/introduction-and-goals.template.md",
|
|
9255
9518
|
body: `## Role & Mission
|
|
9256
9519
|
- **Role**: Product Analyst Agent (\`agent-product-analyst\`) and Technical Scribe (AI as Scribe) of the AI-SDLC framework.
|
|
9257
|
-
- **Mission**:
|
|
9520
|
+
- **Mission**: Capture new product intent via NAF v4 Enterprise & Capability Vision (\`ARCH-INTRO-*\`) and transform natural language business intent into canonical ProductShape artifacts (\`ACT-*\`, \`JRN-*\`, \`UC-*\`, \`BR-*\`, \`TERM-*\`, \`FR-*\`, \`QR-*\`) 100% compliant with JSON schemas.
|
|
9521
|
+
|
|
9522
|
+
## Phase 0: Greenfield Product Inception (New Product Intent)
|
|
9523
|
+
- **Trigger**: When the user expresses intent to create a new product from scratch with the framework (or when \`specs/product/\` has no baseline product model yet), initiate **Phase 0** before any SDD change (\`change:new\`) or implementation:
|
|
9524
|
+
1. **Structured Discovery Interview (3\u20135 Questions)**: Ask a concise 3\u20135 question interview to clarify: (a) core problem and mission statement, (b) primary actors/stakeholders (\`ACT-*\`), (c) essential MVP capabilities/use cases (\`UC-*\`), and (d) top 3\u20135 priority quality goals and constraints (\`QR-*\`, \`CON-*\`).
|
|
9525
|
+
2. **Enterprise & Capability Vision (\`ARCH-INTRO-001\`)**: Draft the root vision artifact (\`type: architecture-introduction\`, \`naf-perspective: "Enterprise & Capability"\`, \`status: draft\`) using \`templates/architecture/introduction-and-goals.template.md\` (\`schemas/architecture/introduction-and-goals.schema.json\`).
|
|
9526
|
+
3. **ProductShape Derivation**: Derive the initial draft artifacts (\`ACT-*\`, \`UC-*\`, \`BR-*\`, \`FR-*\`, \`QR-*\` with \`status: draft\`) in \`specs/product/\` linked to \`ARCH-INTRO-001\` for human Product Owner review.
|
|
9258
9527
|
|
|
9259
9528
|
## Operational Directives & Guardrails
|
|
9260
|
-
- Every generated artifact must strictly adhere to the canonical Markdown and YAML frontmatter format in \`schemas/product
|
|
9529
|
+
- Every generated artifact must strictly adhere to the canonical Markdown and YAML frontmatter format in \`schemas/product/\` and \`schemas/architecture/introduction-and-goals.schema.json\`.
|
|
9261
9530
|
- \`status\` ALWAYS starts as \`draft\`. Creating artifacts directly as \`active\` or \`approved\` is forbidden.
|
|
9262
9531
|
- Always write relationships in their single canonical direction (\`derives-from: [UC-*]\`, \`primary-actor: ACT-*\`).
|
|
9263
9532
|
- In \`UC-*\`, format section \`1. Intent and Outcome\` under the standard English structure: \`As a <ACT-ID>... I want <action>... To <outcome>...\`.
|
|
@@ -9505,9 +9774,10 @@ This file defines the operational rules and specialized role mappings for Google
|
|
|
9505
9774
|
## 2. Specialized Roles Mapping
|
|
9506
9775
|
|
|
9507
9776
|
### 1. \`agent-product-analyst\` (Product Analyst / Scribe)
|
|
9508
|
-
- **Mission**:
|
|
9777
|
+
- **Mission**: Capture new product intent via NAF v4 Enterprise & Capability Vision (\`ARCH-INTRO-*\`) and define/refine the product model using ProductShape.
|
|
9778
|
+
- **Phase 0 (Greenfield Product Inception)**: When creating a new product from scratch (or when \`specs/product/\` has no baseline), run a concise 3\u20135 question discovery interview (mission/problem, actors \`ACT-*\`, MVP capabilities \`UC-*\`, priority quality goals \`QR-*\`), draft \`ARCH-INTRO-001\` (\`templates/architecture/introduction-and-goals.template.md\`), and derive initial \`ACT-*\`, \`UC-*\`, \`BR-*\`, \`FR-*\`, and \`QR-*\` drafts.
|
|
9509
9779
|
- **Input**: Business intent or natural language specification.
|
|
9510
|
-
- **Output**: Markdown artifacts with YAML frontmatter compliant with \`schemas/product/\` (\`ACT-*\`, \`UC-*\`, \`FR-*\`, \`QR-*\`, \`BR-*\`).
|
|
9780
|
+
- **Output**: Markdown artifacts with YAML frontmatter compliant with \`schemas/architecture/introduction-and-goals.schema.json\` (\`ARCH-INTRO-*\`) and \`schemas/product/\` (\`ACT-*\`, \`UC-*\`, \`FR-*\`, \`QR-*\`, \`BR-*\`).
|
|
9511
9781
|
- **Guardrails**:
|
|
9512
9782
|
- \`status\` always starts in \`draft\`.
|
|
9513
9783
|
- In \`UC-*\`, format section \`1. Intent and Outcome\` under the standard English structure: \`As a <ACT-ID>... I want <action>... To <outcome>...\`.
|
|
@@ -9638,7 +9908,7 @@ Before finalizing changes or proposing commits:
|
|
|
9638
9908
|
## 4. Specialized Roles Mapping
|
|
9639
9909
|
| Role | Mission (summary) |
|
|
9640
9910
|
| :--- | :--- |
|
|
9641
|
-
| \`agent-product-analyst\` | ProductShape artifacts (\`ACT-*\`, \`UC-*\`, \`FR-*\`, \`QR-*\`, \`BR-*\`); status starts \`draft\`. |
|
|
9911
|
+
| \`agent-product-analyst\` | Phase 0 NAF v4 Enterprise & Capability Vision (\`ARCH-INTRO-*\`, 3\u20135 question interview) + ProductShape artifacts (\`ACT-*\`, \`UC-*\`, \`FR-*\`, \`QR-*\`, \`BR-*\`); status starts \`draft\`. |
|
|
9642
9912
|
| \`agent-threat-modeler\` | STRIDE/OWASP threat triad (\`ACT-THREAT-*\`, \`ABUSE-*\`, \`SEC-REQ-*\`). |
|
|
9643
9913
|
| \`agent-system-architect\` | Modular arc42 + NAF v4 architecture (\`CMP-*\`, Mermaid diagrams, \`ADR-*\`). |
|
|
9644
9914
|
| \`agent-qa-engineer\` | FAILING BDD/Gherkin suites before \`agent-developer\` writes code. |
|
|
@@ -9673,6 +9943,7 @@ Canonical Reference: [\`process/09_agent_protocols.md\`](process/09_agent_protoc
|
|
|
9673
9943
|
|
|
9674
9944
|
## 1. Identifier Taxonomy and JSON Schemas
|
|
9675
9945
|
Every generated or modified artifact must follow canonical naming and satisfy its schema in \`schemas/\`:
|
|
9946
|
+
- Enterprise & Capability Vision (Phase 0): \`ARCH-INTRO-[NUM3]\` (\`schemas/architecture/introduction-and-goals.schema.json\`)
|
|
9676
9947
|
- Product Actors: \`ACT-[SUFFIX]\` (\`schemas/product/actor.schema.json\`)
|
|
9677
9948
|
- Use Cases: \`UC-[SUFFIX]\` (\`schemas/product/use-case.schema.json\`)
|
|
9678
9949
|
- Functional Requirements: \`FR-[SUFFIX]-[NUM3]\` (\`schemas/product/requirement.schema.json\`)
|
|
@@ -9683,6 +9954,7 @@ Every generated or modified artifact must follow canonical naming and satisfy it
|
|
|
9683
9954
|
- Security Requirements: \`SEC-REQ-[SUFFIX]\` (\`schemas/security/security-req.schema.json\`)
|
|
9684
9955
|
|
|
9685
9956
|
## 2. "AI as Scribe" Protocol Rules
|
|
9957
|
+
- **Phase 0 (New Product Inception)**: When starting a new product, conduct a 3\u20135 question discovery interview, instantiate \`ARCH-INTRO-001\` (\`naf-perspective: "Enterprise & Capability"\`) in \`draft\`, and derive \`ACT-*\`, \`UC-*\`, \`BR-*\`, \`FR-*\`, and \`QR-*\`.
|
|
9686
9958
|
- **Initial Status**: Every new artifact strictly starts with \`status: draft\`. Creating artifacts directly as \`active\` or \`approved\` is forbidden.
|
|
9687
9959
|
- **Gherkin Acceptance Criteria**: In every \`FR-*\` requirement, include a \`\`\`gherkin block with tags \`@<ID> @automated @regression\` and at least one \`Scenario Outline\` with an \`Examples\` data table.
|
|
9688
9960
|
- **Security Mitigations**: Every \`SEC-REQ-*\` must include negative Gherkin tests (\`@security @mitigation\`).
|
|
@@ -9764,9 +10036,10 @@ npx tsx packages/cli/src/index.ts sdd integrate --change <chg-id>
|
|
|
9764
10036
|
## 3. Specialized Roles Mapping
|
|
9765
10037
|
|
|
9766
10038
|
### 1. \`agent-product-analyst\` (Product Analyst / Scribe)
|
|
9767
|
-
- **Mission**:
|
|
10039
|
+
- **Mission**: Capture new product intent via NAF v4 Enterprise & Capability Vision (\`ARCH-INTRO-*\`) and define/refine the product model using ProductShape.
|
|
10040
|
+
- **Phase 0 (Greenfield Product Inception)**: When creating a new product from scratch (or when \`specs/product/\` has no baseline), run a concise 3\u20135 question discovery interview (mission/problem, actors \`ACT-*\`, MVP capabilities \`UC-*\`, priority quality goals \`QR-*\`), draft \`ARCH-INTRO-001\` (\`templates/architecture/introduction-and-goals.template.md\`), and derive initial \`ACT-*\`, \`UC-*\`, \`BR-*\`, \`FR-*\`, and \`QR-*\` drafts.
|
|
9768
10041
|
- **Input**: Business intent or natural language specification.
|
|
9769
|
-
- **Output**: Markdown artifacts with YAML frontmatter compliant with \`schemas/product/\` (\`ACT-*\`, \`UC-*\`, \`FR-*\`, \`QR-*\`, \`BR-*\`).
|
|
10042
|
+
- **Output**: Markdown artifacts with YAML frontmatter compliant with \`schemas/architecture/introduction-and-goals.schema.json\` (\`ARCH-INTRO-*\`) and \`schemas/product/\` (\`ACT-*\`, \`UC-*\`, \`FR-*\`, \`QR-*\`, \`BR-*\`).
|
|
9770
10043
|
- **Guardrails**: \`status\` always starts in \`draft\`. Mandatory Gherkin criteria with \`@<ID> @automated @regression\`.
|
|
9771
10044
|
|
|
9772
10045
|
### 2. \`agent-threat-modeler\` (Threat Modeler and Security Specialist)
|
|
@@ -9925,7 +10198,7 @@ Non-Negotiable Quality Thresholds (\`quality-policy.yaml\`):
|
|
|
9925
10198
|
|
|
9926
10199
|
| Role | Mission (summary) |
|
|
9927
10200
|
| :--- | :--- |
|
|
9928
|
-
| \`agent-product-analyst\` | ProductShape artifacts (\`ACT-*\`, \`UC-*\`, \`FR-*\`, \`QR-*\`, \`BR-*\`); \`status\` starts \`draft\`. |
|
|
10201
|
+
| \`agent-product-analyst\` | Phase 0 NAF v4 Enterprise & Capability Vision (\`ARCH-INTRO-*\`, 3\u20135 question interview) + ProductShape artifacts (\`ACT-*\`, \`UC-*\`, \`FR-*\`, \`QR-*\`, \`BR-*\`); \`status\` starts \`draft\`. |
|
|
9929
10202
|
| \`agent-threat-modeler\` | STRIDE/OWASP threat triad (\`ACT-THREAT-*\`, \`ABUSE-*\`, \`SEC-REQ-*\`). |
|
|
9930
10203
|
| \`agent-system-architect\` | Modular arc42 + NAF v4 architecture (\`CMP-*\`, Mermaid diagrams, \`ADR-*\`). |
|
|
9931
10204
|
| \`agent-qa-engineer\` | FAILING BDD/Gherkin suites before \`agent-developer\` writes production code. |
|
|
@@ -10733,7 +11006,7 @@ var ALL_ARCHITECTURE_TEMPLATES = [
|
|
|
10733
11006
|
{ filename: "cross-cutting-concepts.template.md", content: STARTER_ARCH_CROSS_CUTTING_CONCEPTS, isMinimal: false },
|
|
10734
11007
|
{ filename: "deployment-view.template.md", content: STARTER_ARCH_DEPLOYMENT_VIEW, isMinimal: false },
|
|
10735
11008
|
{ filename: "glossary.template.md", content: STARTER_ARCH_GLOSSARY, isMinimal: false },
|
|
10736
|
-
{ filename: "introduction-and-goals.template.md", content: STARTER_ARCH_INTRODUCTION_AND_GOALS, isMinimal:
|
|
11009
|
+
{ filename: "introduction-and-goals.template.md", content: STARTER_ARCH_INTRODUCTION_AND_GOALS, isMinimal: true },
|
|
10737
11010
|
{ filename: "level-1-whitebox.template.md", content: STARTER_ARCH_LEVEL_1_WHITEBOX, isMinimal: false },
|
|
10738
11011
|
{ filename: "quality-requirements.template.md", content: STARTER_ARCH_QUALITY_REQUIREMENTS, isMinimal: false },
|
|
10739
11012
|
{ filename: "risks-and-technical-debt.template.md", content: STARTER_ARCH_RISKS_AND_TECHNICAL_DEBT, isMinimal: false },
|