pretense-py 0.2.0__tar.gz

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 (31) hide show
  1. pretense_py-0.2.0/.gitignore +34 -0
  2. pretense_py-0.2.0/PKG-INFO +44 -0
  3. pretense_py-0.2.0/README.md +33 -0
  4. pretense_py-0.2.0/__init__.py +82 -0
  5. pretense_py-0.2.0/cli.py +35 -0
  6. pretense_py-0.2.0/collections.py +206 -0
  7. pretense_py-0.2.0/compiler.py +47 -0
  8. pretense_py-0.2.0/context.py +9 -0
  9. pretense_py-0.2.0/fake.py +5 -0
  10. pretense_py-0.2.0/parts/autofab.toml +4 -0
  11. pretense_py-0.2.0/parts/pretense/__init__.py +1 -0
  12. pretense_py-0.2.0/parts/pretense/description.md +20 -0
  13. pretense_py-0.2.0/parts/pretense/high/pretense.md +23 -0
  14. pretense_py-0.2.0/parts/pretense/high/pretense_impl.md +23 -0
  15. pretense_py-0.2.0/parts/pretense/lib/pretense.py +1303 -0
  16. pretense_py-0.2.0/parts/pretense/lib/pretense_impl.py +806 -0
  17. pretense_py-0.2.0/parts/pretense/low/pretense.pyi +422 -0
  18. pretense_py-0.2.0/parts/pretense/low/pretense_impl.pyi +86 -0
  19. pretense_py-0.2.0/parts/pretense/planning/pretense.md +72 -0
  20. pretense_py-0.2.0/parts/pretense/planning/pretense_impl.md +59 -0
  21. pretense_py-0.2.0/parts/pretense/pretense/pretense_impl_pretense.py +218 -0
  22. pretense_py-0.2.0/parts/pretense/scenarios/pretense.md +76 -0
  23. pretense_py-0.2.0/parts/pretense/scenarios/pretense_impl.md +58 -0
  24. pretense_py-0.2.0/parts/pretense/tests/pretense_impl_test.py +895 -0
  25. pretense_py-0.2.0/proto.py +9 -0
  26. pretense_py-0.2.0/pyproject.toml +40 -0
  27. pretense_py-0.2.0/sentinels.py +25 -0
  28. pretense_py-0.2.0/support/tests/counterexample_synthesis_test.py +97 -0
  29. pretense_py-0.2.0/support/tests/pretense_core_test.py +244 -0
  30. pretense_py-0.2.0/synthesis.py +44 -0
  31. pretense_py-0.2.0/transition.py +11 -0
@@ -0,0 +1,34 @@
1
+ /bazel-*
2
+ /agent_loop.log*
3
+ /staging/
4
+ /testing/
5
+ __pycache__/
6
+ *.py[cod]
7
+ *$py.class
8
+ .update_with_ai.textproto
9
+ .update_with_ai.proto
10
+ /.mcp.active*
11
+ /.cleanroom/
12
+ /.autofab/
13
+ .pytest_cache/
14
+ .ruff_cache/
15
+ .hypothesis/
16
+ .mcp.worker_sessions.json
17
+ .DS_Store
18
+ /.cleanroom_workspaces.json
19
+ /.cleanroom_blame_buffer.json
20
+ /.autofab_workspaces.json
21
+ /.autofab_blame_buffer.json
22
+ *.bak
23
+ *.bak/
24
+ /logs/
25
+ *.cleanroom.log*
26
+ *.autofab.log*
27
+ /benchmark_*
28
+ scratch/
29
+ .coverage*
30
+ autofab_role_workspaces/
31
+ role_workspaces/
32
+ dist/
33
+ build/
34
+ *.egg-info/
@@ -0,0 +1,44 @@
1
+ Metadata-Version: 2.5
2
+ Name: pretense-py
3
+ Version: 0.2.0
4
+ Summary: Lightweight stateful property testing and behavioral contract framework
5
+ Author-email: Sean McDirmid <mcdirmid@outlook.com>
6
+ License: Apache-2.0
7
+ Requires-Python: >=3.11
8
+ Requires-Dist: hypothesis>=6.100.0
9
+ Requires-Dist: pytest>=8.0.0
10
+ Description-Content-Type: text/markdown
11
+
12
+ # pretense-py
13
+
14
+ A lightweight stateful property-testing and behavioral contract framework.
15
+
16
+ ## Overview
17
+
18
+ Pretense provides model-based state machine property testing, fuzz generation, and specification parity arbiters.
19
+
20
+ ### Key Capabilities
21
+ - **State Machine Specification**: Declare states, transitions, preconditions, and invariants using `@transition`.
22
+ - **Fuzz Testing**: Deterministic state machine exploration powered by Hypothesis.
23
+ - **Contract Verification**: Parity and behavioral conformance testing between specifications and implementations.
24
+ - **Command Line Runner**: Run state machine suites across packages via `pretense <path>`.
25
+
26
+ ## Installation
27
+
28
+ ```bash
29
+ uv pip install pretense-py
30
+ ```
31
+
32
+ ## Quick Start
33
+
34
+ ```python
35
+ import pretense
36
+
37
+ # Import core pretense primitives
38
+ from pretense import transition, TransitionContext, StateMachine
39
+ ```
40
+
41
+ Or run test suites directly:
42
+ ```bash
43
+ pretense parts/
44
+ ```
@@ -0,0 +1,33 @@
1
+ # pretense-py
2
+
3
+ A lightweight stateful property-testing and behavioral contract framework.
4
+
5
+ ## Overview
6
+
7
+ Pretense provides model-based state machine property testing, fuzz generation, and specification parity arbiters.
8
+
9
+ ### Key Capabilities
10
+ - **State Machine Specification**: Declare states, transitions, preconditions, and invariants using `@transition`.
11
+ - **Fuzz Testing**: Deterministic state machine exploration powered by Hypothesis.
12
+ - **Contract Verification**: Parity and behavioral conformance testing between specifications and implementations.
13
+ - **Command Line Runner**: Run state machine suites across packages via `pretense <path>`.
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ uv pip install pretense-py
19
+ ```
20
+
21
+ ## Quick Start
22
+
23
+ ```python
24
+ import pretense
25
+
26
+ # Import core pretense primitives
27
+ from pretense import transition, TransitionContext, StateMachine
28
+ ```
29
+
30
+ Or run test suites directly:
31
+ ```bash
32
+ pretense parts/
33
+ ```
@@ -0,0 +1,82 @@
1
+ """Pretense: Unified State-Machine Verification & Fake Synthesis Engine."""
2
+
3
+ import os
4
+ import sys
5
+ from pathlib import Path
6
+
7
+ _curr = Path(__file__).resolve().parent
8
+ _REPO_ROOT = _curr
9
+ while _curr and _curr != _curr.parent:
10
+ if (_curr / "pyproject.toml").is_file():
11
+ _REPO_ROOT = _curr
12
+ break
13
+ _curr = _curr.parent
14
+
15
+ for _p in (_REPO_ROOT, _REPO_ROOT / "autofab_python", _REPO_ROOT / "autofab", _REPO_ROOT / "pretense"):
16
+ _str_p = str(_p)
17
+ if _p.is_dir() and _str_p not in sys.path:
18
+ sys.path.insert(0, _str_p)
19
+
20
+ from pretense.parts.pretense.lib.pretense import (
21
+ AmbiguousTransitionError,
22
+ Domain,
23
+ EnsuresCheck,
24
+ FakeAdapter,
25
+ NoMatchingTransitionError,
26
+ NotBound,
27
+ NotBoundType,
28
+ Outcome,
29
+ PretenseEngine,
30
+ PretenseError,
31
+ PretenseRunResult,
32
+ PretenseRunnerConfig,
33
+ PretenseSpecificationError,
34
+ Raised,
35
+ RequiresCheck,
36
+ StateMachine,
37
+ StateMachineProto,
38
+ TraceStep,
39
+ Transition,
40
+ TransitionContext,
41
+ Value,
42
+ transition,
43
+ )
44
+ from pretense.collections import PretenseDict, PretenseSet, choose_weighted, make_tup
45
+ from pretense.context import get_current_draw, with_draw
46
+ from pretense.compiler import compile_hypothesis_test_case
47
+ from pretense.synthesis import synthesize_unit_test
48
+
49
+ __version__ = "0.2.0"
50
+
51
+ __all__ = [
52
+ "AmbiguousTransitionError",
53
+ "Domain",
54
+ "EnsuresCheck",
55
+ "FakeAdapter",
56
+ "NoMatchingTransitionError",
57
+ "NotBound",
58
+ "NotBoundType",
59
+ "Outcome",
60
+ "PretenseDict",
61
+ "PretenseEngine",
62
+ "PretenseError",
63
+ "PretenseRunResult",
64
+ "PretenseRunnerConfig",
65
+ "PretenseSet",
66
+ "PretenseSpecificationError",
67
+ "Raised",
68
+ "RequiresCheck",
69
+ "StateMachine",
70
+ "StateMachineProto",
71
+ "TraceStep",
72
+ "Transition",
73
+ "TransitionContext",
74
+ "Value",
75
+ "choose_weighted",
76
+ "compile_hypothesis_test_case",
77
+ "get_current_draw",
78
+ "make_tup",
79
+ "synthesize_unit_test",
80
+ "transition",
81
+ "with_draw",
82
+ ]
@@ -0,0 +1,35 @@
1
+ """CLI runner for Pretense state machines (uv run pretense)."""
2
+
3
+ import os
4
+ import sys
5
+ from pathlib import Path
6
+
7
+ _curr = Path(__file__).resolve().parent
8
+ _REPO_ROOT = _curr
9
+ while _curr and _curr != _curr.parent:
10
+ if (_curr / "pyproject.toml").is_file():
11
+ _REPO_ROOT = _curr
12
+ break
13
+ _curr = _curr.parent
14
+
15
+ for _p in (_REPO_ROOT, _REPO_ROOT / "autofab_python", _REPO_ROOT / "autofab", _REPO_ROOT / "pretense"):
16
+ _str_p = str(_p)
17
+ if _p.is_dir() and _str_p not in sys.path:
18
+ sys.path.insert(0, _str_p)
19
+
20
+ # Also discover support/lib if run within a role workspace
21
+ _curr = Path.cwd().resolve()
22
+ while _curr and _curr != _curr.parent:
23
+ if (_curr / "support" / "lib").is_dir():
24
+ _sup = str(_curr / "support" / "lib")
25
+ if _sup not in sys.path:
26
+ sys.path.insert(0, _sup)
27
+ break
28
+ _curr = _curr.parent
29
+
30
+ from pretense.parts.pretense.lib.pretense_impl import main, run_pretense_cli
31
+
32
+ if __name__ == "__main__":
33
+ sys.exit(main())
34
+
35
+ __all__ = ["main", "run_pretense_cli"]
@@ -0,0 +1,206 @@
1
+ """Bidirectional collection helpers and recognizers/generators for Pretense."""
2
+
3
+ import random
4
+ from collections import deque
5
+ from typing import Any, Callable, Dict, List, Optional, Set, Tuple, TypeVar, Union
6
+
7
+ from pretense.context import get_current_draw
8
+ from pretense.sentinels import NotBound, NotBoundType
9
+
10
+ T = TypeVar("T")
11
+ K = TypeVar("K")
12
+ V = TypeVar("V")
13
+
14
+
15
+ def make_tup(*choosers: Callable[..., Any]) -> Callable[..., Optional[Tuple[Any, ...]]]:
16
+ """Compose multiple argument recognizers/generators into a single joint tuple chooser.
17
+
18
+ If any individual chooser returns None, the combined chooser returns None (rejection).
19
+ """
20
+ def combined(state: Any, this: Any, *args: Any) -> Optional[Tuple[Any, ...]]:
21
+ res: List[Any] = []
22
+ for chooser, arg in zip(choosers, args):
23
+ val = chooser(state, this, arg)
24
+ if val is None:
25
+ return None
26
+ res.append(val)
27
+ return tuple(res)
28
+ return combined
29
+
30
+
31
+ def choose_weighted(*weighted_options: Tuple[float, Callable[[Any], Any]]) -> Any:
32
+ """Statistical selection across weighted alternatives.
33
+
34
+ Under Hypothesis, uses st.frequency() to allow full byte-stream shrinking.
35
+ Outside Hypothesis, falls back to random.choices.
36
+ """
37
+ draw = get_current_draw()
38
+ if draw is not None:
39
+ try:
40
+ import hypothesis.strategies as st
41
+ st_mod: Any = st
42
+ freq_strategies = []
43
+ for weight, builder in weighted_options:
44
+ int_weight = max(1, int(round(weight * 100)))
45
+ try:
46
+ strat = builder(st_mod)
47
+ if isinstance(strat, st.SearchStrategy):
48
+ freq_strategies.append((int_weight, strat))
49
+ else:
50
+ freq_strategies.append((int_weight, st.just(strat)))
51
+ except Exception:
52
+ freq_strategies.append((int_weight, st.just(builder(random))))
53
+ return draw(st_mod.frequency(freq_strategies))
54
+ except ImportError:
55
+ pass
56
+
57
+ # Deterministic fallback / PRNG
58
+ weights = [w for w, _ in weighted_options]
59
+ builders = [b for _, b in weighted_options]
60
+ chosen_builder = random.choices(builders, weights=weights, k=1)[0]
61
+ return chosen_builder(random)
62
+
63
+
64
+ class PretenseSet(Set[T]):
65
+ """State collection tracking rolling tombstones and providing bidirectional helpers."""
66
+
67
+ def __init__(self, elements: Any = ()) -> None:
68
+ super().__init__(elements)
69
+ self._tombstones: deque[T] = deque(maxlen=50)
70
+
71
+ def remove(self, element: T) -> None:
72
+ super().remove(element)
73
+ self._tombstones.append(element)
74
+
75
+ def discard(self, element: object) -> None:
76
+ if element in self:
77
+ super().discard(element)
78
+ self._tombstones.append(element) # type: ignore
79
+
80
+ def get_in(self, val: Union[T, NotBoundType]) -> Optional[T]:
81
+ """Recognize membership or generate an existing element from the set."""
82
+ if isinstance(val, NotBoundType):
83
+ if not self:
84
+ return None
85
+ draw = get_current_draw()
86
+ if draw is not None:
87
+ try:
88
+ import hypothesis.strategies as st
89
+ return draw(st.sampled_from(list(self)))
90
+ except ImportError:
91
+ pass
92
+ return next(iter(self))
93
+ return val if val in self else None
94
+
95
+ def get_not_in(self, val: Union[T, NotBoundType], prefix: str = "item_") -> Optional[T]:
96
+ """Recognize non-membership or generate an absent element across 4 tiers."""
97
+ if isinstance(val, NotBoundType):
98
+ draw = get_current_draw()
99
+ if draw is not None:
100
+ try:
101
+ import hypothesis.strategies as st
102
+ # Tier 1: The Graveyard (Tombstone History) - 40% probability if available
103
+ if self._tombstones and draw(st.booleans()) and draw(st.booleans()):
104
+ candidate = draw(st.sampled_from(list(self._tombstones)))
105
+ if candidate not in self:
106
+ return candidate
107
+
108
+ # Tier 2: Near-Miss Mutations - 30% probability if string elements exist
109
+ if self and all(isinstance(x, str) for x in self) and draw(st.booleans()):
110
+ base = str(draw(st.sampled_from(list(self))))
111
+ mutation_type = draw(st.integers(0, 3))
112
+ if mutation_type == 0:
113
+ candidate_str = base.upper() if base.islower() else base.lower()
114
+ elif mutation_type == 1:
115
+ candidate_str = base + " "
116
+ elif mutation_type == 2:
117
+ candidate_str = "_" + base
118
+ else:
119
+ candidate_str = base + "_alt"
120
+ if candidate_str not in self:
121
+ return candidate_str # type: ignore
122
+
123
+ # Tier 3: Open Universe Fuzzing
124
+ if not self or all(isinstance(x, str) for x in self):
125
+ fresh_str = draw(st.text(min_size=1, max_size=10).filter(lambda s: s not in self))
126
+ return fresh_str # type: ignore
127
+ except ImportError:
128
+ pass
129
+
130
+ # Tier 4: Deterministic Sequential Fallback
131
+ idx = len(self)
132
+ candidate = f"{prefix}{idx}"
133
+ while candidate in self:
134
+ idx += 1
135
+ candidate = f"{prefix}{idx}"
136
+ return candidate # type: ignore
137
+
138
+ return val if val not in self else None
139
+
140
+ def get_subset(self, val: Union[Set[T], NotBoundType]) -> Optional[Set[T]]:
141
+ """Recognize a subset or generate a valid subset from this set."""
142
+ if isinstance(val, NotBoundType):
143
+ draw = get_current_draw()
144
+ if draw is not None:
145
+ try:
146
+ import hypothesis.strategies as st
147
+ return set(draw(st.lists(st.sampled_from(list(self)), unique=True))) if self else set()
148
+ except ImportError:
149
+ pass
150
+ return set()
151
+ return val if isinstance(val, (set, frozenset)) and val.issubset(self) else None
152
+
153
+
154
+ class PretenseDict(Dict[K, V]):
155
+ """Dictionary collection tracking key tombstones for bidirectional key recognition/generation."""
156
+
157
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
158
+ super().__init__(*args, **kwargs)
159
+ self._tombstones: deque[K] = deque(maxlen=50)
160
+
161
+ def __delitem__(self, key: K) -> None:
162
+ super().__delitem__(key)
163
+ self._tombstones.append(key)
164
+
165
+ def pop(self, key: K, *args: Any) -> V:
166
+ res = super().pop(key, *args)
167
+ self._tombstones.append(key)
168
+ return res
169
+
170
+ def get_key_in(self, key: Union[K, NotBoundType]) -> Optional[K]:
171
+ """Recognize key existence or generate an existing key."""
172
+ if isinstance(key, NotBoundType):
173
+ if not self:
174
+ return None
175
+ draw = get_current_draw()
176
+ if draw is not None:
177
+ try:
178
+ import hypothesis.strategies as st
179
+ return draw(st.sampled_from(list(self.keys())))
180
+ except ImportError:
181
+ pass
182
+ return next(iter(self.keys()))
183
+ return key if key in self else None
184
+
185
+ def get_key_not_in(self, key: Union[K, NotBoundType], prefix: str = "key_") -> Optional[K]:
186
+ """Recognize key absence or generate an absent key."""
187
+ if isinstance(key, NotBoundType):
188
+ draw = get_current_draw()
189
+ if draw is not None:
190
+ try:
191
+ import hypothesis.strategies as st
192
+ if self._tombstones and draw(st.booleans()):
193
+ cand = draw(st.sampled_from(list(self._tombstones)))
194
+ if cand not in self:
195
+ return cand
196
+ if not self or all(isinstance(k, str) for k in self.keys()):
197
+ return draw(st.text(min_size=1, max_size=10).filter(lambda s: s not in self)) # type: ignore
198
+ except ImportError:
199
+ pass
200
+ idx = len(self)
201
+ cand_str = f"{prefix}{idx}"
202
+ while cand_str in self:
203
+ idx += 1
204
+ cand_str = f"{prefix}{idx}"
205
+ return cand_str # type: ignore
206
+ return key if key not in self else None
@@ -0,0 +1,47 @@
1
+ """Hypothesis stateful test case generation for Pretense prototypes."""
2
+
3
+ from typing import Any, List, Optional
4
+ import pretense.parts.pretense.lib.pretense_impl as _impl
5
+
6
+ _ACTIVE_STEP: Any = None
7
+ _ACTIVE_TRACE: List[Any] = []
8
+
9
+
10
+ def get_active_step() -> Any:
11
+ global _ACTIVE_STEP
12
+ if _ACTIVE_STEP is not None:
13
+ return _ACTIVE_STEP
14
+ return _impl.get_active_step()
15
+
16
+
17
+ def get_active_trace() -> List[Any]:
18
+ global _ACTIVE_TRACE
19
+ if _ACTIVE_TRACE:
20
+ return list(_ACTIVE_TRACE)
21
+ return _impl.get_active_trace()
22
+
23
+
24
+ def format_active_step_diagnostic(*args: Any, **kwargs: Any) -> Optional[str]:
25
+ global _ACTIVE_STEP, _ACTIVE_TRACE
26
+ if _ACTIVE_STEP is not None:
27
+ lines = [
28
+ f"Active Pretense Transition: '{_ACTIVE_STEP.transition_name}' (method: {_ACTIVE_STEP.target_name or '<seeding>'})",
29
+ f"Arguments: {_ACTIVE_STEP.args!r}",
30
+ ]
31
+ if len(_ACTIVE_TRACE) > 1:
32
+ lines.append(f"Preceding Steps ({len(_ACTIVE_TRACE) - 1}):")
33
+ for i, step in enumerate(_ACTIVE_TRACE[:-1], 1):
34
+ args_str = ", ".join(repr(a) for a in step.args)
35
+ lines.append(f" {i}. {step.transition_name}({args_str})")
36
+ return "\n".join(lines)
37
+ return _impl.format_active_step_diagnostic(*args, **kwargs)
38
+
39
+
40
+ compile_hypothesis_test_case = _impl.compile_hypothesis_test_case
41
+
42
+ __all__ = [
43
+ "compile_hypothesis_test_case",
44
+ "format_active_step_diagnostic",
45
+ "get_active_step",
46
+ "get_active_trace",
47
+ ]
@@ -0,0 +1,9 @@
1
+ """Dynamic scope context for Hypothesis draw integration in Pretense."""
2
+
3
+ from pretense.parts.pretense.lib.pretense import (
4
+ DrawContext,
5
+ get_current_draw,
6
+ with_draw,
7
+ )
8
+
9
+ __all__ = ["DrawContext", "get_current_draw", "with_draw"]
@@ -0,0 +1,5 @@
1
+ """In-memory Fake adapter synthesis."""
2
+
3
+ from pretense.parts.pretense.lib.pretense import FakeAdapter
4
+
5
+ __all__ = ["FakeAdapter"]
@@ -0,0 +1,4 @@
1
+ # autofab.toml
2
+ # Methodology binding for pretense/parts
3
+
4
+ methodology = "//autofab_python"
@@ -0,0 +1 @@
1
+ # Pretense part package marker.
@@ -0,0 +1,20 @@
1
+ # Pretense Part (`update_python_with_ai/parts/pretense`)
2
+
3
+ ## Purpose
4
+
5
+ The **pretense** part provides Cleanroom's unified state-machine-driven testing, verification, and fake synthesis engine.
6
+
7
+ Software verification driven purely by example-based testing or AST statement coverage suffers from severe blind spots in LLM-generated code: high statement coverage often greenlights state desynchronization, omission bugs, and boundary condition regressions. Pretense solves this by expressing behavioral specifications as executable state transition models. Powered by property-based conjecture search and minimal counterexample shrinking, Pretense verifies state-transition invariants, synthesizes zero-maintenance interface fakes, enforces execution watchdogs against infinite loops, and drives differential testing between specifications and implementations.
8
+
9
+ ## Key Components & Specifications
10
+
11
+ - [`pretense.md`](file:///Users/seanmcdirmid/projects/cleanroom/update_python_with_ai/parts/pretense/high/pretense.md): Defines the core state machine abstractions, sentinels, outcome descriptors, transition models, stateful collection structures, hypothesis draw contexts, fake adapter contracts, and the `PretenseEngine` interface.
12
+ - [`pretense_impl.md`](file:///Users/seanmcdirmid/projects/cleanroom/update_python_with_ai/parts/pretense/high/pretense_impl.md): Realizes the dynamic Hypothesis state machine compiler, active step diagnostic tracking, minimal counterexample unit test synthesis, watchdog timeout enforcement, test discovery, and the `pretense` command-line test runner.
13
+
14
+ ## How It Is Used by Other Parts
15
+
16
+ Pretense serves as Cleanroom's primary state-machine testing and contract verification engine:
17
+ - **`cleanroom_roles.toml`**: Configures the `pretense`, `pretense_qa`, and `pretense_coverage` roles to invoke `uv run pretense ...` across all parts.
18
+ - **`update_python_with_ai/support`**: `pretense_lint.py` enforces structural rules on `*_pretense.py` files and validates that state machines conform to Pretense contracts.
19
+ - **`benchmark`**: Provisions `.env` watchdogs (`PYTHONFAULTHANDLER=1`, `PRETENSE_TIMEOUT=45.0`) and provides baseline developer models with Pretense verification tools.
20
+ - **All constituent parts**: Every Cleanroom part maintains executable state machine specifications under `parts/<name>/pretense/` targeting the part's implementation modules.
@@ -0,0 +1,23 @@
1
+ # pretense interface component
2
+
3
+ ## Purpose
4
+
5
+ The pretense interface component defines the declarative state machine abstractions, sentinels, collection models, transition specifications, fake adapters, and verification engine contracts for stateful software testing in Cleanroom.
6
+
7
+ Example-based testing and AST statement coverage frequently miss critical state desynchronizations, boundary regressions, and omitted invariant logic in neural-generated code. By defining stateful systems as executable state transition models rather than static unit test sequences, this component enables automated property-based exploration, invariant checking across arbitrary operation orderings, and automatic fake synthesis. Centralizing these state abstractions prevents fragmentation across test harnesses and ensures that specification contracts remain mathematically verifiable.
8
+
9
+ **Out of scope:** Subprocess invocation, filesystem scanning, and shell argument parsing; these are handled by other components.
10
+
11
+ ## Types and Behavior
12
+
13
+ A system's *pretense engine* coordinates state machine compilation, test suite execution, and fake generation.
14
+
15
+ A *pretense sentinel* distinguishes unprovided inputs and specific runtime states from standard program values. The sentinel *not bound* indicates that a parameter was omitted by a caller. An *execution outcome* encapsulates the result of evaluating an operation against an implementation under test. A *value outcome* wraps a successful return value. A *raised outcome* wraps an expected or intercepted exception instance. A *specification error* indicates that a state machine contract, transition invariant, or antecedent predicate was violated.
16
+
17
+ A *draw context* provides a dynamically bound generator for sampling values during property-based test exploration. A *pretense collection* provides an observable state container that tracks mutations and verifies invariants. A *pretense dictionary* provides an observable key-value mapping with existence assertions and weighted key selection. A *pretense set* provides an observable unique item container with element sampling and existence assertions.
18
+
19
+ A *state transition* defines a single atomic operation step within a state machine. Each state transition specifies a *requires* condition that must hold before the operation executes, an *argument binder* that generates or recognizes operation arguments, an expected return outcome or contracted exception, an *ensures* postcondition verified against the concrete singleton under test during real test execution, and an *update* condition that applies reference model state mutations. An *argument domain* unifies generative sampling with analytical validation for an operation parameter. A domain produces randomized values conforming to its specification during property fuzzing and validates whether arbitrary candidate values belong to its domain during adapter dispatch. Argument domains support scalar categoricals, discrete ranges, lexical patterns, structural data types, dependent parameter domains whose boundaries derive dynamically from preceding arguments, and constructive perturbations that derive candidate values from anchor values via targeted near-boundary mutations. An argument binder binds transition arguments exclusively from explicit domains, native collections, ranges, patterns, data types, dependent domain functions, and keyword domain mappings. An unresolved domain placeholder enforces explicit domain definition by failing at runtime if left unspecialized. An argument binder generates operation arguments from direct values, callables, domains, or property-based search strategies treated directly as values, automatically drawing randomized instances from active draw contexts during property fuzzing while drawing default examples when evaluated outside fuzzing contexts. A *transition context* provides methods for specifying requires preconditions, argument binders, expected returns, contracted exceptions, ensures postconditions, and model updates for a single transition method. A transition context provides a *check helper* for evaluating requirements without exception overhead and evaluating postconditions against immediate and collaborating singletons under test during real test runs while omitting ensures verification during fake adapter dispatch. A transition context strictly enforces mutual exclusivity between expected returns and contracted exceptions: declaring both on the same transition context raises an invalid transition definition error. When synthesizing fake exceptions from contracted exception types, the transition context safely instantiates exception classes that declare mandatory positional parameters. A *transition decorator* registers a transition method against a target singleton class operation.
20
+
21
+ A *state machine* declares the complete behavioral contract of an interface or implementation through a collection of state transitions and system invariants. A state machine stores singletons under test as direct references in its state representation to drive implementation logic under test, or provides synthesized in-memory fake adapters backed by the shared reference model. A *fake adapter* acts as a dynamic test double conforming to an interface protocol, delegating method invocations directly to matching state transitions and verifying preconditions. A *trace step* records the operation name, arguments, and outcome of an executed transition within a state machine run.
22
+
23
+ A *runner configuration* specifies test execution parameters including target paths, fuzzing iterations, statement coverage thresholds, execution timeout durations, and active step diagnostic reporting. A *run result* reports execution metrics, including passed test counts, failure counts, statement coverage percentages, and synthesized counterexamples.
@@ -0,0 +1,23 @@
1
+ # pretense_impl implementation component
2
+
3
+ implements: pretense
4
+
5
+ ## Purpose
6
+
7
+ The pretense_impl implementation component realizes the state machine compiler, diagnostic tracer, fake adapter proxy, execution watchdog, and test runner for the pretense engine.
8
+
9
+ Executing stateful test suites against neural implementations requires robust test case synthesis, minimal counterexample shrinking, and failsafe execution bounds. Without automatic shrinking and active step tracing, developers and models struggle to debug complex multi-step failures. Without execution watchdogs, unbounded loops or blocking operations hang test runners indefinitely. This component bridges abstract state models to property-based test engines, synthesizes reproducible unit test files from minimized counterexamples, and guarantees execution termination through signal-based watchdogs.
10
+
11
+ **Out of scope:** Static type checking, code generation templates, and language server protocols; these are handled by other components.
12
+
13
+ ## Types and Behavior
14
+
15
+ The *pretense engine realization* implements the pretense engine service on the system tier.
16
+
17
+ A *state machine compiler* translates declarative state machine specifications into executable property-based test suites. The compiler inspects each declared state transition on a state machine, binding requires guards to test generation preconditions, and evaluating ensures postconditions against the concrete system under test after invocation and outcome recognition, while applying model update mutations to backing state. When a postcondition or invariant fails during property search, the compiler shrinks the failure sequence to a minimal sequence of trace steps and formats an *active step diagnostic* detailing the active transition, input arguments, and current state snapshot. When the system under test produces an outcome rejected by the transition's return recognizer, the active step diagnostic details whether the transition was configured expecting an exception or a return value.
18
+
19
+ A *unit test synthesizer* generates a standalone, reproducible Python test function from a shrunken counterexample sequence. The synthesized test instantiates the system under test, applies each step in sequence with literal arguments, and verifies that the failure reproduces deterministically.
20
+
21
+ A *watchdog monitor* oversees test execution using a dual-layer timeout mechanism. A software timer emits a warning before expiration, dumping active step diagnostics to standard error. Concurrently, a system-level fault handler registers an abrupt termination alarm that interrupts blocking system calls or infinite loops, exiting with a non-zero status code to prevent test runner hangs.
22
+
23
+ A *test runner coordinator* scans target directories for state machine test files, rejecting loading errors or missing test targets with diagnostics and a non-zero exit status code rather than reporting success. The coordinator executes test cases within configured execution phases, verifies statement coverage thresholds against the corresponding implementation modules under test (excluding abstract interface stubs), suppresses property fuzzing during coverage evaluation to bound execution to deterministic test suites while reserving fuzzing for QA verification, formats and reports all failure and error details across all executed test methods in failing test targets to prevent defect masking, formats auditor guidance reminders upon test failures and coverage deficits directing the agent to formulate blame feedback strictly in terms of how the blamed file is not compliant with the common source of truth specification, permitting line numbers only within the blamed file while strictly forbidding exposing details of other files, and reports aggregated test outcomes through a run result payload, exiting with a non-zero exit status code whenever any test fails, any test target fails to load, zero test targets are executed, or coverage thresholds are not met.