speclogician 0.0.0b1__py3-none-any.whl
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.
- speclogician/__init__.py +0 -0
- speclogician/commands/__init__.py +15 -0
- speclogician/commands/cmd_ch.py +616 -0
- speclogician/commands/cmd_find.py +256 -0
- speclogician/commands/cmd_view.py +202 -0
- speclogician/commands/runner.py +149 -0
- speclogician/commands/utils.py +101 -0
- speclogician/data/__init__.py +0 -0
- speclogician/data/artifact.py +63 -0
- speclogician/data/container.py +402 -0
- speclogician/data/mapping.py +88 -0
- speclogician/data/refs.py +24 -0
- speclogician/data/traces.py +26 -0
- speclogician/demos/.DS_Store +0 -0
- speclogician/demos/cmd_demo.py +278 -0
- speclogician/demos/loader.py +135 -0
- speclogician/demos/model.py +27 -0
- speclogician/demos/runner.py +51 -0
- speclogician/logic/__init__.py +11 -0
- speclogician/logic/api/__init__.py +29 -0
- speclogician/logic/api/client.py +606 -0
- speclogician/logic/api/decomp.py +67 -0
- speclogician/logic/api/scenario.py +102 -0
- speclogician/logic/api/traces.py +59 -0
- speclogician/logic/lib/__init__.py +19 -0
- speclogician/logic/lib/complement.py +107 -0
- speclogician/logic/lib/domain_model.py +59 -0
- speclogician/logic/lib/predicates.py +151 -0
- speclogician/logic/lib/scenarios.py +369 -0
- speclogician/logic/lib/traces.py +114 -0
- speclogician/logic/lib/transitions.py +104 -0
- speclogician/logic/main.py +246 -0
- speclogician/logic/strings.py +194 -0
- speclogician/logic/utils.py +135 -0
- speclogician/main.py +139 -0
- speclogician/modeling/__init__.py +31 -0
- speclogician/modeling/complement.py +104 -0
- speclogician/modeling/component.py +71 -0
- speclogician/modeling/conflict.py +26 -0
- speclogician/modeling/domain.py +349 -0
- speclogician/modeling/predicates.py +59 -0
- speclogician/modeling/scenario.py +162 -0
- speclogician/modeling/spec.py +306 -0
- speclogician/modeling/spec_stats.py +39 -0
- speclogician/presentation/__init__.py +0 -0
- speclogician/presentation/api.py +244 -0
- speclogician/presentation/builders/__init__.py +0 -0
- speclogician/presentation/builders/_links.py +44 -0
- speclogician/presentation/builders/container.py +53 -0
- speclogician/presentation/builders/data_artifact.py +42 -0
- speclogician/presentation/builders/domain.py +54 -0
- speclogician/presentation/builders/instances_list.py +38 -0
- speclogician/presentation/builders/predicate.py +51 -0
- speclogician/presentation/builders/recommendations.py +41 -0
- speclogician/presentation/builders/scenario.py +41 -0
- speclogician/presentation/builders/scenario_complement.py +82 -0
- speclogician/presentation/builders/smart_find.py +39 -0
- speclogician/presentation/builders/spec.py +39 -0
- speclogician/presentation/builders/state_diff.py +150 -0
- speclogician/presentation/builders/state_instance.py +42 -0
- speclogician/presentation/builders/state_instance_summary.py +84 -0
- speclogician/presentation/builders/trace.py +58 -0
- speclogician/presentation/ctx.py +38 -0
- speclogician/presentation/models/__init__.py +0 -0
- speclogician/presentation/models/container.py +44 -0
- speclogician/presentation/models/data_artifact.py +33 -0
- speclogician/presentation/models/domain.py +50 -0
- speclogician/presentation/models/instances_list.py +23 -0
- speclogician/presentation/models/predicate.py +60 -0
- speclogician/presentation/models/recommendations.py +34 -0
- speclogician/presentation/models/scenario.py +31 -0
- speclogician/presentation/models/scenario_complement.py +40 -0
- speclogician/presentation/models/smart_find.py +34 -0
- speclogician/presentation/models/spec.py +32 -0
- speclogician/presentation/models/state_diff.py +34 -0
- speclogician/presentation/models/state_instance.py +31 -0
- speclogician/presentation/models/state_instance_summary.py +102 -0
- speclogician/presentation/models/trace.py +42 -0
- speclogician/presentation/preview/__init__.py +13 -0
- speclogician/presentation/preview/cli.py +50 -0
- speclogician/presentation/preview/fixtures/__init__.py +205 -0
- speclogician/presentation/preview/fixtures/artifact_container.py +150 -0
- speclogician/presentation/preview/fixtures/data_artifact.py +144 -0
- speclogician/presentation/preview/fixtures/domain_model.py +162 -0
- speclogician/presentation/preview/fixtures/instances_list.py +162 -0
- speclogician/presentation/preview/fixtures/predicate.py +184 -0
- speclogician/presentation/preview/fixtures/scenario.py +84 -0
- speclogician/presentation/preview/fixtures/scenario_complement.py +81 -0
- speclogician/presentation/preview/fixtures/smart_find.py +140 -0
- speclogician/presentation/preview/fixtures/spec.py +95 -0
- speclogician/presentation/preview/fixtures/state_diff.py +158 -0
- speclogician/presentation/preview/fixtures/state_instance.py +128 -0
- speclogician/presentation/preview/fixtures/state_instance_summary.py +80 -0
- speclogician/presentation/preview/fixtures/trace.py +206 -0
- speclogician/presentation/preview/registry.py +42 -0
- speclogician/presentation/renderers/__init__.py +24 -0
- speclogician/presentation/renderers/container.py +136 -0
- speclogician/presentation/renderers/data_artifact.py +144 -0
- speclogician/presentation/renderers/domain.py +123 -0
- speclogician/presentation/renderers/instances_list.py +120 -0
- speclogician/presentation/renderers/predicate.py +180 -0
- speclogician/presentation/renderers/recommendations.py +90 -0
- speclogician/presentation/renderers/scenario.py +94 -0
- speclogician/presentation/renderers/scenario_complement.py +59 -0
- speclogician/presentation/renderers/smart_find.py +307 -0
- speclogician/presentation/renderers/spec.py +105 -0
- speclogician/presentation/renderers/state_diff.py +102 -0
- speclogician/presentation/renderers/state_instance.py +82 -0
- speclogician/presentation/renderers/state_instance_summary.py +143 -0
- speclogician/presentation/renderers/trace.py +122 -0
- speclogician/py.typed +0 -0
- speclogician/shell/app.py +170 -0
- speclogician/shell/shell_ch.py +263 -0
- speclogician/shell/shell_view.py +153 -0
- speclogician/state/__init__.py +0 -0
- speclogician/state/change.py +428 -0
- speclogician/state/change_result.py +32 -0
- speclogician/state/diff.py +191 -0
- speclogician/state/inst.py +574 -0
- speclogician/state/recommendation.py +13 -0
- speclogician/state/recommender.py +577 -0
- speclogician/state/state.py +465 -0
- speclogician/state/state_stats.py +133 -0
- speclogician/tui/__init__.py +0 -0
- speclogician/tui/app.py +257 -0
- speclogician/tui/app.tcss +160 -0
- speclogician/tui/demo.py +45 -0
- speclogician/tui/images/speclogician-full.png +0 -0
- speclogician/tui/images/speclogician-minimal.png +0 -0
- speclogician/tui/main_screen.py +454 -0
- speclogician/tui/splash_screen.py +51 -0
- speclogician/tui/stats_screen.py +125 -0
- speclogician/utils/__init__.py +78 -0
- speclogician/utils/load.py +166 -0
- speclogician/utils/prompt.md +325 -0
- speclogician/utils/testing.py +151 -0
- speclogician-0.0.0b1.dist-info/METADATA +116 -0
- speclogician-0.0.0b1.dist-info/RECORD +139 -0
- speclogician-0.0.0b1.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Imandra Inc.
|
|
3
|
+
#
|
|
4
|
+
# speclogician/presentation/preview/fixtures/smart_find.py
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from speclogician.presentation.ctx import RenderCtx
|
|
10
|
+
from speclogician.presentation.models.smart_find import (
|
|
11
|
+
SmartFindPM,
|
|
12
|
+
SmartFindCountsPM,
|
|
13
|
+
SmartFindItemsPM,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
from speclogician.presentation.preview.fixtures.trace import (
|
|
17
|
+
minimal_test_trace_pm,
|
|
18
|
+
typical_test_trace_pm,
|
|
19
|
+
edge_test_trace_pm,
|
|
20
|
+
minimal_log_trace_pm,
|
|
21
|
+
typical_log_trace_pm,
|
|
22
|
+
edge_log_trace_pm,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
from speclogician.presentation.preview.fixtures.data_artifact import (
|
|
26
|
+
minimal_doc_ref_pm,
|
|
27
|
+
typical_doc_ref_pm,
|
|
28
|
+
edge_doc_ref_pm,
|
|
29
|
+
minimal_src_code_ref_pm,
|
|
30
|
+
typical_src_code_ref_pm,
|
|
31
|
+
edge_src_code_ref_pm,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# -----------------------------------------------------------------------------
|
|
36
|
+
# variants
|
|
37
|
+
# -----------------------------------------------------------------------------
|
|
38
|
+
|
|
39
|
+
def _smart_find_minimal() -> SmartFindPM:
|
|
40
|
+
needle = ""
|
|
41
|
+
return SmartFindPM(
|
|
42
|
+
counts=SmartFindCountsPM(
|
|
43
|
+
needle=needle,
|
|
44
|
+
num_test_traces=0,
|
|
45
|
+
num_log_traces=0,
|
|
46
|
+
num_doc_refs=0,
|
|
47
|
+
num_src_code_refs=0,
|
|
48
|
+
),
|
|
49
|
+
items=SmartFindItemsPM(
|
|
50
|
+
test_traces=[],
|
|
51
|
+
log_traces=[],
|
|
52
|
+
doc_refs=[],
|
|
53
|
+
src_code_refs=[],
|
|
54
|
+
),
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _smart_find_typical() -> SmartFindPM:
|
|
59
|
+
needle = "order size"
|
|
60
|
+
tt = typical_test_trace_pm(with_contents=False, invalid=False)
|
|
61
|
+
lt = typical_log_trace_pm(with_contents=False, invalid=False)
|
|
62
|
+
dr = typical_doc_ref_pm()
|
|
63
|
+
sr = typical_src_code_ref_pm()
|
|
64
|
+
|
|
65
|
+
return SmartFindPM(
|
|
66
|
+
counts=SmartFindCountsPM(
|
|
67
|
+
needle=needle,
|
|
68
|
+
num_test_traces=1,
|
|
69
|
+
num_log_traces=1,
|
|
70
|
+
num_doc_refs=1,
|
|
71
|
+
num_src_code_refs=1,
|
|
72
|
+
),
|
|
73
|
+
items=SmartFindItemsPM(
|
|
74
|
+
test_traces=[tt],
|
|
75
|
+
log_traces=[lt],
|
|
76
|
+
doc_refs=[dr],
|
|
77
|
+
src_code_refs=[sr],
|
|
78
|
+
),
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _smart_find_edge() -> SmartFindPM:
|
|
83
|
+
needle = "pred_eq_ten OR max_qty (line:42)"
|
|
84
|
+
# Stress renderers: mix long contents + invalid + lots of items
|
|
85
|
+
tts = [
|
|
86
|
+
typical_test_trace_pm(with_contents=True, invalid=True),
|
|
87
|
+
edge_test_trace_pm(),
|
|
88
|
+
]
|
|
89
|
+
lts = [
|
|
90
|
+
typical_log_trace_pm(with_contents=True, invalid=True),
|
|
91
|
+
edge_log_trace_pm(),
|
|
92
|
+
]
|
|
93
|
+
drs = [
|
|
94
|
+
edge_doc_ref_pm(),
|
|
95
|
+
typical_doc_ref_pm(),
|
|
96
|
+
minimal_doc_ref_pm(),
|
|
97
|
+
]
|
|
98
|
+
srs = [
|
|
99
|
+
edge_src_code_ref_pm(),
|
|
100
|
+
typical_src_code_ref_pm(),
|
|
101
|
+
minimal_src_code_ref_pm(),
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
return SmartFindPM(
|
|
105
|
+
counts=SmartFindCountsPM(
|
|
106
|
+
needle=needle,
|
|
107
|
+
num_test_traces=len(tts),
|
|
108
|
+
num_log_traces=len(lts),
|
|
109
|
+
num_doc_refs=len(drs),
|
|
110
|
+
num_src_code_refs=len(srs),
|
|
111
|
+
),
|
|
112
|
+
items=SmartFindItemsPM(
|
|
113
|
+
test_traces=tts,
|
|
114
|
+
log_traces=lts,
|
|
115
|
+
doc_refs=drs,
|
|
116
|
+
src_code_refs=srs,
|
|
117
|
+
),
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
# -----------------------------------------------------------------------------
|
|
122
|
+
# top-level fixture entrypoint (matches your preview setup)
|
|
123
|
+
# -----------------------------------------------------------------------------
|
|
124
|
+
|
|
125
|
+
def make_smart_find_pm(ctx: RenderCtx, variant: str = "typical") -> SmartFindPM:
|
|
126
|
+
v = (variant or "typical").strip().lower()
|
|
127
|
+
if v == "minimal":
|
|
128
|
+
return _smart_find_minimal()
|
|
129
|
+
if v == "edge":
|
|
130
|
+
return _smart_find_edge()
|
|
131
|
+
return _smart_find_typical()
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
# -----------------------------------------------------------------------------
|
|
135
|
+
# renderer adapter (matches other fixtures style)
|
|
136
|
+
# -----------------------------------------------------------------------------
|
|
137
|
+
|
|
138
|
+
def render(pm: SmartFindPM, ctx: RenderCtx):
|
|
139
|
+
from speclogician.presentation.renderers.smart_find import render_smart_find
|
|
140
|
+
return render_smart_find(pm, ctx=ctx)
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Imandra Inc.
|
|
3
|
+
#
|
|
4
|
+
# speclogician/presentation/preview/fixtures/spec.py
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from speclogician.presentation.ctx import RenderCtx
|
|
10
|
+
from speclogician.presentation.models.spec import SpecPM, SpecCountsPM
|
|
11
|
+
|
|
12
|
+
from .domain_model import make_domain_model_pm
|
|
13
|
+
from .scenario_complement import make_scenario_complement_pm
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# -----------------------------------------------------------------------------
|
|
17
|
+
# internal constructors
|
|
18
|
+
# -----------------------------------------------------------------------------
|
|
19
|
+
|
|
20
|
+
def _spec_minimal(ctx: RenderCtx) -> SpecPM:
|
|
21
|
+
dm = make_domain_model_pm(ctx, variant="minimal")
|
|
22
|
+
return SpecPM(
|
|
23
|
+
domain=dm,
|
|
24
|
+
counts=SpecCountsPM(
|
|
25
|
+
num_sc_total=0,
|
|
26
|
+
num_sc_missing=0,
|
|
27
|
+
num_sc_matched=0,
|
|
28
|
+
num_sc_inconsistent=0,
|
|
29
|
+
num_sc_conflicted=0,
|
|
30
|
+
),
|
|
31
|
+
scenario_names=[],
|
|
32
|
+
scenario_complement=None,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _spec_typical(ctx: RenderCtx) -> SpecPM:
|
|
37
|
+
dm = make_domain_model_pm(ctx, variant="typical")
|
|
38
|
+
return SpecPM(
|
|
39
|
+
domain=dm,
|
|
40
|
+
counts=SpecCountsPM(
|
|
41
|
+
num_sc_total=9,
|
|
42
|
+
num_sc_missing=1,
|
|
43
|
+
num_sc_matched=0,
|
|
44
|
+
num_sc_inconsistent=0,
|
|
45
|
+
num_sc_conflicted=0,
|
|
46
|
+
),
|
|
47
|
+
scenario_names=[
|
|
48
|
+
"scenario_1",
|
|
49
|
+
"scenario_2",
|
|
50
|
+
"scenario_3",
|
|
51
|
+
"order_rejects_on_max_qty",
|
|
52
|
+
"order_accepts_on_small_qty",
|
|
53
|
+
],
|
|
54
|
+
scenario_complement=make_scenario_complement_pm("typical"),
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _spec_edge(ctx: RenderCtx) -> SpecPM:
|
|
59
|
+
dm = make_domain_model_pm(ctx, variant="edge")
|
|
60
|
+
# stress: lots of scenarios, some missing + inconsistent + conflicted
|
|
61
|
+
names = [f"scenario_{i}" for i in range(1, 26)]
|
|
62
|
+
return SpecPM(
|
|
63
|
+
domain=dm,
|
|
64
|
+
counts=SpecCountsPM(
|
|
65
|
+
num_sc_total=len(names),
|
|
66
|
+
num_sc_missing=5,
|
|
67
|
+
num_sc_matched=12,
|
|
68
|
+
num_sc_inconsistent=3,
|
|
69
|
+
num_sc_conflicted=2,
|
|
70
|
+
),
|
|
71
|
+
scenario_names=names,
|
|
72
|
+
scenario_complement=make_scenario_complement_pm("edge"),
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
# -----------------------------------------------------------------------------
|
|
77
|
+
# public entrypoint (matches other fixtures)
|
|
78
|
+
# -----------------------------------------------------------------------------
|
|
79
|
+
|
|
80
|
+
def make_spec_pm(ctx: RenderCtx, variant: str = "typical") -> SpecPM:
|
|
81
|
+
v = (variant or "typical").strip().lower()
|
|
82
|
+
if v == "minimal":
|
|
83
|
+
return _spec_minimal(ctx)
|
|
84
|
+
if v == "edge":
|
|
85
|
+
return _spec_edge(ctx)
|
|
86
|
+
return _spec_typical(ctx)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
# -----------------------------------------------------------------------------
|
|
90
|
+
# renderer adapter (matches other fixtures style)
|
|
91
|
+
# -----------------------------------------------------------------------------
|
|
92
|
+
|
|
93
|
+
def render(pm: SpecPM, ctx: RenderCtx):
|
|
94
|
+
from speclogician.presentation.renderers.spec import render_spec
|
|
95
|
+
return render_spec(pm, ctx=ctx)
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Imandra Inc.
|
|
3
|
+
#
|
|
4
|
+
# speclogician/presentation/preview/fixtures/state_diff.py
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from rich.console import RenderableType
|
|
10
|
+
|
|
11
|
+
from speclogician.presentation.ctx import RenderCtx
|
|
12
|
+
from speclogician.presentation.models.state_diff import StateDiffPM, DiffSectionPM, DiffRowPM
|
|
13
|
+
from speclogician.state.diff import ComparisonOutcome
|
|
14
|
+
from speclogician.presentation.renderers.state_diff import render_state_diff
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def make_state_diff_pm(ctx: RenderCtx, variant: str) -> StateDiffPM:
|
|
18
|
+
# keep fixtures deterministic, not dependent on real state
|
|
19
|
+
if variant == "minimal":
|
|
20
|
+
return StateDiffPM(has_changes=False, sections=[])
|
|
21
|
+
|
|
22
|
+
if variant == "edge":
|
|
23
|
+
return StateDiffPM(
|
|
24
|
+
has_changes=True,
|
|
25
|
+
sections=[
|
|
26
|
+
DiffSectionPM(
|
|
27
|
+
title="Domain Model: Base",
|
|
28
|
+
rows=[
|
|
29
|
+
DiffRowPM(
|
|
30
|
+
label="base_status",
|
|
31
|
+
before="UNKNOWN",
|
|
32
|
+
after="VALID",
|
|
33
|
+
outcome=ComparisonOutcome.IMPROVED,
|
|
34
|
+
message="base_status improved",
|
|
35
|
+
),
|
|
36
|
+
DiffRowPM(
|
|
37
|
+
label="base_has_action",
|
|
38
|
+
before=False,
|
|
39
|
+
after=False,
|
|
40
|
+
outcome=ComparisonOutcome.NO_CHANGE_BAD,
|
|
41
|
+
message="still missing action",
|
|
42
|
+
),
|
|
43
|
+
DiffRowPM(
|
|
44
|
+
label="base_src",
|
|
45
|
+
before="type state = ...\n" * 3,
|
|
46
|
+
after="type state = int\ntype action = int\n",
|
|
47
|
+
outcome=ComparisonOutcome.UNKNOWN,
|
|
48
|
+
message="multi-line (unknown comparator)",
|
|
49
|
+
),
|
|
50
|
+
],
|
|
51
|
+
),
|
|
52
|
+
DiffSectionPM(
|
|
53
|
+
title="Scenarios",
|
|
54
|
+
rows=[
|
|
55
|
+
DiffRowPM(
|
|
56
|
+
label="num_sc_total",
|
|
57
|
+
before=3,
|
|
58
|
+
after=5,
|
|
59
|
+
outcome=ComparisonOutcome.IMPROVED,
|
|
60
|
+
message="more scenarios",
|
|
61
|
+
),
|
|
62
|
+
DiffRowPM(
|
|
63
|
+
label="num_sc_inconsistent",
|
|
64
|
+
before=0,
|
|
65
|
+
after=1,
|
|
66
|
+
outcome=ComparisonOutcome.DECLINED,
|
|
67
|
+
message="introduced inconsistency",
|
|
68
|
+
),
|
|
69
|
+
],
|
|
70
|
+
),
|
|
71
|
+
DiffSectionPM(
|
|
72
|
+
title="Coverage: Complement",
|
|
73
|
+
rows=[
|
|
74
|
+
DiffRowPM(
|
|
75
|
+
label="scenario_comp_present",
|
|
76
|
+
before=False,
|
|
77
|
+
after=True,
|
|
78
|
+
outcome=ComparisonOutcome.IMPROVED,
|
|
79
|
+
message="complement now computed",
|
|
80
|
+
),
|
|
81
|
+
DiffRowPM(
|
|
82
|
+
label="num_comp_regions_total",
|
|
83
|
+
before=12,
|
|
84
|
+
after=4,
|
|
85
|
+
outcome=ComparisonOutcome.IMPROVED,
|
|
86
|
+
message="fewer uncovered regions",
|
|
87
|
+
),
|
|
88
|
+
],
|
|
89
|
+
),
|
|
90
|
+
],
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
return StateDiffPM(
|
|
94
|
+
has_changes=True,
|
|
95
|
+
sections=[
|
|
96
|
+
DiffSectionPM(
|
|
97
|
+
title="Domain Model: Base",
|
|
98
|
+
rows=[
|
|
99
|
+
DiffRowPM(
|
|
100
|
+
label="base_status",
|
|
101
|
+
before="UNKNOWN",
|
|
102
|
+
after="VALID",
|
|
103
|
+
outcome=ComparisonOutcome.IMPROVED,
|
|
104
|
+
message="base status improved",
|
|
105
|
+
),
|
|
106
|
+
DiffRowPM(
|
|
107
|
+
label="base_has_state",
|
|
108
|
+
before=False,
|
|
109
|
+
after=True,
|
|
110
|
+
outcome=ComparisonOutcome.IMPROVED,
|
|
111
|
+
message="now has state",
|
|
112
|
+
),
|
|
113
|
+
],
|
|
114
|
+
),
|
|
115
|
+
DiffSectionPM(
|
|
116
|
+
title="Scenarios",
|
|
117
|
+
rows=[
|
|
118
|
+
DiffRowPM(
|
|
119
|
+
label="num_sc_total",
|
|
120
|
+
before=3,
|
|
121
|
+
after=5,
|
|
122
|
+
outcome=ComparisonOutcome.IMPROVED,
|
|
123
|
+
message="more scenarios",
|
|
124
|
+
),
|
|
125
|
+
DiffRowPM(
|
|
126
|
+
label="num_sc_inconsistent",
|
|
127
|
+
before=0,
|
|
128
|
+
after=1,
|
|
129
|
+
outcome=ComparisonOutcome.DECLINED,
|
|
130
|
+
message="inconsistency added",
|
|
131
|
+
),
|
|
132
|
+
],
|
|
133
|
+
),
|
|
134
|
+
DiffSectionPM(
|
|
135
|
+
title="Coverage: Complement",
|
|
136
|
+
rows=[
|
|
137
|
+
DiffRowPM(
|
|
138
|
+
label="scenario_comp_present",
|
|
139
|
+
before=True,
|
|
140
|
+
after=True,
|
|
141
|
+
outcome=ComparisonOutcome.NO_CHANGE_GOOD,
|
|
142
|
+
message="complement still present",
|
|
143
|
+
),
|
|
144
|
+
DiffRowPM(
|
|
145
|
+
label="num_comp_regions_total",
|
|
146
|
+
before=6,
|
|
147
|
+
after=6,
|
|
148
|
+
outcome=ComparisonOutcome.NO_CHANGE_BAD,
|
|
149
|
+
message="coverage not improving yet",
|
|
150
|
+
),
|
|
151
|
+
],
|
|
152
|
+
),
|
|
153
|
+
],
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def render(pm: StateDiffPM, ctx: RenderCtx) -> RenderableType:
|
|
158
|
+
return render_state_diff(pm, ctx=ctx)
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Imandra Inc.
|
|
3
|
+
#
|
|
4
|
+
# speclogician/presentation/preview/fixtures/state_instance.py
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from speclogician.presentation.ctx import RenderCtx
|
|
10
|
+
from speclogician.presentation.models.state_instance import StateInstancePM
|
|
11
|
+
from speclogician.presentation.models.recommendations import (
|
|
12
|
+
RecommendationPM,
|
|
13
|
+
RecommendationsPM,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
from .state_instance_summary import make_state_instance_summary_pm
|
|
17
|
+
from .spec import make_spec_pm
|
|
18
|
+
from .artifact_container import make_artifact_container_pm
|
|
19
|
+
from .state_diff import make_state_diff_pm
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# -----------------------------------------------------------------------------
|
|
23
|
+
# Shared recommendations PMs
|
|
24
|
+
# -----------------------------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
_EMPTY_RECOMMENDATIONS = RecommendationsPM(
|
|
27
|
+
count=0,
|
|
28
|
+
items=[],
|
|
29
|
+
num_error=0,
|
|
30
|
+
num_warning=0,
|
|
31
|
+
num_next=0,
|
|
32
|
+
num_info=0,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
_TYPICAL_RECOMMENDATIONS = RecommendationsPM(
|
|
36
|
+
count=4,
|
|
37
|
+
items=[
|
|
38
|
+
RecommendationPM(
|
|
39
|
+
kind="error",
|
|
40
|
+
priority=0,
|
|
41
|
+
text=(
|
|
42
|
+
"Domain model base declined (VALID → INVALID_IML). "
|
|
43
|
+
"Fix base IML/type issues before trusting any further analysis."
|
|
44
|
+
),
|
|
45
|
+
),
|
|
46
|
+
RecommendationPM(
|
|
47
|
+
kind="warning",
|
|
48
|
+
priority=8,
|
|
49
|
+
text=(
|
|
50
|
+
"Some scenarios reference predicates/transitions that do not exist yet.\n"
|
|
51
|
+
"- `HappyPath` missing preds=['p_user_exists'] trans=['t_create_user']\n"
|
|
52
|
+
"Recommendation: add the missing predicates/transitions or edit the scenarios to match the domain model."
|
|
53
|
+
),
|
|
54
|
+
),
|
|
55
|
+
RecommendationPM(
|
|
56
|
+
kind="next",
|
|
57
|
+
priority=25,
|
|
58
|
+
text=(
|
|
59
|
+
"More transitions are logic-valid (1 → 3). "
|
|
60
|
+
"Attach these transitions to scenarios’ `then` lists so traces can match end-to-end."
|
|
61
|
+
),
|
|
62
|
+
),
|
|
63
|
+
RecommendationPM(
|
|
64
|
+
kind="info",
|
|
65
|
+
priority=40,
|
|
66
|
+
text=(
|
|
67
|
+
"More log traces matched scenarios (0 → 2). "
|
|
68
|
+
"Treat these as in-the-wild confirmation and use them to justify model boundaries."
|
|
69
|
+
),
|
|
70
|
+
),
|
|
71
|
+
],
|
|
72
|
+
num_error=1,
|
|
73
|
+
num_warning=1,
|
|
74
|
+
num_next=1,
|
|
75
|
+
num_info=1,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
# -----------------------------------------------------------------------------
|
|
80
|
+
# Variants
|
|
81
|
+
# -----------------------------------------------------------------------------
|
|
82
|
+
|
|
83
|
+
def _state_instance_minimal(ctx: RenderCtx) -> StateInstancePM:
|
|
84
|
+
return StateInstancePM(
|
|
85
|
+
summary=make_state_instance_summary_pm(ctx, "minimal"),
|
|
86
|
+
recommendations=_EMPTY_RECOMMENDATIONS,
|
|
87
|
+
spec=None,
|
|
88
|
+
artifacts=None,
|
|
89
|
+
state_diff=None,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _state_instance_typical(ctx: RenderCtx) -> StateInstancePM:
|
|
94
|
+
return StateInstancePM(
|
|
95
|
+
summary=make_state_instance_summary_pm(ctx, "typical"),
|
|
96
|
+
recommendations=_TYPICAL_RECOMMENDATIONS,
|
|
97
|
+
spec=make_spec_pm(ctx, "typical"),
|
|
98
|
+
artifacts=make_artifact_container_pm(ctx, "typical"),
|
|
99
|
+
state_diff=make_state_diff_pm(ctx, "typical"),
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _state_instance_edge(ctx: RenderCtx) -> StateInstancePM:
|
|
104
|
+
return StateInstancePM(
|
|
105
|
+
summary=make_state_instance_summary_pm(ctx, "edge"),
|
|
106
|
+
recommendations=_EMPTY_RECOMMENDATIONS,
|
|
107
|
+
spec=make_spec_pm(ctx, "edge"),
|
|
108
|
+
artifacts=make_artifact_container_pm(ctx, "edge"),
|
|
109
|
+
state_diff=make_state_diff_pm(ctx, "edge"),
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
# -----------------------------------------------------------------------------
|
|
114
|
+
# Public entry point (used by PreviewSpec)
|
|
115
|
+
# -----------------------------------------------------------------------------
|
|
116
|
+
|
|
117
|
+
def make_state_instance_pm(ctx: RenderCtx, variant: str = "typical") -> StateInstancePM:
|
|
118
|
+
v = (variant or "typical").strip().lower()
|
|
119
|
+
if v == "minimal":
|
|
120
|
+
return _state_instance_minimal(ctx)
|
|
121
|
+
if v == "edge":
|
|
122
|
+
return _state_instance_edge(ctx)
|
|
123
|
+
return _state_instance_typical(ctx)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def render(pm: StateInstancePM, ctx: RenderCtx):
|
|
127
|
+
from speclogician.presentation.renderers.state_instance import render_state_instance
|
|
128
|
+
return render_state_instance(pm, ctx=ctx)
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Imandra Inc.
|
|
3
|
+
#
|
|
4
|
+
# speclogician/presentation/preview/fixtures/state_instance_summary.py
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from speclogician.presentation.ctx import RenderCtx
|
|
10
|
+
from speclogician.presentation.models.state_instance_summary import StateInstanceSummaryPM
|
|
11
|
+
from speclogician.presentation.renderers.state_instance_summary import render_state_instance_summary
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def make_state_instance_summary_pm(ctx: RenderCtx, variant: str) -> StateInstanceSummaryPM:
|
|
15
|
+
if variant == "minimal":
|
|
16
|
+
return StateInstanceSummaryPM(
|
|
17
|
+
created_at="1970-01-01T00:00:00Z",
|
|
18
|
+
num_changes=0,
|
|
19
|
+
base_status="UNKNOWN",
|
|
20
|
+
base_has_state=False,
|
|
21
|
+
base_has_action=False,
|
|
22
|
+
num_preds_total=0,
|
|
23
|
+
num_preds_matched=0,
|
|
24
|
+
num_trans_total=0,
|
|
25
|
+
num_trans_valid_logic=0,
|
|
26
|
+
num_sc_total=0,
|
|
27
|
+
num_sc_missing=0,
|
|
28
|
+
num_sc_inconsistent=0,
|
|
29
|
+
num_sc_conflicted=0,
|
|
30
|
+
num_test_traces_total=0,
|
|
31
|
+
num_test_traces_logic_good=0,
|
|
32
|
+
num_log_traces_total=0,
|
|
33
|
+
num_log_traces_logic_good=0,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
if variant == "edge":
|
|
37
|
+
return StateInstanceSummaryPM(
|
|
38
|
+
created_at="2026-01-09T10:12:00Z",
|
|
39
|
+
num_changes=1234,
|
|
40
|
+
base_status="VALID",
|
|
41
|
+
base_has_state=True,
|
|
42
|
+
base_has_action=True,
|
|
43
|
+
num_preds_total=999,
|
|
44
|
+
num_preds_matched=888,
|
|
45
|
+
num_trans_total=77,
|
|
46
|
+
num_trans_valid_logic=66,
|
|
47
|
+
num_sc_total=55,
|
|
48
|
+
num_sc_missing=44,
|
|
49
|
+
num_sc_inconsistent=33,
|
|
50
|
+
num_sc_conflicted=22,
|
|
51
|
+
num_test_traces_total=111,
|
|
52
|
+
num_test_traces_logic_good=100,
|
|
53
|
+
num_log_traces_total=200,
|
|
54
|
+
num_log_traces_logic_good=199,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
# typical
|
|
58
|
+
return StateInstanceSummaryPM(
|
|
59
|
+
created_at="2026-01-09T10:12:00Z",
|
|
60
|
+
num_changes=2,
|
|
61
|
+
base_status="VALID",
|
|
62
|
+
base_has_state=True,
|
|
63
|
+
base_has_action=True,
|
|
64
|
+
num_preds_total=12,
|
|
65
|
+
num_preds_matched=7,
|
|
66
|
+
num_trans_total=4,
|
|
67
|
+
num_trans_valid_logic=3,
|
|
68
|
+
num_sc_total=9,
|
|
69
|
+
num_sc_missing=1,
|
|
70
|
+
num_sc_inconsistent=0,
|
|
71
|
+
num_sc_conflicted=0,
|
|
72
|
+
num_test_traces_total=8,
|
|
73
|
+
num_test_traces_logic_good=6,
|
|
74
|
+
num_log_traces_total=4,
|
|
75
|
+
num_log_traces_logic_good=4,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def render(pm: StateInstanceSummaryPM, ctx: RenderCtx):
|
|
80
|
+
return render_state_instance_summary(pm, ctx=ctx)
|