@metaobjectsdev/metadata 0.24.1 → 0.24.3
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/attr-contradictions.d.ts +52 -0
- package/dist/attr-contradictions.d.ts.map +1 -0
- package/dist/attr-contradictions.js +100 -0
- package/dist/attr-contradictions.js.map +1 -0
- package/dist/core/requirement/meta-requirement.d.ts +9 -1
- package/dist/core/requirement/meta-requirement.d.ts.map +1 -1
- package/dist/core/requirement/meta-requirement.js +15 -2
- package/dist/core/requirement/meta-requirement.js.map +1 -1
- package/dist/core/requirement/requirement-constants.d.ts +30 -2
- package/dist/core/requirement/requirement-constants.d.ts.map +1 -1
- package/dist/core/requirement/requirement-constants.js +32 -1
- 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 +22 -4
- package/dist/core/requirement/requirement-definition.embedded.js.map +1 -1
- package/dist/core/vocabulary-rewrite-yaml.d.ts.map +1 -1
- package/dist/core/vocabulary-rewrite-yaml.js +103 -0
- package/dist/core/vocabulary-rewrite-yaml.js.map +1 -1
- package/dist/errors.d.ts +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +10 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/loader/meta-data-loader.d.ts.map +1 -1
- package/dist/loader/meta-data-loader.js +5 -1
- package/dist/loader/meta-data-loader.js.map +1 -1
- package/dist/loader/validation-passes.d.ts +1 -0
- package/dist/loader/validation-passes.d.ts.map +1 -1
- package/dist/loader/validation-passes.js +73 -6
- package/dist/loader/validation-passes.js.map +1 -1
- package/dist/registry-manifest.d.ts +1 -1
- package/dist/registry-manifest.js +1 -1
- package/dist/retired-vocabulary.d.ts.map +1 -1
- package/dist/retired-vocabulary.js +54 -11
- package/dist/retired-vocabulary.js.map +1 -1
- package/dist/vocabulary-rewrite.d.ts.map +1 -1
- package/dist/vocabulary-rewrite.js +115 -7
- package/dist/vocabulary-rewrite.js.map +1 -1
- package/package.json +1 -1
- package/src/attr-contradictions.ts +141 -0
- package/src/core/requirement/meta-requirement.ts +18 -1
- package/src/core/requirement/requirement-constants.ts +34 -1
- package/src/core/requirement/requirement-definition.embedded.ts +22 -4
- package/src/core/vocabulary-rewrite-yaml.ts +108 -0
- package/src/errors.ts +10 -0
- package/src/index.ts +9 -0
- package/src/loader/meta-data-loader.ts +6 -1
- package/src/loader/validation-passes.ts +95 -5
- package/src/registry-manifest.ts +1 -1
- package/src/retired-vocabulary.ts +54 -11
- package/src/vocabulary-rewrite.ts +125 -7
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One pair of attributes that may not co-occur on a node.
|
|
3
|
+
*
|
|
4
|
+
* `drop` and `keep` are named for the REWRITE, not for importance: an entry exists only
|
|
5
|
+
* where one side is provably redundant. An entry with no mechanical answer does not belong
|
|
6
|
+
* here — it belongs in the loader alone, refusing.
|
|
7
|
+
*/
|
|
8
|
+
export interface AttrContradiction {
|
|
9
|
+
readonly type: string;
|
|
10
|
+
/** `*` for every subtype of `type`, else the exact subtype. */
|
|
11
|
+
readonly subType: string;
|
|
12
|
+
/** Declared alongside `keep`, this one goes. Matched on PRESENCE — see below. */
|
|
13
|
+
readonly drop: string;
|
|
14
|
+
/** The attribute whose presence makes `drop` illegal, and which survives the rewrite. */
|
|
15
|
+
readonly keep: string;
|
|
16
|
+
/**
|
|
17
|
+
* When set, `keep` makes `drop` illegal only at THESE values — the pair is a
|
|
18
|
+
* contradiction of meaning rather than of mere co-occurrence.
|
|
19
|
+
*
|
|
20
|
+
* It lists every spelling that has ever carried the meaning, across the version
|
|
21
|
+
* boundary, and that is load-bearing rather than defensive: the rewriter runs the
|
|
22
|
+
* contradiction pass BEFORE the retirement pass, so a legacy document still says
|
|
23
|
+
* `abandoned` at the moment this is evaluated. Listing only the modern value would
|
|
24
|
+
* make `meta upgrade --apply` rewrite the status, leave the contradicting sibling
|
|
25
|
+
* behind, and exit 0 on a file that still does not load — the exact failure #342
|
|
26
|
+
* was filed for.
|
|
27
|
+
*/
|
|
28
|
+
readonly keepValues?: readonly string[];
|
|
29
|
+
/** The release that started refusing the pair. */
|
|
30
|
+
readonly since: string;
|
|
31
|
+
/** One line stating the RULE, in the present tense — the loader has already said WHICH
|
|
32
|
+
* node broke it, so this says what the rule is. */
|
|
33
|
+
readonly why: string;
|
|
34
|
+
/** What the rewrite costs, completing "so <effect>" — the sentence that tells an adopter
|
|
35
|
+
* it is safe to run, and why the answer is not a guess. */
|
|
36
|
+
readonly effect: string;
|
|
37
|
+
}
|
|
38
|
+
export declare const ATTR_CONTRADICTIONS: readonly AttrContradiction[];
|
|
39
|
+
/** True when `c` governs `typeKey` (`"<type>.<subType>"`). Mirrors `scopeMatches`. */
|
|
40
|
+
export declare function contradictionScopeMatches(c: AttrContradiction, typeKey: string): boolean;
|
|
41
|
+
/** Every contradiction governing this type key. */
|
|
42
|
+
export declare function contradictionsFor(typeKey: string): readonly AttrContradiction[];
|
|
43
|
+
/**
|
|
44
|
+
* The sentence appended to the load error that refuses the pair.
|
|
45
|
+
*
|
|
46
|
+
* Kept beside the table for the reason #337 recorded: an adopter who is told only that
|
|
47
|
+
* their metadata is invalid concludes the tool is broken, because nothing in the message
|
|
48
|
+
* says a fixer exists. Naming the command is the difference between a dead end and a
|
|
49
|
+
* one-line migration.
|
|
50
|
+
*/
|
|
51
|
+
export declare function contradictionHint(c: AttrContradiction): string;
|
|
52
|
+
//# sourceMappingURL=attr-contradictions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attr-contradictions.d.ts","sourceRoot":"","sources":["../src/attr-contradictions.ts"],"names":[],"mappings":"AA4BA;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,iFAAiF;IACjF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,yFAAyF;IACzF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,kDAAkD;IAClD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;wDACoD;IACpD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB;gEAC4D;IAC5D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,eAAO,MAAM,mBAAmB,EAAE,SAAS,iBAAiB,EA8C3D,CAAC;AAEF,sFAAsF;AACtF,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAKxF;AAED,mDAAmD;AACnD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,iBAAiB,EAAE,CAE/E;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,iBAAiB,GAAG,MAAM,CAK9D"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// server/typescript/packages/metadata/src/attr-contradictions.ts
|
|
2
|
+
//
|
|
3
|
+
// Pairs of LIVE attributes that may not both be declared on one node — and, where the
|
|
4
|
+
// resolution is mechanical, which one `meta upgrade` drops.
|
|
5
|
+
//
|
|
6
|
+
// THE SIBLING OF `retired-vocabulary.ts`, DELIBERATELY NOT PART OF IT. That table answers
|
|
7
|
+
// "this name is gone"; this one answers "both these names are fine, and together they are
|
|
8
|
+
// not". The match shape differs (one attribute versus a pair on the same node), the fix
|
|
9
|
+
// shape differs (rewrite a value versus delete one of two), and folding them together
|
|
10
|
+
// would give every retirement entry fields it can never use. They share the thing that
|
|
11
|
+
// matters instead: both are consulted by the LOADER for its diagnostic and by the
|
|
12
|
+
// `meta upgrade` rewriter for its fix, so the message an adopter reads and the edit the
|
|
13
|
+
// tool makes come from one place and cannot drift apart.
|
|
14
|
+
//
|
|
15
|
+
// WHY A MECHANICAL FIX IS AVAILABLE HERE AT ALL, when `@status: abandoned` is refused.
|
|
16
|
+
// A refusal is right when the correct edit depends on intent nobody recorded. It is wrong
|
|
17
|
+
// when the metadata's own history says what the declaration MEANT. `@fields` + `@expr`
|
|
18
|
+
// loaded before 0.24.1 and `@fields` was silently DISCARDED — `migrate-ts` has always run
|
|
19
|
+
// `columns: expr ? [] : cols`, so the index in the adopter's database is the expression
|
|
20
|
+
// one. Dropping `@fields` therefore reproduces the object that already exists; keeping
|
|
21
|
+
// `@fields` and dropping `@expr` would invent a different index and emit a migration
|
|
22
|
+
// against live data. There is one answer, and the deployed schema is the evidence for it.
|
|
23
|
+
//
|
|
24
|
+
// CROSS-PORT: like the retirement map this is a DIAGNOSTIC plus a TS-only fixer. It
|
|
25
|
+
// changes no load OUTCOME — every port already refuses the contradiction with the same
|
|
26
|
+
// code — and the shared corpus compares error code and source, never message text. So it
|
|
27
|
+
// carries no registry-conformance obligation; mirroring it is per-port ergonomics.
|
|
28
|
+
export const ATTR_CONTRADICTIONS = [
|
|
29
|
+
// ── FR-039: a retired requirement has no implementation (0.24.2) ──
|
|
30
|
+
//
|
|
31
|
+
// The pair is @status: retired + @implementedBy. It is a contradiction of MEANING,
|
|
32
|
+
// not of co-occurrence — @status and @implementedBy sit together happily on every
|
|
33
|
+
// other status — which is why this is the first entry needing `keepValues`.
|
|
34
|
+
//
|
|
35
|
+
// Mechanical, and the reason it is: a retired capability has no implementation BY
|
|
36
|
+
// DEFINITION, so the reference list describes nodes that are gone. That is not a
|
|
37
|
+
// judgement call about what the author meant; it is what retiring something IS. The
|
|
38
|
+
// record of what used to implement it belongs in `notes` (the shape one adopting
|
|
39
|
+
// estate reached by hand before any ruling, on the grounds that "what used to
|
|
40
|
+
// implement a retired capability is real information in the wrong field") and what
|
|
41
|
+
// REPLACED it belongs in @supersededBy, which resolves.
|
|
42
|
+
{
|
|
43
|
+
type: "requirement", subType: "*",
|
|
44
|
+
drop: "implementedBy", keep: "status",
|
|
45
|
+
keepValues: ["retired", "abandoned", "superseded"],
|
|
46
|
+
since: "0.24.2",
|
|
47
|
+
why: "a retired requirement has no implementation — that is what retiring it means",
|
|
48
|
+
effect: "the references named nodes that are gone, so dropping them removes a list " +
|
|
49
|
+
"nothing could resolve; what REPLACED the capability goes in @supersededBy " +
|
|
50
|
+
"and why it went goes in `notes`",
|
|
51
|
+
},
|
|
52
|
+
// ── #342: an index key is @fields XOR @expr (0.24.1) ──
|
|
53
|
+
//
|
|
54
|
+
// Both subtypes, because ADR-0040 puts uniqueness in the TYPE: `identity.secondary` IS a
|
|
55
|
+
// unique index, keys itself identically, and carries `@expr` from the same db provider.
|
|
56
|
+
// `identity.primary` and `identity.reference` are absent on purpose — a primary key or an
|
|
57
|
+
// FK is always plain columns and has no `@expr` to contradict.
|
|
58
|
+
{
|
|
59
|
+
type: "index", subType: "lookup",
|
|
60
|
+
drop: "fields", keep: "expr",
|
|
61
|
+
since: "0.24.1",
|
|
62
|
+
why: "an index keys off plain columns (@fields) or a key expression (@expr), never both",
|
|
63
|
+
effect: "the index in your database is the expression one and dropping @fields " +
|
|
64
|
+
"changes no emitted DDL",
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
type: "identity", subType: "secondary",
|
|
68
|
+
drop: "fields", keep: "expr",
|
|
69
|
+
since: "0.24.1",
|
|
70
|
+
why: "a unique key keys off plain columns (@fields) or a key expression (@expr), never both",
|
|
71
|
+
effect: "the constraint in your database is the expression one and dropping @fields " +
|
|
72
|
+
"changes no emitted DDL",
|
|
73
|
+
},
|
|
74
|
+
];
|
|
75
|
+
/** True when `c` governs `typeKey` (`"<type>.<subType>"`). Mirrors `scopeMatches`. */
|
|
76
|
+
export function contradictionScopeMatches(c, typeKey) {
|
|
77
|
+
const dot = typeKey.indexOf(".");
|
|
78
|
+
if (dot < 0)
|
|
79
|
+
return false;
|
|
80
|
+
if (c.type !== typeKey.slice(0, dot))
|
|
81
|
+
return false;
|
|
82
|
+
return c.subType === "*" || c.subType === typeKey.slice(dot + 1);
|
|
83
|
+
}
|
|
84
|
+
/** Every contradiction governing this type key. */
|
|
85
|
+
export function contradictionsFor(typeKey) {
|
|
86
|
+
return ATTR_CONTRADICTIONS.filter((c) => contradictionScopeMatches(c, typeKey));
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The sentence appended to the load error that refuses the pair.
|
|
90
|
+
*
|
|
91
|
+
* Kept beside the table for the reason #337 recorded: an adopter who is told only that
|
|
92
|
+
* their metadata is invalid concludes the tool is broken, because nothing in the message
|
|
93
|
+
* says a fixer exists. Naming the command is the difference between a dead end and a
|
|
94
|
+
* one-line migration.
|
|
95
|
+
*/
|
|
96
|
+
export function contradictionHint(c) {
|
|
97
|
+
return (`${c.why} — drop one. Declaring both previously loaded but silently discarded ` +
|
|
98
|
+
`@${c.drop}, so ${c.effect}. \`meta upgrade --apply\` drops it for you.`);
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=attr-contradictions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attr-contradictions.js","sourceRoot":"","sources":["../src/attr-contradictions.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,EAAE;AACF,sFAAsF;AACtF,4DAA4D;AAC5D,EAAE;AACF,0FAA0F;AAC1F,0FAA0F;AAC1F,wFAAwF;AACxF,sFAAsF;AACtF,uFAAuF;AACvF,kFAAkF;AAClF,wFAAwF;AACxF,yDAAyD;AACzD,EAAE;AACF,uFAAuF;AACvF,0FAA0F;AAC1F,uFAAuF;AACvF,0FAA0F;AAC1F,wFAAwF;AACxF,uFAAuF;AACvF,qFAAqF;AACrF,0FAA0F;AAC1F,EAAE;AACF,oFAAoF;AACpF,uFAAuF;AACvF,yFAAyF;AACzF,mFAAmF;AAwCnF,MAAM,CAAC,MAAM,mBAAmB,GAAiC;IAC/D,qEAAqE;IACrE,EAAE;IACF,mFAAmF;IACnF,kFAAkF;IAClF,4EAA4E;IAC5E,EAAE;IACF,kFAAkF;IAClF,iFAAiF;IACjF,oFAAoF;IACpF,iFAAiF;IACjF,8EAA8E;IAC9E,mFAAmF;IACnF,wDAAwD;IACxD;QACE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,GAAG;QACjC,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,QAAQ;QACrC,UAAU,EAAE,CAAC,SAAS,EAAE,WAAW,EAAE,YAAY,CAAC;QAClD,KAAK,EAAE,QAAQ;QACf,GAAG,EAAE,8EAA8E;QACnF,MAAM,EAAE,4EAA4E;YAC5E,4EAA4E;YAC5E,iCAAiC;KAC1C;IACD,yDAAyD;IACzD,EAAE;IACF,yFAAyF;IACzF,wFAAwF;IACxF,0FAA0F;IAC1F,+DAA+D;IAC/D;QACE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ;QAChC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM;QAC5B,KAAK,EAAE,QAAQ;QACf,GAAG,EAAE,mFAAmF;QACxF,MAAM,EAAE,wEAAwE;YACxE,wBAAwB;KACjC;IACD;QACE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,WAAW;QACtC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM;QAC5B,KAAK,EAAE,QAAQ;QACf,GAAG,EAAE,uFAAuF;QAC5F,MAAM,EAAE,6EAA6E;YAC7E,wBAAwB;KACjC;CACF,CAAC;AAEF,sFAAsF;AACtF,MAAM,UAAU,yBAAyB,CAAC,CAAoB,EAAE,OAAe;IAC7E,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACjC,IAAI,GAAG,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1B,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACnD,OAAO,CAAC,CAAC,OAAO,KAAK,GAAG,IAAI,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;AACnE,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,OAAO,mBAAmB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,yBAAyB,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;AAClF,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAAC,CAAoB;IACpD,OAAO,CACL,GAAG,CAAC,CAAC,GAAG,uEAAuE;QAC/E,IAAI,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,MAAM,8CAA8C,CACzE,CAAC;AACJ,CAAC"}
|
|
@@ -22,6 +22,13 @@ export declare class MetaRequirement extends MetaData {
|
|
|
22
22
|
isPlanned(): boolean;
|
|
23
23
|
/** True when there is outstanding work, so a `@disposition` says something. */
|
|
24
24
|
hasOutstandingWork(): boolean;
|
|
25
|
+
/** Built, then deliberately removed. Carries no `@implementedBy` (the loader
|
|
26
|
+
* refuses it), never counts toward object coverage, and is exempt from the
|
|
27
|
+
* architectural universality check — a withdrawn policy governs nothing. */
|
|
28
|
+
isRetired(): boolean;
|
|
29
|
+
/** The requirement that REPLACED this one (FR-039). Legal on `retired` only;
|
|
30
|
+
* `verify` resolves it, so a supersession chain stays walkable. */
|
|
31
|
+
supersededBy(): string | undefined;
|
|
25
32
|
implementedBy(): string[];
|
|
26
33
|
/** True when this requirement is permitted to reference the model at all.
|
|
27
34
|
*
|
|
@@ -33,7 +40,8 @@ export declare class MetaRequirement extends MetaData {
|
|
|
33
40
|
* the floor unconditionally would have broken every existing flat policy. */
|
|
34
41
|
mayReferenceModel(): boolean;
|
|
35
42
|
/** True when a dangling `@implementedBy` is an ERROR rather than expected.
|
|
36
|
-
* `planned` is
|
|
43
|
+
* `planned` is exempt (the nodes do not exist YET) and `retired` cannot reach
|
|
44
|
+
* this at all, because the loader refuses `@implementedBy` there. */
|
|
37
45
|
requiresLiveNodes(): boolean;
|
|
38
46
|
}
|
|
39
47
|
//# sourceMappingURL=meta-requirement.d.ts.map
|
|
@@ -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,EAYL,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,
|
|
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,EAYL,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EAGvB,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;;iFAE6E;IAC7E,SAAS,IAAI,OAAO;IAIpB;wEACoE;IACpE,YAAY,IAAI,MAAM,GAAG,SAAS;IAKlC,aAAa,IAAI,MAAM,EAAE;IAKzB;;;;;;;kFAO8E;IAC9E,iBAAiB,IAAI,OAAO;IAM5B;;0EAEsE;IACtE,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_DISPOSITION, REQUIREMENT_ATTR_TRACKED_BY, REQUIREMENT_ATTR_IMPLEMENTED_BY, REQUIREMENT_LINK_FLOOR_LEVEL, REQUIREMENT_STATUS_PLANNED, REQUIREMENT_STATUSES_REQUIRING_LIVE_NODES, REQUIREMENT_STATUSES_WITH_OUTSTANDING_WORK, } 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_LINK_FLOOR_LEVEL, REQUIREMENT_STATUS_PLANNED, REQUIREMENT_STATUSES_REQUIRING_LIVE_NODES, REQUIREMENT_STATUSES_WITH_OUTSTANDING_WORK, REQUIREMENT_STATUS_RETIRED, REQUIREMENT_ATTR_SUPERSEDED_BY, } 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() {
|
|
@@ -48,6 +48,18 @@ export class MetaRequirement extends MetaData {
|
|
|
48
48
|
const s = this.status();
|
|
49
49
|
return s !== undefined && REQUIREMENT_STATUSES_WITH_OUTSTANDING_WORK.includes(s);
|
|
50
50
|
}
|
|
51
|
+
/** Built, then deliberately removed. Carries no `@implementedBy` (the loader
|
|
52
|
+
* refuses it), never counts toward object coverage, and is exempt from the
|
|
53
|
+
* architectural universality check — a withdrawn policy governs nothing. */
|
|
54
|
+
isRetired() {
|
|
55
|
+
return this.status() === REQUIREMENT_STATUS_RETIRED;
|
|
56
|
+
}
|
|
57
|
+
/** The requirement that REPLACED this one (FR-039). Legal on `retired` only;
|
|
58
|
+
* `verify` resolves it, so a supersession chain stays walkable. */
|
|
59
|
+
supersededBy() {
|
|
60
|
+
const v = this.attr(REQUIREMENT_ATTR_SUPERSEDED_BY);
|
|
61
|
+
return typeof v === "string" && v.trim() !== "" ? v : undefined;
|
|
62
|
+
}
|
|
51
63
|
implementedBy() {
|
|
52
64
|
const v = this.attr(REQUIREMENT_ATTR_IMPLEMENTED_BY);
|
|
53
65
|
return Array.isArray(v) ? v : [];
|
|
@@ -67,7 +79,8 @@ export class MetaRequirement extends MetaData {
|
|
|
67
79
|
return lvl >= REQUIREMENT_LINK_FLOOR_LEVEL;
|
|
68
80
|
}
|
|
69
81
|
/** True when a dangling `@implementedBy` is an ERROR rather than expected.
|
|
70
|
-
* `planned` is
|
|
82
|
+
* `planned` is exempt (the nodes do not exist YET) and `retired` cannot reach
|
|
83
|
+
* this at all, because the loader refuses `@implementedBy` there. */
|
|
71
84
|
requiresLiveNodes() {
|
|
72
85
|
const s = this.status();
|
|
73
86
|
return s !== undefined && REQUIREMENT_STATUSES_REQUIRING_LIVE_NODES.includes(s);
|
|
@@ -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,4BAA4B,EAC5B,2BAA2B,EAC3B,+BAA+B,EAC/B,4BAA4B,EAC5B,0BAA0B,EAC1B,yCAAyC,EACzC,0CAA0C,
|
|
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,0BAA0B,EAC1B,yCAAyC,EACzC,0CAA0C,EAG1C,0BAA0B,EAC1B,8BAA8B,GAC/B,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;;iFAE6E;IAC7E,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,EAAE,KAAK,0BAA0B,CAAC;IACtD,CAAC;IAED;wEACoE;IACpE,YAAY;QACV,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;QACpD,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAClE,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;;;;;;;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;;0EAEsE;IACtE,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"}
|
|
@@ -12,19 +12,47 @@ export declare const REQUIREMENT_ATTR_TRACKED_BY = "trackedBy";
|
|
|
12
12
|
export declare const REQUIREMENT_ATTR_STATEMENT = "statement";
|
|
13
13
|
export declare const REQUIREMENT_ATTR_COUNTEREXAMPLE = "counterexample";
|
|
14
14
|
export declare const REQUIREMENT_ATTR_IMPLEMENTED_BY = "implementedBy";
|
|
15
|
+
/** FR-039 — the requirement that REPLACED a retired one. A resolving reference,
|
|
16
|
+
* so a supersession chain stays walkable: A -> B, and when B is retired too it
|
|
17
|
+
* carries its own. Legal ONLY on `retired`; the original 2026-08-10 ruling
|
|
18
|
+
* asked for a resolving `supersededBy` (point 4) and 0.24.0 deregistered the
|
|
19
|
+
* unresolved string version without ever building it. */
|
|
20
|
+
export declare const REQUIREMENT_ATTR_SUPERSEDED_BY = "supersededBy";
|
|
15
21
|
export declare const REQUIREMENT_STATUS_PLANNED = "planned";
|
|
16
22
|
export declare const REQUIREMENT_STATUS_LIVE = "live";
|
|
17
23
|
export declare const REQUIREMENT_STATUS_PARTIAL = "partial";
|
|
18
|
-
|
|
24
|
+
/** FR-039 — built, then deliberately removed; it must NOT be rebuilt.
|
|
25
|
+
*
|
|
26
|
+
* PRESCRIPTIVE, which is what makes it admissible under FR-038's rule that a
|
|
27
|
+
* requirement never journals what happened: the entry states a prohibition in
|
|
28
|
+
* force, falsifiable by exactly one observable — the capability reappearing.
|
|
29
|
+
* The retired `abandoned` described the past; this describes the standing rule.
|
|
30
|
+
*
|
|
31
|
+
* This is the status the ledger's only surviving controlled result is about:
|
|
32
|
+
* model-only agents flagged a deliberately-retired capability 0 times out of
|
|
33
|
+
* 24, ledger arms 19 of 40. */
|
|
34
|
+
export declare const REQUIREMENT_STATUS_RETIRED = "retired";
|
|
35
|
+
export declare const REQUIREMENT_STATUSES: readonly ["planned", "live", "partial", "retired"];
|
|
19
36
|
export type RequirementStatus = (typeof REQUIREMENT_STATUSES)[number];
|
|
20
37
|
/** Statuses whose implementing nodes are supposed to still exist. A dangling
|
|
21
38
|
* `@implementedBy` on one of these means the model moved and the requirement is
|
|
22
|
-
* stale. `planned` is
|
|
39
|
+
* stale. `planned` is exempt — there the nodes do not exist YET — and `retired`
|
|
40
|
+
* cannot appear here at all, because it may not carry `@implementedBy`. */
|
|
23
41
|
export declare const REQUIREMENT_STATUSES_REQUIRING_LIVE_NODES: readonly RequirementStatus[];
|
|
24
42
|
/** Statuses with outstanding work, so a `@disposition` is meaningful on them.
|
|
25
43
|
* On any other status the decision IS the status, and recording a second one
|
|
26
44
|
* can only agree with it or contradict it. */
|
|
27
45
|
export declare const REQUIREMENT_STATUSES_WITH_OUTSTANDING_WORK: readonly RequirementStatus[];
|
|
46
|
+
/** Statuses on which `@implementedBy` is REFUSED AT LOAD (FR-039).
|
|
47
|
+
*
|
|
48
|
+
* This is the structural half of FR-039 and the reason it is a list rather
|
|
49
|
+
* than an inline test. FR-038 removed `abandoned` because `verify` was SILENT
|
|
50
|
+
* on dangling refs for it, hiding 29 unresolvable references across 14 entries
|
|
51
|
+
* in one estate. That silence was a deliberate EXEMPTION — dangling was
|
|
52
|
+
* specified as correct there. Forbidding the attribute outright makes the bug
|
|
53
|
+
* class UNREACHABLE instead: a retired capability has no implementation by
|
|
54
|
+
* definition, so the references cannot dangle because they cannot exist. */
|
|
55
|
+
export declare const REQUIREMENT_STATUSES_FORBIDDING_IMPLEMENTORS: readonly RequirementStatus[];
|
|
28
56
|
export declare const REQUIREMENT_DISPOSITION_ACCEPTED = "accepted";
|
|
29
57
|
export declare const REQUIREMENT_DISPOSITION_DEFERRED = "deferred";
|
|
30
58
|
export declare const REQUIREMENT_DISPOSITIONS: readonly ["accepted", "deferred"];
|
|
@@ -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;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,+BAA+B,mBAAmB,CAAC;AAChE,eAAO,MAAM,+BAA+B,kBAAkB,CAAC;
|
|
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,+BAA+B,mBAAmB,CAAC;AAChE,eAAO,MAAM,+BAA+B,kBAAkB,CAAC;AAE/D;;;;0DAI0D;AAC1D,eAAO,MAAM,8BAA8B,iBAAiB,CAAC;AAS7D,eAAO,MAAM,0BAA0B,YAAY,CAAC;AACpD,eAAO,MAAM,uBAAuB,SAAS,CAAC;AAC9C,eAAO,MAAM,0BAA0B,YAAY,CAAC;AACpD;;;;;;;;;gCASgC;AAChC,eAAO,MAAM,0BAA0B,YAAY,CAAC;AAEpD,eAAO,MAAM,oBAAoB,oDAKvB,CAAC;AACX,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEtE;;;4EAG4E;AAC5E,eAAO,MAAM,yCAAyC,EAAE,SAAS,iBAAiB,EAGjF,CAAC;AAEF;;+CAE+C;AAC/C,eAAO,MAAM,0CAA0C,EAAE,SAAS,iBAAiB,EAGlF,CAAC;AAEF;;;;;;;;6EAQ6E;AAC7E,eAAO,MAAM,4CAA4C,EAAE,SAAS,iBAAiB,EAEpF,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"}
|
|
@@ -29,6 +29,12 @@ export const REQUIREMENT_ATTR_TRACKED_BY = "trackedBy";
|
|
|
29
29
|
export const REQUIREMENT_ATTR_STATEMENT = "statement";
|
|
30
30
|
export const REQUIREMENT_ATTR_COUNTEREXAMPLE = "counterexample";
|
|
31
31
|
export const REQUIREMENT_ATTR_IMPLEMENTED_BY = "implementedBy";
|
|
32
|
+
/** FR-039 — the requirement that REPLACED a retired one. A resolving reference,
|
|
33
|
+
* so a supersession chain stays walkable: A -> B, and when B is retired too it
|
|
34
|
+
* carries its own. Legal ONLY on `retired`; the original 2026-08-10 ruling
|
|
35
|
+
* asked for a resolving `supersededBy` (point 4) and 0.24.0 deregistered the
|
|
36
|
+
* unresolved string version without ever building it. */
|
|
37
|
+
export const REQUIREMENT_ATTR_SUPERSEDED_BY = "supersededBy";
|
|
32
38
|
// ---------------------------------------------------------------------------
|
|
33
39
|
// Status — a closed enum, enforced by the registry via `allowedValues`. This is
|
|
34
40
|
// the one payload with controlled evidence behind it: model-only agents flagged
|
|
@@ -38,14 +44,27 @@ export const REQUIREMENT_ATTR_IMPLEMENTED_BY = "implementedBy";
|
|
|
38
44
|
export const REQUIREMENT_STATUS_PLANNED = "planned";
|
|
39
45
|
export const REQUIREMENT_STATUS_LIVE = "live";
|
|
40
46
|
export const REQUIREMENT_STATUS_PARTIAL = "partial";
|
|
47
|
+
/** FR-039 — built, then deliberately removed; it must NOT be rebuilt.
|
|
48
|
+
*
|
|
49
|
+
* PRESCRIPTIVE, which is what makes it admissible under FR-038's rule that a
|
|
50
|
+
* requirement never journals what happened: the entry states a prohibition in
|
|
51
|
+
* force, falsifiable by exactly one observable — the capability reappearing.
|
|
52
|
+
* The retired `abandoned` described the past; this describes the standing rule.
|
|
53
|
+
*
|
|
54
|
+
* This is the status the ledger's only surviving controlled result is about:
|
|
55
|
+
* model-only agents flagged a deliberately-retired capability 0 times out of
|
|
56
|
+
* 24, ledger arms 19 of 40. */
|
|
57
|
+
export const REQUIREMENT_STATUS_RETIRED = "retired";
|
|
41
58
|
export const REQUIREMENT_STATUSES = [
|
|
42
59
|
REQUIREMENT_STATUS_PLANNED,
|
|
43
60
|
REQUIREMENT_STATUS_LIVE,
|
|
44
61
|
REQUIREMENT_STATUS_PARTIAL,
|
|
62
|
+
REQUIREMENT_STATUS_RETIRED,
|
|
45
63
|
];
|
|
46
64
|
/** Statuses whose implementing nodes are supposed to still exist. A dangling
|
|
47
65
|
* `@implementedBy` on one of these means the model moved and the requirement is
|
|
48
|
-
* stale. `planned` is
|
|
66
|
+
* stale. `planned` is exempt — there the nodes do not exist YET — and `retired`
|
|
67
|
+
* cannot appear here at all, because it may not carry `@implementedBy`. */
|
|
49
68
|
export const REQUIREMENT_STATUSES_REQUIRING_LIVE_NODES = [
|
|
50
69
|
REQUIREMENT_STATUS_LIVE,
|
|
51
70
|
REQUIREMENT_STATUS_PARTIAL,
|
|
@@ -57,6 +76,18 @@ export const REQUIREMENT_STATUSES_WITH_OUTSTANDING_WORK = [
|
|
|
57
76
|
REQUIREMENT_STATUS_PLANNED,
|
|
58
77
|
REQUIREMENT_STATUS_PARTIAL,
|
|
59
78
|
];
|
|
79
|
+
/** Statuses on which `@implementedBy` is REFUSED AT LOAD (FR-039).
|
|
80
|
+
*
|
|
81
|
+
* This is the structural half of FR-039 and the reason it is a list rather
|
|
82
|
+
* than an inline test. FR-038 removed `abandoned` because `verify` was SILENT
|
|
83
|
+
* on dangling refs for it, hiding 29 unresolvable references across 14 entries
|
|
84
|
+
* in one estate. That silence was a deliberate EXEMPTION — dangling was
|
|
85
|
+
* specified as correct there. Forbidding the attribute outright makes the bug
|
|
86
|
+
* class UNREACHABLE instead: a retired capability has no implementation by
|
|
87
|
+
* definition, so the references cannot dangle because they cannot exist. */
|
|
88
|
+
export const REQUIREMENT_STATUSES_FORBIDDING_IMPLEMENTORS = [
|
|
89
|
+
REQUIREMENT_STATUS_RETIRED,
|
|
90
|
+
];
|
|
60
91
|
// ---------------------------------------------------------------------------
|
|
61
92
|
// Disposition — what was DECIDED about the outstanding work. Orthogonal to
|
|
62
93
|
// status, which says whether the work is done. Absent means UNDECIDED, and that
|
|
@@ -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;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,+BAA+B,GAAG,gBAAgB,CAAC;AAChE,MAAM,CAAC,MAAM,+BAA+B,GAAG,eAAe,CAAC;AAE/D,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;AAEpD,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,0BAA0B;IAC1B,uBAAuB;IACvB,0BAA0B;CAClB,CAAC;AAGX
|
|
1
|
+
{"version":3,"file":"requirement-constants.js","sourceRoot":"","sources":["../../../src/core/requirement/requirement-constants.ts"],"names":[],"mappings":"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"}
|
|
@@ -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,kBA4LpC,CAAC"}
|
|
@@ -24,9 +24,10 @@ export const REQUIREMENT_DEFINITION = {
|
|
|
24
24
|
"allowedValues": [
|
|
25
25
|
"planned",
|
|
26
26
|
"live",
|
|
27
|
-
"partial"
|
|
27
|
+
"partial",
|
|
28
|
+
"retired"
|
|
28
29
|
],
|
|
29
|
-
"description": "planned intended but not built yet; live implemented and in use; partial implemented with known gaps. A requirement is PRESCRIPTIVE
|
|
30
|
+
"description": "planned intended but not built yet; live implemented and in use; partial implemented with known gaps; retired BUILT THEN DELIBERATELY REMOVED — it must not be rebuilt. A requirement is PRESCRIPTIVE: it states what SHOULD be true and never journals what happened, and retired satisfies that because it states a prohibition in force, falsifiable by the capability reappearing. On retired, @implementedBy is REFUSED at load (ERR_REQUIREMENT_RETIRED_HAS_IMPLEMENTORS) — a retired capability has no implementation by definition, so its references cannot dangle because they cannot exist; @supersededBy names the requirement that replaced it. A dangling @implementedBy is an ERROR on live/partial (the model moved, the requirement is stale) and ALLOWED on planned, where the nodes do not exist YET. Neither planned nor retired contributes to object coverage: planning a capability must not silence the warning that nothing implements it, and neither must retiring one."
|
|
30
31
|
},
|
|
31
32
|
{
|
|
32
33
|
"type": "attr",
|
|
@@ -65,6 +66,14 @@ export const REQUIREMENT_DEFINITION = {
|
|
|
65
66
|
"max": 1,
|
|
66
67
|
"description": "What breaking it looks like, in one sentence — a STATIC falsifiability test, authored once, never a state. A requirement MUST be violable: 'every entity has a uuid primary key' is (point at one with a composite string key); 'things are persisted' is not, and is a description rather than a requirement. Renamed from @violation in 0.24.0, which read as a status."
|
|
67
68
|
},
|
|
69
|
+
{
|
|
70
|
+
"type": "attr",
|
|
71
|
+
"subType": "string",
|
|
72
|
+
"name": "supersededBy",
|
|
73
|
+
"min": 0,
|
|
74
|
+
"max": 1,
|
|
75
|
+
"description": "The requirement that REPLACED this one. Legal on @status: retired only (ERR_REQUIREMENT_SUPERSEDED_BY_NOT_RETIRED otherwise), and RESOLVED like any other reference, so a dangling one is ERR_REQUIREMENT_DANGLING_REF and a supersession chain stays walkable: A names B, and when B is retired in turn it names C. That resolution is the whole point — 0.24.0 deregistered an unresolved string, and the 2026-08-10 ruling had asked for the resolving form (point 4) which was never built. A prose note in @notes points one hop and goes stale; this does not."
|
|
76
|
+
},
|
|
68
77
|
{
|
|
69
78
|
"type": "attr",
|
|
70
79
|
"subType": "string",
|
|
@@ -107,9 +116,10 @@ export const REQUIREMENT_DEFINITION = {
|
|
|
107
116
|
"allowedValues": [
|
|
108
117
|
"planned",
|
|
109
118
|
"live",
|
|
110
|
-
"partial"
|
|
119
|
+
"partial",
|
|
120
|
+
"retired"
|
|
111
121
|
],
|
|
112
|
-
"description": "As on requirement.functional. A live or partial architectural requirement claimed by NOTHING is an error: a policy declared and applied to nothing.
|
|
122
|
+
"description": "As on requirement.functional. A live or partial architectural requirement claimed by NOTHING is an error: a policy declared and applied to nothing. planned is exempt from that check — it is not applied yet by definition — and retired is exempt because a withdrawn policy governs nothing."
|
|
113
123
|
},
|
|
114
124
|
{
|
|
115
125
|
"type": "attr",
|
|
@@ -148,6 +158,14 @@ export const REQUIREMENT_DEFINITION = {
|
|
|
148
158
|
"max": 1,
|
|
149
159
|
"description": "What breaking it looks like — the node that would contradict it. A STATIC falsifiability test, not a state. This is what makes universality checkable. Renamed from @violation in 0.24.0, which read as a status."
|
|
150
160
|
},
|
|
161
|
+
{
|
|
162
|
+
"type": "attr",
|
|
163
|
+
"subType": "string",
|
|
164
|
+
"name": "supersededBy",
|
|
165
|
+
"min": 0,
|
|
166
|
+
"max": 1,
|
|
167
|
+
"description": "The requirement that REPLACED this one. Legal on @status: retired only (ERR_REQUIREMENT_SUPERSEDED_BY_NOT_RETIRED otherwise), and RESOLVED like any other reference, so a dangling one is ERR_REQUIREMENT_DANGLING_REF and a supersession chain stays walkable: A names B, and when B is retired in turn it names C. That resolution is the whole point — 0.24.0 deregistered an unresolved string, and the 2026-08-10 ruling had asked for the resolving form (point 4) which was never built. A prose note in @notes points one hop and goes stale; this does not."
|
|
168
|
+
},
|
|
151
169
|
{
|
|
152
170
|
"type": "attr",
|
|
153
171
|
"subType": "string",
|
|
@@ -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,gbAAgb;YAC7b,UAAU,EAAE;gBACV;oBACE,MAAM,EAAE,MAAM;oBACd,SAAS,EAAE,KAAK;oBAChB,MAAM,EAAE,OAAO;oBACf,KAAK,EAAE,CAAC;oBACR,KAAK,EAAE,CAAC;oBACR,aAAa,EAAE,sOAAsO;iBACtP;gBACD;oBACE,MAAM,EAAE,MAAM;oBACd,SAAS,EAAE,QAAQ;oBACnB,MAAM,EAAE,QAAQ;oBAChB,KAAK,EAAE,CAAC;oBACR,KAAK,EAAE,CAAC;oBACR,eAAe,EAAE;wBACf,SAAS;wBACT,MAAM;wBACN,SAAS;qBACV;oBACD,aAAa,EAAE,
|
|
1
|
+
{"version":3,"file":"requirement-definition.embedded.js","sourceRoot":"","sources":["../../../src/core/requirement/requirement-definition.embedded.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vocabulary-rewrite-yaml.d.ts","sourceRoot":"","sources":["../../src/core/vocabulary-rewrite-yaml.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"vocabulary-rewrite-yaml.d.ts","sourceRoot":"","sources":["../../src/core/vocabulary-rewrite-yaml.ts"],"names":[],"mappings":"AA2CA,OAAO,KAAK,EAAiC,WAAW,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE1G;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACtD,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CAC/B;AA0KD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,GAAG,iBAAiB,CA8I7F"}
|
|
@@ -22,11 +22,17 @@
|
|
|
22
22
|
// span replacement on the original text, and any region not deliberately changed comes back
|
|
23
23
|
// byte-identical. That is the same guarantee the JSON arm makes, by the same means.
|
|
24
24
|
//
|
|
25
|
+
// IT ALSO RESOLVES ATTRIBUTE CONTRADICTIONS (`../attr-contradictions.ts`), matched per NODE
|
|
26
|
+
// rather than per pair — the illegal thing is the PAIR of keys, so the unit is the mapping
|
|
27
|
+
// that holds one node's own keys. `eachNodeBody` below is that walk. Doing it by proximity
|
|
28
|
+
// instead was tried in the JSON arm and took a `fields` belonging to a sibling node.
|
|
29
|
+
//
|
|
25
30
|
// SIGIL-FREE, PER ADR-0006. YAML authoring writes bare attribute keys (`violation:`) and the
|
|
26
31
|
// desugar re-adds the `@` when lowering to canonical JSON. So a rename emits a BARE key here
|
|
27
32
|
// where the JSON arm emits `"@name"`. A leading `@` is still matched on input — an author who
|
|
28
33
|
// wrote one gets it fixed rather than skipped — but is never introduced.
|
|
29
34
|
import { LineCounter, isMap, isSeq, parseDocument } from "yaml";
|
|
35
|
+
import { ATTR_CONTRADICTIONS, contradictionScopeMatches } from "../attr-contradictions.js";
|
|
30
36
|
import { RETIRED_VOCABULARY, note, scopeMatches, } from "../retired-vocabulary.js";
|
|
31
37
|
/** A canonical node key: `<type>.<subType>`. Identical to the JSON arm's scope shape. */
|
|
32
38
|
const TYPE_KEY = /^[a-z][A-Za-z0-9]*\.[A-Za-z0-9_*]+$/;
|
|
@@ -139,6 +145,53 @@ function eachPair(node, scope, visit) {
|
|
|
139
145
|
eachPair(item, scope, visit);
|
|
140
146
|
}
|
|
141
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* Visit every node BODY in the document.
|
|
150
|
+
*
|
|
151
|
+
* The unit is the body rather than the pair because a contradiction is a property of a
|
|
152
|
+
* SIBLING SET. `body.items` is exactly this node's own keys — a child node lives inside the
|
|
153
|
+
* value of a `children:` pair, so it is reached by recursion and never mistaken for a
|
|
154
|
+
* sibling.
|
|
155
|
+
*/
|
|
156
|
+
function eachNodeBody(node, visit) {
|
|
157
|
+
if (isMap(node)) {
|
|
158
|
+
for (const pair of node.items) {
|
|
159
|
+
const k = keyText(pair.key);
|
|
160
|
+
if (k !== undefined && TYPE_KEY.test(k) && isMap(pair.value)) {
|
|
161
|
+
visit(k, { items: pair.value.items, flow: pair.value.flow === true });
|
|
162
|
+
}
|
|
163
|
+
if (pair.value != null)
|
|
164
|
+
eachNodeBody(pair.value, visit);
|
|
165
|
+
}
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
if (isSeq(node)) {
|
|
169
|
+
for (const item of node.items)
|
|
170
|
+
eachNodeBody(item, visit);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/** An authored `@` must not hide a key from either table; the sigil is never introduced. */
|
|
174
|
+
function bareKey(pair) {
|
|
175
|
+
const k = keyText(pair.key);
|
|
176
|
+
if (k === undefined)
|
|
177
|
+
return undefined;
|
|
178
|
+
return k.startsWith("@") ? k.slice(1) : k;
|
|
179
|
+
}
|
|
180
|
+
/** True when `keep` holds one of the entry's `keepValues` (or the entry names none,
|
|
181
|
+
* in which case mere presence is the contradiction). Mirrors the JSON rewriter's
|
|
182
|
+
* `keepValueMatches` — one rule, two doors, and a divergence here is a file format
|
|
183
|
+
* silently migrating differently from the other. */
|
|
184
|
+
function keepValueMatches(pair, c) {
|
|
185
|
+
if (c.keepValues === undefined)
|
|
186
|
+
return true;
|
|
187
|
+
const v = pair.value?.value;
|
|
188
|
+
return typeof v === "string" && c.keepValues.includes(v);
|
|
189
|
+
}
|
|
190
|
+
/** Does this pair carry a string that actually says something? */
|
|
191
|
+
function suppliesText(pair) {
|
|
192
|
+
const v = pair.value?.value;
|
|
193
|
+
return typeof v === "string" && v.trim().length > 0;
|
|
194
|
+
}
|
|
142
195
|
/**
|
|
143
196
|
* Rewrite retired vocabulary in one raw YAML metadata document.
|
|
144
197
|
*
|
|
@@ -160,6 +213,49 @@ export function rewriteYamlDocument(source, opts = {}) {
|
|
|
160
213
|
}
|
|
161
214
|
const lineOf = (offset) => lineCounter.linePos(offset).line;
|
|
162
215
|
const inWindow = (e) => opts.maxVersion === undefined || atOrBefore(e.since, opts.maxVersion);
|
|
216
|
+
// ── Attribute contradictions: two LIVE attrs that may not sit on one node ──
|
|
217
|
+
//
|
|
218
|
+
// THE TWO SIDES ARE ASKED DIFFERENT QUESTIONS, mirroring the loader's Rule 1a exactly
|
|
219
|
+
// (`validation-passes.ts`, `hasFieldsAttr` vs `hasExpr`) and the JSON arm's copy of it.
|
|
220
|
+
// The DROP side counts on PRESENCE — an empty `fields: []` beside `expr` is still a
|
|
221
|
+
// declaration of both, and is the case where the discard is total. The KEEP side counts
|
|
222
|
+
// only when it supplies a key, so a blank `expr: ""` beside `fields` is a plain column
|
|
223
|
+
// index the loader accepts and this must leave alone.
|
|
224
|
+
//
|
|
225
|
+
// IT SEES ONLY THIS NODE'S OWN KEYS. A node declaring `expr` while INHERITING `fields`
|
|
226
|
+
// through `extends` contradicts itself in the loaded model and not on the page; no
|
|
227
|
+
// raw-document rewriter can resolve a super-reference, so that stays the loader's refusal.
|
|
228
|
+
eachNodeBody(doc.contents, (typeKey, body) => {
|
|
229
|
+
for (const c of ATTR_CONTRADICTIONS) {
|
|
230
|
+
if (opts.maxVersion !== undefined && !atOrBefore(c.since, opts.maxVersion))
|
|
231
|
+
continue;
|
|
232
|
+
if (!contradictionScopeMatches(c, typeKey))
|
|
233
|
+
continue;
|
|
234
|
+
// `keep` must be present AND, when the entry names values, hold one of them —
|
|
235
|
+
// otherwise status and implementedBy would contradict on every status.
|
|
236
|
+
if (!body.items.some((p) => bareKey(p) === c.keep && suppliesText(p) && keepValueMatches(p, c)))
|
|
237
|
+
continue;
|
|
238
|
+
for (const pair of body.items) {
|
|
239
|
+
if (bareKey(pair) !== c.drop)
|
|
240
|
+
continue;
|
|
241
|
+
const span = pairSpan(pair);
|
|
242
|
+
if (span === undefined)
|
|
243
|
+
continue;
|
|
244
|
+
const d = dropSpan(source, span, body.flow);
|
|
245
|
+
// Undeletable in place (a sequence item's leading key) — leave it, and let the
|
|
246
|
+
// loader keep refusing rather than reshape the author's sequence.
|
|
247
|
+
if (d === undefined)
|
|
248
|
+
continue;
|
|
249
|
+
edits.push({ ...d, text: "" });
|
|
250
|
+
changes.push({
|
|
251
|
+
attr: c.drop,
|
|
252
|
+
from: c.drop,
|
|
253
|
+
to: `(removed — ${c.keep} keys this node)`,
|
|
254
|
+
line: lineOf(span.keyStart),
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
});
|
|
163
259
|
eachPair(doc.contents, undefined, (pair, scope, flow) => {
|
|
164
260
|
const key = keyText(pair.key);
|
|
165
261
|
if (key === undefined)
|
|
@@ -213,6 +309,13 @@ export function rewriteYamlDocument(source, opts = {}) {
|
|
|
213
309
|
if (rw === undefined)
|
|
214
310
|
refuse();
|
|
215
311
|
else if (rw.kind === "renameAttr") {
|
|
312
|
+
// NOTE — the JSON rewriter refuses a rename onto a key the node already declares,
|
|
313
|
+
// because two `"@counterexample"` members in one object parse silently with the
|
|
314
|
+
// last one winning. YAML needs no such guard: a duplicate key is a hard PARSE
|
|
315
|
+
// ERROR, so the same document fails loudly on the next load rather than quietly
|
|
316
|
+
// losing the author's surviving sentence. Same rule, different blast radius —
|
|
317
|
+
// if `eachPair` ever gains sibling access, mirror the JSON guard here anyway.
|
|
318
|
+
//
|
|
216
319
|
// Preserve the author's quoting style; YAML keys are usually bare, but a quoted key
|
|
217
320
|
// must stay quoted or the surrounding style stops being self-consistent.
|
|
218
321
|
const rawKey = source.slice(span.keyStart, span.keyEnd);
|