@metaobjectsdev/metadata 0.22.1 → 0.23.1-rc.1
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/core/documentation/documentation-definition.embedded.js +4 -4
- package/dist/core/documentation/documentation-definition.embedded.js.map +1 -1
- package/dist/core/requirement/meta-requirement.d.ts +23 -6
- package/dist/core/requirement/meta-requirement.d.ts.map +1 -1
- package/dist/core/requirement/meta-requirement.js +37 -9
- package/dist/core/requirement/meta-requirement.js.map +1 -1
- package/dist/core/requirement/requirement-constants.d.ts +16 -4
- package/dist/core/requirement/requirement-constants.d.ts.map +1 -1
- package/dist/core/requirement/requirement-constants.js +27 -3
- package/dist/core/requirement/requirement-constants.js.map +1 -1
- package/dist/core/requirement/requirement-definition.embedded.d.ts.map +1 -1
- package/dist/core/requirement/requirement-definition.embedded.js +76 -7
- package/dist/core/requirement/requirement-definition.embedded.js.map +1 -1
- package/package.json +1 -1
- package/src/core/documentation/documentation-definition.embedded.ts +4 -4
- package/src/core/requirement/meta-requirement.ts +44 -7
- package/src/core/requirement/requirement-constants.ts +32 -3
- package/src/core/requirement/requirement-definition.embedded.ts +76 -7
|
@@ -12,7 +12,7 @@ export const DOCUMENTATION_DEFINITION = {
|
|
|
12
12
|
"name": "description",
|
|
13
13
|
"min": 0,
|
|
14
14
|
"max": 1,
|
|
15
|
-
"description": "
|
|
15
|
+
"description": "What this element IS and COVERS, written for someone using it. Markdown allowed, multi-line via YAML '|' block scalar. Flows into doc-gen surfaces (JSDoc / XML-doc / Postgres COMMENT / Mermaid prose). State scope and boundary — what it covers, what it deliberately does NOT, and which sibling owns the rest — all of which is derivable from the model itself. Anything you had to read the implementation to learn belongs in @notes, not here."
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
18
|
"type": "attr",
|
|
@@ -20,7 +20,7 @@ export const DOCUMENTATION_DEFINITION = {
|
|
|
20
20
|
"name": "summary",
|
|
21
21
|
"min": 0,
|
|
22
22
|
"max": 1,
|
|
23
|
-
"description": "Short single-line
|
|
23
|
+
"description": "Short single-line SENTENCE (OpenAPI `summary` pattern) — used in index tables, sidebar previews, and AI prompts where the full @description is too long. Distinct from @title, which is a noun label rather than a sentence. When @summary is unset, doc surfaces typically fall back to the first sentence of @description."
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
"type": "attr",
|
|
@@ -28,7 +28,7 @@ export const DOCUMENTATION_DEFINITION = {
|
|
|
28
28
|
"name": "title",
|
|
29
29
|
"min": 0,
|
|
30
30
|
"max": 1,
|
|
31
|
-
"description": "Short single-line human label (e.g. 'Email' for a `field.string email`).
|
|
31
|
+
"description": "Short single-line human label — a NOUN PHRASE naming the element (e.g. 'Email' for a `field.string email`), never a sentence. What a tab, an index row or a sidebar shows when the name is an identifier rather than a label. See @summary for the one-line sentence form."
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
34
|
"type": "attr",
|
|
@@ -36,7 +36,7 @@ export const DOCUMENTATION_DEFINITION = {
|
|
|
36
36
|
"name": "notes",
|
|
37
37
|
"min": 0,
|
|
38
38
|
"max": 1,
|
|
39
|
-
"description": "Internal-only rationale
|
|
39
|
+
"description": "Internal-only rationale, never emitted to user-facing docs — the slot for what you had to look OUTSIDE the model to learn: evidence, measurements, citations, the control that proved an absence was real, and what breaks if this changes. It is NOT a longer @description, and restating the description here is the failure mode this slot invites. Mechanical test: a sentence belongs in @notes exactly when it would have to change because the IMPLEMENTATION changed while the model did not."
|
|
40
40
|
},
|
|
41
41
|
{
|
|
42
42
|
"type": "attr",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"documentation-definition.embedded.js","sourceRoot":"","sources":["../../../src/core/documentation/documentation-definition.embedded.ts"],"names":[],"mappings":"AAQA,MAAM,CAAC,MAAM,wBAAwB,GAAuB;IAC1D,UAAU,EAAE,2BAA2B;IACvC,OAAO,EAAE;QACP;YACE,MAAM,EAAE,GAAG;YACX,SAAS,EAAE,GAAG;YACd,aAAa,EAAE,+KAA+K;YAC9L,UAAU,EAAE;gBACV;oBACE,MAAM,EAAE,MAAM;oBACd,SAAS,EAAE,QAAQ;oBACnB,MAAM,EAAE,aAAa;oBACrB,KAAK,EAAE,CAAC;oBACR,KAAK,EAAE,CAAC;oBACR,aAAa,EAAE,
|
|
1
|
+
{"version":3,"file":"documentation-definition.embedded.js","sourceRoot":"","sources":["../../../src/core/documentation/documentation-definition.embedded.ts"],"names":[],"mappings":"AAQA,MAAM,CAAC,MAAM,wBAAwB,GAAuB;IAC1D,UAAU,EAAE,2BAA2B;IACvC,OAAO,EAAE;QACP;YACE,MAAM,EAAE,GAAG;YACX,SAAS,EAAE,GAAG;YACd,aAAa,EAAE,+KAA+K;YAC9L,UAAU,EAAE;gBACV;oBACE,MAAM,EAAE,MAAM;oBACd,SAAS,EAAE,QAAQ;oBACnB,MAAM,EAAE,aAAa;oBACrB,KAAK,EAAE,CAAC;oBACR,KAAK,EAAE,CAAC;oBACR,aAAa,EAAE,ybAAyb;iBACzc;gBACD;oBACE,MAAM,EAAE,MAAM;oBACd,SAAS,EAAE,QAAQ;oBACnB,MAAM,EAAE,SAAS;oBACjB,KAAK,EAAE,CAAC;oBACR,KAAK,EAAE,CAAC;oBACR,aAAa,EAAE,8TAA8T;iBAC9U;gBACD;oBACE,MAAM,EAAE,MAAM;oBACd,SAAS,EAAE,QAAQ;oBACnB,MAAM,EAAE,OAAO;oBACf,KAAK,EAAE,CAAC;oBACR,KAAK,EAAE,CAAC;oBACR,aAAa,EAAE,4QAA4Q;iBAC5R;gBACD;oBACE,MAAM,EAAE,MAAM;oBACd,SAAS,EAAE,QAAQ;oBACnB,MAAM,EAAE,OAAO;oBACf,KAAK,EAAE,CAAC;oBACR,KAAK,EAAE,CAAC;oBACR,aAAa,EAAE,ueAAue;iBACvf;gBACD;oBACE,MAAM,EAAE,MAAM;oBACd,SAAS,EAAE,QAAQ;oBACnB,MAAM,EAAE,YAAY;oBACpB,KAAK,EAAE,CAAC;oBACR,KAAK,EAAE,CAAC;oBACR,aAAa,EAAE,8GAA8G;iBAC9H;gBACD;oBACE,MAAM,EAAE,MAAM;oBACd,SAAS,EAAE,QAAQ;oBACnB,MAAM,EAAE,YAAY;oBACpB,KAAK,EAAE,CAAC;oBACR,KAAK,EAAE,CAAC;oBACR,aAAa,EAAE,2IAA2I;iBAC3J;gBACD;oBACE,MAAM,EAAE,MAAM;oBACd,SAAS,EAAE,QAAQ;oBACnB,MAAM,EAAE,SAAS;oBACjB,KAAK,EAAE,CAAC;oBACR,KAAK,EAAE,CAAC;oBACR,SAAS,EAAE,IAAI;oBACf,aAAa,EAAE,uEAAuE;iBACvF;gBACD;oBACE,MAAM,EAAE,MAAM;oBACd,SAAS,EAAE,QAAQ;oBACnB,MAAM,EAAE,SAAS;oBACjB,KAAK,EAAE,CAAC;oBACR,KAAK,EAAE,CAAC;oBACR,SAAS,EAAE,IAAI;oBACf,aAAa,EAAE,wFAAwF;iBACxG;aACF;SACF;KACF;CACF,CAAC"}
|
|
@@ -1,20 +1,37 @@
|
|
|
1
1
|
import { MetaData } from "../../shared/meta-data.js";
|
|
2
|
-
import { type RequirementStatus } from "./requirement-constants.js";
|
|
2
|
+
import { type RequirementDisposition, type RequirementStatus } from "./requirement-constants.js";
|
|
3
3
|
export declare class MetaRequirement extends MetaData {
|
|
4
4
|
/** What the product does for a user — checked by EXISTENCE. */
|
|
5
5
|
isFunctional(): boolean;
|
|
6
6
|
/** How the system is built — checked by UNIVERSALITY (the opposite polarity). */
|
|
7
7
|
isArchitectural(): boolean;
|
|
8
|
-
/** 1 solution · 2 segment · 3 service · 4 object · 5 member.
|
|
9
|
-
*
|
|
8
|
+
/** 1 solution · 2 segment · 3 service · 4 object · 5 member. Required on a
|
|
9
|
+
* functional requirement. OPTIONAL on an architectural one, where absent
|
|
10
|
+
* means the original flat, object-independent form and present means it
|
|
11
|
+
* sits in a levelled tree (a quality taxonomy over non-functional claims). */
|
|
10
12
|
level(): number | undefined;
|
|
11
13
|
status(): RequirementStatus | undefined;
|
|
14
|
+
/** What was DECIDED about the outstanding work. Undefined means UNDECIDED —
|
|
15
|
+
* a real state, and the one worth finding in a review. */
|
|
16
|
+
disposition(): RequirementDisposition | undefined;
|
|
17
|
+
/** Issue/ticket references. Free-form; never resolved (verify has no network). */
|
|
18
|
+
trackedBy(): string[];
|
|
19
|
+
/** Intended but not built. Its nodes may legitimately not exist yet, and it
|
|
20
|
+
* must NOT count toward object coverage — planning a capability cannot be
|
|
21
|
+
* allowed to silence the warning that nothing implements it. */
|
|
22
|
+
isPlanned(): boolean;
|
|
23
|
+
/** True when there is outstanding work, so a `@disposition` says something. */
|
|
24
|
+
hasOutstandingWork(): boolean;
|
|
12
25
|
implementedBy(): string[];
|
|
13
26
|
verifiedBy(): string[];
|
|
14
27
|
/** True when this requirement is permitted to reference the model at all.
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
28
|
+
*
|
|
29
|
+
* An UNLEVELLED architectural requirement always may — its claim set is the
|
|
30
|
+
* whole point, and that is the original flat form. Once a level is present,
|
|
31
|
+
* the node has opted into a tree and the link floor applies to it exactly as
|
|
32
|
+
* it does to a functional one, so an "ISO 25010 Security" grouping node
|
|
33
|
+
* cannot quietly start naming entities. Levelling is the opt-in; enforcing
|
|
34
|
+
* the floor unconditionally would have broken every existing flat policy. */
|
|
18
35
|
mayReferenceModel(): boolean;
|
|
19
36
|
/** True when a dangling `@implementedBy` is an ERROR rather than expected.
|
|
20
37
|
* An abandoned or superseded requirement's nodes are supposed to be gone. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meta-requirement.d.ts","sourceRoot":"","sources":["../../../src/core/requirement/meta-requirement.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,
|
|
1
|
+
{"version":3,"file":"meta-requirement.d.ts","sourceRoot":"","sources":["../../../src/core/requirement/meta-requirement.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,EAaL,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACvB,MAAM,4BAA4B,CAAC;AAEpC,qBAAa,eAAgB,SAAQ,QAAQ;IAC3C,+DAA+D;IAC/D,YAAY,IAAI,OAAO;IAIvB,iFAAiF;IACjF,eAAe,IAAI,OAAO;IAI1B;;;mFAG+E;IAC/E,KAAK,IAAI,MAAM,GAAG,SAAS;IAK3B,MAAM,IAAI,iBAAiB,GAAG,SAAS;IAKvC;+DAC2D;IAC3D,WAAW,IAAI,sBAAsB,GAAG,SAAS;IAKjD,kFAAkF;IAClF,SAAS,IAAI,MAAM,EAAE;IAKrB;;qEAEiE;IACjE,SAAS,IAAI,OAAO;IAIpB,+EAA+E;IAC/E,kBAAkB,IAAI,OAAO;IAK7B,aAAa,IAAI,MAAM,EAAE;IAKzB,UAAU,IAAI,MAAM,EAAE;IAKtB;;;;;;;kFAO8E;IAC9E,iBAAiB,IAAI,OAAO;IAM5B;kFAC8E;IAC9E,iBAAiB,IAAI,OAAO;CAI7B"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// Accessors are RESOLVING (ADR-0039) so a requirement that `extends` an
|
|
5
5
|
// abstract parent inherits its properties.
|
|
6
6
|
import { MetaData } from "../../shared/meta-data.js";
|
|
7
|
-
import { REQUIREMENT_SUBTYPE_FUNCTIONAL, REQUIREMENT_SUBTYPE_ARCHITECTURAL, REQUIREMENT_ATTR_LEVEL, REQUIREMENT_ATTR_STATUS, REQUIREMENT_ATTR_IMPLEMENTED_BY, REQUIREMENT_ATTR_VERIFIED_BY, REQUIREMENT_LINK_FLOOR_LEVEL, REQUIREMENT_STATUSES_REQUIRING_LIVE_NODES, } from "./requirement-constants.js";
|
|
7
|
+
import { REQUIREMENT_SUBTYPE_FUNCTIONAL, REQUIREMENT_SUBTYPE_ARCHITECTURAL, REQUIREMENT_ATTR_LEVEL, REQUIREMENT_ATTR_STATUS, REQUIREMENT_ATTR_DISPOSITION, REQUIREMENT_ATTR_TRACKED_BY, REQUIREMENT_ATTR_IMPLEMENTED_BY, REQUIREMENT_ATTR_VERIFIED_BY, REQUIREMENT_LINK_FLOOR_LEVEL, REQUIREMENT_STATUS_PLANNED, REQUIREMENT_STATUSES_REQUIRING_LIVE_NODES, REQUIREMENT_STATUSES_WITH_OUTSTANDING_WORK, } from "./requirement-constants.js";
|
|
8
8
|
export class MetaRequirement extends MetaData {
|
|
9
9
|
/** What the product does for a user — checked by EXISTENCE. */
|
|
10
10
|
isFunctional() {
|
|
@@ -14,8 +14,10 @@ export class MetaRequirement extends MetaData {
|
|
|
14
14
|
isArchitectural() {
|
|
15
15
|
return this.subType === REQUIREMENT_SUBTYPE_ARCHITECTURAL;
|
|
16
16
|
}
|
|
17
|
-
/** 1 solution · 2 segment · 3 service · 4 object · 5 member.
|
|
18
|
-
*
|
|
17
|
+
/** 1 solution · 2 segment · 3 service · 4 object · 5 member. Required on a
|
|
18
|
+
* functional requirement. OPTIONAL on an architectural one, where absent
|
|
19
|
+
* means the original flat, object-independent form and present means it
|
|
20
|
+
* sits in a levelled tree (a quality taxonomy over non-functional claims). */
|
|
19
21
|
level() {
|
|
20
22
|
const v = this.attr(REQUIREMENT_ATTR_LEVEL);
|
|
21
23
|
return typeof v === "number" ? v : undefined;
|
|
@@ -24,6 +26,28 @@ export class MetaRequirement extends MetaData {
|
|
|
24
26
|
const v = this.attr(REQUIREMENT_ATTR_STATUS);
|
|
25
27
|
return typeof v === "string" ? v : undefined;
|
|
26
28
|
}
|
|
29
|
+
/** What was DECIDED about the outstanding work. Undefined means UNDECIDED —
|
|
30
|
+
* a real state, and the one worth finding in a review. */
|
|
31
|
+
disposition() {
|
|
32
|
+
const v = this.attr(REQUIREMENT_ATTR_DISPOSITION);
|
|
33
|
+
return typeof v === "string" ? v : undefined;
|
|
34
|
+
}
|
|
35
|
+
/** Issue/ticket references. Free-form; never resolved (verify has no network). */
|
|
36
|
+
trackedBy() {
|
|
37
|
+
const v = this.attr(REQUIREMENT_ATTR_TRACKED_BY);
|
|
38
|
+
return Array.isArray(v) ? v : [];
|
|
39
|
+
}
|
|
40
|
+
/** Intended but not built. Its nodes may legitimately not exist yet, and it
|
|
41
|
+
* must NOT count toward object coverage — planning a capability cannot be
|
|
42
|
+
* allowed to silence the warning that nothing implements it. */
|
|
43
|
+
isPlanned() {
|
|
44
|
+
return this.status() === REQUIREMENT_STATUS_PLANNED;
|
|
45
|
+
}
|
|
46
|
+
/** True when there is outstanding work, so a `@disposition` says something. */
|
|
47
|
+
hasOutstandingWork() {
|
|
48
|
+
const s = this.status();
|
|
49
|
+
return s !== undefined && REQUIREMENT_STATUSES_WITH_OUTSTANDING_WORK.includes(s);
|
|
50
|
+
}
|
|
27
51
|
implementedBy() {
|
|
28
52
|
const v = this.attr(REQUIREMENT_ATTR_IMPLEMENTED_BY);
|
|
29
53
|
return Array.isArray(v) ? v : [];
|
|
@@ -33,14 +57,18 @@ export class MetaRequirement extends MetaData {
|
|
|
33
57
|
return Array.isArray(v) ? v : [];
|
|
34
58
|
}
|
|
35
59
|
/** True when this requirement is permitted to reference the model at all.
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
60
|
+
*
|
|
61
|
+
* An UNLEVELLED architectural requirement always may — its claim set is the
|
|
62
|
+
* whole point, and that is the original flat form. Once a level is present,
|
|
63
|
+
* the node has opted into a tree and the link floor applies to it exactly as
|
|
64
|
+
* it does to a functional one, so an "ISO 25010 Security" grouping node
|
|
65
|
+
* cannot quietly start naming entities. Levelling is the opt-in; enforcing
|
|
66
|
+
* the floor unconditionally would have broken every existing flat policy. */
|
|
39
67
|
mayReferenceModel() {
|
|
40
|
-
if (this.isArchitectural())
|
|
41
|
-
return true;
|
|
42
68
|
const lvl = this.level();
|
|
43
|
-
|
|
69
|
+
if (lvl === undefined)
|
|
70
|
+
return this.isArchitectural();
|
|
71
|
+
return lvl >= REQUIREMENT_LINK_FLOOR_LEVEL;
|
|
44
72
|
}
|
|
45
73
|
/** True when a dangling `@implementedBy` is an ERROR rather than expected.
|
|
46
74
|
* An abandoned or superseded requirement's nodes are supposed to be gone. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meta-requirement.js","sourceRoot":"","sources":["../../../src/core/requirement/meta-requirement.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,EAAE;AACF,wEAAwE;AACxE,wEAAwE;AACxE,2CAA2C;AAE3C,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,EACL,8BAA8B,EAC9B,iCAAiC,EACjC,sBAAsB,EACtB,uBAAuB,EACvB,+BAA+B,EAC/B,4BAA4B,EAC5B,4BAA4B,EAC5B,yCAAyC,
|
|
1
|
+
{"version":3,"file":"meta-requirement.js","sourceRoot":"","sources":["../../../src/core/requirement/meta-requirement.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,EAAE;AACF,wEAAwE;AACxE,wEAAwE;AACxE,2CAA2C;AAE3C,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,EACL,8BAA8B,EAC9B,iCAAiC,EACjC,sBAAsB,EACtB,uBAAuB,EACvB,4BAA4B,EAC5B,2BAA2B,EAC3B,+BAA+B,EAC/B,4BAA4B,EAC5B,4BAA4B,EAC5B,0BAA0B,EAC1B,yCAAyC,EACzC,0CAA0C,GAG3C,MAAM,4BAA4B,CAAC;AAEpC,MAAM,OAAO,eAAgB,SAAQ,QAAQ;IAC3C,+DAA+D;IAC/D,YAAY;QACV,OAAO,IAAI,CAAC,OAAO,KAAK,8BAA8B,CAAC;IACzD,CAAC;IAED,iFAAiF;IACjF,eAAe;QACb,OAAO,IAAI,CAAC,OAAO,KAAK,iCAAiC,CAAC;IAC5D,CAAC;IAED;;;mFAG+E;IAC/E,KAAK;QACH,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QAC5C,OAAO,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/C,CAAC;IAED,MAAM;QACJ,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;QAC7C,OAAO,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAE,CAAuB,CAAC,CAAC,CAAC,SAAS,CAAC;IACtE,CAAC;IAED;+DAC2D;IAC3D,WAAW;QACT,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QAClD,OAAO,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAE,CAA4B,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3E,CAAC;IAED,kFAAkF;IAClF,SAAS;QACP,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;QACjD,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAAc,CAAC,CAAC,CAAC,EAAE,CAAC;IACjD,CAAC;IAED;;qEAEiE;IACjE,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,EAAE,KAAK,0BAA0B,CAAC;IACtD,CAAC;IAED,+EAA+E;IAC/E,kBAAkB;QAChB,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACxB,OAAO,CAAC,KAAK,SAAS,IAAI,0CAA0C,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACnF,CAAC;IAED,aAAa;QACX,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;QACrD,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAAc,CAAC,CAAC,CAAC,EAAE,CAAC;IACjD,CAAC;IAED,UAAU;QACR,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QAClD,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAAc,CAAC,CAAC,CAAC,EAAE,CAAC;IACjD,CAAC;IAED;;;;;;;kFAO8E;IAC9E,iBAAiB;QACf,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QACzB,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC,eAAe,EAAE,CAAC;QACrD,OAAO,GAAG,IAAI,4BAA4B,CAAC;IAC7C,CAAC;IAED;kFAC8E;IAC9E,iBAAiB;QACf,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACxB,OAAO,CAAC,KAAK,SAAS,IAAI,yCAAyC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAClF,CAAC;CACF"}
|
|
@@ -3,25 +3,37 @@ export declare const REQUIREMENT_SUBTYPE_FUNCTIONAL = "functional";
|
|
|
3
3
|
export declare const REQUIREMENT_SUBTYPE_ARCHITECTURAL = "architectural";
|
|
4
4
|
export declare const REQUIREMENT_SUBTYPES: readonly ["functional", "architectural"];
|
|
5
5
|
export type RequirementSubType = (typeof REQUIREMENT_SUBTYPES)[number];
|
|
6
|
-
/** 1 solution · 2 segment
|
|
6
|
+
/** 1 solution · 2 segment · 3 service · 4 object · 5 member — levels of
|
|
7
|
+
* ABSTRACTION AND OWNERSHIP in the problem domain, never of code structure. */
|
|
7
8
|
export declare const REQUIREMENT_ATTR_LEVEL = "level";
|
|
8
9
|
export declare const REQUIREMENT_ATTR_STATUS = "status";
|
|
10
|
+
export declare const REQUIREMENT_ATTR_DISPOSITION = "disposition";
|
|
11
|
+
export declare const REQUIREMENT_ATTR_TRACKED_BY = "trackedBy";
|
|
9
12
|
export declare const REQUIREMENT_ATTR_STATEMENT = "statement";
|
|
10
13
|
export declare const REQUIREMENT_ATTR_VIOLATION = "violation";
|
|
11
14
|
export declare const REQUIREMENT_ATTR_IMPLEMENTED_BY = "implementedBy";
|
|
12
15
|
export declare const REQUIREMENT_ATTR_VERIFIED_BY = "verifiedBy";
|
|
13
16
|
export declare const REQUIREMENT_ATTR_SUPERSEDED_BY = "supersededBy";
|
|
17
|
+
export declare const REQUIREMENT_STATUS_PLANNED = "planned";
|
|
14
18
|
export declare const REQUIREMENT_STATUS_LIVE = "live";
|
|
15
19
|
export declare const REQUIREMENT_STATUS_PARTIAL = "partial";
|
|
16
20
|
export declare const REQUIREMENT_STATUS_ABANDONED = "abandoned";
|
|
17
21
|
export declare const REQUIREMENT_STATUS_SUPERSEDED = "superseded";
|
|
18
|
-
export declare const REQUIREMENT_STATUSES: readonly ["live", "partial", "abandoned", "superseded"];
|
|
22
|
+
export declare const REQUIREMENT_STATUSES: readonly ["planned", "live", "partial", "abandoned", "superseded"];
|
|
19
23
|
export type RequirementStatus = (typeof REQUIREMENT_STATUSES)[number];
|
|
20
24
|
/** Statuses whose implementing nodes are supposed to still exist. A dangling
|
|
21
25
|
* `@implementedBy` on one of these means the model moved and the requirement is
|
|
22
|
-
* stale
|
|
23
|
-
*
|
|
26
|
+
* stale. On `planned` the nodes do not exist YET; on `abandoned`/`superseded`
|
|
27
|
+
* they are supposed to be GONE — which is the whole point of those entries. */
|
|
24
28
|
export declare const REQUIREMENT_STATUSES_REQUIRING_LIVE_NODES: readonly RequirementStatus[];
|
|
29
|
+
/** Statuses with outstanding work, so a `@disposition` is meaningful on them.
|
|
30
|
+
* On any other status the decision IS the status, and recording a second one
|
|
31
|
+
* can only agree with it or contradict it. */
|
|
32
|
+
export declare const REQUIREMENT_STATUSES_WITH_OUTSTANDING_WORK: readonly RequirementStatus[];
|
|
33
|
+
export declare const REQUIREMENT_DISPOSITION_ACCEPTED = "accepted";
|
|
34
|
+
export declare const REQUIREMENT_DISPOSITION_DEFERRED = "deferred";
|
|
35
|
+
export declare const REQUIREMENT_DISPOSITIONS: readonly ["accepted", "deferred"];
|
|
36
|
+
export type RequirementDisposition = (typeof REQUIREMENT_DISPOSITIONS)[number];
|
|
25
37
|
export declare const REQUIREMENT_LEVEL_SOLUTION = 1;
|
|
26
38
|
export declare const REQUIREMENT_LEVEL_SEGMENT = 2;
|
|
27
39
|
export declare const REQUIREMENT_LEVEL_SERVICE = 3;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"requirement-constants.d.ts","sourceRoot":"","sources":["../../../src/core/requirement/requirement-constants.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,WAAW,gBAAgB,CAAC;AASzC,eAAO,MAAM,8BAA8B,eAAe,CAAC;AAC3D,eAAO,MAAM,iCAAiC,kBAAkB,CAAC;AAEjE,eAAO,MAAM,oBAAoB,0CAGvB,CAAC;AACX,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AAMvE
|
|
1
|
+
{"version":3,"file":"requirement-constants.d.ts","sourceRoot":"","sources":["../../../src/core/requirement/requirement-constants.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,WAAW,gBAAgB,CAAC;AASzC,eAAO,MAAM,8BAA8B,eAAe,CAAC;AAC3D,eAAO,MAAM,iCAAiC,kBAAkB,CAAC;AAEjE,eAAO,MAAM,oBAAoB,0CAGvB,CAAC;AACX,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AAMvE;gFACgF;AAChF,eAAO,MAAM,sBAAsB,UAAU,CAAC;AAC9C,eAAO,MAAM,uBAAuB,WAAW,CAAC;AAChD,eAAO,MAAM,4BAA4B,gBAAgB,CAAC;AAC1D,eAAO,MAAM,2BAA2B,cAAc,CAAC;AACvD,eAAO,MAAM,0BAA0B,cAAc,CAAC;AACtD,eAAO,MAAM,0BAA0B,cAAc,CAAC;AACtD,eAAO,MAAM,+BAA+B,kBAAkB,CAAC;AAC/D,eAAO,MAAM,4BAA4B,eAAe,CAAC;AACzD,eAAO,MAAM,8BAA8B,iBAAiB,CAAC;AAS7D,eAAO,MAAM,0BAA0B,YAAY,CAAC;AACpD,eAAO,MAAM,uBAAuB,SAAS,CAAC;AAC9C,eAAO,MAAM,0BAA0B,YAAY,CAAC;AACpD,eAAO,MAAM,4BAA4B,cAAc,CAAC;AACxD,eAAO,MAAM,6BAA6B,eAAe,CAAC;AAE1D,eAAO,MAAM,oBAAoB,oEAMvB,CAAC;AACX,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEtE;;;gFAGgF;AAChF,eAAO,MAAM,yCAAyC,EAAE,SAAS,iBAAiB,EAGjF,CAAC;AAEF;;+CAE+C;AAC/C,eAAO,MAAM,0CAA0C,EAAE,SAAS,iBAAiB,EAGlF,CAAC;AASF,eAAO,MAAM,gCAAgC,aAAa,CAAC;AAC3D,eAAO,MAAM,gCAAgC,aAAa,CAAC;AAE3D,eAAO,MAAM,wBAAwB,mCAG3B,CAAC;AACX,MAAM,MAAM,sBAAsB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAC;AAM/E,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAC5C,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAC3C,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAC3C,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAC1C,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C;mDACmD;AACnD,eAAO,MAAM,4BAA4B,IAA2B,CAAC;AACrE,eAAO,MAAM,qBAAqB,IAA6B,CAAC;AAChE,eAAO,MAAM,qBAAqB,IAA2B,CAAC"}
|
|
@@ -20,9 +20,12 @@ export const REQUIREMENT_SUBTYPES = [
|
|
|
20
20
|
// ---------------------------------------------------------------------------
|
|
21
21
|
// Attrs
|
|
22
22
|
// ---------------------------------------------------------------------------
|
|
23
|
-
/** 1 solution · 2 segment
|
|
23
|
+
/** 1 solution · 2 segment · 3 service · 4 object · 5 member — levels of
|
|
24
|
+
* ABSTRACTION AND OWNERSHIP in the problem domain, never of code structure. */
|
|
24
25
|
export const REQUIREMENT_ATTR_LEVEL = "level";
|
|
25
26
|
export const REQUIREMENT_ATTR_STATUS = "status";
|
|
27
|
+
export const REQUIREMENT_ATTR_DISPOSITION = "disposition";
|
|
28
|
+
export const REQUIREMENT_ATTR_TRACKED_BY = "trackedBy";
|
|
26
29
|
export const REQUIREMENT_ATTR_STATEMENT = "statement";
|
|
27
30
|
export const REQUIREMENT_ATTR_VIOLATION = "violation";
|
|
28
31
|
export const REQUIREMENT_ATTR_IMPLEMENTED_BY = "implementedBy";
|
|
@@ -34,11 +37,13 @@ export const REQUIREMENT_ATTR_SUPERSEDED_BY = "supersededBy";
|
|
|
34
37
|
// a deliberately-retired capability 0 times out of 24, so a typo that silently
|
|
35
38
|
// disabled it would disable the whole mechanism.
|
|
36
39
|
// ---------------------------------------------------------------------------
|
|
40
|
+
export const REQUIREMENT_STATUS_PLANNED = "planned";
|
|
37
41
|
export const REQUIREMENT_STATUS_LIVE = "live";
|
|
38
42
|
export const REQUIREMENT_STATUS_PARTIAL = "partial";
|
|
39
43
|
export const REQUIREMENT_STATUS_ABANDONED = "abandoned";
|
|
40
44
|
export const REQUIREMENT_STATUS_SUPERSEDED = "superseded";
|
|
41
45
|
export const REQUIREMENT_STATUSES = [
|
|
46
|
+
REQUIREMENT_STATUS_PLANNED,
|
|
42
47
|
REQUIREMENT_STATUS_LIVE,
|
|
43
48
|
REQUIREMENT_STATUS_PARTIAL,
|
|
44
49
|
REQUIREMENT_STATUS_ABANDONED,
|
|
@@ -46,12 +51,31 @@ export const REQUIREMENT_STATUSES = [
|
|
|
46
51
|
];
|
|
47
52
|
/** Statuses whose implementing nodes are supposed to still exist. A dangling
|
|
48
53
|
* `@implementedBy` on one of these means the model moved and the requirement is
|
|
49
|
-
* stale
|
|
50
|
-
*
|
|
54
|
+
* stale. On `planned` the nodes do not exist YET; on `abandoned`/`superseded`
|
|
55
|
+
* they are supposed to be GONE — which is the whole point of those entries. */
|
|
51
56
|
export const REQUIREMENT_STATUSES_REQUIRING_LIVE_NODES = [
|
|
52
57
|
REQUIREMENT_STATUS_LIVE,
|
|
53
58
|
REQUIREMENT_STATUS_PARTIAL,
|
|
54
59
|
];
|
|
60
|
+
/** Statuses with outstanding work, so a `@disposition` is meaningful on them.
|
|
61
|
+
* On any other status the decision IS the status, and recording a second one
|
|
62
|
+
* can only agree with it or contradict it. */
|
|
63
|
+
export const REQUIREMENT_STATUSES_WITH_OUTSTANDING_WORK = [
|
|
64
|
+
REQUIREMENT_STATUS_PLANNED,
|
|
65
|
+
REQUIREMENT_STATUS_PARTIAL,
|
|
66
|
+
];
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
// Disposition — what was DECIDED about the outstanding work. Orthogonal to
|
|
69
|
+
// status, which says whether the work is done. Absent means UNDECIDED, and that
|
|
70
|
+
// is the state a review exists to find; collapsing it into the status enum
|
|
71
|
+
// would make "there is a gap" and "we chose to live with it" the same fact.
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
export const REQUIREMENT_DISPOSITION_ACCEPTED = "accepted";
|
|
74
|
+
export const REQUIREMENT_DISPOSITION_DEFERRED = "deferred";
|
|
75
|
+
export const REQUIREMENT_DISPOSITIONS = [
|
|
76
|
+
REQUIREMENT_DISPOSITION_ACCEPTED,
|
|
77
|
+
REQUIREMENT_DISPOSITION_DEFERRED,
|
|
78
|
+
];
|
|
55
79
|
// ---------------------------------------------------------------------------
|
|
56
80
|
// Levels — organisational above the link floor, model-referencing at or below.
|
|
57
81
|
// ---------------------------------------------------------------------------
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"requirement-constants.js","sourceRoot":"","sources":["../../../src/core/requirement/requirement-constants.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,EAAE;AACF,+EAA+E;AAC/E,6EAA6E;AAC7E,+EAA+E;AAC/E,2CAA2C;AAE3C,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAC;AAEzC,8EAA8E;AAC9E,0EAA0E;AAC1E,wDAAwD;AACxD,oEAAoE;AACpE,oEAAoE;AACpE,8EAA8E;AAE9E,MAAM,CAAC,MAAM,8BAA8B,GAAG,YAAY,CAAC;AAC3D,MAAM,CAAC,MAAM,iCAAiC,GAAG,eAAe,CAAC;AAEjE,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,8BAA8B;IAC9B,iCAAiC;CACzB,CAAC;AAGX,8EAA8E;AAC9E,QAAQ;AACR,8EAA8E;AAE9E
|
|
1
|
+
{"version":3,"file":"requirement-constants.js","sourceRoot":"","sources":["../../../src/core/requirement/requirement-constants.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,EAAE;AACF,+EAA+E;AAC/E,6EAA6E;AAC7E,+EAA+E;AAC/E,2CAA2C;AAE3C,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAC;AAEzC,8EAA8E;AAC9E,0EAA0E;AAC1E,wDAAwD;AACxD,oEAAoE;AACpE,oEAAoE;AACpE,8EAA8E;AAE9E,MAAM,CAAC,MAAM,8BAA8B,GAAG,YAAY,CAAC;AAC3D,MAAM,CAAC,MAAM,iCAAiC,GAAG,eAAe,CAAC;AAEjE,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,8BAA8B;IAC9B,iCAAiC;CACzB,CAAC;AAGX,8EAA8E;AAC9E,QAAQ;AACR,8EAA8E;AAE9E;gFACgF;AAChF,MAAM,CAAC,MAAM,sBAAsB,GAAG,OAAO,CAAC;AAC9C,MAAM,CAAC,MAAM,uBAAuB,GAAG,QAAQ,CAAC;AAChD,MAAM,CAAC,MAAM,4BAA4B,GAAG,aAAa,CAAC;AAC1D,MAAM,CAAC,MAAM,2BAA2B,GAAG,WAAW,CAAC;AACvD,MAAM,CAAC,MAAM,0BAA0B,GAAG,WAAW,CAAC;AACtD,MAAM,CAAC,MAAM,0BAA0B,GAAG,WAAW,CAAC;AACtD,MAAM,CAAC,MAAM,+BAA+B,GAAG,eAAe,CAAC;AAC/D,MAAM,CAAC,MAAM,4BAA4B,GAAG,YAAY,CAAC;AACzD,MAAM,CAAC,MAAM,8BAA8B,GAAG,cAAc,CAAC;AAE7D,8EAA8E;AAC9E,gFAAgF;AAChF,gFAAgF;AAChF,+EAA+E;AAC/E,iDAAiD;AACjD,8EAA8E;AAE9E,MAAM,CAAC,MAAM,0BAA0B,GAAG,SAAS,CAAC;AACpD,MAAM,CAAC,MAAM,uBAAuB,GAAG,MAAM,CAAC;AAC9C,MAAM,CAAC,MAAM,0BAA0B,GAAG,SAAS,CAAC;AACpD,MAAM,CAAC,MAAM,4BAA4B,GAAG,WAAW,CAAC;AACxD,MAAM,CAAC,MAAM,6BAA6B,GAAG,YAAY,CAAC;AAE1D,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,0BAA0B;IAC1B,uBAAuB;IACvB,0BAA0B;IAC1B,4BAA4B;IAC5B,6BAA6B;CACrB,CAAC;AAGX;;;gFAGgF;AAChF,MAAM,CAAC,MAAM,yCAAyC,GAAiC;IACrF,uBAAuB;IACvB,0BAA0B;CAC3B,CAAC;AAEF;;+CAE+C;AAC/C,MAAM,CAAC,MAAM,0CAA0C,GAAiC;IACtF,0BAA0B;IAC1B,0BAA0B;CAC3B,CAAC;AAEF,8EAA8E;AAC9E,2EAA2E;AAC3E,gFAAgF;AAChF,2EAA2E;AAC3E,4EAA4E;AAC5E,8EAA8E;AAE9E,MAAM,CAAC,MAAM,gCAAgC,GAAG,UAAU,CAAC;AAC3D,MAAM,CAAC,MAAM,gCAAgC,GAAG,UAAU,CAAC;AAE3D,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,gCAAgC;IAChC,gCAAgC;CACxB,CAAC;AAGX,8EAA8E;AAC9E,+EAA+E;AAC/E,8EAA8E;AAE9E,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC;AAC5C,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC;AAC3C,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC;AAC3C,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC;AAC1C,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC;AAE1C;mDACmD;AACnD,MAAM,CAAC,MAAM,4BAA4B,GAAG,wBAAwB,CAAC;AACrE,MAAM,CAAC,MAAM,qBAAqB,GAAG,0BAA0B,CAAC;AAChE,MAAM,CAAC,MAAM,qBAAqB,GAAG,wBAAwB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"requirement-definition.embedded.d.ts","sourceRoot":"","sources":["../../../src/core/requirement/requirement-definition.embedded.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAEjE,eAAO,MAAM,sBAAsB,EAAE,
|
|
1
|
+
{"version":3,"file":"requirement-definition.embedded.d.ts","sourceRoot":"","sources":["../../../src/core/requirement/requirement-definition.embedded.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAEjE,eAAO,MAAM,sBAAsB,EAAE,kBAgNpC,CAAC"}
|
|
@@ -5,7 +5,7 @@ export const REQUIREMENT_DEFINITION = {
|
|
|
5
5
|
"type": "requirement",
|
|
6
6
|
"subType": "functional",
|
|
7
7
|
"description": "What the product does for a user, stated as one violable claim. Its check is EXISTENCE: it fails when nothing implements it. Hierarchy is nesting — an L1 solution contains its L2 segments, which contain L3 services, and so on down to the levels that reference the model.",
|
|
8
|
-
"whenToUse": "Something exists because someone asked for it.
|
|
8
|
+
"whenToUse": "Something exists because someone asked for it. L1-L3 are levels of ABSTRACTION AND OWNERSHIP in the problem domain — whose need is this, and at what altitude — and are never a directory, package, deployable or module. Binding to technical constructs happens only at L4 (an object) and L5 (a member), which is the allocation step. Test every node: if a refactor that changes no behaviour would force it to move, its level is wrong.",
|
|
9
9
|
"children": [
|
|
10
10
|
{
|
|
11
11
|
"type": "attr",
|
|
@@ -13,7 +13,7 @@ export const REQUIREMENT_DEFINITION = {
|
|
|
13
13
|
"name": "level",
|
|
14
14
|
"min": 1,
|
|
15
15
|
"max": 1,
|
|
16
|
-
"description": "1 solution, 2 segment
|
|
16
|
+
"description": "1 solution, 2 segment, 3 service, 4 object, 5 member. L1-L3 are levels of abstraction and ownership in the problem domain, NOT of code structure. Nesting depth must agree with it; skipping a level is legal, going back up is not."
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"type": "attr",
|
|
@@ -22,12 +22,34 @@ export const REQUIREMENT_DEFINITION = {
|
|
|
22
22
|
"min": 1,
|
|
23
23
|
"max": 1,
|
|
24
24
|
"allowedValues": [
|
|
25
|
+
"planned",
|
|
25
26
|
"live",
|
|
26
27
|
"partial",
|
|
27
28
|
"abandoned",
|
|
28
29
|
"superseded"
|
|
29
30
|
],
|
|
30
|
-
"description": "live implemented and in use; partial implemented with known gaps; abandoned built then deliberately retired; superseded replaced by a different mechanism. A dangling @implementedBy is an ERROR on live/partial (the model moved, the requirement is stale) and ALLOWED on abandoned/superseded
|
|
31
|
+
"description": "planned intended but not built yet; live implemented and in use; partial implemented with known gaps; abandoned built then deliberately retired; superseded replaced by a different mechanism. A dangling @implementedBy is an ERROR on live/partial (the model moved, the requirement is stale) and ALLOWED on planned/abandoned/superseded — on planned the nodes do not exist YET, on the other two they are meant to be gone, and that is the entry doing its job. A planned requirement also never contributes to object coverage: planning a capability must not silence the warning that nothing implements it."
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"type": "attr",
|
|
35
|
+
"subType": "string",
|
|
36
|
+
"name": "disposition",
|
|
37
|
+
"min": 0,
|
|
38
|
+
"max": 1,
|
|
39
|
+
"allowedValues": [
|
|
40
|
+
"accepted",
|
|
41
|
+
"deferred"
|
|
42
|
+
],
|
|
43
|
+
"description": "What has been DECIDED about outstanding work — a different question from whether the work is done, which is what @status answers. accepted: the gap is understood and deliberately not being closed. deferred: it will be closed, but not now. ABSENT MEANS UNDECIDED, which is a real and useful state — it is what an unreviewed gap looks like, and it is the one a review should be able to find. Meaningful on planned and partial only; on a status with no outstanding work it is a WARNING. Deliberately NOT a workflow vocabulary: which sprint, who owns it and whether it is in progress belong in the tracker named by @trackedBy, because two systems holding that answer will drift and only one of them is refreshed daily."
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"type": "attr",
|
|
47
|
+
"subType": "string",
|
|
48
|
+
"name": "trackedBy",
|
|
49
|
+
"isArray": true,
|
|
50
|
+
"min": 0,
|
|
51
|
+
"max": 1,
|
|
52
|
+
"description": "Issue or ticket references for outstanding work — a URL, an owner/repo#123 shorthand, or a tracker key. Free-form and NOT resolved by verify, which does not reach the network; unlike @verifiedBy, nothing here is checked to exist. Its job is to stop a deferred gap becoming invisible, so verify warns when a deferred requirement names no ticket. Also the right place to link the ticket that a planned requirement will be built under."
|
|
31
53
|
},
|
|
32
54
|
{
|
|
33
55
|
"type": "attr",
|
|
@@ -61,7 +83,7 @@ export const REQUIREMENT_DEFINITION = {
|
|
|
61
83
|
"isArray": true,
|
|
62
84
|
"min": 0,
|
|
63
85
|
"max": 1,
|
|
64
|
-
"description": "Names of
|
|
86
|
+
"description": "OPTIONAL — omit unless you have opened the test and read what it asserts. Names of tests that assert the behaviour. verify checks each name EXISTS and is not skipped; it never runs them, and it cannot tell whether the named test verifies this requirement — any occurrence in the test corpus satisfies it."
|
|
65
87
|
},
|
|
66
88
|
{
|
|
67
89
|
"type": "attr",
|
|
@@ -84,9 +106,17 @@ export const REQUIREMENT_DEFINITION = {
|
|
|
84
106
|
{
|
|
85
107
|
"type": "requirement",
|
|
86
108
|
"subType": "architectural",
|
|
87
|
-
"description": "How the system is built, applied uniformly across the model. Its check is UNIVERSALITY: it fails when something VIOLATES it, which is the opposite polarity to a functional requirement.
|
|
88
|
-
"whenToUse": "Something exists because every entity here looks like this — a uuid primary key, an @autoSet createdAt, a change-attribution column, tenant scoping. The discriminator is mechanical: did this exist because someone asked for something, or because it is the architecture?",
|
|
109
|
+
"description": "How the system is built, applied uniformly across the model. Its check is UNIVERSALITY: it fails when something VIOLATES it, which is the opposite polarity to a functional requirement. Flat by default and object-independent; it may optionally sit in a levelled tree when a quality taxonomy is being used to organise non-functional requirements.",
|
|
110
|
+
"whenToUse": "Something exists because every entity here looks like this — a uuid primary key, an @autoSet createdAt, a change-attribution column, tenant scoping. The discriminator is mechanical: did this exist because someone asked for something, or because it is the architecture? For a non-functional tree, an established quality taxonomy makes a good fixed upper structure (e.g. an ISO/IEC 25010 characteristic at L1, its sub-characteristic or a control-catalogue category at L2), with the model-binding claims at L4 and L5 as usual.",
|
|
89
111
|
"children": [
|
|
112
|
+
{
|
|
113
|
+
"type": "attr",
|
|
114
|
+
"subType": "int",
|
|
115
|
+
"name": "level",
|
|
116
|
+
"min": 0,
|
|
117
|
+
"max": 1,
|
|
118
|
+
"description": "OPTIONAL here, unlike on a functional requirement where it is required. ABSENT means a flat, object-independent policy that may reference the model directly — the original and still the default form. PRESENT means this node sits in a levelled tree, and then the same rules as functional apply: nesting must agree with the level, and only L4/L5 may carry @implementedBy. Levelling is opt-in so that adding a taxonomy on top of existing flat policies does not invalidate them."
|
|
119
|
+
},
|
|
90
120
|
{
|
|
91
121
|
"type": "attr",
|
|
92
122
|
"subType": "string",
|
|
@@ -94,12 +124,34 @@ export const REQUIREMENT_DEFINITION = {
|
|
|
94
124
|
"min": 1,
|
|
95
125
|
"max": 1,
|
|
96
126
|
"allowedValues": [
|
|
127
|
+
"planned",
|
|
97
128
|
"live",
|
|
98
129
|
"partial",
|
|
99
130
|
"abandoned",
|
|
100
131
|
"superseded"
|
|
101
132
|
],
|
|
102
|
-
"description": "As on requirement.functional. A live or partial architectural requirement claimed by NOTHING is an error: a policy declared and applied to nothing."
|
|
133
|
+
"description": "As on requirement.functional. A live or partial architectural requirement claimed by NOTHING is an error: a policy declared and applied to nothing. A planned one is exempt from that check — it is not applied yet by definition."
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"type": "attr",
|
|
137
|
+
"subType": "string",
|
|
138
|
+
"name": "disposition",
|
|
139
|
+
"min": 0,
|
|
140
|
+
"max": 1,
|
|
141
|
+
"allowedValues": [
|
|
142
|
+
"accepted",
|
|
143
|
+
"deferred"
|
|
144
|
+
],
|
|
145
|
+
"description": "As on requirement.functional. On an architectural requirement, accepted is the common and important case: a policy that is genuinely not universal, where the exceptions are known and tolerated, is more honest as partial+accepted than as a live claim nobody audits."
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"type": "attr",
|
|
149
|
+
"subType": "string",
|
|
150
|
+
"name": "trackedBy",
|
|
151
|
+
"isArray": true,
|
|
152
|
+
"min": 0,
|
|
153
|
+
"max": 1,
|
|
154
|
+
"description": "As on requirement.functional. Issue or ticket references for outstanding work; free-form, not resolved."
|
|
103
155
|
},
|
|
104
156
|
{
|
|
105
157
|
"type": "attr",
|
|
@@ -126,6 +178,15 @@ export const REQUIREMENT_DEFINITION = {
|
|
|
126
178
|
"max": 1,
|
|
127
179
|
"description": "FQN references to the nodes applying this policy. High fan-out is normal and expected: one uuid-primary-key requirement is claimed by every entity."
|
|
128
180
|
},
|
|
181
|
+
{
|
|
182
|
+
"type": "attr",
|
|
183
|
+
"subType": "string",
|
|
184
|
+
"name": "verifiedBy",
|
|
185
|
+
"isArray": true,
|
|
186
|
+
"min": 0,
|
|
187
|
+
"max": 1,
|
|
188
|
+
"description": "OPTIONAL — omit unless you have opened the test and read what it asserts. Names of tests that assert the policy holds. verify checks each name EXISTS and is not skipped; it never runs them, and it cannot tell whether the named test verifies this requirement — any occurrence in the test corpus satisfies it."
|
|
189
|
+
},
|
|
129
190
|
{
|
|
130
191
|
"type": "attr",
|
|
131
192
|
"subType": "string",
|
|
@@ -133,6 +194,14 @@ export const REQUIREMENT_DEFINITION = {
|
|
|
133
194
|
"min": 0,
|
|
134
195
|
"max": 1,
|
|
135
196
|
"description": "The requirement that replaced this one. Expected on status=superseded."
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"type": "requirement",
|
|
200
|
+
"subType": "*",
|
|
201
|
+
"name": "*",
|
|
202
|
+
"min": 0,
|
|
203
|
+
"max": null,
|
|
204
|
+
"description": "Nested child requirements. Present so a non-functional tree can be organised by a quality taxonomy the same way a functional tree is organised by capability — the absence of this rule, while requirement.functional had it, is what previously made an architectural node nestable UNDER a functional one but never under another architectural one."
|
|
136
205
|
}
|
|
137
206
|
]
|
|
138
207
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"requirement-definition.embedded.js","sourceRoot":"","sources":["../../../src/core/requirement/requirement-definition.embedded.ts"],"names":[],"mappings":"AAQA,MAAM,CAAC,MAAM,sBAAsB,GAAuB;IACxD,UAAU,EAAE,wBAAwB;IACpC,OAAO,EAAE;QACP;YACE,MAAM,EAAE,aAAa;YACrB,SAAS,EAAE,YAAY;YACvB,aAAa,EAAE,gRAAgR;YAC/R,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"requirement-definition.embedded.js","sourceRoot":"","sources":["../../../src/core/requirement/requirement-definition.embedded.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -20,7 +20,7 @@ export const DOCUMENTATION_DEFINITION: ProviderDefinition = {
|
|
|
20
20
|
"name": "description",
|
|
21
21
|
"min": 0,
|
|
22
22
|
"max": 1,
|
|
23
|
-
"description": "
|
|
23
|
+
"description": "What this element IS and COVERS, written for someone using it. Markdown allowed, multi-line via YAML '|' block scalar. Flows into doc-gen surfaces (JSDoc / XML-doc / Postgres COMMENT / Mermaid prose). State scope and boundary — what it covers, what it deliberately does NOT, and which sibling owns the rest — all of which is derivable from the model itself. Anything you had to read the implementation to learn belongs in @notes, not here."
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
"type": "attr",
|
|
@@ -28,7 +28,7 @@ export const DOCUMENTATION_DEFINITION: ProviderDefinition = {
|
|
|
28
28
|
"name": "summary",
|
|
29
29
|
"min": 0,
|
|
30
30
|
"max": 1,
|
|
31
|
-
"description": "Short single-line
|
|
31
|
+
"description": "Short single-line SENTENCE (OpenAPI `summary` pattern) — used in index tables, sidebar previews, and AI prompts where the full @description is too long. Distinct from @title, which is a noun label rather than a sentence. When @summary is unset, doc surfaces typically fall back to the first sentence of @description."
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
34
|
"type": "attr",
|
|
@@ -36,7 +36,7 @@ export const DOCUMENTATION_DEFINITION: ProviderDefinition = {
|
|
|
36
36
|
"name": "title",
|
|
37
37
|
"min": 0,
|
|
38
38
|
"max": 1,
|
|
39
|
-
"description": "Short single-line human label (e.g. 'Email' for a `field.string email`).
|
|
39
|
+
"description": "Short single-line human label — a NOUN PHRASE naming the element (e.g. 'Email' for a `field.string email`), never a sentence. What a tab, an index row or a sidebar shows when the name is an identifier rather than a label. See @summary for the one-line sentence form."
|
|
40
40
|
},
|
|
41
41
|
{
|
|
42
42
|
"type": "attr",
|
|
@@ -44,7 +44,7 @@ export const DOCUMENTATION_DEFINITION: ProviderDefinition = {
|
|
|
44
44
|
"name": "notes",
|
|
45
45
|
"min": 0,
|
|
46
46
|
"max": 1,
|
|
47
|
-
"description": "Internal-only rationale
|
|
47
|
+
"description": "Internal-only rationale, never emitted to user-facing docs — the slot for what you had to look OUTSIDE the model to learn: evidence, measurements, citations, the control that proved an absence was real, and what breaks if this changes. It is NOT a longer @description, and restating the description here is the failure mode this slot invites. Mechanical test: a sentence belongs in @notes exactly when it would have to change because the IMPLEMENTATION changed while the model did not."
|
|
48
48
|
},
|
|
49
49
|
{
|
|
50
50
|
"type": "attr",
|
|
@@ -10,10 +10,15 @@ import {
|
|
|
10
10
|
REQUIREMENT_SUBTYPE_ARCHITECTURAL,
|
|
11
11
|
REQUIREMENT_ATTR_LEVEL,
|
|
12
12
|
REQUIREMENT_ATTR_STATUS,
|
|
13
|
+
REQUIREMENT_ATTR_DISPOSITION,
|
|
14
|
+
REQUIREMENT_ATTR_TRACKED_BY,
|
|
13
15
|
REQUIREMENT_ATTR_IMPLEMENTED_BY,
|
|
14
16
|
REQUIREMENT_ATTR_VERIFIED_BY,
|
|
15
17
|
REQUIREMENT_LINK_FLOOR_LEVEL,
|
|
18
|
+
REQUIREMENT_STATUS_PLANNED,
|
|
16
19
|
REQUIREMENT_STATUSES_REQUIRING_LIVE_NODES,
|
|
20
|
+
REQUIREMENT_STATUSES_WITH_OUTSTANDING_WORK,
|
|
21
|
+
type RequirementDisposition,
|
|
17
22
|
type RequirementStatus,
|
|
18
23
|
} from "./requirement-constants.js";
|
|
19
24
|
|
|
@@ -28,8 +33,10 @@ export class MetaRequirement extends MetaData {
|
|
|
28
33
|
return this.subType === REQUIREMENT_SUBTYPE_ARCHITECTURAL;
|
|
29
34
|
}
|
|
30
35
|
|
|
31
|
-
/** 1 solution · 2 segment · 3 service · 4 object · 5 member.
|
|
32
|
-
*
|
|
36
|
+
/** 1 solution · 2 segment · 3 service · 4 object · 5 member. Required on a
|
|
37
|
+
* functional requirement. OPTIONAL on an architectural one, where absent
|
|
38
|
+
* means the original flat, object-independent form and present means it
|
|
39
|
+
* sits in a levelled tree (a quality taxonomy over non-functional claims). */
|
|
33
40
|
level(): number | undefined {
|
|
34
41
|
const v = this.attr(REQUIREMENT_ATTR_LEVEL);
|
|
35
42
|
return typeof v === "number" ? v : undefined;
|
|
@@ -40,6 +47,32 @@ export class MetaRequirement extends MetaData {
|
|
|
40
47
|
return typeof v === "string" ? (v as RequirementStatus) : undefined;
|
|
41
48
|
}
|
|
42
49
|
|
|
50
|
+
/** What was DECIDED about the outstanding work. Undefined means UNDECIDED —
|
|
51
|
+
* a real state, and the one worth finding in a review. */
|
|
52
|
+
disposition(): RequirementDisposition | undefined {
|
|
53
|
+
const v = this.attr(REQUIREMENT_ATTR_DISPOSITION);
|
|
54
|
+
return typeof v === "string" ? (v as RequirementDisposition) : undefined;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Issue/ticket references. Free-form; never resolved (verify has no network). */
|
|
58
|
+
trackedBy(): string[] {
|
|
59
|
+
const v = this.attr(REQUIREMENT_ATTR_TRACKED_BY);
|
|
60
|
+
return Array.isArray(v) ? (v as string[]) : [];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Intended but not built. Its nodes may legitimately not exist yet, and it
|
|
64
|
+
* must NOT count toward object coverage — planning a capability cannot be
|
|
65
|
+
* allowed to silence the warning that nothing implements it. */
|
|
66
|
+
isPlanned(): boolean {
|
|
67
|
+
return this.status() === REQUIREMENT_STATUS_PLANNED;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** True when there is outstanding work, so a `@disposition` says something. */
|
|
71
|
+
hasOutstandingWork(): boolean {
|
|
72
|
+
const s = this.status();
|
|
73
|
+
return s !== undefined && REQUIREMENT_STATUSES_WITH_OUTSTANDING_WORK.includes(s);
|
|
74
|
+
}
|
|
75
|
+
|
|
43
76
|
implementedBy(): string[] {
|
|
44
77
|
const v = this.attr(REQUIREMENT_ATTR_IMPLEMENTED_BY);
|
|
45
78
|
return Array.isArray(v) ? (v as string[]) : [];
|
|
@@ -51,13 +84,17 @@ export class MetaRequirement extends MetaData {
|
|
|
51
84
|
}
|
|
52
85
|
|
|
53
86
|
/** True when this requirement is permitted to reference the model at all.
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
87
|
+
*
|
|
88
|
+
* An UNLEVELLED architectural requirement always may — its claim set is the
|
|
89
|
+
* whole point, and that is the original flat form. Once a level is present,
|
|
90
|
+
* the node has opted into a tree and the link floor applies to it exactly as
|
|
91
|
+
* it does to a functional one, so an "ISO 25010 Security" grouping node
|
|
92
|
+
* cannot quietly start naming entities. Levelling is the opt-in; enforcing
|
|
93
|
+
* the floor unconditionally would have broken every existing flat policy. */
|
|
57
94
|
mayReferenceModel(): boolean {
|
|
58
|
-
if (this.isArchitectural()) return true;
|
|
59
95
|
const lvl = this.level();
|
|
60
|
-
|
|
96
|
+
if (lvl === undefined) return this.isArchitectural();
|
|
97
|
+
return lvl >= REQUIREMENT_LINK_FLOOR_LEVEL;
|
|
61
98
|
}
|
|
62
99
|
|
|
63
100
|
/** True when a dangling `@implementedBy` is an ERROR rather than expected.
|
|
@@ -27,9 +27,12 @@ export type RequirementSubType = (typeof REQUIREMENT_SUBTYPES)[number];
|
|
|
27
27
|
// Attrs
|
|
28
28
|
// ---------------------------------------------------------------------------
|
|
29
29
|
|
|
30
|
-
/** 1 solution · 2 segment
|
|
30
|
+
/** 1 solution · 2 segment · 3 service · 4 object · 5 member — levels of
|
|
31
|
+
* ABSTRACTION AND OWNERSHIP in the problem domain, never of code structure. */
|
|
31
32
|
export const REQUIREMENT_ATTR_LEVEL = "level";
|
|
32
33
|
export const REQUIREMENT_ATTR_STATUS = "status";
|
|
34
|
+
export const REQUIREMENT_ATTR_DISPOSITION = "disposition";
|
|
35
|
+
export const REQUIREMENT_ATTR_TRACKED_BY = "trackedBy";
|
|
33
36
|
export const REQUIREMENT_ATTR_STATEMENT = "statement";
|
|
34
37
|
export const REQUIREMENT_ATTR_VIOLATION = "violation";
|
|
35
38
|
export const REQUIREMENT_ATTR_IMPLEMENTED_BY = "implementedBy";
|
|
@@ -43,12 +46,14 @@ export const REQUIREMENT_ATTR_SUPERSEDED_BY = "supersededBy";
|
|
|
43
46
|
// disabled it would disable the whole mechanism.
|
|
44
47
|
// ---------------------------------------------------------------------------
|
|
45
48
|
|
|
49
|
+
export const REQUIREMENT_STATUS_PLANNED = "planned";
|
|
46
50
|
export const REQUIREMENT_STATUS_LIVE = "live";
|
|
47
51
|
export const REQUIREMENT_STATUS_PARTIAL = "partial";
|
|
48
52
|
export const REQUIREMENT_STATUS_ABANDONED = "abandoned";
|
|
49
53
|
export const REQUIREMENT_STATUS_SUPERSEDED = "superseded";
|
|
50
54
|
|
|
51
55
|
export const REQUIREMENT_STATUSES = [
|
|
56
|
+
REQUIREMENT_STATUS_PLANNED,
|
|
52
57
|
REQUIREMENT_STATUS_LIVE,
|
|
53
58
|
REQUIREMENT_STATUS_PARTIAL,
|
|
54
59
|
REQUIREMENT_STATUS_ABANDONED,
|
|
@@ -58,13 +63,37 @@ export type RequirementStatus = (typeof REQUIREMENT_STATUSES)[number];
|
|
|
58
63
|
|
|
59
64
|
/** Statuses whose implementing nodes are supposed to still exist. A dangling
|
|
60
65
|
* `@implementedBy` on one of these means the model moved and the requirement is
|
|
61
|
-
* stale
|
|
62
|
-
*
|
|
66
|
+
* stale. On `planned` the nodes do not exist YET; on `abandoned`/`superseded`
|
|
67
|
+
* they are supposed to be GONE — which is the whole point of those entries. */
|
|
63
68
|
export const REQUIREMENT_STATUSES_REQUIRING_LIVE_NODES: readonly RequirementStatus[] = [
|
|
64
69
|
REQUIREMENT_STATUS_LIVE,
|
|
65
70
|
REQUIREMENT_STATUS_PARTIAL,
|
|
66
71
|
];
|
|
67
72
|
|
|
73
|
+
/** Statuses with outstanding work, so a `@disposition` is meaningful on them.
|
|
74
|
+
* On any other status the decision IS the status, and recording a second one
|
|
75
|
+
* can only agree with it or contradict it. */
|
|
76
|
+
export const REQUIREMENT_STATUSES_WITH_OUTSTANDING_WORK: readonly RequirementStatus[] = [
|
|
77
|
+
REQUIREMENT_STATUS_PLANNED,
|
|
78
|
+
REQUIREMENT_STATUS_PARTIAL,
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
// Disposition — what was DECIDED about the outstanding work. Orthogonal to
|
|
83
|
+
// status, which says whether the work is done. Absent means UNDECIDED, and that
|
|
84
|
+
// is the state a review exists to find; collapsing it into the status enum
|
|
85
|
+
// would make "there is a gap" and "we chose to live with it" the same fact.
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
87
|
+
|
|
88
|
+
export const REQUIREMENT_DISPOSITION_ACCEPTED = "accepted";
|
|
89
|
+
export const REQUIREMENT_DISPOSITION_DEFERRED = "deferred";
|
|
90
|
+
|
|
91
|
+
export const REQUIREMENT_DISPOSITIONS = [
|
|
92
|
+
REQUIREMENT_DISPOSITION_ACCEPTED,
|
|
93
|
+
REQUIREMENT_DISPOSITION_DEFERRED,
|
|
94
|
+
] as const;
|
|
95
|
+
export type RequirementDisposition = (typeof REQUIREMENT_DISPOSITIONS)[number];
|
|
96
|
+
|
|
68
97
|
// ---------------------------------------------------------------------------
|
|
69
98
|
// Levels — organisational above the link floor, model-referencing at or below.
|
|
70
99
|
// ---------------------------------------------------------------------------
|
|
@@ -13,7 +13,7 @@ export const REQUIREMENT_DEFINITION: ProviderDefinition = {
|
|
|
13
13
|
"type": "requirement",
|
|
14
14
|
"subType": "functional",
|
|
15
15
|
"description": "What the product does for a user, stated as one violable claim. Its check is EXISTENCE: it fails when nothing implements it. Hierarchy is nesting — an L1 solution contains its L2 segments, which contain L3 services, and so on down to the levels that reference the model.",
|
|
16
|
-
"whenToUse": "Something exists because someone asked for it.
|
|
16
|
+
"whenToUse": "Something exists because someone asked for it. L1-L3 are levels of ABSTRACTION AND OWNERSHIP in the problem domain — whose need is this, and at what altitude — and are never a directory, package, deployable or module. Binding to technical constructs happens only at L4 (an object) and L5 (a member), which is the allocation step. Test every node: if a refactor that changes no behaviour would force it to move, its level is wrong.",
|
|
17
17
|
"children": [
|
|
18
18
|
{
|
|
19
19
|
"type": "attr",
|
|
@@ -21,7 +21,7 @@ export const REQUIREMENT_DEFINITION: ProviderDefinition = {
|
|
|
21
21
|
"name": "level",
|
|
22
22
|
"min": 1,
|
|
23
23
|
"max": 1,
|
|
24
|
-
"description": "1 solution, 2 segment
|
|
24
|
+
"description": "1 solution, 2 segment, 3 service, 4 object, 5 member. L1-L3 are levels of abstraction and ownership in the problem domain, NOT of code structure. Nesting depth must agree with it; skipping a level is legal, going back up is not."
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
27
|
"type": "attr",
|
|
@@ -30,12 +30,34 @@ export const REQUIREMENT_DEFINITION: ProviderDefinition = {
|
|
|
30
30
|
"min": 1,
|
|
31
31
|
"max": 1,
|
|
32
32
|
"allowedValues": [
|
|
33
|
+
"planned",
|
|
33
34
|
"live",
|
|
34
35
|
"partial",
|
|
35
36
|
"abandoned",
|
|
36
37
|
"superseded"
|
|
37
38
|
],
|
|
38
|
-
"description": "live implemented and in use; partial implemented with known gaps; abandoned built then deliberately retired; superseded replaced by a different mechanism. A dangling @implementedBy is an ERROR on live/partial (the model moved, the requirement is stale) and ALLOWED on abandoned/superseded
|
|
39
|
+
"description": "planned intended but not built yet; live implemented and in use; partial implemented with known gaps; abandoned built then deliberately retired; superseded replaced by a different mechanism. A dangling @implementedBy is an ERROR on live/partial (the model moved, the requirement is stale) and ALLOWED on planned/abandoned/superseded — on planned the nodes do not exist YET, on the other two they are meant to be gone, and that is the entry doing its job. A planned requirement also never contributes to object coverage: planning a capability must not silence the warning that nothing implements it."
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"type": "attr",
|
|
43
|
+
"subType": "string",
|
|
44
|
+
"name": "disposition",
|
|
45
|
+
"min": 0,
|
|
46
|
+
"max": 1,
|
|
47
|
+
"allowedValues": [
|
|
48
|
+
"accepted",
|
|
49
|
+
"deferred"
|
|
50
|
+
],
|
|
51
|
+
"description": "What has been DECIDED about outstanding work — a different question from whether the work is done, which is what @status answers. accepted: the gap is understood and deliberately not being closed. deferred: it will be closed, but not now. ABSENT MEANS UNDECIDED, which is a real and useful state — it is what an unreviewed gap looks like, and it is the one a review should be able to find. Meaningful on planned and partial only; on a status with no outstanding work it is a WARNING. Deliberately NOT a workflow vocabulary: which sprint, who owns it and whether it is in progress belong in the tracker named by @trackedBy, because two systems holding that answer will drift and only one of them is refreshed daily."
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"type": "attr",
|
|
55
|
+
"subType": "string",
|
|
56
|
+
"name": "trackedBy",
|
|
57
|
+
"isArray": true,
|
|
58
|
+
"min": 0,
|
|
59
|
+
"max": 1,
|
|
60
|
+
"description": "Issue or ticket references for outstanding work — a URL, an owner/repo#123 shorthand, or a tracker key. Free-form and NOT resolved by verify, which does not reach the network; unlike @verifiedBy, nothing here is checked to exist. Its job is to stop a deferred gap becoming invisible, so verify warns when a deferred requirement names no ticket. Also the right place to link the ticket that a planned requirement will be built under."
|
|
39
61
|
},
|
|
40
62
|
{
|
|
41
63
|
"type": "attr",
|
|
@@ -69,7 +91,7 @@ export const REQUIREMENT_DEFINITION: ProviderDefinition = {
|
|
|
69
91
|
"isArray": true,
|
|
70
92
|
"min": 0,
|
|
71
93
|
"max": 1,
|
|
72
|
-
"description": "Names of
|
|
94
|
+
"description": "OPTIONAL — omit unless you have opened the test and read what it asserts. Names of tests that assert the behaviour. verify checks each name EXISTS and is not skipped; it never runs them, and it cannot tell whether the named test verifies this requirement — any occurrence in the test corpus satisfies it."
|
|
73
95
|
},
|
|
74
96
|
{
|
|
75
97
|
"type": "attr",
|
|
@@ -92,9 +114,17 @@ export const REQUIREMENT_DEFINITION: ProviderDefinition = {
|
|
|
92
114
|
{
|
|
93
115
|
"type": "requirement",
|
|
94
116
|
"subType": "architectural",
|
|
95
|
-
"description": "How the system is built, applied uniformly across the model. Its check is UNIVERSALITY: it fails when something VIOLATES it, which is the opposite polarity to a functional requirement.
|
|
96
|
-
"whenToUse": "Something exists because every entity here looks like this — a uuid primary key, an @autoSet createdAt, a change-attribution column, tenant scoping. The discriminator is mechanical: did this exist because someone asked for something, or because it is the architecture?",
|
|
117
|
+
"description": "How the system is built, applied uniformly across the model. Its check is UNIVERSALITY: it fails when something VIOLATES it, which is the opposite polarity to a functional requirement. Flat by default and object-independent; it may optionally sit in a levelled tree when a quality taxonomy is being used to organise non-functional requirements.",
|
|
118
|
+
"whenToUse": "Something exists because every entity here looks like this — a uuid primary key, an @autoSet createdAt, a change-attribution column, tenant scoping. The discriminator is mechanical: did this exist because someone asked for something, or because it is the architecture? For a non-functional tree, an established quality taxonomy makes a good fixed upper structure (e.g. an ISO/IEC 25010 characteristic at L1, its sub-characteristic or a control-catalogue category at L2), with the model-binding claims at L4 and L5 as usual.",
|
|
97
119
|
"children": [
|
|
120
|
+
{
|
|
121
|
+
"type": "attr",
|
|
122
|
+
"subType": "int",
|
|
123
|
+
"name": "level",
|
|
124
|
+
"min": 0,
|
|
125
|
+
"max": 1,
|
|
126
|
+
"description": "OPTIONAL here, unlike on a functional requirement where it is required. ABSENT means a flat, object-independent policy that may reference the model directly — the original and still the default form. PRESENT means this node sits in a levelled tree, and then the same rules as functional apply: nesting must agree with the level, and only L4/L5 may carry @implementedBy. Levelling is opt-in so that adding a taxonomy on top of existing flat policies does not invalidate them."
|
|
127
|
+
},
|
|
98
128
|
{
|
|
99
129
|
"type": "attr",
|
|
100
130
|
"subType": "string",
|
|
@@ -102,12 +132,34 @@ export const REQUIREMENT_DEFINITION: ProviderDefinition = {
|
|
|
102
132
|
"min": 1,
|
|
103
133
|
"max": 1,
|
|
104
134
|
"allowedValues": [
|
|
135
|
+
"planned",
|
|
105
136
|
"live",
|
|
106
137
|
"partial",
|
|
107
138
|
"abandoned",
|
|
108
139
|
"superseded"
|
|
109
140
|
],
|
|
110
|
-
"description": "As on requirement.functional. A live or partial architectural requirement claimed by NOTHING is an error: a policy declared and applied to nothing."
|
|
141
|
+
"description": "As on requirement.functional. A live or partial architectural requirement claimed by NOTHING is an error: a policy declared and applied to nothing. A planned one is exempt from that check — it is not applied yet by definition."
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"type": "attr",
|
|
145
|
+
"subType": "string",
|
|
146
|
+
"name": "disposition",
|
|
147
|
+
"min": 0,
|
|
148
|
+
"max": 1,
|
|
149
|
+
"allowedValues": [
|
|
150
|
+
"accepted",
|
|
151
|
+
"deferred"
|
|
152
|
+
],
|
|
153
|
+
"description": "As on requirement.functional. On an architectural requirement, accepted is the common and important case: a policy that is genuinely not universal, where the exceptions are known and tolerated, is more honest as partial+accepted than as a live claim nobody audits."
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"type": "attr",
|
|
157
|
+
"subType": "string",
|
|
158
|
+
"name": "trackedBy",
|
|
159
|
+
"isArray": true,
|
|
160
|
+
"min": 0,
|
|
161
|
+
"max": 1,
|
|
162
|
+
"description": "As on requirement.functional. Issue or ticket references for outstanding work; free-form, not resolved."
|
|
111
163
|
},
|
|
112
164
|
{
|
|
113
165
|
"type": "attr",
|
|
@@ -134,6 +186,15 @@ export const REQUIREMENT_DEFINITION: ProviderDefinition = {
|
|
|
134
186
|
"max": 1,
|
|
135
187
|
"description": "FQN references to the nodes applying this policy. High fan-out is normal and expected: one uuid-primary-key requirement is claimed by every entity."
|
|
136
188
|
},
|
|
189
|
+
{
|
|
190
|
+
"type": "attr",
|
|
191
|
+
"subType": "string",
|
|
192
|
+
"name": "verifiedBy",
|
|
193
|
+
"isArray": true,
|
|
194
|
+
"min": 0,
|
|
195
|
+
"max": 1,
|
|
196
|
+
"description": "OPTIONAL — omit unless you have opened the test and read what it asserts. Names of tests that assert the policy holds. verify checks each name EXISTS and is not skipped; it never runs them, and it cannot tell whether the named test verifies this requirement — any occurrence in the test corpus satisfies it."
|
|
197
|
+
},
|
|
137
198
|
{
|
|
138
199
|
"type": "attr",
|
|
139
200
|
"subType": "string",
|
|
@@ -141,6 +202,14 @@ export const REQUIREMENT_DEFINITION: ProviderDefinition = {
|
|
|
141
202
|
"min": 0,
|
|
142
203
|
"max": 1,
|
|
143
204
|
"description": "The requirement that replaced this one. Expected on status=superseded."
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
"type": "requirement",
|
|
208
|
+
"subType": "*",
|
|
209
|
+
"name": "*",
|
|
210
|
+
"min": 0,
|
|
211
|
+
"max": null,
|
|
212
|
+
"description": "Nested child requirements. Present so a non-functional tree can be organised by a quality taxonomy the same way a functional tree is organised by capability — the absence of this rule, while requirement.functional had it, is what previously made an architectural node nestable UNDER a functional one but never under another architectural one."
|
|
144
213
|
}
|
|
145
214
|
]
|
|
146
215
|
}
|