@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.cjs
CHANGED
|
@@ -750,6 +750,12 @@ function walkMdFiles(dir, fileList = [], excludeDirs = [
|
|
|
750
750
|
"node_modules",
|
|
751
751
|
".git",
|
|
752
752
|
"dist",
|
|
753
|
+
"bin",
|
|
754
|
+
"obj",
|
|
755
|
+
"build",
|
|
756
|
+
"out",
|
|
757
|
+
"target",
|
|
758
|
+
"coverage",
|
|
753
759
|
".changeset",
|
|
754
760
|
"scratch",
|
|
755
761
|
"test-scaffold",
|
|
@@ -761,7 +767,9 @@ function walkMdFiles(dir, fileList = [], excludeDirs = [
|
|
|
761
767
|
".claude",
|
|
762
768
|
".cursor",
|
|
763
769
|
".github",
|
|
764
|
-
".vscode"
|
|
770
|
+
".vscode",
|
|
771
|
+
".vs",
|
|
772
|
+
".idea"
|
|
765
773
|
]) {
|
|
766
774
|
try {
|
|
767
775
|
if (!fs6__namespace.existsSync(dir)) return fileList;
|
|
@@ -2080,6 +2088,7 @@ var TYPE_TO_SCHEMA_MAP = {
|
|
|
2080
2088
|
"security-requirement": "schemas/security/security-req.schema.json",
|
|
2081
2089
|
"threat-actor": "schemas/security/threat-actor.schema.json",
|
|
2082
2090
|
// Architecture
|
|
2091
|
+
"architecture-introduction": "schemas/architecture/introduction-and-goals.schema.json",
|
|
2083
2092
|
"architecture-decision-record": "schemas/architecture/adr.schema.json",
|
|
2084
2093
|
component: "schemas/architecture/component.schema.json",
|
|
2085
2094
|
// Safety
|
|
@@ -2123,6 +2132,7 @@ var PREFIX_TAXONOMY = [
|
|
|
2123
2132
|
["HAZ-", "hazard"],
|
|
2124
2133
|
["SAF-REQ-", "safety-requirement"],
|
|
2125
2134
|
["SAF-", "safety-requirement"],
|
|
2135
|
+
["ARCH-INTRO-", "architecture-introduction"],
|
|
2126
2136
|
["ADR-", "architecture-decision-record"],
|
|
2127
2137
|
["CMP-", "component"],
|
|
2128
2138
|
["MAN-USER-", "user-manual"],
|
|
@@ -3312,10 +3322,18 @@ var SKIPPED_DIR_NAMES = /* @__PURE__ */ new Set([
|
|
|
3312
3322
|
"node_modules",
|
|
3313
3323
|
".git",
|
|
3314
3324
|
"dist",
|
|
3325
|
+
"bin",
|
|
3326
|
+
"obj",
|
|
3327
|
+
"build",
|
|
3328
|
+
"out",
|
|
3329
|
+
"target",
|
|
3330
|
+
"coverage",
|
|
3315
3331
|
"scratch",
|
|
3316
3332
|
"fixtures",
|
|
3317
3333
|
"templates",
|
|
3318
|
-
"examples"
|
|
3334
|
+
"examples",
|
|
3335
|
+
".vs",
|
|
3336
|
+
".idea"
|
|
3319
3337
|
]);
|
|
3320
3338
|
function shouldSkipDir(name) {
|
|
3321
3339
|
return SKIPPED_DIR_NAMES.has(name) || name.startsWith("temp-");
|
|
@@ -3417,8 +3435,14 @@ function verifyTraceability(options = {}) {
|
|
|
3417
3435
|
});
|
|
3418
3436
|
}
|
|
3419
3437
|
}
|
|
3420
|
-
|
|
3421
|
-
|
|
3438
|
+
const isArchIntro = frontmatter.type === "architecture-introduction" || frontmatter.id !== void 0 && String(frontmatter.id).trim().startsWith("ARCH-INTRO-");
|
|
3439
|
+
if (!isArchIntro && (relFile.includes("architecture/") || relFile.includes("06_runtime_view") || relFile.includes("08_security_concept") || relFile.includes("09_decisions"))) {
|
|
3440
|
+
architectureViews.push({
|
|
3441
|
+
file: relFile,
|
|
3442
|
+
id: frontmatter.id ? String(frontmatter.id).trim() : void 0,
|
|
3443
|
+
type: typeof frontmatter.type === "string" ? frontmatter.type.trim() : void 0,
|
|
3444
|
+
content
|
|
3445
|
+
});
|
|
3422
3446
|
}
|
|
3423
3447
|
} catch {
|
|
3424
3448
|
}
|
|
@@ -3501,6 +3525,14 @@ function verifyTraceability(options = {}) {
|
|
|
3501
3525
|
productTraces.push(...associatedHandoff.subgraph.abuseCases);
|
|
3502
3526
|
}
|
|
3503
3527
|
}
|
|
3528
|
+
for (const [artId, artEntry] of artifactMap.entries()) {
|
|
3529
|
+
if (artEntry.type === "architecture-introduction" || artId.startsWith("ARCH-INTRO-")) {
|
|
3530
|
+
const citedGoals = artEntry.frontmatter["cites-quality-goals"];
|
|
3531
|
+
if (Array.isArray(citedGoals) && citedGoals.includes(reqId)) {
|
|
3532
|
+
productTraces.push(artId);
|
|
3533
|
+
}
|
|
3534
|
+
}
|
|
3535
|
+
}
|
|
3504
3536
|
const validProductTraces = Array.from(
|
|
3505
3537
|
new Set(productTraces.filter((id) => artifactMap.has(id)))
|
|
3506
3538
|
);
|
|
@@ -3521,8 +3553,9 @@ function verifyTraceability(options = {}) {
|
|
|
3521
3553
|
}
|
|
3522
3554
|
for (const view of architectureViews) {
|
|
3523
3555
|
if (view.content.includes(reqId)) {
|
|
3524
|
-
const
|
|
3525
|
-
|
|
3556
|
+
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-"));
|
|
3557
|
+
const viewIdentifier = isEntityWithId && view.id ? view.id : path8__namespace.basename(view.file);
|
|
3558
|
+
if (!archTraces.includes(viewIdentifier)) archTraces.push(viewIdentifier);
|
|
3526
3559
|
}
|
|
3527
3560
|
}
|
|
3528
3561
|
const uniqueArchTraces = Array.from(new Set(archTraces));
|
|
@@ -3859,7 +3892,7 @@ function scanAllTestArtifacts(rootDir) {
|
|
|
3859
3892
|
for (const e of entries) {
|
|
3860
3893
|
const fullPath = path8__namespace.join(dir, e.name);
|
|
3861
3894
|
if (e.isDirectory()) {
|
|
3862
|
-
if (!["node_modules", ".git", "dist", ".changeset", "scratch", "fixtures", "templates", "examples"].includes(e.name)) {
|
|
3895
|
+
if (!["node_modules", ".git", "dist", "bin", "obj", "build", "out", "target", "coverage", ".changeset", "scratch", "fixtures", "templates", "examples", ".vs", ".idea"].includes(e.name)) {
|
|
3863
3896
|
walk(fullPath);
|
|
3864
3897
|
}
|
|
3865
3898
|
} else {
|
|
@@ -7164,7 +7197,31 @@ function buildGraphElements(rootDir = process.cwd()) {
|
|
|
7164
7197
|
for (const n of pdac.drifts) {
|
|
7165
7198
|
driftTargets.add(n.targetId);
|
|
7166
7199
|
}
|
|
7200
|
+
const NON_GRAPH_TYPES = /* @__PURE__ */ new Set([
|
|
7201
|
+
"term",
|
|
7202
|
+
"handoff",
|
|
7203
|
+
"agent-handoff",
|
|
7204
|
+
"tasks",
|
|
7205
|
+
"task-plan",
|
|
7206
|
+
"spec-change-proposal",
|
|
7207
|
+
"proposal",
|
|
7208
|
+
"spec-design",
|
|
7209
|
+
"spec-change-design",
|
|
7210
|
+
"design",
|
|
7211
|
+
"delivery-spec",
|
|
7212
|
+
"spec",
|
|
7213
|
+
"pre-merge-audit-report",
|
|
7214
|
+
"user-design-feedback",
|
|
7215
|
+
"release-kpis",
|
|
7216
|
+
"session-telemetry",
|
|
7217
|
+
"license-manifest",
|
|
7218
|
+
"mcp-config",
|
|
7219
|
+
"user-manual",
|
|
7220
|
+
"production-manual",
|
|
7221
|
+
"architecture-glossary"
|
|
7222
|
+
]);
|
|
7167
7223
|
const scannedArtifactsMap = /* @__PURE__ */ new Map();
|
|
7224
|
+
const archViewByBasename = /* @__PURE__ */ new Map();
|
|
7168
7225
|
const artifactDirs = ["product", "architecture", "specs", "security"];
|
|
7169
7226
|
for (const dirName of artifactDirs) {
|
|
7170
7227
|
const fullDirPath = path8__namespace.join(rootDir, dirName);
|
|
@@ -7174,6 +7231,7 @@ function buildGraphElements(rootDir = process.cwd()) {
|
|
|
7174
7231
|
try {
|
|
7175
7232
|
const fileContent = fs6__namespace.readFileSync(f, "utf-8");
|
|
7176
7233
|
const relPath = path8__namespace.relative(rootDir, f).replace(/\\/g, "/");
|
|
7234
|
+
if (relPath.includes("/changes/") || relPath.startsWith("changes/")) continue;
|
|
7177
7235
|
const match = fileContent.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
7178
7236
|
if (!match) continue;
|
|
7179
7237
|
let fm = {};
|
|
@@ -7185,8 +7243,14 @@ function buildGraphElements(rootDir = process.cwd()) {
|
|
|
7185
7243
|
const id = typeof fm.id === "string" ? fm.id.trim() : void 0;
|
|
7186
7244
|
if (!id) continue;
|
|
7187
7245
|
let type = typeof fm.type === "string" ? fm.type.trim() : "";
|
|
7246
|
+
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-")) {
|
|
7247
|
+
continue;
|
|
7248
|
+
}
|
|
7188
7249
|
let layer = "product";
|
|
7189
|
-
if (id.startsWith("
|
|
7250
|
+
if (id.startsWith("ARCH-INTRO-") || type === "architecture-introduction") {
|
|
7251
|
+
type = "architecture-introduction";
|
|
7252
|
+
layer = "product";
|
|
7253
|
+
} else if (id.startsWith("JRN-") || type === "journey") {
|
|
7190
7254
|
type = "journey";
|
|
7191
7255
|
layer = "product";
|
|
7192
7256
|
} else if (id.startsWith("ACT-THREAT-") || type === "threat-actor") {
|
|
@@ -7219,16 +7283,19 @@ function buildGraphElements(rootDir = process.cwd()) {
|
|
|
7219
7283
|
} else if (id.startsWith("SEC-REQ-") || type === "security-requirement") {
|
|
7220
7284
|
type = "security-requirement";
|
|
7221
7285
|
layer = "requirement";
|
|
7222
|
-
} else if (id.startsWith("FR-") || id.startsWith("QR-") || id.startsWith("CON-") || type === "requirement") {
|
|
7286
|
+
} else if (id.startsWith("FR-") || id.startsWith("QR-") || id.startsWith("CON-") || type === "requirement" || type === "functional-requirement" || type === "quality-requirement") {
|
|
7223
7287
|
type = "requirement";
|
|
7224
7288
|
layer = "requirement";
|
|
7289
|
+
} else if (id.startsWith("ARCH-") || relPath.includes("architecture/")) {
|
|
7290
|
+
type = "architecture";
|
|
7291
|
+
layer = "architecture";
|
|
7225
7292
|
} else {
|
|
7226
7293
|
type = type || "product";
|
|
7227
7294
|
layer = "product";
|
|
7228
7295
|
}
|
|
7229
7296
|
const title = typeof fm.title === "string" ? fm.title.trim() : id;
|
|
7230
7297
|
const content = fileContent.replace(/^---\r?\n[\s\S]*?\r?\n---/, "").trim();
|
|
7231
|
-
|
|
7298
|
+
const scannedArt = {
|
|
7232
7299
|
id,
|
|
7233
7300
|
type,
|
|
7234
7301
|
title,
|
|
@@ -7236,7 +7303,12 @@ function buildGraphElements(rootDir = process.cwd()) {
|
|
|
7236
7303
|
filePath: relPath,
|
|
7237
7304
|
content,
|
|
7238
7305
|
frontmatter: fm
|
|
7239
|
-
}
|
|
7306
|
+
};
|
|
7307
|
+
if (layer === "architecture" && type === "architecture") {
|
|
7308
|
+
archViewByBasename.set(path8__namespace.basename(relPath), scannedArt);
|
|
7309
|
+
} else {
|
|
7310
|
+
scannedArtifactsMap.set(id, scannedArt);
|
|
7311
|
+
}
|
|
7240
7312
|
} catch {
|
|
7241
7313
|
}
|
|
7242
7314
|
}
|
|
@@ -7245,7 +7317,7 @@ function buildGraphElements(rootDir = process.cwd()) {
|
|
|
7245
7317
|
for (const r of trace.rows) {
|
|
7246
7318
|
const isOk = (r.productStatus === "COMPLIANT" || r.productStatus === "CONFORME") && (r.archStatus === "COMPLIANT" || r.archStatus === "CONFORME") && (r.testStatus === "COMPLIANT" || r.testStatus === "CONFORME");
|
|
7247
7319
|
const status = isOk ? "COMPLIANT" : "ORPHAN";
|
|
7248
|
-
const reqType = r.id.startsWith("SEC-REQ-") ? "security-requirement" :
|
|
7320
|
+
const reqType = r.id.startsWith("SEC-REQ-") ? "security-requirement" : "requirement";
|
|
7249
7321
|
nodeMap.set(r.id, {
|
|
7250
7322
|
id: r.id,
|
|
7251
7323
|
label: r.id,
|
|
@@ -7271,16 +7343,18 @@ function buildGraphElements(rootDir = process.cwd()) {
|
|
|
7271
7343
|
const u = up.trim();
|
|
7272
7344
|
if (u && u !== "NINGUNO" && u !== "NONE") {
|
|
7273
7345
|
const isAbuse = u.startsWith("ABUSE-");
|
|
7346
|
+
const isArchIntro = u.startsWith("ARCH-INTRO-");
|
|
7347
|
+
const rel = isAbuse ? "mitigated-by" : isArchIntro ? "defines-goal" : "derives-from";
|
|
7274
7348
|
addEdge({
|
|
7275
7349
|
id: `edge-${u}-${r.id}`,
|
|
7276
7350
|
source: u,
|
|
7277
7351
|
target: r.id,
|
|
7278
|
-
label:
|
|
7279
|
-
relation:
|
|
7352
|
+
label: rel,
|
|
7353
|
+
relation: rel,
|
|
7280
7354
|
status
|
|
7281
7355
|
});
|
|
7282
7356
|
if (!nodeMap.has(u)) {
|
|
7283
|
-
const upType = u.startsWith("ACT-") ? "actor" : u.startsWith("UC-") ? "use-case" : u.startsWith("BR-") ? "business-rule" : u.startsWith("ABUSE-") ? "abuse-case" : "product";
|
|
7357
|
+
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";
|
|
7284
7358
|
nodeMap.set(u, {
|
|
7285
7359
|
id: u,
|
|
7286
7360
|
label: u,
|
|
@@ -7305,13 +7379,16 @@ function buildGraphElements(rootDir = process.cwd()) {
|
|
|
7305
7379
|
});
|
|
7306
7380
|
if (!nodeMap.has(a)) {
|
|
7307
7381
|
const aType = a.startsWith("CMP-") ? "component" : a.startsWith("ADR-") ? "adr" : a.startsWith("SEC-ENC-") ? "security-enclave" : "architecture";
|
|
7382
|
+
const viewArt = archViewByBasename.get(a);
|
|
7308
7383
|
nodeMap.set(a, {
|
|
7309
7384
|
id: a,
|
|
7310
7385
|
label: a,
|
|
7311
|
-
title: a,
|
|
7386
|
+
title: viewArt?.title || a,
|
|
7312
7387
|
type: aType,
|
|
7313
7388
|
layer: "architecture",
|
|
7314
|
-
status: "COMPLIANT"
|
|
7389
|
+
status: "COMPLIANT",
|
|
7390
|
+
filePath: viewArt?.filePath,
|
|
7391
|
+
content: viewArt?.content
|
|
7315
7392
|
});
|
|
7316
7393
|
}
|
|
7317
7394
|
}
|
|
@@ -7375,7 +7452,80 @@ function buildGraphElements(rootDir = process.cwd()) {
|
|
|
7375
7452
|
}
|
|
7376
7453
|
for (const art of scannedArtifactsMap.values()) {
|
|
7377
7454
|
const fm = art.frontmatter;
|
|
7378
|
-
if (art.type === "
|
|
7455
|
+
if (art.type === "architecture-introduction") {
|
|
7456
|
+
const citedActors = Array.isArray(fm["cites-product-actors"]) ? fm["cites-product-actors"] : [];
|
|
7457
|
+
for (const actId of citedActors) {
|
|
7458
|
+
if (typeof actId === "string" && actId.trim()) {
|
|
7459
|
+
const a = actId.trim();
|
|
7460
|
+
if (!nodeMap.has(a)) {
|
|
7461
|
+
nodeMap.set(a, {
|
|
7462
|
+
id: a,
|
|
7463
|
+
label: a,
|
|
7464
|
+
title: a,
|
|
7465
|
+
type: "actor",
|
|
7466
|
+
layer: "product",
|
|
7467
|
+
status: "COMPLIANT"
|
|
7468
|
+
});
|
|
7469
|
+
}
|
|
7470
|
+
addEdge({
|
|
7471
|
+
id: `edge-${art.id}-${a}`,
|
|
7472
|
+
source: art.id,
|
|
7473
|
+
target: a,
|
|
7474
|
+
label: "identifies",
|
|
7475
|
+
relation: "identifies",
|
|
7476
|
+
status: "COMPLIANT"
|
|
7477
|
+
});
|
|
7478
|
+
}
|
|
7479
|
+
}
|
|
7480
|
+
const citedUcs = Array.isArray(fm["cites-use-cases"]) ? fm["cites-use-cases"] : [];
|
|
7481
|
+
for (const ucId of citedUcs) {
|
|
7482
|
+
if (typeof ucId === "string" && ucId.trim()) {
|
|
7483
|
+
const u = ucId.trim();
|
|
7484
|
+
if (!nodeMap.has(u)) {
|
|
7485
|
+
nodeMap.set(u, {
|
|
7486
|
+
id: u,
|
|
7487
|
+
label: u,
|
|
7488
|
+
title: u,
|
|
7489
|
+
type: "use-case",
|
|
7490
|
+
layer: "product",
|
|
7491
|
+
status: "COMPLIANT"
|
|
7492
|
+
});
|
|
7493
|
+
}
|
|
7494
|
+
addEdge({
|
|
7495
|
+
id: `edge-${art.id}-${u}`,
|
|
7496
|
+
source: art.id,
|
|
7497
|
+
target: u,
|
|
7498
|
+
label: "envisions",
|
|
7499
|
+
relation: "envisions",
|
|
7500
|
+
status: "COMPLIANT"
|
|
7501
|
+
});
|
|
7502
|
+
}
|
|
7503
|
+
}
|
|
7504
|
+
const citedGoals = Array.isArray(fm["cites-quality-goals"]) ? fm["cites-quality-goals"] : [];
|
|
7505
|
+
for (const qrId of citedGoals) {
|
|
7506
|
+
if (typeof qrId === "string" && qrId.trim()) {
|
|
7507
|
+
const q = qrId.trim();
|
|
7508
|
+
if (!nodeMap.has(q)) {
|
|
7509
|
+
nodeMap.set(q, {
|
|
7510
|
+
id: q,
|
|
7511
|
+
label: q,
|
|
7512
|
+
title: q,
|
|
7513
|
+
type: q.startsWith("SEC-REQ-") ? "security-requirement" : "requirement",
|
|
7514
|
+
layer: "requirement",
|
|
7515
|
+
status: "COMPLIANT"
|
|
7516
|
+
});
|
|
7517
|
+
}
|
|
7518
|
+
addEdge({
|
|
7519
|
+
id: `edge-${art.id}-${q}`,
|
|
7520
|
+
source: art.id,
|
|
7521
|
+
target: q,
|
|
7522
|
+
label: "defines-goal",
|
|
7523
|
+
relation: "defines-goal",
|
|
7524
|
+
status: "COMPLIANT"
|
|
7525
|
+
});
|
|
7526
|
+
}
|
|
7527
|
+
}
|
|
7528
|
+
} else if (art.type === "journey") {
|
|
7379
7529
|
const persona = typeof fm.persona === "string" ? fm.persona : typeof fm.actor === "string" ? fm.actor : void 0;
|
|
7380
7530
|
if (persona) {
|
|
7381
7531
|
if (!nodeMap.has(persona)) {
|
|
@@ -7443,7 +7593,31 @@ function buildGraphElements(rootDir = process.cwd()) {
|
|
|
7443
7593
|
status: "COMPLIANT"
|
|
7444
7594
|
});
|
|
7445
7595
|
}
|
|
7446
|
-
const
|
|
7596
|
+
const supportingActors = Array.isArray(fm["supporting-actors"]) ? fm["supporting-actors"] : Array.isArray(fm["secondary-actors"]) ? fm["secondary-actors"] : [];
|
|
7597
|
+
for (const actorId of supportingActors) {
|
|
7598
|
+
if (typeof actorId === "string" && actorId.trim()) {
|
|
7599
|
+
const a = actorId.trim();
|
|
7600
|
+
if (!nodeMap.has(a)) {
|
|
7601
|
+
nodeMap.set(a, {
|
|
7602
|
+
id: a,
|
|
7603
|
+
label: a,
|
|
7604
|
+
title: a,
|
|
7605
|
+
type: "actor",
|
|
7606
|
+
layer: "product",
|
|
7607
|
+
status: "COMPLIANT"
|
|
7608
|
+
});
|
|
7609
|
+
}
|
|
7610
|
+
addEdge({
|
|
7611
|
+
id: `edge-${a}-${art.id}`,
|
|
7612
|
+
source: a,
|
|
7613
|
+
target: art.id,
|
|
7614
|
+
label: "initiates",
|
|
7615
|
+
relation: "initiates",
|
|
7616
|
+
status: "COMPLIANT"
|
|
7617
|
+
});
|
|
7618
|
+
}
|
|
7619
|
+
}
|
|
7620
|
+
const governedBy = Array.isArray(fm["governed-by"]) ? fm["governed-by"] : Array.isArray(fm["business-rules"]) ? fm["business-rules"] : [];
|
|
7447
7621
|
for (const ruleId of governedBy) {
|
|
7448
7622
|
if (typeof ruleId === "string" && ruleId.trim()) {
|
|
7449
7623
|
const r = ruleId.trim();
|
|
@@ -7504,7 +7678,31 @@ function buildGraphElements(rootDir = process.cwd()) {
|
|
|
7504
7678
|
status: "COMPLIANT"
|
|
7505
7679
|
});
|
|
7506
7680
|
}
|
|
7507
|
-
const
|
|
7681
|
+
const secondaryThreatActors = Array.isArray(fm["secondary-actors"]) ? fm["secondary-actors"] : Array.isArray(fm["supporting-actors"]) ? fm["supporting-actors"] : [];
|
|
7682
|
+
for (const secActor of secondaryThreatActors) {
|
|
7683
|
+
if (typeof secActor === "string" && secActor.trim()) {
|
|
7684
|
+
const sa = secActor.trim();
|
|
7685
|
+
if (!nodeMap.has(sa)) {
|
|
7686
|
+
nodeMap.set(sa, {
|
|
7687
|
+
id: sa,
|
|
7688
|
+
label: sa,
|
|
7689
|
+
title: sa,
|
|
7690
|
+
type: sa.startsWith("ACT-THREAT-") ? "threat-actor" : "actor",
|
|
7691
|
+
layer: "product",
|
|
7692
|
+
status: "COMPLIANT"
|
|
7693
|
+
});
|
|
7694
|
+
}
|
|
7695
|
+
addEdge({
|
|
7696
|
+
id: `edge-${sa}-${art.id}`,
|
|
7697
|
+
source: sa,
|
|
7698
|
+
target: art.id,
|
|
7699
|
+
label: "threatens",
|
|
7700
|
+
relation: "threatens",
|
|
7701
|
+
status: "COMPLIANT"
|
|
7702
|
+
});
|
|
7703
|
+
}
|
|
7704
|
+
}
|
|
7705
|
+
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"] : [];
|
|
7508
7706
|
for (const tgt of rawTargets) {
|
|
7509
7707
|
if (typeof tgt === "string" && tgt.trim()) {
|
|
7510
7708
|
const t = tgt.trim();
|
|
@@ -7569,6 +7767,40 @@ function buildGraphElements(rootDir = process.cwd()) {
|
|
|
7569
7767
|
});
|
|
7570
7768
|
}
|
|
7571
7769
|
}
|
|
7770
|
+
} else if (art.type === "adr") {
|
|
7771
|
+
const affectedComponents = Array.isArray(fm["affects-components"]) ? fm["affects-components"] : typeof fm["affects-components"] === "string" ? [fm["affects-components"]] : [];
|
|
7772
|
+
for (const cmpId of affectedComponents) {
|
|
7773
|
+
if (typeof cmpId === "string" && cmpId.trim()) {
|
|
7774
|
+
const c = cmpId.trim();
|
|
7775
|
+
if (nodeMap.has(c)) {
|
|
7776
|
+
addEdge({
|
|
7777
|
+
id: `edge-${art.id}-${c}`,
|
|
7778
|
+
source: art.id,
|
|
7779
|
+
target: c,
|
|
7780
|
+
label: "governs",
|
|
7781
|
+
relation: "governs",
|
|
7782
|
+
status: "COMPLIANT"
|
|
7783
|
+
});
|
|
7784
|
+
}
|
|
7785
|
+
}
|
|
7786
|
+
}
|
|
7787
|
+
} else if (art.type === "security-enclave") {
|
|
7788
|
+
const enforcedBy = Array.isArray(fm["enforced-by"]) ? fm["enforced-by"] : typeof fm["enforced-by"] === "string" ? [fm["enforced-by"]] : [];
|
|
7789
|
+
for (const secReq of enforcedBy) {
|
|
7790
|
+
if (typeof secReq === "string" && secReq.trim()) {
|
|
7791
|
+
const s = secReq.trim();
|
|
7792
|
+
if (nodeMap.has(s)) {
|
|
7793
|
+
addEdge({
|
|
7794
|
+
id: `edge-${s}-${art.id}`,
|
|
7795
|
+
source: s,
|
|
7796
|
+
target: art.id,
|
|
7797
|
+
label: "satisfies",
|
|
7798
|
+
relation: "satisfies",
|
|
7799
|
+
status: "COMPLIANT"
|
|
7800
|
+
});
|
|
7801
|
+
}
|
|
7802
|
+
}
|
|
7803
|
+
}
|
|
7572
7804
|
}
|
|
7573
7805
|
}
|
|
7574
7806
|
for (const [id, node] of nodeMap.entries()) {
|
|
@@ -7718,6 +7950,9 @@ function collectDashboardMetrics(rootDir) {
|
|
|
7718
7950
|
function escapeHtml(str) {
|
|
7719
7951
|
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
7720
7952
|
}
|
|
7953
|
+
function safeJsonForScript(data) {
|
|
7954
|
+
return JSON.stringify(data).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
7955
|
+
}
|
|
7721
7956
|
function renderAutonomyModeSection(mode, statusIcon, count, roleDescription, allTasks = []) {
|
|
7722
7957
|
const modeTasks = (allTasks || []).filter(
|
|
7723
7958
|
(t) => (t.task?.autonomyMode || "").toUpperCase() === mode
|
|
@@ -7829,14 +8064,14 @@ function renderAutonomyModeSection(mode, statusIcon, count, roleDescription, all
|
|
|
7829
8064
|
}
|
|
7830
8065
|
function renderDashboardHtml(graphData, metricsData, title = "AI-SDLC: Dashboard Interactivo de Trazabilidad y Calidad") {
|
|
7831
8066
|
const cytoscapeScript = getCytoscapeScript();
|
|
7832
|
-
const elementsJson =
|
|
8067
|
+
const elementsJson = safeJsonForScript(graphData.elements);
|
|
7833
8068
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7834
8069
|
return `<!DOCTYPE html>
|
|
7835
8070
|
<html lang="es">
|
|
7836
8071
|
<head>
|
|
7837
8072
|
<meta charset="UTF-8">
|
|
7838
8073
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7839
|
-
<title>${title}</title>
|
|
8074
|
+
<title>${escapeHtml(title)}</title>
|
|
7840
8075
|
<style>
|
|
7841
8076
|
:root {
|
|
7842
8077
|
--bg-dark: #0f172a;
|
|
@@ -8139,6 +8374,7 @@ function renderDashboardHtml(graphData, metricsData, title = "AI-SDLC: Dashboard
|
|
|
8139
8374
|
<div class="tool-row">
|
|
8140
8375
|
<select id="type-filter" class="tool-select" onchange="filterType(this.value)">
|
|
8141
8376
|
<option value="all">All Typologies</option>
|
|
8377
|
+
<option value="architecture-introduction">Vision & Goals (ARCH-INTRO)</option>
|
|
8142
8378
|
<option value="journey">Journeys (JRN)</option>
|
|
8143
8379
|
<option value="actor">Actors (ACT)</option>
|
|
8144
8380
|
<option value="use-case">Use Cases (UC)</option>
|
|
@@ -8173,6 +8409,7 @@ function renderDashboardHtml(graphData, metricsData, title = "AI-SDLC: Dashboard
|
|
|
8173
8409
|
<div class="graph-legend">
|
|
8174
8410
|
<div class="legend-header">Node Typologies</div>
|
|
8175
8411
|
<div class="legend-items">
|
|
8412
|
+
<div class="legend-item"><span class="legend-dot" style="background:#0f766e; border:2px solid #2dd4bf;"></span><strong>Vision / Goals</strong> (ARCH-INTRO)</div>
|
|
8176
8413
|
<div class="legend-item"><span class="legend-dot" style="background:#581c87; border:2px solid #c084fc;"></span><strong>Journey</strong> (JRN)</div>
|
|
8177
8414
|
<div class="legend-item"><span class="legend-dot" style="background:#065f46; border:2px solid #34d399; border-radius:50%;"></span><strong>Actor</strong> (ACT)</div>
|
|
8178
8415
|
<div class="legend-item"><span class="legend-dot" style="background:#0369a1; border:2px solid #38bdf8;"></span><strong>Use Case</strong> (UC)</div>
|
|
@@ -8211,12 +8448,12 @@ function renderDashboardHtml(graphData, metricsData, title = "AI-SDLC: Dashboard
|
|
|
8211
8448
|
${metricsData.trace.rows.map((r) => {
|
|
8212
8449
|
const isRowOk = (r.productStatus === "COMPLIANT" || r.productStatus === "CONFORME") && (r.archStatus === "COMPLIANT" || r.archStatus === "CONFORME") && (r.testStatus === "COMPLIANT" || r.testStatus === "CONFORME");
|
|
8213
8450
|
return `
|
|
8214
|
-
<tr onclick="focusNode('${r.id}')" onmouseenter="startRowTooltip(event, '${r.id}')" onmouseleave="cancelRowTooltip()" onmousemove="updateRowTooltipPos(event)" style="cursor: pointer;">
|
|
8215
|
-
<td><strong><code>${r.id}</code></strong></td>
|
|
8216
|
-
<td>${r.title}</td>
|
|
8217
|
-
<td><code>${r.productTraces}</code></td>
|
|
8218
|
-
<td><code>${r.archTraces}</code></td>
|
|
8219
|
-
<td><code>${r.testTraces}</code></td>
|
|
8451
|
+
<tr onclick="focusNode('${escapeHtml(String(r.id || ""))}')" onmouseenter="startRowTooltip(event, '${escapeHtml(String(r.id || ""))}')" onmouseleave="cancelRowTooltip()" onmousemove="updateRowTooltipPos(event)" style="cursor: pointer;">
|
|
8452
|
+
<td><strong><code>${escapeHtml(String(r.id || ""))}</code></strong></td>
|
|
8453
|
+
<td>${escapeHtml(String(r.title || ""))}</td>
|
|
8454
|
+
<td><code>${escapeHtml(String(r.productTraces || ""))}</code></td>
|
|
8455
|
+
<td><code>${escapeHtml(String(r.archTraces || ""))}</code></td>
|
|
8456
|
+
<td><code>${escapeHtml(String(r.testTraces || ""))}</code></td>
|
|
8220
8457
|
<td><span class="badge ${isRowOk ? "badge-green" : "badge-amber"}">${isRowOk ? "COMPLIANT" : "ORPHAN"}</span></td>
|
|
8221
8458
|
</tr>
|
|
8222
8459
|
`;
|
|
@@ -8429,7 +8666,7 @@ function renderDashboardHtml(graphData, metricsData, title = "AI-SDLC: Dashboard
|
|
|
8429
8666
|
</script>
|
|
8430
8667
|
<script>
|
|
8431
8668
|
var elements = ${elementsJson};
|
|
8432
|
-
var govTasks = ${
|
|
8669
|
+
var govTasks = ${safeJsonForScript(metricsData.gov.tasks || [])};
|
|
8433
8670
|
var cy = null;
|
|
8434
8671
|
|
|
8435
8672
|
var reqHoverTimer = null;
|
|
@@ -8592,6 +8829,19 @@ function renderDashboardHtml(graphData, metricsData, title = "AI-SDLC: Dashboard
|
|
|
8592
8829
|
}
|
|
8593
8830
|
},
|
|
8594
8831
|
// Typology Styles
|
|
8832
|
+
{
|
|
8833
|
+
selector: 'node.type-architecture-introduction',
|
|
8834
|
+
style: {
|
|
8835
|
+
'shape': 'round-rectangle',
|
|
8836
|
+
'background-color': '#0f766e',
|
|
8837
|
+
'border-color': '#2dd4bf',
|
|
8838
|
+
'border-width': 3,
|
|
8839
|
+
'width': 92,
|
|
8840
|
+
'height': 44,
|
|
8841
|
+
'font-weight': 'bold',
|
|
8842
|
+
'text-max-width': '86px'
|
|
8843
|
+
}
|
|
8844
|
+
},
|
|
8595
8845
|
{
|
|
8596
8846
|
selector: 'node.type-journey',
|
|
8597
8847
|
style: {
|
|
@@ -8708,7 +8958,7 @@ function renderDashboardHtml(graphData, metricsData, title = "AI-SDLC: Dashboard
|
|
|
8708
8958
|
},
|
|
8709
8959
|
// Fallback Layer styles if type is missing
|
|
8710
8960
|
{
|
|
8711
|
-
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)',
|
|
8961
|
+
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)',
|
|
8712
8962
|
style: { 'shape': 'diamond', 'background-color': '#0e7490', 'border-color': '#38bdf8', 'width': 50, 'height': 50 }
|
|
8713
8963
|
},
|
|
8714
8964
|
{
|
|
@@ -8737,6 +8987,10 @@ function renderDashboardHtml(graphData, metricsData, title = "AI-SDLC: Dashboard
|
|
|
8737
8987
|
}
|
|
8738
8988
|
},
|
|
8739
8989
|
// Semantic Edge Relations
|
|
8990
|
+
{
|
|
8991
|
+
selector: 'edge.relation-identifies, edge.relation-envisions, edge.relation-defines-goal',
|
|
8992
|
+
style: { 'line-color': '#2dd4bf', 'target-arrow-color': '#2dd4bf', 'width': 2 }
|
|
8993
|
+
},
|
|
8740
8994
|
{
|
|
8741
8995
|
selector: 'edge.relation-pursues',
|
|
8742
8996
|
style: { 'line-color': '#c084fc', 'target-arrow-color': '#c084fc', 'width': 2 }
|
|
@@ -8877,7 +9131,10 @@ function renderDashboardHtml(graphData, metricsData, title = "AI-SDLC: Dashboard
|
|
|
8877
9131
|
var typeName = (data.type || data.layer || 'node').toLowerCase();
|
|
8878
9132
|
var typeBadgeColor = '#334155';
|
|
8879
9133
|
var typeTitle = (data.type || data.layer || 'NODE').toUpperCase();
|
|
8880
|
-
if (typeName === '
|
|
9134
|
+
if (typeName === 'architecture-introduction') {
|
|
9135
|
+
typeBadgeColor = '#0f766e';
|
|
9136
|
+
typeTitle = 'VISION & GOALS (ARCH-INTRO)';
|
|
9137
|
+
} else if (typeName === 'journey') {
|
|
8881
9138
|
typeBadgeColor = '#581c87';
|
|
8882
9139
|
typeTitle = 'JOURNEY (JRN)';
|
|
8883
9140
|
} else if (typeName === 'actor') {
|
|
@@ -8943,6 +9200,11 @@ function renderDashboardHtml(graphData, metricsData, title = "AI-SDLC: Dashboard
|
|
|
8943
9200
|
if (!cy) return;
|
|
8944
9201
|
if (type === 'all') {
|
|
8945
9202
|
cy.elements().show();
|
|
9203
|
+
} else if (type === 'architecture-introduction') {
|
|
9204
|
+
cy.elements().hide();
|
|
9205
|
+
var nodes = cy.nodes('.type-architecture-introduction');
|
|
9206
|
+
nodes.show();
|
|
9207
|
+
nodes.connectedEdges().show();
|
|
8946
9208
|
} else if (type === 'journey') {
|
|
8947
9209
|
cy.elements().hide();
|
|
8948
9210
|
var nodes = cy.nodes('.type-journey');
|
|
@@ -9062,9 +9324,10 @@ function renderDashboardHtml(graphData, metricsData, title = "AI-SDLC: Dashboard
|
|
|
9062
9324
|
|
|
9063
9325
|
function switchTab(name) {
|
|
9064
9326
|
hideTooltip();
|
|
9065
|
-
document.querySelectorAll('.tab-btn').forEach(function(b) {
|
|
9327
|
+
document.querySelectorAll('.tab-btn').forEach(function(b) {
|
|
9328
|
+
b.classList.toggle('active', b.getAttribute('onclick') === "switchTab('" + name + "')");
|
|
9329
|
+
});
|
|
9066
9330
|
document.querySelectorAll('.tab-panel').forEach(function(p) { p.classList.remove('active'); });
|
|
9067
|
-
event.target?.classList?.add('active');
|
|
9068
9331
|
var p = document.getElementById('tab-' + name);
|
|
9069
9332
|
if (p) p.classList.add('active');
|
|
9070
9333
|
if (name === 'graph' && cy) {
|
|
@@ -9278,14 +9541,20 @@ var SPECIALIZED_AGENT_TEMPLATES = [
|
|
|
9278
9541
|
{
|
|
9279
9542
|
id: "agent-product-analyst",
|
|
9280
9543
|
title: "Product Analyst / Scribe",
|
|
9281
|
-
description: "Assist the human Product Owner in exploring, modeling, and refining product definition using ProductShape (ACT-*, UC-*, FR-*, QR-*, BR-*).",
|
|
9282
|
-
globs: "product/**, specs/product/**, templates/product
|
|
9544
|
+
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-*).",
|
|
9545
|
+
globs: "product/**, specs/product/**, templates/product/**, templates/architecture/introduction-and-goals.template.md",
|
|
9283
9546
|
body: `## Role & Mission
|
|
9284
9547
|
- **Role**: Product Analyst Agent (\`agent-product-analyst\`) and Technical Scribe (AI as Scribe) of the AI-SDLC framework.
|
|
9285
|
-
- **Mission**:
|
|
9548
|
+
- **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.
|
|
9549
|
+
|
|
9550
|
+
## Phase 0: Greenfield Product Inception (New Product Intent)
|
|
9551
|
+
- **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:
|
|
9552
|
+
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-*\`).
|
|
9553
|
+
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\`).
|
|
9554
|
+
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.
|
|
9286
9555
|
|
|
9287
9556
|
## Operational Directives & Guardrails
|
|
9288
|
-
- Every generated artifact must strictly adhere to the canonical Markdown and YAML frontmatter format in \`schemas/product
|
|
9557
|
+
- 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\`.
|
|
9289
9558
|
- \`status\` ALWAYS starts as \`draft\`. Creating artifacts directly as \`active\` or \`approved\` is forbidden.
|
|
9290
9559
|
- Always write relationships in their single canonical direction (\`derives-from: [UC-*]\`, \`primary-actor: ACT-*\`).
|
|
9291
9560
|
- In \`UC-*\`, format section \`1. Intent and Outcome\` under the standard English structure: \`As a <ACT-ID>... I want <action>... To <outcome>...\`.
|
|
@@ -9533,9 +9802,10 @@ This file defines the operational rules and specialized role mappings for Google
|
|
|
9533
9802
|
## 2. Specialized Roles Mapping
|
|
9534
9803
|
|
|
9535
9804
|
### 1. \`agent-product-analyst\` (Product Analyst / Scribe)
|
|
9536
|
-
- **Mission**:
|
|
9805
|
+
- **Mission**: Capture new product intent via NAF v4 Enterprise & Capability Vision (\`ARCH-INTRO-*\`) and define/refine the product model using ProductShape.
|
|
9806
|
+
- **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.
|
|
9537
9807
|
- **Input**: Business intent or natural language specification.
|
|
9538
|
-
- **Output**: Markdown artifacts with YAML frontmatter compliant with \`schemas/product/\` (\`ACT-*\`, \`UC-*\`, \`FR-*\`, \`QR-*\`, \`BR-*\`).
|
|
9808
|
+
- **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-*\`).
|
|
9539
9809
|
- **Guardrails**:
|
|
9540
9810
|
- \`status\` always starts in \`draft\`.
|
|
9541
9811
|
- In \`UC-*\`, format section \`1. Intent and Outcome\` under the standard English structure: \`As a <ACT-ID>... I want <action>... To <outcome>...\`.
|
|
@@ -9666,7 +9936,7 @@ Before finalizing changes or proposing commits:
|
|
|
9666
9936
|
## 4. Specialized Roles Mapping
|
|
9667
9937
|
| Role | Mission (summary) |
|
|
9668
9938
|
| :--- | :--- |
|
|
9669
|
-
| \`agent-product-analyst\` | ProductShape artifacts (\`ACT-*\`, \`UC-*\`, \`FR-*\`, \`QR-*\`, \`BR-*\`); status starts \`draft\`. |
|
|
9939
|
+
| \`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\`. |
|
|
9670
9940
|
| \`agent-threat-modeler\` | STRIDE/OWASP threat triad (\`ACT-THREAT-*\`, \`ABUSE-*\`, \`SEC-REQ-*\`). |
|
|
9671
9941
|
| \`agent-system-architect\` | Modular arc42 + NAF v4 architecture (\`CMP-*\`, Mermaid diagrams, \`ADR-*\`). |
|
|
9672
9942
|
| \`agent-qa-engineer\` | FAILING BDD/Gherkin suites before \`agent-developer\` writes code. |
|
|
@@ -9701,6 +9971,7 @@ Canonical Reference: [\`process/09_agent_protocols.md\`](process/09_agent_protoc
|
|
|
9701
9971
|
|
|
9702
9972
|
## 1. Identifier Taxonomy and JSON Schemas
|
|
9703
9973
|
Every generated or modified artifact must follow canonical naming and satisfy its schema in \`schemas/\`:
|
|
9974
|
+
- Enterprise & Capability Vision (Phase 0): \`ARCH-INTRO-[NUM3]\` (\`schemas/architecture/introduction-and-goals.schema.json\`)
|
|
9704
9975
|
- Product Actors: \`ACT-[SUFFIX]\` (\`schemas/product/actor.schema.json\`)
|
|
9705
9976
|
- Use Cases: \`UC-[SUFFIX]\` (\`schemas/product/use-case.schema.json\`)
|
|
9706
9977
|
- Functional Requirements: \`FR-[SUFFIX]-[NUM3]\` (\`schemas/product/requirement.schema.json\`)
|
|
@@ -9711,6 +9982,7 @@ Every generated or modified artifact must follow canonical naming and satisfy it
|
|
|
9711
9982
|
- Security Requirements: \`SEC-REQ-[SUFFIX]\` (\`schemas/security/security-req.schema.json\`)
|
|
9712
9983
|
|
|
9713
9984
|
## 2. "AI as Scribe" Protocol Rules
|
|
9985
|
+
- **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-*\`.
|
|
9714
9986
|
- **Initial Status**: Every new artifact strictly starts with \`status: draft\`. Creating artifacts directly as \`active\` or \`approved\` is forbidden.
|
|
9715
9987
|
- **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.
|
|
9716
9988
|
- **Security Mitigations**: Every \`SEC-REQ-*\` must include negative Gherkin tests (\`@security @mitigation\`).
|
|
@@ -9792,9 +10064,10 @@ npx tsx packages/cli/src/index.ts sdd integrate --change <chg-id>
|
|
|
9792
10064
|
## 3. Specialized Roles Mapping
|
|
9793
10065
|
|
|
9794
10066
|
### 1. \`agent-product-analyst\` (Product Analyst / Scribe)
|
|
9795
|
-
- **Mission**:
|
|
10067
|
+
- **Mission**: Capture new product intent via NAF v4 Enterprise & Capability Vision (\`ARCH-INTRO-*\`) and define/refine the product model using ProductShape.
|
|
10068
|
+
- **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.
|
|
9796
10069
|
- **Input**: Business intent or natural language specification.
|
|
9797
|
-
- **Output**: Markdown artifacts with YAML frontmatter compliant with \`schemas/product/\` (\`ACT-*\`, \`UC-*\`, \`FR-*\`, \`QR-*\`, \`BR-*\`).
|
|
10070
|
+
- **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-*\`).
|
|
9798
10071
|
- **Guardrails**: \`status\` always starts in \`draft\`. Mandatory Gherkin criteria with \`@<ID> @automated @regression\`.
|
|
9799
10072
|
|
|
9800
10073
|
### 2. \`agent-threat-modeler\` (Threat Modeler and Security Specialist)
|
|
@@ -9953,7 +10226,7 @@ Non-Negotiable Quality Thresholds (\`quality-policy.yaml\`):
|
|
|
9953
10226
|
|
|
9954
10227
|
| Role | Mission (summary) |
|
|
9955
10228
|
| :--- | :--- |
|
|
9956
|
-
| \`agent-product-analyst\` | ProductShape artifacts (\`ACT-*\`, \`UC-*\`, \`FR-*\`, \`QR-*\`, \`BR-*\`); \`status\` starts \`draft\`. |
|
|
10229
|
+
| \`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\`. |
|
|
9957
10230
|
| \`agent-threat-modeler\` | STRIDE/OWASP threat triad (\`ACT-THREAT-*\`, \`ABUSE-*\`, \`SEC-REQ-*\`). |
|
|
9958
10231
|
| \`agent-system-architect\` | Modular arc42 + NAF v4 architecture (\`CMP-*\`, Mermaid diagrams, \`ADR-*\`). |
|
|
9959
10232
|
| \`agent-qa-engineer\` | FAILING BDD/Gherkin suites before \`agent-developer\` writes production code. |
|
|
@@ -10761,7 +11034,7 @@ var ALL_ARCHITECTURE_TEMPLATES = [
|
|
|
10761
11034
|
{ filename: "cross-cutting-concepts.template.md", content: STARTER_ARCH_CROSS_CUTTING_CONCEPTS, isMinimal: false },
|
|
10762
11035
|
{ filename: "deployment-view.template.md", content: STARTER_ARCH_DEPLOYMENT_VIEW, isMinimal: false },
|
|
10763
11036
|
{ filename: "glossary.template.md", content: STARTER_ARCH_GLOSSARY, isMinimal: false },
|
|
10764
|
-
{ filename: "introduction-and-goals.template.md", content: STARTER_ARCH_INTRODUCTION_AND_GOALS, isMinimal:
|
|
11037
|
+
{ filename: "introduction-and-goals.template.md", content: STARTER_ARCH_INTRODUCTION_AND_GOALS, isMinimal: true },
|
|
10765
11038
|
{ filename: "level-1-whitebox.template.md", content: STARTER_ARCH_LEVEL_1_WHITEBOX, isMinimal: false },
|
|
10766
11039
|
{ filename: "quality-requirements.template.md", content: STARTER_ARCH_QUALITY_REQUIREMENTS, isMinimal: false },
|
|
10767
11040
|
{ filename: "risks-and-technical-debt.template.md", content: STARTER_ARCH_RISKS_AND_TECHNICAL_DEBT, isMinimal: false },
|