@sigloch/contracts 3.0.0 → 3.1.0

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.
@@ -0,0 +1,39 @@
1
+ /**
2
+ * CR-SM-227: Analysis-Freshness-Legs — the third leg-kind a review gate checks
3
+ * (rule legs, layer-presence legs [R-28], now analysis-freshness legs).
4
+ * Presence/Resolution-Split (wie R-19/R-20/R-26/R-27 vs. RC-01..05): these five
5
+ * rules are the PRÜFBARE FORM only — does a `graphVersion` stamp exist for the
6
+ * artifact, as a graph attribute. They never compare the stamp against the
7
+ * live graphVersion (that staleness/currency check is I/O — a consumer
8
+ * concern, `CreationCurrencyProvider` in `@sigloch/graphcode-client`).
9
+ */
10
+ import type { OntologyGraph } from './ontology.js';
11
+ import type { RuleViolation } from './rules.js';
12
+ export declare const AF_RULES: readonly [{
13
+ readonly id: "AF-01";
14
+ readonly name: "ConOps freshness stamp present";
15
+ readonly severity: "warning";
16
+ readonly evaluate: (graph: OntologyGraph) => RuleViolation[];
17
+ }, {
18
+ readonly id: "AF-02";
19
+ readonly name: "Trade Study freshness stamp present";
20
+ readonly severity: "warning";
21
+ readonly evaluate: (graph: OntologyGraph) => RuleViolation[];
22
+ }, {
23
+ readonly id: "AF-03";
24
+ readonly name: "Assumption Review freshness stamp present";
25
+ readonly severity: "warning";
26
+ readonly evaluate: (graph: OntologyGraph) => RuleViolation[];
27
+ }, {
28
+ readonly id: "AF-04";
29
+ readonly name: "FMEA freshness stamp present";
30
+ readonly severity: "warning";
31
+ readonly evaluate: (graph: OntologyGraph) => RuleViolation[];
32
+ }, {
33
+ readonly id: "AF-05";
34
+ readonly name: "Implementation Plan freshness stamp present";
35
+ readonly severity: "warning";
36
+ readonly evaluate: (graph: OntologyGraph) => RuleViolation[];
37
+ }];
38
+ /** Evaluate all analysis-freshness-presence rules. */
39
+ export declare function evaluateAFRules(graph: OntologyGraph): RuleViolation[];
@@ -0,0 +1,44 @@
1
+ import { AnalysisFreshnessStampSchema } from './ontology.js';
2
+ const ARTIFACT_LABEL = {
3
+ conops: 'Concept of Operations',
4
+ trade: 'Trade Study',
5
+ 'assumption-review': 'Assumption Review',
6
+ fmea: 'FMEA',
7
+ implplan: 'Implementation Plan',
8
+ };
9
+ /** Presence-check for one analysis artifact's freshness stamp, anchored on SYS (like R-28). */
10
+ function analysisFreshnessPresence(ruleId, artifactId) {
11
+ return (graph) => {
12
+ const sys = graph.elements.find(e => e.type === 'SYS');
13
+ if (!sys)
14
+ return []; // nothing to anchor on yet (same vacuous-complete exemption as R-28)
15
+ const stamp = sys.attributes?.analysisFreshness?.[artifactId];
16
+ if (AnalysisFreshnessStampSchema.safeParse(stamp).success)
17
+ return [];
18
+ const label = ARTIFACT_LABEL[artifactId];
19
+ return [{
20
+ rule_id: ruleId,
21
+ severity: 'warning',
22
+ element_id: sys.id,
23
+ message: `${label} (${artifactId}) has no freshness stamp — was it ever written with a graphVersion stamp?`,
24
+ fix_hint: `Set attributes.analysisFreshness.${artifactId}.graphVersion to the current graphVersion() when writing/refreshing the ${label} artifact`,
25
+ context: { element_type: sys.type, element_name: sys.name },
26
+ }];
27
+ };
28
+ }
29
+ const conopsFreshnessPresent = analysisFreshnessPresence('AF-01', 'conops');
30
+ const tradeFreshnessPresent = analysisFreshnessPresence('AF-02', 'trade');
31
+ const assumptionReviewFreshnessPresent = analysisFreshnessPresence('AF-03', 'assumption-review');
32
+ const fmeaFreshnessPresent = analysisFreshnessPresence('AF-04', 'fmea');
33
+ const implplanFreshnessPresent = analysisFreshnessPresence('AF-05', 'implplan');
34
+ export const AF_RULES = [
35
+ { id: 'AF-01', name: 'ConOps freshness stamp present', severity: 'warning', evaluate: conopsFreshnessPresent },
36
+ { id: 'AF-02', name: 'Trade Study freshness stamp present', severity: 'warning', evaluate: tradeFreshnessPresent },
37
+ { id: 'AF-03', name: 'Assumption Review freshness stamp present', severity: 'warning', evaluate: assumptionReviewFreshnessPresent },
38
+ { id: 'AF-04', name: 'FMEA freshness stamp present', severity: 'warning', evaluate: fmeaFreshnessPresent },
39
+ { id: 'AF-05', name: 'Implementation Plan freshness stamp present', severity: 'warning', evaluate: implplanFreshnessPresent },
40
+ ];
41
+ /** Evaluate all analysis-freshness-presence rules. */
42
+ export function evaluateAFRules(graph) {
43
+ return AF_RULES.flatMap(r => r.evaluate(graph));
44
+ }
@@ -9,6 +9,7 @@ import { CR_RULES, evaluateCRRules } from './cr-quality-rules.js';
9
9
  import { ND_RULES, evaluateNDRules } from './near-duplicate-rules.js';
10
10
  import { AO_RULES, evaluateAORules } from './ao-rules.js';
11
11
  import { BQ_RULES, evaluateBQRules } from './quality-rules.js';
12
+ import { AF_RULES, evaluateAFRules } from './analysis-freshness-rules.js';
12
13
  /** All prescribed rule definitions (single source of truth for the catalog). */
13
14
  export const ALL_RULE_DEFS = [
14
15
  ...V3_RULES.map(r => ({ id: r.id, name: r.name, severity: r.severity })),
@@ -22,10 +23,11 @@ export const ALL_RULE_DEFS = [
22
23
  ...AO_RULES.map(r => ({ id: r.id, name: r.name, severity: r.severity })),
23
24
  ...FM_RULES.map(r => ({ id: r.id, name: r.name, severity: r.severity })),
24
25
  ...VIEW_RULES.map(r => ({ id: r.id, name: r.name, severity: r.severity })),
26
+ ...AF_RULES.map(r => ({ id: r.id, name: r.name, severity: r.severity })),
25
27
  ];
26
28
  // CR-SM-221: 'RD-' was missing — 'RD-01'.startsWith('R-') is false, so the
27
29
  // decomposition rules ran in `default` only and never in the `se` profile.
28
- const SE_PREFIXES = ['R-', 'RD-', 'UC-', 'FC-', 'SC-', 'MT-', 'CR-', 'AO-', 'FM-', 'NFR-', 'RT-', 'PH-', 'CA-', 'IO-', 'VR-', 'CL-'];
30
+ const SE_PREFIXES = ['R-', 'RD-', 'UC-', 'FC-', 'SC-', 'MT-', 'CR-', 'AO-', 'FM-', 'NFR-', 'RT-', 'PH-', 'CA-', 'IO-', 'VR-', 'CL-', 'AF-'];
29
31
  const CODING_PREFIXES = ['BQ-', 'ND-'];
30
32
  export function getRuleDefsForProfile(profile) {
31
33
  if (profile === 'se')
@@ -48,5 +50,6 @@ export function evaluateAllRules(graph) {
48
50
  ...evaluateAORules(graph),
49
51
  ...evaluateFMRules(graph),
50
52
  ...evaluateViewRules(graph),
53
+ ...evaluateAFRules(graph),
51
54
  ];
52
55
  }
@@ -5,7 +5,7 @@
5
5
  /** Ontology schema version (element types + trace types). */
6
6
  export declare const ONTOLOGY_VERSION = "4.0.0";
7
7
  /** Rules engine version (validation rules incl. RC conformance). */
8
- export declare const RULES_VERSION = "2.22.0";
8
+ export declare const RULES_VERSION = "2.23.0";
9
9
  /** Meta-model version (trace pattern constraints + format-e parser). */
10
10
  export declare const META_MODEL_VERSION = "1.4.0";
11
11
  export * from './ontology.js';
@@ -21,6 +21,7 @@ export * from './cr-quality-rules.js';
21
21
  export * from './near-duplicate-rules.js';
22
22
  export * from './ao-rules.js';
23
23
  export * from './quality-rules.js';
24
+ export * from './analysis-freshness-rules.js';
24
25
  export * from './evaluate-all.js';
25
26
  export * from './readiness.js';
26
27
  export * from './meta-model.js';
package/dist/se/index.js CHANGED
@@ -5,7 +5,7 @@
5
5
  /** Ontology schema version (element types + trace types). */
6
6
  export const ONTOLOGY_VERSION = '4.0.0'; // BREAKING: `SemanticId` (`Name.TypeAbbr.Counter`) deleted, `ElementUid` (`<TYPE>-<slug>`) is the family canon — the old canon was used by no production graph of the family while 626 of 1145 elements already carried TYPE-slug (CR-SM-217); realRef unifies codeRef+schemaRef (+physical-MOD CAD ref), symbol optional; testRef stays separate (CR-228 C); +RepoRelativePathSchema on testRef/realRef .file — no absolute/`..` paths (CR-GC-255)
7
7
  /** Rules engine version (validation rules incl. RC conformance). */
8
- export const RULES_VERSION = '2.22.0'; // CR-SM-226: +RULE_TO_PHASE (readiness.ts) — rule SRR/PDR/CDR/TRR gate mapping analogous to RULE_TO_DIMENSION, exported PhaseGate enum, completeness-tested (no advisory fall-through); +DIMENSION_READINESS_NAME/PHASE_READINESS_NAME/DIMENSION_READINESS_DELTA_NAME Sprachregelung constants; -emergentPhase/-phaseScore (CR-120/146) DELETED from ReadinessReport a third, undocumented phase construct next to RULE_TO_DIMENSION and the phase-gate grouping, no computation ever lived in contracts; +R-28 Ebenen-Präsenz (funcCount>1 requires ≥1 FLOW AND ≥1 SCHEMA, ONE combined rule closes the vacuous-complete hole where 0 FLOWs/SCHEMAs read as "complete" because no per-element rule had anything to iterate) PDR; +FC-04 FCHAIN-actor-bounded (ACTORFLOW→FUNC∈chain entry AND FUNC∈chainFLOW→ACTOR exit, both required stricter than FC-01's any-direction/UC-bypass check) → PDR; +SC-04 FLOW→SCHEMA sharp rule (every FLOW must relation→SCHEMA, the per-FLOW inverse of SC-02's per-SCHEMA check) CDR; IO-01 extended to ALL FUNC pairs within an FCHAIN (removed the same-module skip — same-module pairs need an explicit FLOW just as much as cross-module ones) and added to RULE_TO_PHASE → PDR (was RULE_TO_DIMENSION-only); harness: +OP_RISK/isDestructiveOp/isStructuralOp destructive/structural classification per MutateCommand op (GVE-Audit F7) — informational only, does not drive the Apply-Gate verdict.
8
+ export const RULES_VERSION = '2.23.0'; // CR-SM-227: +AF-01..05 Analysis-Freshness-Legs (analysis-freshness-rules.ts) — the third leg-kind a review gate checks (rule legs, layer-presence legs [R-28], now analysis-freshness legs, docs/articles/07-the-scoring-landscape.md); presence-only rules (Presence/Resolution-Split like R-19/R-20/R-26/R-27 vs. RC-01..05) checking a `graphVersion` freshness stamp exists under SYS.attributes.analysisFreshness.<AnalysisArtifactId> for each of the 5 CR-GC-221 judgment artifacts (conops/trade/assumption-review/fmea/implplan) staleness (stamp vs live graphVersion) stays a consumer/I-O concern (`CreationCurrencyProvider`, @sigloch/graphcode-client), NOT evaluated here; Familie-Review 2026-08-05 gate assignmentRULE_TO_PHASE: ConOps/Trade/Assumption-ReviewPDR, FMEACDR, Implementation Plan TRR (SRR gets none); +AnalysisArtifactId enum + AnalysisFreshnessStampSchema (ontology.ts) as the SSOT graphcode-client's ARTIFACT_CATALOG analysis ids must match; grober Graph-Versions-Stempel only, no scope-hash in this first cut (conscious CR-SM-227 limitation).
9
9
  /** Meta-model version (trace pattern constraints + format-e parser). */
10
10
  export const META_MODEL_VERSION = '1.4.0'; // -REQ→MOD allocate pattern removed (CR-228 A); +FUNC→FUNC compose (blackbox function decomposition)
11
11
  export * from './ontology.js';
@@ -21,6 +21,7 @@ export * from './cr-quality-rules.js';
21
21
  export * from './near-duplicate-rules.js';
22
22
  export * from './ao-rules.js';
23
23
  export * from './quality-rules.js';
24
+ export * from './analysis-freshness-rules.js';
24
25
  export * from './evaluate-all.js';
25
26
  export * from './readiness.js';
26
27
  export * from './meta-model.js';
@@ -131,6 +131,34 @@ export declare const RealRefSchema: z.ZodObject<{
131
131
  lang: z.ZodOptional<z.ZodString>;
132
132
  }, z.core.$strip>;
133
133
  export type RealRef = z.infer<typeof RealRefSchema>;
134
+ /**
135
+ * The five judgment-work artifact ids (CR-GC-221's creation keys) that graphcode's
136
+ * skills produce and that a phase gate checks for presence+freshness (CR-SM-227).
137
+ * SSOT — `@sigloch/graphcode-client`'s `ARTIFACT_CATALOG` (`kind:'analysis'` rows)
138
+ * must use exactly these ids.
139
+ */
140
+ export declare const AnalysisArtifactId: z.ZodEnum<{
141
+ conops: "conops";
142
+ fmea: "fmea";
143
+ trade: "trade";
144
+ implplan: "implplan";
145
+ "assumption-review": "assumption-review";
146
+ }>;
147
+ export type AnalysisArtifactId = z.infer<typeof AnalysisArtifactId>;
148
+ /**
149
+ * A "this analysis covers graph-stand V" stamp (CR-SM-227) — the grober
150
+ * Graph-Versions-Stempel Familie-Review decided (no scope-hash in the first
151
+ * cut, see CR-SM-227 "Achtung"). `graphVersion` is the harness's monotone
152
+ * counter (`ToolContext.graphVersion()`, graphcode) at the moment the
153
+ * artifact was written — I/O, so writing it stays a consumer (graphcode)
154
+ * concern; contracts only defines the shape.
155
+ * Stored under `OntologyElement.attributes.analysisFreshness.<AnalysisArtifactId>`
156
+ * on the SYS root element (same anchor convention as R-28).
157
+ */
158
+ export declare const AnalysisFreshnessStampSchema: z.ZodObject<{
159
+ graphVersion: z.ZodNumber;
160
+ }, z.core.$strip>;
161
+ export type AnalysisFreshnessStamp = z.infer<typeof AnalysisFreshnessStampSchema>;
134
162
  /**
135
163
  * An element (node) in the SE ontology graph.
136
164
  * `attributes` holds type-specific properties (e.g. FUNC.safety_relevant).
@@ -92,6 +92,26 @@ export const RealRefSchema = z.object({
92
92
  symbol: z.string().optional(),
93
93
  lang: z.string().optional(),
94
94
  });
95
+ /**
96
+ * The five judgment-work artifact ids (CR-GC-221's creation keys) that graphcode's
97
+ * skills produce and that a phase gate checks for presence+freshness (CR-SM-227).
98
+ * SSOT — `@sigloch/graphcode-client`'s `ARTIFACT_CATALOG` (`kind:'analysis'` rows)
99
+ * must use exactly these ids.
100
+ */
101
+ export const AnalysisArtifactId = z.enum(['conops', 'fmea', 'trade', 'implplan', 'assumption-review']);
102
+ /**
103
+ * A "this analysis covers graph-stand V" stamp (CR-SM-227) — the grober
104
+ * Graph-Versions-Stempel Familie-Review decided (no scope-hash in the first
105
+ * cut, see CR-SM-227 "Achtung"). `graphVersion` is the harness's monotone
106
+ * counter (`ToolContext.graphVersion()`, graphcode) at the moment the
107
+ * artifact was written — I/O, so writing it stays a consumer (graphcode)
108
+ * concern; contracts only defines the shape.
109
+ * Stored under `OntologyElement.attributes.analysisFreshness.<AnalysisArtifactId>`
110
+ * on the SYS root element (same anchor convention as R-28).
111
+ */
112
+ export const AnalysisFreshnessStampSchema = z.object({
113
+ graphVersion: z.number().int().nonnegative(),
114
+ });
95
115
  /**
96
116
  * An element (node) in the SE ontology graph.
97
117
  * `attributes` holds type-specific properties (e.g. FUNC.safety_relevant).
@@ -81,6 +81,11 @@ export const RULE_TO_DIMENSION = {
81
81
  'MS-01': 'ms', 'MS-02': 'ms', 'MS-03': 'ms',
82
82
  // FMEA / risk
83
83
  'FM-01': 'req', 'FM-02': 'req', 'FM-03': 'ver',
84
+ // CR-SM-227: analysis-artifact freshness presence — closest topical fit per artifact.
85
+ 'AF-01': 'req', 'AF-03': 'req', // ConOps/Assumption-Review: requirements-adjacent judgment work
86
+ 'AF-02': 'arch', // Trade Study: architecture decision record
87
+ 'AF-04': 'ver', // FMEA: risk/verification, same bucket as FM-03
88
+ 'AF-05': 'ms', // Implementation Plan: milestone/planning
84
89
  // NFR budget
85
90
  'NFR-01': 'arch',
86
91
  // cross-module IO (CR-192)
@@ -108,6 +113,12 @@ export const PhaseGate = z.enum(['SRR', 'PDR', 'CDR', 'TRR']);
108
113
  * single-owner convention as RULE_TO_DIMENSION.
109
114
  */
110
115
  export const RULE_TO_PHASE = {
116
+ // CR-SM-227: Analysis-Freshness-Legs (AF-01..05) — Familie-Review 2026-08-05
117
+ // gate assignment, final: ConOps/Trade/Assumption-Review → PDR, FMEA → CDR,
118
+ // Implementation Plan → TRR. SRR gets no analysis-freshness leg.
119
+ 'AF-01': 'PDR', 'AF-02': 'PDR', 'AF-03': 'PDR', // ConOps, Trade Study, Assumption Review
120
+ 'AF-04': 'CDR', // FMEA
121
+ 'AF-05': 'TRR', // Implementation Plan
111
122
  // SRR — requirements/scope clarity, system+UC boundary definition.
112
123
  'BQ-01': 'SRR', 'BQ-02': 'SRR', 'BQ-04': 'SRR', 'BQ-06': 'SRR', 'BQ-07': 'SRR',
113
124
  'RD-01': 'SRR', 'RD-02': 'SRR', 'RD-03': 'SRR',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sigloch/contracts",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",