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.
Files changed (139) hide show
  1. speclogician/__init__.py +0 -0
  2. speclogician/commands/__init__.py +15 -0
  3. speclogician/commands/cmd_ch.py +616 -0
  4. speclogician/commands/cmd_find.py +256 -0
  5. speclogician/commands/cmd_view.py +202 -0
  6. speclogician/commands/runner.py +149 -0
  7. speclogician/commands/utils.py +101 -0
  8. speclogician/data/__init__.py +0 -0
  9. speclogician/data/artifact.py +63 -0
  10. speclogician/data/container.py +402 -0
  11. speclogician/data/mapping.py +88 -0
  12. speclogician/data/refs.py +24 -0
  13. speclogician/data/traces.py +26 -0
  14. speclogician/demos/.DS_Store +0 -0
  15. speclogician/demos/cmd_demo.py +278 -0
  16. speclogician/demos/loader.py +135 -0
  17. speclogician/demos/model.py +27 -0
  18. speclogician/demos/runner.py +51 -0
  19. speclogician/logic/__init__.py +11 -0
  20. speclogician/logic/api/__init__.py +29 -0
  21. speclogician/logic/api/client.py +606 -0
  22. speclogician/logic/api/decomp.py +67 -0
  23. speclogician/logic/api/scenario.py +102 -0
  24. speclogician/logic/api/traces.py +59 -0
  25. speclogician/logic/lib/__init__.py +19 -0
  26. speclogician/logic/lib/complement.py +107 -0
  27. speclogician/logic/lib/domain_model.py +59 -0
  28. speclogician/logic/lib/predicates.py +151 -0
  29. speclogician/logic/lib/scenarios.py +369 -0
  30. speclogician/logic/lib/traces.py +114 -0
  31. speclogician/logic/lib/transitions.py +104 -0
  32. speclogician/logic/main.py +246 -0
  33. speclogician/logic/strings.py +194 -0
  34. speclogician/logic/utils.py +135 -0
  35. speclogician/main.py +139 -0
  36. speclogician/modeling/__init__.py +31 -0
  37. speclogician/modeling/complement.py +104 -0
  38. speclogician/modeling/component.py +71 -0
  39. speclogician/modeling/conflict.py +26 -0
  40. speclogician/modeling/domain.py +349 -0
  41. speclogician/modeling/predicates.py +59 -0
  42. speclogician/modeling/scenario.py +162 -0
  43. speclogician/modeling/spec.py +306 -0
  44. speclogician/modeling/spec_stats.py +39 -0
  45. speclogician/presentation/__init__.py +0 -0
  46. speclogician/presentation/api.py +244 -0
  47. speclogician/presentation/builders/__init__.py +0 -0
  48. speclogician/presentation/builders/_links.py +44 -0
  49. speclogician/presentation/builders/container.py +53 -0
  50. speclogician/presentation/builders/data_artifact.py +42 -0
  51. speclogician/presentation/builders/domain.py +54 -0
  52. speclogician/presentation/builders/instances_list.py +38 -0
  53. speclogician/presentation/builders/predicate.py +51 -0
  54. speclogician/presentation/builders/recommendations.py +41 -0
  55. speclogician/presentation/builders/scenario.py +41 -0
  56. speclogician/presentation/builders/scenario_complement.py +82 -0
  57. speclogician/presentation/builders/smart_find.py +39 -0
  58. speclogician/presentation/builders/spec.py +39 -0
  59. speclogician/presentation/builders/state_diff.py +150 -0
  60. speclogician/presentation/builders/state_instance.py +42 -0
  61. speclogician/presentation/builders/state_instance_summary.py +84 -0
  62. speclogician/presentation/builders/trace.py +58 -0
  63. speclogician/presentation/ctx.py +38 -0
  64. speclogician/presentation/models/__init__.py +0 -0
  65. speclogician/presentation/models/container.py +44 -0
  66. speclogician/presentation/models/data_artifact.py +33 -0
  67. speclogician/presentation/models/domain.py +50 -0
  68. speclogician/presentation/models/instances_list.py +23 -0
  69. speclogician/presentation/models/predicate.py +60 -0
  70. speclogician/presentation/models/recommendations.py +34 -0
  71. speclogician/presentation/models/scenario.py +31 -0
  72. speclogician/presentation/models/scenario_complement.py +40 -0
  73. speclogician/presentation/models/smart_find.py +34 -0
  74. speclogician/presentation/models/spec.py +32 -0
  75. speclogician/presentation/models/state_diff.py +34 -0
  76. speclogician/presentation/models/state_instance.py +31 -0
  77. speclogician/presentation/models/state_instance_summary.py +102 -0
  78. speclogician/presentation/models/trace.py +42 -0
  79. speclogician/presentation/preview/__init__.py +13 -0
  80. speclogician/presentation/preview/cli.py +50 -0
  81. speclogician/presentation/preview/fixtures/__init__.py +205 -0
  82. speclogician/presentation/preview/fixtures/artifact_container.py +150 -0
  83. speclogician/presentation/preview/fixtures/data_artifact.py +144 -0
  84. speclogician/presentation/preview/fixtures/domain_model.py +162 -0
  85. speclogician/presentation/preview/fixtures/instances_list.py +162 -0
  86. speclogician/presentation/preview/fixtures/predicate.py +184 -0
  87. speclogician/presentation/preview/fixtures/scenario.py +84 -0
  88. speclogician/presentation/preview/fixtures/scenario_complement.py +81 -0
  89. speclogician/presentation/preview/fixtures/smart_find.py +140 -0
  90. speclogician/presentation/preview/fixtures/spec.py +95 -0
  91. speclogician/presentation/preview/fixtures/state_diff.py +158 -0
  92. speclogician/presentation/preview/fixtures/state_instance.py +128 -0
  93. speclogician/presentation/preview/fixtures/state_instance_summary.py +80 -0
  94. speclogician/presentation/preview/fixtures/trace.py +206 -0
  95. speclogician/presentation/preview/registry.py +42 -0
  96. speclogician/presentation/renderers/__init__.py +24 -0
  97. speclogician/presentation/renderers/container.py +136 -0
  98. speclogician/presentation/renderers/data_artifact.py +144 -0
  99. speclogician/presentation/renderers/domain.py +123 -0
  100. speclogician/presentation/renderers/instances_list.py +120 -0
  101. speclogician/presentation/renderers/predicate.py +180 -0
  102. speclogician/presentation/renderers/recommendations.py +90 -0
  103. speclogician/presentation/renderers/scenario.py +94 -0
  104. speclogician/presentation/renderers/scenario_complement.py +59 -0
  105. speclogician/presentation/renderers/smart_find.py +307 -0
  106. speclogician/presentation/renderers/spec.py +105 -0
  107. speclogician/presentation/renderers/state_diff.py +102 -0
  108. speclogician/presentation/renderers/state_instance.py +82 -0
  109. speclogician/presentation/renderers/state_instance_summary.py +143 -0
  110. speclogician/presentation/renderers/trace.py +122 -0
  111. speclogician/py.typed +0 -0
  112. speclogician/shell/app.py +170 -0
  113. speclogician/shell/shell_ch.py +263 -0
  114. speclogician/shell/shell_view.py +153 -0
  115. speclogician/state/__init__.py +0 -0
  116. speclogician/state/change.py +428 -0
  117. speclogician/state/change_result.py +32 -0
  118. speclogician/state/diff.py +191 -0
  119. speclogician/state/inst.py +574 -0
  120. speclogician/state/recommendation.py +13 -0
  121. speclogician/state/recommender.py +577 -0
  122. speclogician/state/state.py +465 -0
  123. speclogician/state/state_stats.py +133 -0
  124. speclogician/tui/__init__.py +0 -0
  125. speclogician/tui/app.py +257 -0
  126. speclogician/tui/app.tcss +160 -0
  127. speclogician/tui/demo.py +45 -0
  128. speclogician/tui/images/speclogician-full.png +0 -0
  129. speclogician/tui/images/speclogician-minimal.png +0 -0
  130. speclogician/tui/main_screen.py +454 -0
  131. speclogician/tui/splash_screen.py +51 -0
  132. speclogician/tui/stats_screen.py +125 -0
  133. speclogician/utils/__init__.py +78 -0
  134. speclogician/utils/load.py +166 -0
  135. speclogician/utils/prompt.md +325 -0
  136. speclogician/utils/testing.py +151 -0
  137. speclogician-0.0.0b1.dist-info/METADATA +116 -0
  138. speclogician-0.0.0b1.dist-info/RECORD +139 -0
  139. speclogician-0.0.0b1.dist-info/WHEEL +4 -0
@@ -0,0 +1,102 @@
1
+ #
2
+ # Imandra Inc.
3
+ #
4
+ # speclogician/presentation/models/state_instance_summary.py
5
+ #
6
+
7
+ from __future__ import annotations
8
+
9
+ from pydantic import BaseModel
10
+ from typing import Optional
11
+
12
+
13
+ class StateInstanceSummaryPM(BaseModel):
14
+ # -----------------
15
+ # metadata
16
+ # -----------------
17
+ created_at: Optional[str] = None
18
+
19
+ # -----------------
20
+ # changes
21
+ # -----------------
22
+ num_changes: int = 0
23
+
24
+ # -----------------
25
+ # Domain model (base)
26
+ # -----------------
27
+ base_status: Optional[str] = None
28
+ base_has_state: Optional[bool] = None
29
+ base_has_action: Optional[bool] = None
30
+
31
+ # -----------------
32
+ # Domain model (state predicates)
33
+ # -----------------
34
+ num_state_preds_total: Optional[int] = None
35
+ num_state_preds_matched: Optional[int] = None
36
+ num_state_preds_valid_logic: Optional[int] = None
37
+ num_state_preds_errored: Optional[int] = None
38
+
39
+ # -----------------
40
+ # Domain model (action predicates)
41
+ # -----------------
42
+ num_action_preds_total: Optional[int] = None
43
+ num_action_preds_matched: Optional[int] = None
44
+ num_action_preds_valid_logic: Optional[int] = None
45
+ num_action_preds_errored: Optional[int] = None
46
+
47
+ # -----------------
48
+ # Domain model (predicate totals)
49
+ # -----------------
50
+ num_preds_total: Optional[int] = None
51
+ num_preds_matched: Optional[int] = None
52
+ num_preds_valid_logic: Optional[int] = None
53
+ num_preds_errored: Optional[int] = None
54
+
55
+ # -----------------
56
+ # Domain model (transitions)
57
+ # -----------------
58
+ num_trans_total: Optional[int] = None
59
+ num_trans_matched: Optional[int] = None
60
+ num_trans_valid_logic: Optional[int] = None
61
+ num_trans_errored: Optional[int] = None
62
+
63
+ # -----------------
64
+ # Scenarios
65
+ # -----------------
66
+ num_sc_total: Optional[int] = None
67
+ num_sc_missing: Optional[int] = None
68
+ num_sc_matched: Optional[int] = None
69
+ num_sc_inconsistent: Optional[int] = None
70
+
71
+ # -----------------
72
+ # Conflicts (spec-level)
73
+ # -----------------
74
+ num_sc_conflicted: Optional[int] = None
75
+ num_sc_overlap: Optional[int] = None
76
+ num_sc_consumed: Optional[int] = None
77
+
78
+ # -----------------
79
+ # Test traces
80
+ # -----------------
81
+ num_test_traces_total: Optional[int] = None
82
+ num_test_traces_matched: Optional[int] = None
83
+ num_test_traces_logic_good: Optional[int] = None
84
+
85
+ # -----------------
86
+ # Log traces
87
+ # -----------------
88
+ num_log_traces_total: Optional[int] = None
89
+ num_log_traces_matched: Optional[int] = None
90
+ num_log_traces_logic_good: Optional[int] = None
91
+
92
+ # -----------------
93
+ # Source code artifacts
94
+ # -----------------
95
+ num_src_code_arts_total: Optional[int] = None
96
+ num_src_code_arts_matched: Optional[int] = None
97
+
98
+ # -----------------
99
+ # Doc artifacts
100
+ # -----------------
101
+ num_doc_arts_total: Optional[int] = None
102
+ num_doc_arts_matched: Optional[int] = None
@@ -0,0 +1,42 @@
1
+ #
2
+ # Imandra Inc.
3
+ #
4
+ # speclogician/presentation/models/trace.py
5
+ #
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import Literal
10
+ from pydantic import BaseModel
11
+
12
+
13
+ class TraceIMLValidityPM(BaseModel):
14
+ iml_valid: str # "unknown" | "valid" | "invalid"
15
+ err: str | None = None
16
+
17
+
18
+ class TraceCorePM(BaseModel):
19
+ art_id: str
20
+ given: str
21
+ when: str | None = None
22
+ then: str | None = None
23
+ time: str = ""
24
+ iml_validity: TraceIMLValidityPM
25
+
26
+
27
+ class TestTracePM(BaseModel):
28
+ kind: Literal["test_trace"] = "test_trace"
29
+ core: TraceCorePM
30
+
31
+ name: str
32
+ filepath: str = ""
33
+ language: str | None = None
34
+ contents: str | None = None # optional / heavy
35
+
36
+
37
+ class LogTracePM(BaseModel):
38
+ kind: Literal["log_trace"] = "log_trace"
39
+ core: TraceCorePM
40
+
41
+ filename: str
42
+ contents: str | None = None # optional / heavy
@@ -0,0 +1,13 @@
1
+ #
2
+ # Imandra Inc.
3
+ #
4
+ # speclogician/presentation/preview/__init__.py
5
+ #
6
+
7
+ from __future__ import annotations
8
+
9
+ from .cli import app as preview_app
10
+
11
+ __all__ = [
12
+ "preview_app"
13
+ ]
@@ -0,0 +1,50 @@
1
+ #
2
+ # Imandra Inc.
3
+ #
4
+ # speclogician/presentation/preview/cli.py
5
+ #
6
+
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ import typer
11
+
12
+ from speclogician.presentation.ctx import RenderCtx
13
+ from speclogician.presentation.preview.registry import get, list_previews
14
+ from speclogician.presentation.preview.fixtures import register_fixtures
15
+ from speclogician.utils import console # your rich console
16
+
17
+
18
+ app = typer.Typer(help="Preview PM renderers using synthetic fixtures.")
19
+
20
+
21
+ @app.command("list")
22
+ def list_cmd() -> None:
23
+ register_fixtures()
24
+ for spec in sorted(list_previews(), key=lambda s: s.name):
25
+ console.print(f"[bold]{spec.name}[/bold] variants={', '.join(spec.variants)}")
26
+
27
+
28
+ @app.command("show")
29
+ def show_cmd(
30
+ name: str = typer.Argument(..., help="Preview name (see: preview list)"),
31
+ variant: str = typer.Argument("typical", help="Variant: typical|minimal|edge"),
32
+ json_only: bool = typer.Option(False, "--json", help="Dump PM as JSON instead of rendering."),
33
+ compact: bool = typer.Option(False, "--compact", help="Use compact rendering."),
34
+ ) -> None:
35
+ register_fixtures()
36
+
37
+ ctx = RenderCtx(compact=compact)
38
+ spec = get(name)
39
+
40
+ if variant not in spec.variants:
41
+ raise typer.BadParameter(f"Unknown variant '{variant}'. Choose one of: {', '.join(spec.variants)}")
42
+
43
+ pm = spec.make(ctx, variant)
44
+
45
+ if json_only:
46
+ # Pydantic v2
47
+ typer.echo(json.dumps(pm.model_dump(), indent=2, default=str))
48
+ raise typer.Exit(0)
49
+
50
+ console.print(spec.render(pm, ctx))
@@ -0,0 +1,205 @@
1
+ #
2
+ # Imandra Inc.
3
+ #
4
+ # speclogician/presentation/preview/fixtures/__init__.py
5
+ #
6
+
7
+ from __future__ import annotations
8
+
9
+ from speclogician.presentation.preview.registry import PreviewSpec, register
10
+
11
+ from . import state_diff
12
+ from . import state_instance_summary
13
+ from . import trace
14
+ from . import data_artifact
15
+ from . import artifact_container
16
+ from . import predicate
17
+ from . import scenario
18
+ from . import domain_model
19
+ from . import instances_list
20
+ from . import spec
21
+ from . import smart_find
22
+ from . import state_instance
23
+
24
+
25
+ def register_fixtures() -> None:
26
+
27
+ # ------------------------------------------------------------------
28
+ # State-level fixtures (already present)
29
+ # ------------------------------------------------------------------
30
+
31
+ register(
32
+ PreviewSpec(
33
+ name="state-diff",
34
+ variants=("typical", "minimal", "edge"),
35
+ make=state_diff.make_state_diff_pm,
36
+ render=state_diff.render,
37
+ )
38
+ )
39
+
40
+ register(
41
+ PreviewSpec(
42
+ name="state-instance-summary",
43
+ variants=("typical", "minimal", "edge"),
44
+ make=state_instance_summary.make_state_instance_summary_pm,
45
+ render=state_instance_summary.render,
46
+ )
47
+ )
48
+
49
+ # ------------------------------------------------------------------
50
+ # Trace fixtures
51
+ # ------------------------------------------------------------------
52
+
53
+ register(
54
+ PreviewSpec(
55
+ name="test-trace",
56
+ variants=("typical", "minimal", "edge"),
57
+ make=trace.make_test_trace_pm,
58
+ render=trace.render_test,
59
+ )
60
+ )
61
+
62
+ register(
63
+ PreviewSpec(
64
+ name="log-trace",
65
+ variants=("typical", "minimal", "edge"),
66
+ make=trace.make_log_trace_pm,
67
+ render=trace.render_log,
68
+ )
69
+ )
70
+
71
+ # ------------------------------------------------------------------
72
+ # Data artifact fixtures
73
+ # ------------------------------------------------------------------
74
+
75
+
76
+ register(
77
+ PreviewSpec(
78
+ name="doc-ref",
79
+ variants=("typical", "minimal", "edge"),
80
+ make=data_artifact.make_doc_ref_pm,
81
+ render=data_artifact.render_doc,
82
+ )
83
+ )
84
+
85
+ register(
86
+ PreviewSpec(
87
+ name="src-code-ref",
88
+ variants=("typical", "minimal", "edge"),
89
+ make=data_artifact.make_src_code_ref_pm,
90
+ render=data_artifact.render_src,
91
+ )
92
+ )
93
+
94
+ # ------------------------------------------------------------------
95
+ # Artifact container fixtures
96
+ # ------------------------------------------------------------------
97
+
98
+ register(
99
+ PreviewSpec(
100
+ name="artifact-container",
101
+ variants=("typical", "minimal", "edge"),
102
+ make=artifact_container.make_artifact_container_pm,
103
+ render=artifact_container.render,
104
+ )
105
+ )
106
+
107
+ # ------------------------------------------------------------------
108
+ # Predicate/Transition fixtures
109
+ # ------------------------------------------------------------------
110
+
111
+ register(
112
+ PreviewSpec(
113
+ name="predicate",
114
+ variants=("typical", "minimal", "edge"),
115
+ make=predicate.make_predicate_pm,
116
+ render=predicate.render_predicate,
117
+ )
118
+ )
119
+
120
+ register(
121
+ PreviewSpec(
122
+ name="transition",
123
+ variants=("typical", "minimal", "edge"),
124
+ make=predicate.make_transition_pm,
125
+ render=predicate.render_transition,
126
+ )
127
+ )
128
+
129
+ # ------------------------------------------------------------------
130
+ # Scenario fixture
131
+ # ------------------------------------------------------------------
132
+
133
+ register(
134
+ PreviewSpec(
135
+ name="scenario",
136
+ variants=("typical", "minimal", "edge"),
137
+ make=scenario.make_scenario_pm,
138
+ render=scenario.render,
139
+ )
140
+ )
141
+
142
+ # ------------------------------------------------------------------
143
+ # DomainModel fixture
144
+ # ------------------------------------------------------------------
145
+
146
+ register(
147
+ PreviewSpec(
148
+ name="domain-model",
149
+ variants=("typical", "minimal", "edge"),
150
+ make=domain_model.make_domain_model_pm,
151
+ render=domain_model.render,
152
+ )
153
+ )
154
+
155
+ # ------------------------------------------------------------------
156
+ # InstancesList fixture
157
+ # ------------------------------------------------------------------
158
+
159
+ register(
160
+ PreviewSpec(
161
+ name="instances-list",
162
+ variants=("typical", "minimal", "edge"),
163
+ make=instances_list.make_instances_list_pm,
164
+ render=instances_list.render,
165
+ )
166
+ )
167
+
168
+ # ------------------------------------------------------------------
169
+ # Spec fixture
170
+ # ------------------------------------------------------------------
171
+
172
+ register(
173
+ PreviewSpec(
174
+ name="spec",
175
+ variants=("typical", "minimal", "edge"),
176
+ make=spec.make_spec_pm,
177
+ render=spec.render,
178
+ )
179
+ )
180
+
181
+ # ------------------------------------------------------------------
182
+ # SmartFind
183
+ # ------------------------------------------------------------------
184
+ register(
185
+ PreviewSpec(
186
+ name="smart-find",
187
+ variants=("typical", "minimal", "edge"),
188
+ make=smart_find.make_smart_find_pm,
189
+ render=smart_find.render,
190
+ )
191
+ )
192
+
193
+
194
+ # ------------------------------------------------------------------
195
+ # SmartFind
196
+ # ------------------------------------------------------------------
197
+
198
+ register(
199
+ PreviewSpec(
200
+ name="state-instance",
201
+ variants=("typical", "minimal", "edge"),
202
+ make=state_instance.make_state_instance_pm,
203
+ render=state_instance.render,
204
+ )
205
+ )
@@ -0,0 +1,150 @@
1
+ #
2
+ # Imandra Inc.
3
+ #
4
+ # speclogician/presentation/preview/fixtures/artifact_container.py
5
+ #
6
+
7
+ from __future__ import annotations
8
+ from speclogician.presentation.ctx import RenderCtx
9
+
10
+ from speclogician.presentation.models.container import (
11
+ ArtifactContainerPM,
12
+ ArtifactContainerCountsPM,
13
+ ArtifactContainerItemsPM,
14
+ )
15
+
16
+ # reuse existing fixtures
17
+ from speclogician.presentation.preview.fixtures.trace import (
18
+ minimal_test_trace_pm,
19
+ typical_test_trace_pm,
20
+ edge_test_trace_pm,
21
+ minimal_log_trace_pm,
22
+ typical_log_trace_pm,
23
+ edge_log_trace_pm,
24
+ )
25
+
26
+ from speclogician.presentation.preview.fixtures.data_artifact import (
27
+ minimal_doc_ref_pm,
28
+ typical_doc_ref_pm,
29
+ edge_doc_ref_pm,
30
+ minimal_src_code_ref_pm,
31
+ typical_src_code_ref_pm,
32
+ edge_src_code_ref_pm,
33
+ )
34
+
35
+
36
+ # -----------------------------------------------------------------------------
37
+ # helpers
38
+ # -----------------------------------------------------------------------------
39
+
40
+ def _counts_from_items(items: ArtifactContainerItemsPM) -> ArtifactContainerCountsPM:
41
+ # totals
42
+ num_test_total = len(items.test_traces)
43
+ num_log_total = len(items.log_traces)
44
+ num_doc_total = len(items.doc_refs)
45
+ num_src_total = len(items.src_code_refs)
46
+
47
+ # matched / logic_good are not explicitly present on PMs yet,
48
+ # so we keep these deterministic for fixtures. You can refine
49
+ # this later once you encode matched flags in PMs.
50
+ def _half(n: int) -> int:
51
+ return 0 if n == 0 else max(1, n // 2)
52
+
53
+ return ArtifactContainerCountsPM(
54
+ num_test_traces_total=num_test_total,
55
+ num_test_traces_matched=_half(num_test_total),
56
+ num_test_traces_logic_good=_half(num_test_total),
57
+
58
+ num_log_traces_total=num_log_total,
59
+ num_log_traces_matched=_half(num_log_total),
60
+ num_log_traces_logic_good=_half(num_log_total),
61
+
62
+ num_src_code_arts_total=num_src_total,
63
+ num_src_code_arts_matched=_half(num_src_total),
64
+
65
+ num_doc_arts_total=num_doc_total,
66
+ num_doc_arts_matched=_half(num_doc_total),
67
+ )
68
+
69
+
70
+ # -----------------------------------------------------------------------------
71
+ # main fixture entrypoint (matches PreviewSpec.make signature)
72
+ # -----------------------------------------------------------------------------
73
+
74
+ def make_artifact_container_pm(ctx: RenderCtx, variant: str = "typical") -> ArtifactContainerPM:
75
+ v = (variant or "typical").lower().strip()
76
+
77
+ # -------------------------
78
+ # minimal
79
+ # -------------------------
80
+ if v == "minimal":
81
+ items = ArtifactContainerItemsPM(
82
+ test_traces=[],
83
+ log_traces=[],
84
+ doc_refs=[],
85
+ src_code_refs=[],
86
+ )
87
+ return ArtifactContainerPM(
88
+ counts=_counts_from_items(items),
89
+ items=items,
90
+ )
91
+
92
+ # -------------------------
93
+ # edge (stress: long content, many items)
94
+ # -------------------------
95
+ if v == "edge":
96
+ items = ArtifactContainerItemsPM(
97
+ test_traces=[
98
+ edge_test_trace_pm(),
99
+ typical_test_trace_pm(with_contents=True, invalid=True),
100
+ typical_test_trace_pm(with_contents=False, invalid=False),
101
+ ],
102
+ log_traces=[
103
+ edge_log_trace_pm(),
104
+ typical_log_trace_pm(with_contents=True, invalid=True),
105
+ ],
106
+ doc_refs=[
107
+ edge_doc_ref_pm(),
108
+ typical_doc_ref_pm(),
109
+ ],
110
+ src_code_refs=[
111
+ edge_src_code_ref_pm(),
112
+ typical_src_code_ref_pm(),
113
+ ],
114
+ )
115
+ return ArtifactContainerPM(
116
+ counts=_counts_from_items(items),
117
+ items=items,
118
+ )
119
+
120
+ # -------------------------
121
+ # typical
122
+ # -------------------------
123
+ items = ArtifactContainerItemsPM(
124
+ test_traces=[
125
+ typical_test_trace_pm(with_contents=False, invalid=False),
126
+ typical_test_trace_pm(with_contents=True, invalid=True),
127
+ ],
128
+ log_traces=[
129
+ typical_log_trace_pm(with_contents=False, invalid=False),
130
+ ],
131
+ doc_refs=[
132
+ typical_doc_ref_pm(),
133
+ ],
134
+ src_code_refs=[
135
+ typical_src_code_ref_pm(),
136
+ ],
137
+ )
138
+ return ArtifactContainerPM(
139
+ counts=_counts_from_items(items),
140
+ items=items,
141
+ )
142
+
143
+
144
+ # -----------------------------------------------------------------------------
145
+ # renderer adapter (matches other fixtures style)
146
+ # -----------------------------------------------------------------------------
147
+
148
+ def render(pm: ArtifactContainerPM, ctx : RenderCtx):
149
+ from speclogician.presentation.renderers.container import render_artifact_container
150
+ return render_artifact_container(pm, ctx=ctx)
@@ -0,0 +1,144 @@
1
+ #
2
+ # Imandra Inc.
3
+ #
4
+ # speclogician/presentation/preview/fixtures/data_artifact.py
5
+ #
6
+
7
+ from __future__ import annotations
8
+
9
+ from speclogician.presentation.ctx import RenderCtx
10
+ from speclogician.presentation.models.data_artifact import DataArtifactCorePM, DocRefPM, SrcCodeRefPM
11
+ from speclogician.presentation.renderers.data_artifact import (
12
+ render_doc_ref,
13
+ render_src_code_ref,
14
+ )
15
+
16
+ # -----------------------------------------------------------------------------
17
+ # Shared helpers
18
+ # -----------------------------------------------------------------------------
19
+
20
+ def _core(*, art_id: str) -> DataArtifactCorePM:
21
+ return DataArtifactCorePM(art_id=art_id)
22
+
23
+
24
+ # -----------------------------------------------------------------------------
25
+ # DocRefPM fixtures
26
+ # -----------------------------------------------------------------------------
27
+
28
+ def minimal_doc_ref_pm() -> DocRefPM:
29
+ return DocRefPM(
30
+ core=_core(art_id="00000000-0000-0000-0000-000000000000"),
31
+ text="",
32
+ meta=None,
33
+ )
34
+
35
+
36
+ def typical_doc_ref_pm() -> DocRefPM:
37
+ return DocRefPM(
38
+ core=_core(art_id="11111111-1111-1111-1111-111111111111"),
39
+ text="Order must be rejected if quantity exceeds max order size.",
40
+ meta="spec:order_limits; source=confluence; section=Risk Checks",
41
+ )
42
+
43
+
44
+ def edge_doc_ref_pm() -> DocRefPM:
45
+ return DocRefPM(
46
+ core=_core(art_id="99999999-9999-9999-9999-999999999999"),
47
+ text=(
48
+ "A very long doc note that should wrap nicely and still be readable. "
49
+ "It may contain bullet-like text, punctuation, and ‘quoted’ phrases.\n\n"
50
+ "- Must preserve meaning\n"
51
+ "- Must keep formatting\n"
52
+ "- Should not overflow tables\n"
53
+ ),
54
+ meta=(
55
+ "url=https://example.com/really/long/path/to/a/doc\n"
56
+ "tags=risk,limits,edge-case\n"
57
+ "owner=QA\n"
58
+ ),
59
+ )
60
+
61
+
62
+ def make_doc_ref_pm(ctx: RenderCtx, variant: str) -> DocRefPM:
63
+ match variant:
64
+ case "minimal":
65
+ return minimal_doc_ref_pm()
66
+ case "edge":
67
+ return edge_doc_ref_pm()
68
+ case _:
69
+ return typical_doc_ref_pm()
70
+
71
+
72
+ # -----------------------------------------------------------------------------
73
+ # SrcCodeRefPM fixtures
74
+ # -----------------------------------------------------------------------------
75
+
76
+ def minimal_src_code_ref_pm() -> SrcCodeRefPM:
77
+ return SrcCodeRefPM(
78
+ core=_core(art_id="00000000-0000-0000-0000-000000000000"),
79
+ src_code="",
80
+ language=None,
81
+ file_path=None,
82
+ iml_code=None,
83
+ meta=None,
84
+ )
85
+
86
+
87
+ def typical_src_code_ref_pm(*, with_iml: bool = True) -> SrcCodeRefPM:
88
+ return SrcCodeRefPM(
89
+ core=_core(art_id="22222222-2222-2222-2222-222222222222"),
90
+ src_code=(
91
+ "def check_qty(order):\n"
92
+ " return order.qty <= 10000\n"
93
+ ),
94
+ language="python",
95
+ file_path="risk/checks/order_limits.py",
96
+ iml_code=(
97
+ "let check_qty (o: order) : bool = o.qty <= 10000"
98
+ if with_iml
99
+ else None
100
+ ),
101
+ meta="repo=speclogician; commit=abc123; kind=snippet",
102
+ )
103
+
104
+
105
+ def edge_src_code_ref_pm() -> SrcCodeRefPM:
106
+ return SrcCodeRefPM(
107
+ core=_core(art_id="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"),
108
+ src_code=(
109
+ "class RiskEngine:\n"
110
+ " def check(self, order, market_data, limits):\n"
111
+ " # extremely long snippet to stress wrapping\n"
112
+ + (" # line\n" * 60)
113
+ + " return True\n"
114
+ ),
115
+ language="python",
116
+ file_path=("very/long/path/" * 6) + "risk_engine.py",
117
+ iml_code=(
118
+ "type order = { qty : int }\n"
119
+ "let check (o: order) : bool = o.qty > 0\n"
120
+ + ("(* comment *)\n" * 40)
121
+ ),
122
+ meta=(
123
+ "repo=monorepo\n"
124
+ "component=risk_engine\n"
125
+ "note=this meta is multi-line to stress rendering\n"
126
+ ),
127
+ )
128
+
129
+
130
+ def make_src_code_ref_pm(ctx: RenderCtx, variant: str) -> SrcCodeRefPM:
131
+ match variant:
132
+ case "minimal":
133
+ return minimal_src_code_ref_pm()
134
+ case "edge":
135
+ return edge_src_code_ref_pm()
136
+ case _:
137
+ return typical_src_code_ref_pm()
138
+
139
+ def render_doc(pm: DocRefPM, ctx: RenderCtx):
140
+ return render_doc_ref(pm, ctx=ctx)
141
+
142
+
143
+ def render_src(pm: SrcCodeRefPM, ctx: RenderCtx):
144
+ return render_src_code_ref(pm, ctx=ctx)