@sigloch/graphcode-client 2.0.0 → 3.0.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.
package/dist/index.d.ts CHANGED
@@ -18,5 +18,5 @@
18
18
  */
19
19
  export { HOST_SOCK_BASENAME, callHost, type ShimRequest, type ShimResponse, } from './host-client.js';
20
20
  export { MARKDOWN_VIEWS, VIEW_FILENAMES, type MarkdownView } from './view-catalog.js';
21
- export { GRAPHCODE_INCOSE_SCOPE, MARK_LABELS, computeMarks, summarizeReadiness, computeReadiness, scoreReadiness, getFamilyRuleIds, type IncoseScope, type ReadinessDimension, type ReadinessMark, type ReadinessReport, } from './readiness.js';
21
+ export { GRAPHCODE_INCOSE_SCOPE, MARK_LABELS, computeMarks, countByStage, summarizeReadiness, computeReadiness, scoreReadiness, getFamilyRuleIds, type IncoseScope, type ReadinessMark, type StageCount, type ReadinessReport, } from './readiness.js';
22
22
  export * from './panels.js';
package/dist/index.js CHANGED
@@ -18,5 +18,5 @@
18
18
  */
19
19
  export { HOST_SOCK_BASENAME, callHost, } from './host-client.js';
20
20
  export { MARKDOWN_VIEWS, VIEW_FILENAMES } from './view-catalog.js';
21
- export { GRAPHCODE_INCOSE_SCOPE, MARK_LABELS, computeMarks, summarizeReadiness, computeReadiness, scoreReadiness, getFamilyRuleIds, } from './readiness.js';
21
+ export { GRAPHCODE_INCOSE_SCOPE, MARK_LABELS, computeMarks, countByStage, summarizeReadiness, computeReadiness, scoreReadiness, getFamilyRuleIds, } from './readiness.js';
22
22
  export * from './panels.js';
package/dist/panels.d.ts CHANGED
@@ -18,9 +18,6 @@ import type { ReadinessReport, ReadinessMark } from './readiness.js';
18
18
  import type { RuleViolation, LiveUpdateEvent } from '@sigloch/contracts/harness';
19
19
  import type { Graph } from '@sigloch/graph-api-core';
20
20
  export interface ReadinessPanel {
21
- compliancePct: number;
22
- totalElements: number;
23
- elementsWithErrors: number;
24
21
  /** SRR, PDR, CDR, TRR, Bau — reached or not, with the findings that hold each (CR-SM-395). */
25
22
  marks: ReadinessMark[];
26
23
  }
package/dist/panels.js CHANGED
@@ -1,11 +1,6 @@
1
1
  import { AnalysisArtifactId, AnalysisFreshnessStampSchema } from '@sigloch/contracts/se';
2
2
  export function readinessPanel(report) {
3
- return {
4
- compliancePct: Math.round(report.compliance.score * 1000) / 10,
5
- totalElements: report.compliance.totalElements,
6
- elementsWithErrors: report.compliance.elementsWithErrors,
7
- marks: report.marks,
8
- };
3
+ return { marks: report.marks };
9
4
  }
10
5
  const SEVERITY_RANK = { error: 0, warning: 1, info: 2 };
11
6
  export function recommendationsPanel(violations, limit = 5) {
@@ -1,62 +1,5 @@
1
- /**
2
- * Readiness — compliance and the marks (CR-GC-107, CR-GC-125; rebuilt CR-SM-395).
3
- *
4
- * Computed purely from rule violations of `@sigloch/contracts` (the family rule base, never a
5
- * foreign rule set) and the stage each rule carries at its definition. There is no gate
6
- * computation of its own in this package any more.
7
- *
8
- * THE MARKS. The rule catalog orders its sets in twelve stages (`STAGE_SETS`); a mark lies
9
- * between two stages: SRR after stage 4, PDR after 7, CDR after 8, TRR after 9, Bau after 12.
10
- * A mark is REACHED iff no finding holds it. A finding holds a mark when its rule lies at or
11
- * before the mark's stage — or at every stage (`'immer'`) — and it is
12
- * - an error, or
13
- * - a finding of an existence rule: a set the stage requires is missing.
14
- * Other warnings do not hold a mark; "free of warnings" is a separate statement.
15
- *
16
- * The mark Bau additionally is held by every warning of the stages 10 to 12 (plan, binding,
17
- * conformance): those findings ARE the work list of the build, and the mark reads "nothing left
18
- * to plan, bind or reconcile". It opens again with every change.
19
- *
20
- * A NOTE (severity `info`, e.g. MS-03, VR-01) holds no mark, at no stage (CR-SM-396).
21
- *
22
- * AN ACCEPTED FINDING HOLDS ITS MARK (CR-SM-396). The rules keep firing on a finding the human
23
- * accepted with a reason (`acceptedFindings`), and the marks are computed from all of them: an
24
- * accepted AF-05 ("unbuilt, no order") still holds Bau. Acceptance takes a finding out of the
25
- * work focus; it is no way to read a mark as reached. Callers pass the findings UNFILTERED.
26
- *
27
- * Why "0 of 0" cannot read as reached: every mandatory set is demanded by an existence rule of
28
- * the stage before it (no system → R-33, no use case → R-17, …). An empty set is therefore either
29
- * voluntary, or the existence rule before it is open and holds the mark. Stage 8 (schema) carries
30
- * no existence rule of its own (CR-SM-396): a data flow without a schema is a grammar error
31
- * (R-18, every stage), and no data flow at all is held by R-31 (stage 6).
32
- *
33
- * What is gone with CR-SM-395: the three-valued gate state and its labels, the gate score, the
34
- * gate completeness and its legs (`COMPLETENESS_SLICES`), the four build gates bound to milestone
35
- * ids, the required creations per gate and the currency of analysis artifacts. The assignment
36
- * rule → mark is `ALL_RULE_DEFS[].mark` in contracts, not a list here.
37
- *
38
- * Host/dashboard wiring (panels) lives in `panels.ts`; this module provides the scoring
39
- * primitive only — no dashboard, no renderer.
40
- *
41
- * @author andreas@siglochconsulting
42
- */
43
- import type { Graph } from '@sigloch/graph-api-core';
44
- import { type MarkType } from '@sigloch/contracts/se';
1
+ import { type MarkType, type RuleStage } from '@sigloch/contracts/se';
45
2
  import type { RuleViolation } from '@sigloch/contracts/harness';
46
- /**
47
- * A readiness dimension score in [0, 1].
48
- * 0 = fully non-compliant, 1 = fully compliant.
49
- */
50
- export interface ReadinessDimension {
51
- /** Score in [0, 1]. */
52
- score: number;
53
- /** Short human-readable label for display. */
54
- label: string;
55
- /** How many elements were evaluated. */
56
- totalElements: number;
57
- /** How many elements carry at least one error-severity violation. */
58
- elementsWithErrors: number;
59
- }
60
3
  /**
61
4
  * INCOSE artifact scope for the system under governance.
62
5
  * `lean` — graph = SSOT; renders are deterministic projections, analyses are lightweight
@@ -80,16 +23,30 @@ export interface ReadinessMark {
80
23
  }
81
24
  /** The marks in order, each with the findings that hold it. */
82
25
  export declare function computeMarks(violations: RuleViolation[]): ReadinessMark[];
26
+ /** One stage of the rule catalog and the number of findings whose rule lies at it. */
27
+ export interface StageCount {
28
+ /** 1–12, or `'immer'` for the rules over all elements. */
29
+ stage: RuleStage;
30
+ /** The set of the stage (`STAGE_SETS`); `'immer'` carries its own value. */
31
+ name: string;
32
+ /** Number of findings of the rules at this stage — every severity, accepted or not. */
33
+ findings: number;
34
+ }
35
+ /**
36
+ * The findings counted per stage: the stages 1 to 12 in order, then `'immer'` — always 13 entries.
37
+ * Derived from the stage each rule carries at its definition and from nothing else: no table, no
38
+ * denominator, no percentage. The sum over the entries is the number of findings. A finding of a
39
+ * rule the catalog does not know throws, as in `holds`.
40
+ *
41
+ * This replaces the eight readiness dimensions and their scores (decision of the author,
42
+ * 2026-10-07: "Stufe statt Dimension, Befunde zaehlen statt Prozent").
43
+ */
44
+ export declare function countByStage(violations: RuleViolation[]): StageCount[];
83
45
  /**
84
46
  * Full readiness snapshot derived from rule violations.
85
47
  * All violation ruleIds are contracts rule-IDs — never a foreign rule set.
86
48
  */
87
49
  export interface ReadinessReport {
88
- /**
89
- * Compliance dimension: fraction of graph elements with NO error-severity
90
- * violation. 1.0 = all elements clean, 0.0 = all elements have ≥1 error.
91
- */
92
- compliance: ReadinessDimension;
93
50
  /** Declared INCOSE artifact scope for this system (graphcode = `lean`). */
94
51
  incoseScope: IncoseScope;
95
52
  /** The marks SRR, PDR, CDR, TRR, Bau — in order. */
@@ -111,23 +68,22 @@ export interface ReadinessReport {
111
68
  */
112
69
  export declare function summarizeReadiness(report: ReadinessReport): ReadinessReport;
113
70
  /**
114
- * Compute readiness from a violations array + the full graph (nodes + edges).
71
+ * Compute readiness from a violations array — and from nothing else (CR-SM-402: the graph was
72
+ * read for the compliance percentage only).
115
73
  *
116
74
  * @param violations - from `harness.evaluateRules()` (contracts rule IDs), UNFILTERED: a finding
117
75
  * the human accepted with a reason still holds its mark (CR-SM-396).
118
- * @param graph - from `harness.getGraph()` (elements + traces)
119
76
  */
120
- export declare function computeReadiness(violations: RuleViolation[], graph: Pick<Graph, 'nodes' | 'edges'>): ReadinessReport;
77
+ export declare function computeReadiness(violations: RuleViolation[]): ReadinessReport;
121
78
  /**
122
- * Convenience wrapper: runs `evaluateRules()` + `getGraph()` on the harness
123
- * and returns the full ReadinessReport.
79
+ * Convenience wrapper: runs `evaluateRules()` on the harness and returns the full
80
+ * ReadinessReport.
124
81
  *
125
82
  * Accepts a minimal harness-duck-type so callers can pass `GraphCodeHarness`
126
83
  * directly without importing its class (avoids circular dep risk in consumers).
127
84
  */
128
85
  export declare function scoreReadiness(harness: {
129
86
  evaluateRules(): RuleViolation[];
130
- getGraph(): Pick<Graph, 'nodes' | 'edges'>;
131
87
  }): ReadinessReport;
132
88
  /**
133
89
  * The authoritative set of family rule-IDs (derived at runtime from
package/dist/readiness.js CHANGED
@@ -1,5 +1,51 @@
1
+ /**
2
+ * Readiness — the marks and the findings (CR-GC-107, CR-GC-125; rebuilt CR-SM-395).
3
+ *
4
+ * Computed purely from rule violations of `@sigloch/contracts` (the family rule base, never a
5
+ * foreign rule set) and the stage each rule carries at its definition. There is no gate
6
+ * computation of its own in this package any more.
7
+ *
8
+ * THE MARKS. The rule catalog orders its sets in twelve stages (`STAGE_SETS`); a mark lies
9
+ * between two stages: SRR after stage 4, PDR after 7, CDR after 8, TRR after 9, Bau after 12.
10
+ * A mark is REACHED iff no finding holds it. A finding holds a mark when its rule lies at or
11
+ * before the mark's stage — or at every stage (`'immer'`) — and it is
12
+ * - an error, or
13
+ * - a finding of an existence rule: a set the stage requires is missing.
14
+ * Other warnings do not hold a mark; "free of warnings" is a separate statement.
15
+ *
16
+ * The mark Bau additionally is held by every warning of the stages 10 to 12 (plan, binding,
17
+ * conformance): those findings ARE the work list of the build, and the mark reads "nothing left
18
+ * to plan, bind or reconcile". It opens again with every change.
19
+ *
20
+ * A NOTE (severity `info`, e.g. MS-03, VR-01) holds no mark, at no stage (CR-SM-396).
21
+ *
22
+ * AN ACCEPTED FINDING HOLDS ITS MARK (CR-SM-396). The rules keep firing on a finding the human
23
+ * accepted with a reason (`acceptedFindings`), and the marks are computed from all of them: an
24
+ * accepted AF-05 ("unbuilt, no order") still holds Bau. Acceptance takes a finding out of the
25
+ * work focus; it is no way to read a mark as reached. Callers pass the findings UNFILTERED.
26
+ *
27
+ * Why "0 of 0" cannot read as reached: every mandatory set is demanded by an existence rule of
28
+ * the stage before it (no system → R-33, no use case → R-17, …). An empty set is therefore either
29
+ * voluntary, or the existence rule before it is open and holds the mark. Stage 8 (schema) carries
30
+ * no existence rule of its own (CR-SM-396): a data flow without a schema is a grammar error
31
+ * (R-18, every stage), and no data flow at all is held by R-31 (stage 6).
32
+ *
33
+ * What is gone with CR-SM-395: the three-valued gate state and its labels, the gate score, the
34
+ * gate completeness and its legs (`COMPLETENESS_SLICES`), the four build gates bound to milestone
35
+ * ids, the required creations per gate and the currency of analysis artifacts. The assignment
36
+ * rule → mark is `ALL_RULE_DEFS[].mark` in contracts, not a list here.
37
+ *
38
+ * What is gone with CR-SM-402: the compliance percentage (share of elements without an error
39
+ * finding) with its denominator and its two counts. The report carries marks and findings — what
40
+ * the agent reads and acts on — and nothing a viewer would see on top of that.
41
+ *
42
+ * Host/dashboard wiring (panels) lives in `panels.ts`; this module provides the scoring
43
+ * primitive only — no dashboard, no renderer.
44
+ *
45
+ * @author andreas@siglochconsulting
46
+ */
1
47
  import { SE_DESCRIPTOR } from '@sigloch/graph-api-core';
2
- import { ALL_RULE_DEFS, CODE_CONFORMANCE_RULES, Mark, MARK_STAGE } from '@sigloch/contracts/se';
48
+ import { ALL_RULE_DEFS, CODE_CONFORMANCE_RULES, Mark, MARK_STAGE, STAGE_SETS } from '@sigloch/contracts/se';
3
49
  /** graphcode's declared scope. */
4
50
  export const GRAPHCODE_INCOSE_SCOPE = 'lean';
5
51
  // ---------------------------------------------------------------------------
@@ -16,14 +62,14 @@ export const MARK_LABELS = {
16
62
  const RULES = new Map(ALL_RULE_DEFS.map((r) => [r.id, r]));
17
63
  /** Does this finding hold this mark? See the module header for the rule. */
18
64
  function holds(v, mark) {
65
+ // A finding of a rule the catalog does not know is a programming error and throws (CR-SM-399).
66
+ const rule = RULES.get(v.ruleId);
67
+ const stage = rule.stage;
19
68
  if (v.severity === 'info')
20
69
  return false; // a note holds no mark (CR-SM-396)
21
- const rule = RULES.get(v.ruleId);
22
- // A finding of a rule the catalog does not know cannot be placed on the ladder: like `'immer'`.
23
- const stage = rule?.stage ?? 'immer';
24
70
  if (stage !== 'immer' && stage > MARK_STAGE[mark])
25
71
  return false;
26
- if (v.severity === 'error' || rule?.role === 'existence')
72
+ if (v.severity === 'error' || rule.role === 'existence')
27
73
  return true;
28
74
  return mark === 'Bau' && stage !== 'immer' && stage > MARK_STAGE.TRR;
29
75
  }
@@ -34,6 +80,22 @@ export function computeMarks(violations) {
34
80
  return { id, label: MARK_LABELS[id], reached: holding.length === 0, holding };
35
81
  });
36
82
  }
83
+ /**
84
+ * The findings counted per stage: the stages 1 to 12 in order, then `'immer'` — always 13 entries.
85
+ * Derived from the stage each rule carries at its definition and from nothing else: no table, no
86
+ * denominator, no percentage. The sum over the entries is the number of findings. A finding of a
87
+ * rule the catalog does not know throws, as in `holds`.
88
+ *
89
+ * This replaces the eight readiness dimensions and their scores (decision of the author,
90
+ * 2026-10-07: "Stufe statt Dimension, Befunde zaehlen statt Prozent").
91
+ */
92
+ export function countByStage(violations) {
93
+ const count = (stage) => violations.filter((v) => RULES.get(v.ruleId).stage === stage).length;
94
+ return [
95
+ ...STAGE_SETS.map((name, i) => ({ stage: (i + 1), name, findings: count((i + 1)) })),
96
+ { stage: 'immer', name: 'immer', findings: count('immer') },
97
+ ];
98
+ }
37
99
  /**
38
100
  * Summary projection of a ReadinessReport (CR-GC-203 item 2): drops the heavy
39
101
  * per-element lists — `violations` and every mark's `holding` — while keeping
@@ -53,16 +115,13 @@ export function summarizeReadiness(report) {
53
115
  // Scorer
54
116
  // ---------------------------------------------------------------------------
55
117
  /**
56
- * Compute readiness from a violations array + the full graph (nodes + edges).
118
+ * Compute readiness from a violations array — and from nothing else (CR-SM-402: the graph was
119
+ * read for the compliance percentage only).
57
120
  *
58
121
  * @param violations - from `harness.evaluateRules()` (contracts rule IDs), UNFILTERED: a finding
59
122
  * the human accepted with a reason still holds its mark (CR-SM-396).
60
- * @param graph - from `harness.getGraph()` (elements + traces)
61
123
  */
62
- export function computeReadiness(violations, graph) {
63
- const totalElements = graph.nodes.length;
64
- const elementsWithErrors = new Set(violations.filter((v) => v.severity === 'error' && v.elementId !== undefined).map((v) => v.elementId)).size;
65
- const complianceScore = totalElements > 0 ? (totalElements - elementsWithErrors) / totalElements : 1;
124
+ export function computeReadiness(violations) {
66
125
  const violationsByRule = {};
67
126
  for (const v of violations) {
68
127
  violationsByRule[v.ruleId] = (violationsByRule[v.ruleId] ?? 0) + 1;
@@ -71,12 +130,6 @@ export function computeReadiness(violations, graph) {
71
130
  const severityRank = { error: 0, warning: 1, info: 2 };
72
131
  const sorted = [...violations].sort((a, b) => (severityRank[a.severity] ?? 3) - (severityRank[b.severity] ?? 3));
73
132
  return {
74
- compliance: {
75
- score: complianceScore,
76
- label: 'Compliance (V3_RULES, error-severity)',
77
- totalElements,
78
- elementsWithErrors,
79
- },
80
133
  incoseScope: GRAPHCODE_INCOSE_SCOPE,
81
134
  marks: computeMarks(violations),
82
135
  violationsByRule,
@@ -85,14 +138,14 @@ export function computeReadiness(violations, graph) {
85
138
  };
86
139
  }
87
140
  /**
88
- * Convenience wrapper: runs `evaluateRules()` + `getGraph()` on the harness
89
- * and returns the full ReadinessReport.
141
+ * Convenience wrapper: runs `evaluateRules()` on the harness and returns the full
142
+ * ReadinessReport.
90
143
  *
91
144
  * Accepts a minimal harness-duck-type so callers can pass `GraphCodeHarness`
92
145
  * directly without importing its class (avoids circular dep risk in consumers).
93
146
  */
94
147
  export function scoreReadiness(harness) {
95
- return computeReadiness(harness.evaluateRules(), harness.getGraph());
148
+ return computeReadiness(harness.evaluateRules());
96
149
  }
97
150
  /**
98
151
  * The authoritative set of family rule-IDs (derived at runtime from
@@ -22,7 +22,7 @@
22
22
  * grouped by type and answered the same question as `srs` (the ISO-29148 narrative)
23
23
  * with different completeness — two requirements documents, one truth. `srs` stays.
24
24
  */
25
- export declare const MARKDOWN_VIEWS: readonly ["architecture", "cr-list", "references", "srs", "nfr", "rtm", "icd", "testconcept", "testmatrix", "intplan", "changelog", "fmea", "conops", "trade", "implplan"];
25
+ export declare const MARKDOWN_VIEWS: readonly ["architecture", "cr-list", "references", "srs", "nfr", "rtm", "icd", "testconcept", "testmatrix", "intplan", "changelog", "fmea", "conops", "implplan"];
26
26
  export type MarkdownView = (typeof MARKDOWN_VIEWS)[number];
27
27
  /** Default file name for each view (under docs/views/). */
28
28
  export declare const VIEW_FILENAMES: Record<MarkdownView, string>;
@@ -38,7 +38,6 @@ export const MARKDOWN_VIEWS = [
38
38
  'changelog',
39
39
  'fmea',
40
40
  'conops',
41
- 'trade',
42
41
  'implplan',
43
42
  ];
44
43
  /** Default file name for each view (under docs/views/). */
@@ -56,6 +55,5 @@ export const VIEW_FILENAMES = {
56
55
  changelog: 'changelog.md',
57
56
  fmea: 'fmea.md',
58
57
  conops: 'conops.md',
59
- trade: 'trade.md',
60
58
  implplan: 'implplan.md',
61
59
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sigloch/graphcode-client",
3
- "version": "2.0.0",
3
+ "version": "3.0.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -40,11 +40,11 @@
40
40
  "zod": "^4.3.6"
41
41
  },
42
42
  "peerDependencies": {
43
- "@sigloch/contracts": ">=11 <12",
43
+ "@sigloch/contracts": ">=12 <13",
44
44
  "@sigloch/graph-api-core": ">=5 <6"
45
45
  },
46
46
  "devDependencies": {
47
- "@sigloch/contracts": ">=11 <12",
47
+ "@sigloch/contracts": ">=12 <13",
48
48
  "@sigloch/graph-api-core": ">=5.4 <6"
49
49
  }
50
50
  }