stipulate 0.1.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 (82) hide show
  1. stipulate-0.1.0/MANIFEST.in +4 -0
  2. stipulate-0.1.0/PKG-INFO +153 -0
  3. stipulate-0.1.0/README.md +134 -0
  4. stipulate-0.1.0/docs/ARCHITECTURE.md +71 -0
  5. stipulate-0.1.0/docs/COMPATIBILITY.md +45 -0
  6. stipulate-0.1.0/docs/COMPETITION.md +50 -0
  7. stipulate-0.1.0/docs/CONTRACT_ENGINE.md +100 -0
  8. stipulate-0.1.0/docs/DEPENDENCIES.md +35 -0
  9. stipulate-0.1.0/docs/DESIGN_DECISIONS.md +101 -0
  10. stipulate-0.1.0/docs/ERROR_MODEL.md +92 -0
  11. stipulate-0.1.0/docs/EXPERIENCE_DESIGN.md +129 -0
  12. stipulate-0.1.0/docs/IMPLEMENTATION_PLAN.md +115 -0
  13. stipulate-0.1.0/docs/IMPLEMENTED_0_1.md +37 -0
  14. stipulate-0.1.0/docs/INTERFACE_MODEL.md +131 -0
  15. stipulate-0.1.0/docs/OPEN_TECHNICAL_PROBLEMS.md +729 -0
  16. stipulate-0.1.0/docs/PERFORMANCE.md +63 -0
  17. stipulate-0.1.0/docs/PHASE_0_1_IMPLEMENTATION_CONTRACT.md +275 -0
  18. stipulate-0.1.0/docs/PHASE_0_1_IMPLEMENTATION_REPORT.md +67 -0
  19. stipulate-0.1.0/docs/PRODUCT_VISION.md +74 -0
  20. stipulate-0.1.0/docs/PYDANTIC_INTEGRATION.md +54 -0
  21. stipulate-0.1.0/docs/QUICKSTART.md +72 -0
  22. stipulate-0.1.0/docs/RELEASING.md +63 -0
  23. stipulate-0.1.0/docs/ROADMAP.md +263 -0
  24. stipulate-0.1.0/docs/STATIC_TYPING.md +84 -0
  25. stipulate-0.1.0/docs/TESTING_STRATEGY.md +60 -0
  26. stipulate-0.1.0/docs/TYPE_SYSTEM.md +69 -0
  27. stipulate-0.1.0/docs/VALIDATION_ENGINE.md +70 -0
  28. stipulate-0.1.0/docs/examples/report_scenarios.json +233 -0
  29. stipulate-0.1.0/docs/history/OPEN_TECHNICAL_PROBLEMS_ORIGINAL.md +1083 -0
  30. stipulate-0.1.0/docs/releases/0.1.0/FINAL_001_ESCALATION.md +125 -0
  31. stipulate-0.1.0/docs/releases/0.1.0/SOL_REVIEW_01.md +254 -0
  32. stipulate-0.1.0/docs/releases/0.1.0/SOL_REVIEW_02.md +213 -0
  33. stipulate-0.1.0/docs/releases/0.1.0/SOL_REVIEW_03.md +102 -0
  34. stipulate-0.1.0/docs/releases/0.1.0/benchmark.json +66 -0
  35. stipulate-0.1.0/pyproject.toml +38 -0
  36. stipulate-0.1.0/setup.cfg +4 -0
  37. stipulate-0.1.0/src/stipulate/__init__.py +16 -0
  38. stipulate-0.1.0/src/stipulate/_annotations.py +154 -0
  39. stipulate-0.1.0/src/stipulate/_cache.py +73 -0
  40. stipulate-0.1.0/src/stipulate/_compatibility.py +538 -0
  41. stipulate-0.1.0/src/stipulate/_compile.py +311 -0
  42. stipulate-0.1.0/src/stipulate/_contract.py +83 -0
  43. stipulate-0.1.0/src/stipulate/_errors.py +76 -0
  44. stipulate-0.1.0/src/stipulate/_evidence.py +112 -0
  45. stipulate-0.1.0/src/stipulate/_relations.py +301 -0
  46. stipulate-0.1.0/src/stipulate/_render.py +64 -0
  47. stipulate-0.1.0/src/stipulate/_signatures.py +259 -0
  48. stipulate-0.1.0/src/stipulate/py.typed +0 -0
  49. stipulate-0.1.0/src/stipulate.egg-info/PKG-INFO +153 -0
  50. stipulate-0.1.0/src/stipulate.egg-info/SOURCES.txt +80 -0
  51. stipulate-0.1.0/src/stipulate.egg-info/dependency_links.txt +1 -0
  52. stipulate-0.1.0/src/stipulate.egg-info/requires.txt +10 -0
  53. stipulate-0.1.0/src/stipulate.egg-info/top_level.txt +1 -0
  54. stipulate-0.1.0/tests/test_annotation_layers.py +246 -0
  55. stipulate-0.1.0/tests/test_boundaries.py +269 -0
  56. stipulate-0.1.0/tests/test_cache_and_policy.py +79 -0
  57. stipulate-0.1.0/tests/test_call_partition.py +101 -0
  58. stipulate-0.1.0/tests/test_contract.py +95 -0
  59. stipulate-0.1.0/tests/test_lifecycle_and_evidence.py +50 -0
  60. stipulate-0.1.0/tests/test_member_edges.py +103 -0
  61. stipulate-0.1.0/tests/test_members_and_relations.py +96 -0
  62. stipulate-0.1.0/tests/test_packaging_api.py +41 -0
  63. stipulate-0.1.0/tests/test_release_evidence.py +180 -0
  64. stipulate-0.1.0/tests/test_reliability.py +241 -0
  65. stipulate-0.1.0/tests/test_reports_and_examples.py +142 -0
  66. stipulate-0.1.0/tests/test_sol_review_02_blockers.py +131 -0
  67. stipulate-0.1.0/tests/test_sol_review_04_blockers.py +40 -0
  68. stipulate-0.1.0/tests/test_sol_review_blockers.py +206 -0
  69. stipulate-0.1.0/tests/test_type_table.py +173 -0
  70. stipulate-0.1.0/tests/test_wrapped_owner_identity.py +148 -0
  71. stipulate-0.1.0/tests/tests_support.py +16 -0
  72. stipulate-0.1.0/tests/typing_fixtures/negative.py +15 -0
  73. stipulate-0.1.0/tests/typing_fixtures/public_api.py +15 -0
  74. stipulate-0.1.0/tools/__init__.py +1 -0
  75. stipulate-0.1.0/tools/assemble_evidence.py +118 -0
  76. stipulate-0.1.0/tools/benchmark.py +161 -0
  77. stipulate-0.1.0/tools/check_docs.py +28 -0
  78. stipulate-0.1.0/tools/feature_inventory.json +4 -0
  79. stipulate-0.1.0/tools/installed_check.py +182 -0
  80. stipulate-0.1.0/tools/quality.py +107 -0
  81. stipulate-0.1.0/tools/release_evidence.py +261 -0
  82. stipulate-0.1.0/uv.lock +937 -0
@@ -0,0 +1,4 @@
1
+ include uv.lock
2
+ recursive-include docs *.md *.json
3
+ recursive-include tools *.py *.json
4
+ recursive-include tests *.py
@@ -0,0 +1,153 @@
1
+ Metadata-Version: 2.4
2
+ Name: stipulate
3
+ Version: 0.1.0
4
+ Summary: Contracts for Python interfaces
5
+ Author: Stipulate contributors
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: Programming Language :: Python :: 3 :: Only
8
+ Requires-Python: >=3.11
9
+ Description-Content-Type: text/markdown
10
+ Requires-Dist: typing_extensions>=4.15.0
11
+ Provides-Extra: dev
12
+ Requires-Dist: pytest==8.4.2; extra == "dev"
13
+ Requires-Dist: hypothesis==6.140.3; extra == "dev"
14
+ Requires-Dist: ruff==0.13.2; extra == "dev"
15
+ Requires-Dist: pyright==1.1.411; extra == "dev"
16
+ Requires-Dist: mypy==1.19.1; extra == "dev"
17
+ Requires-Dist: build==1.3.0; extra == "dev"
18
+ Requires-Dist: twine==6.2.0; extra == "dev"
19
+
20
+ # Stipulate
21
+
22
+ **Contracts for Python interfaces.**
23
+
24
+ **Define. Validate. Evolve.**
25
+
26
+ Stipulate checks dynamically supplied implementations against Python structural interfaces, explains mismatches, and preserves what available metadata cannot establish.
27
+
28
+ ## Status
29
+
30
+ This repository contains the Stipulate 0.1 implementation, design specification, and design probes. The core API checks declared Protocol compatibility without executing candidate operations. Earlier prototypes are historical inputs, not release evidence.
31
+
32
+ Install with `python -m pip install .` (CPython 3.11–3.14). See the [implemented feature guide](docs/IMPLEMENTED_0_1.md) for the supported boundary. Independent Sol review is still required before release approval.
33
+
34
+ ## Define and validate
35
+
36
+ ```python
37
+ from typing import Protocol
38
+ from stipulate import Contract
39
+
40
+
41
+ class Storage(Protocol):
42
+ def read(self, key: str) -> bytes | None: ...
43
+
44
+ async def write(self, key: str, value: bytes) -> None: ...
45
+
46
+
47
+ class MemoryStorage:
48
+ def __init__(self) -> None:
49
+ self._items: dict[str, bytes] = {}
50
+
51
+ def read(self, key: str) -> bytes | None:
52
+ return self._items.get(key)
53
+
54
+ async def write(self, key: str, value: bytes) -> None:
55
+ self._items[key] = value
56
+
57
+
58
+ candidate = MemoryStorage()
59
+ storage_contract = Contract(Storage)
60
+ storage = storage_contract.validate(candidate)
61
+ ```
62
+
63
+ Implementations are ordinary Python classes. They need no inheritance, registration, or decorators. Validation returns the original object, typed as `Storage`, after checking its available declarations against the contract. The constructor uses TypeForm for inference; the [typing guide](docs/STATIC_TYPING.md) records supported checker settings, including the current mypy feature flag.
64
+
65
+ Strict validation is the default: incompatible or insufficient evidence raises `ContractError`. To allow missing implementation type annotations deliberately, use `strict=False`; known mismatches and unsupported or uninspectable candidate capabilities still fail. Invalid requirements fail contract construction.
66
+
67
+ ## Understand a result
68
+
69
+ ```python
70
+ result = storage_contract.check(candidate)
71
+ print(result)
72
+
73
+ if result:
74
+ print("Storage declarations are compatible")
75
+
76
+ result.status
77
+ result.complete
78
+ result.errors()
79
+ result.unknowns()
80
+ result.evidence
81
+ ```
82
+
83
+ `check()` reports candidate mismatches without raising `ContractError`. Truthiness means compatibility was established for every requirement; unknown evidence is false. Invalid contract definitions raise `ContractDefinitionError`. The result includes locations, reasons, and suggested fixes.
84
+
85
+ Stipulate compares signatures, annotation assignability, binding, and supported member capabilities. It assumes implementations honor their declarations; it does not execute methods to verify their behavior, validate future return values, or prevent later mutation. Annotation resolution may execute Python annotation expressions in the default trusted mode.
86
+
87
+ ## Friendly errors
88
+
89
+ ```text
90
+ Incompatible with Storage
91
+ 2 incompatible findings; 0 unknown findings (0 blocked obligations).
92
+
93
+ read.key
94
+ The implementation input is too narrow for required caller values
95
+ Required: str
96
+ Provided: bytes
97
+ [parameter_type; incompatible]
98
+
99
+ write.kind
100
+ The coroutine execution kind differs
101
+ [async_mismatch; incompatible]
102
+ ```
103
+
104
+ ## Interface shorthand — experimental design target
105
+
106
+ ```python
107
+ from stipulate import Interface
108
+
109
+ class Storage(Interface):
110
+ def read(self, key: str) -> bytes | None: ...
111
+
112
+ storage = Storage.validate(candidate)
113
+ ```
114
+
115
+ This shorthand is not a 0.1 promise. It must preserve structural typing, precise class-side methods, inheritance, and clean protocol members in installed-package Pyright/mypy tests before promotion. The supported 0.1 plan uses `Protocol` plus `Contract`, with the same method-based operations and compatibility engine.
116
+
117
+ ## Evolution and tooling — later releases
118
+
119
+ ```python
120
+ report = Contract(StorageV1).compare(Contract(StorageV2))
121
+ schema = storage_contract.schema()
122
+ fingerprint = storage_contract.fingerprint()
123
+ ```
124
+
125
+ Comparison will report implementer and consumer compatibility separately. Unknown results cannot certify a non-breaking change. Schemas and fingerprints will be versioned before publication. None of these three operations is in the 0.1 public surface.
126
+
127
+ ## Documentation
128
+
129
+ Start with the [quickstart](docs/QUICKSTART.md). The [experience design](docs/EXPERIENCE_DESIGN.md) specifies the API journey, readable reports, and usability bar.
130
+
131
+ - [Product Vision](docs/PRODUCT_VISION.md)
132
+ - [Public Interface Model](docs/INTERFACE_MODEL.md)
133
+ - [Contract Engine](docs/CONTRACT_ENGINE.md)
134
+ - [Architecture](docs/ARCHITECTURE.md)
135
+ - [Type System](docs/TYPE_SYSTEM.md)
136
+ - [Validation Engine](docs/VALIDATION_ENGINE.md)
137
+ - [Static Typing](docs/STATIC_TYPING.md)
138
+ - [Errors](docs/ERROR_MODEL.md)
139
+ - [Performance and Caching](docs/PERFORMANCE.md)
140
+ - [Testing](docs/TESTING_STRATEGY.md)
141
+ - [Compatibility](docs/COMPATIBILITY.md)
142
+ - [Dependencies](docs/DEPENDENCIES.md)
143
+ - [Competition](docs/COMPETITION.md)
144
+ - [Pydantic Integration](docs/PYDANTIC_INTEGRATION.md)
145
+ - [Roadmap and 0.x release phases](docs/ROADMAP.md)
146
+ - [Release and PyPI trusted publishing](docs/RELEASING.md)
147
+ - [Design Decisions](docs/DESIGN_DECISIONS.md)
148
+ - [Implementation Plan](docs/IMPLEMENTATION_PLAN.md)
149
+ - [Phase 0.1 implementation contract](docs/PHASE_0_1_IMPLEMENTATION_CONTRACT.md)
150
+ - [Open Technical Problems](docs/OPEN_TECHNICAL_PROBLEMS.md)
151
+ - [Design probes](design_probes/README.md)
152
+
153
+ The roadmap owns release scope; design decisions own durable policy; focused specifications own behavior; the open-problem register owns implementation evidence and unresolved acceptance work. Contradictions must be reconciled in the same change. A decision does not count as a tested implementation.
@@ -0,0 +1,134 @@
1
+ # Stipulate
2
+
3
+ **Contracts for Python interfaces.**
4
+
5
+ **Define. Validate. Evolve.**
6
+
7
+ Stipulate checks dynamically supplied implementations against Python structural interfaces, explains mismatches, and preserves what available metadata cannot establish.
8
+
9
+ ## Status
10
+
11
+ This repository contains the Stipulate 0.1 implementation, design specification, and design probes. The core API checks declared Protocol compatibility without executing candidate operations. Earlier prototypes are historical inputs, not release evidence.
12
+
13
+ Install with `python -m pip install .` (CPython 3.11–3.14). See the [implemented feature guide](docs/IMPLEMENTED_0_1.md) for the supported boundary. Independent Sol review is still required before release approval.
14
+
15
+ ## Define and validate
16
+
17
+ ```python
18
+ from typing import Protocol
19
+ from stipulate import Contract
20
+
21
+
22
+ class Storage(Protocol):
23
+ def read(self, key: str) -> bytes | None: ...
24
+
25
+ async def write(self, key: str, value: bytes) -> None: ...
26
+
27
+
28
+ class MemoryStorage:
29
+ def __init__(self) -> None:
30
+ self._items: dict[str, bytes] = {}
31
+
32
+ def read(self, key: str) -> bytes | None:
33
+ return self._items.get(key)
34
+
35
+ async def write(self, key: str, value: bytes) -> None:
36
+ self._items[key] = value
37
+
38
+
39
+ candidate = MemoryStorage()
40
+ storage_contract = Contract(Storage)
41
+ storage = storage_contract.validate(candidate)
42
+ ```
43
+
44
+ Implementations are ordinary Python classes. They need no inheritance, registration, or decorators. Validation returns the original object, typed as `Storage`, after checking its available declarations against the contract. The constructor uses TypeForm for inference; the [typing guide](docs/STATIC_TYPING.md) records supported checker settings, including the current mypy feature flag.
45
+
46
+ Strict validation is the default: incompatible or insufficient evidence raises `ContractError`. To allow missing implementation type annotations deliberately, use `strict=False`; known mismatches and unsupported or uninspectable candidate capabilities still fail. Invalid requirements fail contract construction.
47
+
48
+ ## Understand a result
49
+
50
+ ```python
51
+ result = storage_contract.check(candidate)
52
+ print(result)
53
+
54
+ if result:
55
+ print("Storage declarations are compatible")
56
+
57
+ result.status
58
+ result.complete
59
+ result.errors()
60
+ result.unknowns()
61
+ result.evidence
62
+ ```
63
+
64
+ `check()` reports candidate mismatches without raising `ContractError`. Truthiness means compatibility was established for every requirement; unknown evidence is false. Invalid contract definitions raise `ContractDefinitionError`. The result includes locations, reasons, and suggested fixes.
65
+
66
+ Stipulate compares signatures, annotation assignability, binding, and supported member capabilities. It assumes implementations honor their declarations; it does not execute methods to verify their behavior, validate future return values, or prevent later mutation. Annotation resolution may execute Python annotation expressions in the default trusted mode.
67
+
68
+ ## Friendly errors
69
+
70
+ ```text
71
+ Incompatible with Storage
72
+ 2 incompatible findings; 0 unknown findings (0 blocked obligations).
73
+
74
+ read.key
75
+ The implementation input is too narrow for required caller values
76
+ Required: str
77
+ Provided: bytes
78
+ [parameter_type; incompatible]
79
+
80
+ write.kind
81
+ The coroutine execution kind differs
82
+ [async_mismatch; incompatible]
83
+ ```
84
+
85
+ ## Interface shorthand — experimental design target
86
+
87
+ ```python
88
+ from stipulate import Interface
89
+
90
+ class Storage(Interface):
91
+ def read(self, key: str) -> bytes | None: ...
92
+
93
+ storage = Storage.validate(candidate)
94
+ ```
95
+
96
+ This shorthand is not a 0.1 promise. It must preserve structural typing, precise class-side methods, inheritance, and clean protocol members in installed-package Pyright/mypy tests before promotion. The supported 0.1 plan uses `Protocol` plus `Contract`, with the same method-based operations and compatibility engine.
97
+
98
+ ## Evolution and tooling — later releases
99
+
100
+ ```python
101
+ report = Contract(StorageV1).compare(Contract(StorageV2))
102
+ schema = storage_contract.schema()
103
+ fingerprint = storage_contract.fingerprint()
104
+ ```
105
+
106
+ Comparison will report implementer and consumer compatibility separately. Unknown results cannot certify a non-breaking change. Schemas and fingerprints will be versioned before publication. None of these three operations is in the 0.1 public surface.
107
+
108
+ ## Documentation
109
+
110
+ Start with the [quickstart](docs/QUICKSTART.md). The [experience design](docs/EXPERIENCE_DESIGN.md) specifies the API journey, readable reports, and usability bar.
111
+
112
+ - [Product Vision](docs/PRODUCT_VISION.md)
113
+ - [Public Interface Model](docs/INTERFACE_MODEL.md)
114
+ - [Contract Engine](docs/CONTRACT_ENGINE.md)
115
+ - [Architecture](docs/ARCHITECTURE.md)
116
+ - [Type System](docs/TYPE_SYSTEM.md)
117
+ - [Validation Engine](docs/VALIDATION_ENGINE.md)
118
+ - [Static Typing](docs/STATIC_TYPING.md)
119
+ - [Errors](docs/ERROR_MODEL.md)
120
+ - [Performance and Caching](docs/PERFORMANCE.md)
121
+ - [Testing](docs/TESTING_STRATEGY.md)
122
+ - [Compatibility](docs/COMPATIBILITY.md)
123
+ - [Dependencies](docs/DEPENDENCIES.md)
124
+ - [Competition](docs/COMPETITION.md)
125
+ - [Pydantic Integration](docs/PYDANTIC_INTEGRATION.md)
126
+ - [Roadmap and 0.x release phases](docs/ROADMAP.md)
127
+ - [Release and PyPI trusted publishing](docs/RELEASING.md)
128
+ - [Design Decisions](docs/DESIGN_DECISIONS.md)
129
+ - [Implementation Plan](docs/IMPLEMENTATION_PLAN.md)
130
+ - [Phase 0.1 implementation contract](docs/PHASE_0_1_IMPLEMENTATION_CONTRACT.md)
131
+ - [Open Technical Problems](docs/OPEN_TECHNICAL_PROBLEMS.md)
132
+ - [Design probes](design_probes/README.md)
133
+
134
+ The roadmap owns release scope; design decisions own durable policy; focused specifications own behavior; the open-problem register owns implementation evidence and unresolved acceptance work. Contradictions must be reconciled in the same change. A decision does not count as a tested implementation.
@@ -0,0 +1,71 @@
1
+ # Architecture
2
+
3
+ ## Overview
4
+
5
+ ```text
6
+ Protocol declaration
7
+ -> Contract[T] facade
8
+ -> controlled annotation resolution and member compiler
9
+ -> immutable ContractIR snapshot
10
+ -> candidate inspection (per call)
11
+ -> shared capability/type relation engine
12
+ -> Evidence + CompatibilityResult
13
+ -> explicit enforcement policy
14
+ -> original candidate or ContractError
15
+ ```
16
+
17
+ Compilation failures use `ContractDefinitionError`. Inspection does not execute candidate methods or getters. Default trusted annotation evaluation may execute annotation expressions; see VALIDATION_ENGINE.md.
18
+
19
+ ## Public boundary
20
+
21
+ The 0.1 entry point is `Contract(ProtocolType)`. Its constructor accepts `TypeForm[T]`, preserves T through validation, and performs a runtime supported-declaration check. A normal class, union, or arbitrary type form is not automatically a valid requirement.
22
+
23
+ `Contract` exposes `validate()`, `check()`, and `.contract` identity. Later `schema()`, `fingerprint()`, and `compare()` are release-gated. Experimental Interface class-side methods delegate to Contract and never become protocol instance members.
24
+
25
+ ## Internal modules
26
+
27
+ ```text
28
+ src/stipulate/
29
+ __init__.py
30
+ _contract.py public typed facade
31
+ _compile.py requirement compilation
32
+ _ir.py immutable normalized records
33
+ _members.py static member classification
34
+ _signatures.py binding and legal call relations
35
+ _assignability.py directional type relations
36
+ _annotations.py trusted/raw annotation policies
37
+ _compatibility.py result aggregation and enforcement
38
+ _evidence.py immutable findings
39
+ _errors.py public exceptions
40
+ _render.py pure plain-text result/exception presentation
41
+ _cache.py weak compilation cache
42
+ _typing_compat.py isolated version-specific typing behavior
43
+ ```
44
+
45
+ Keep the experimental `_interface.py` bridge separate from release-critical code until accepted.
46
+
47
+ ## Data ownership
48
+
49
+ The Contract facade strongly owns its immutable IR. The IR may strongly retain the declaration and type objects when needed to preserve identity and diagnostics. The global compilation cache must not strongly own that IR; both keys and cached IR values are weak references. See PERFORMANCE.md for lifecycle and race rules.
50
+
51
+ Do not attach a globally owned adapter that closes the weak-reference lifecycle through an indirect path. Do not cache candidates or successful results globally.
52
+
53
+ ## Requirement versus candidate
54
+
55
+ The requirement compiler has no candidate-specific state. Candidate inspection creates an ephemeral provided view with its own resolution context and evidence provenance. Expected limitations are represented as unknown facts. A current attribute value cannot substitute for a missing declared writable type.
56
+
57
+ Read-only capabilities compare covariantly. Writable capabilities add contravariant write obligations. Methods compare every legal call shape, then argument/return relations. Execution-kind requirements are an explicit Stipulate policy, not inferred from textual return annotations alone.
58
+
59
+ ## Configuration boundaries
60
+
61
+ Annotation policy and namespace identity affect compilation and cache reuse. Strictness affects enforcement only. Mutating configuration after compilation is unsupported; create a new Contract snapshot instead.
62
+
63
+ Do not hold cache locks while evaluating annotations, inspecting candidate code, or comparing types. Concurrent duplicate compilation is acceptable when publication is safe and diagnostics are deterministic. Annotation evaluation must not be advertised as exactly-once under concurrency.
64
+
65
+ ## Presentation boundary
66
+
67
+ The presenter accepts normalized evidence and sanitized display metadata. It produces text without invoking candidate code, checking compatibility again, or selecting a policy implicitly. Result str/repr and exception strings share this implementation. Later terminal or browser views may style the same facts; no view is permitted to promote UNKNOWN to compatible.
68
+
69
+ ## Extension rule
70
+
71
+ New types and member forms add normalized representation and relation handlers with conformance tests. They must preserve unknown evidence and share rules with future evolution analysis. A public extension/plugin framework is deferred until internal semantics stabilize.
@@ -0,0 +1,45 @@
1
+ # Compatibility Policy
2
+
3
+ ## Runtime targets
4
+
5
+ Minimum package metadata is CPython 3.11 (`requires-python >=3.11`). The test targets are CPython 3.11, 3.12, 3.13, and 3.14. The implementation report records full runtime and installed-consumer verification; release approval additionally requires independent review.
6
+
7
+ Advertise a minor version only after compilation, annotation resolution, signature normalization, supported type relations, evidence, lifecycle, and installed-package tests pass. Import success is insufficient. PyPy and other implementations are outside the initial support claim.
8
+
9
+ Newer annotation metadata must be handled deliberately, including deferred evaluation. New interpreter features do not automatically expand the supported type-form subset. Use typing_extensions when its behavior is tested; do not invent unavailable runtime metadata.
10
+
11
+ ## Checkers and packaging
12
+
13
+ Pyright strict is permanent for first-party code. Public fixtures also run on supported mypy configurations. Record exact versions and required feature flags; the current design probe's mypy 1.19.1 requires its TypeForm flag. No required checker plugin or consumer ignores.
14
+
15
+ The TypeForm constructor and inferred return type are part of the public contract. Test installed wheels and sdists outside the source tree with py.typed and any required stubs present. Do not claim that local declaration probes prove package behavior.
16
+
17
+ ## Typing semantics and runtime policy
18
+
19
+ The typing specification governs supported annotation relations. Strict evidence, trusted/raw annotation evaluation, static inspection limits, and the initial coroutine-kind rule are explicit Stipulate policies. Document intentional differences from ordinary checker assignment behavior.
20
+
21
+ Supported constructs form a versioned subset. New support can turn UNKNOWN into COMPATIBLE or INCOMPATIBLE; treat resulting acceptance changes as observable behavior and explain them in release notes. Never market strict validation as method-body or future-value enforcement.
22
+
23
+ ## Versioning
24
+
25
+ During 0.x, call out breaking API, policy, diagnostic, or supported-subset changes clearly. At 1.0, semantic versioning covers documented Python APIs, supported compatibility semantics, enforcement defaults, diagnostic fields/codes, and public schema versions.
26
+
27
+ Correctness fixes can legitimately reject previously accepted candidates. Classify and document their impact; do not quietly claim acceptance is unchanged because a change is a bug fix.
28
+
29
+ ## Schema and diagnostics
30
+
31
+ Public schema()/fingerprint() follow their later release gate, including explicit schema versions and identity/portability policy. Internal IR records are not a public interchange format.
32
+
33
+ Diagnostic location, code, serialized fields, and semantic category become stable at 1.0. Exact human wording remains free to improve. Unknown and incompatible categories must remain distinguishable.
34
+
35
+ ## Mutation and evaluation
36
+
37
+ Contracts are immutable requirement snapshots; refresh=True makes a new snapshot. Candidate checks are point-in-time and are repeated after candidate mutation. Trusted annotation evaluation can execute expressions; raw mode does not request evaluation and can produce unresolved evidence. Neither mode is a security boundary.
38
+
39
+ ## Dependencies and integrations
40
+
41
+ Core results must not change merely because Pydantic or another optional integration is installed. Third-party annotation metadata is not supported implicitly. Raising Python/dependency minimums requires an explicit compatibility decision and a tested migration path.
42
+
43
+ ## Deprecation
44
+
45
+ At 1.0, announce deprecations and normally retain them through at least one minor release, with removal in a major release. An exceptional correctness/security removal must explain why ordinary deprecation was insufficient.
@@ -0,0 +1,50 @@
1
+ # Competition and Positioning
2
+
3
+ ## Scope
4
+
5
+ This is a positioning document, not a verified exhaustive feature ranking. Stipulate's initial implementation is in progress and its release gates remain authoritative. Planned or unsupported capabilities must not be compared as shipped advantages against other projects.
6
+
7
+ Its intended focus is explicit Python structural contracts: check a dynamically supplied implementation, explain incompatible and unknown evidence, and eventually compare contract evolution with the same underlying rules.
8
+
9
+ ## Language foundation
10
+
11
+ Protocol is the foundation. Python's typing tools already provide structural checking where the relationship is statically visible; runtime-checkable Protocol checks are intentionally shallower. Stipulate's proposed addition is deeper declaration inspection at dynamic boundaries, subject to available metadata. [Python typing documentation](https://docs.python.org/3/library/typing.html#typing.runtime_checkable)
12
+
13
+ Do not claim runtime inspection proves method behavior that static checking could not prove.
14
+
15
+ ## Useful adjacent references
16
+
17
+ | Reference | Documented focus | Stipulate design lesson |
18
+ | --- | --- | --- |
19
+ | Pydantic | Typed value validation and associated tooling | Simple entry points, useful diagnostics, deliberate value semantics |
20
+ | Griffe | Package API extraction, serialization, and breaking-change analysis | Treat public schema and change reports as compatibility surfaces |
21
+ | Typeguard | Runtime checking of annotated values and instrumented calls | Study runtime annotation limits without conflating value checks with declaration relations |
22
+
23
+ Sources: [Pydantic](https://pydantic.dev/docs/validation/latest/concepts/types/), [Griffe](https://mkdocstrings.github.io/griffe/), [Typeguard](https://typeguard.readthedocs.io/en/latest/). This table does not assert that adjacent tools lack all forms of Protocol support or that Stipulate has uniquely solved those problems.
24
+
25
+ Other historical interface systems, behavioral contract libraries, schema-diff tools, and API-impact projects can inform later evaluation. Specific competitive rankings require dated primary sources, concrete examples, and reproducible comparison criteria before inclusion.
26
+
27
+ ## Product distinction to prove
28
+
29
+ The intended combination is:
30
+
31
+ - Standard Protocol declarations with ordinary implementations.
32
+ - Precise, method-based Contract API and inferred validation return types.
33
+ - Directional call/member/type checking for an explicitly supported subset.
34
+ - Unknown evidence preserved separately from mismatch and policy acceptance.
35
+ - Eventual universal implementer/consumer evolution analysis using shared rules.
36
+ - Eventual versioned schemas and portable fingerprints.
37
+
38
+ The first four belong to the 0.1 plan. The last two are later release gates, not current feature claims.
39
+
40
+ ## Boundaries
41
+
42
+ Do not expand into package-wide source extraction, general function instrumentation, call-site analytics, dependency injection, behavioral preconditions, or a nominal interface ecosystem merely to match a competitor's feature list.
43
+
44
+ For tooling, a deliberate user-supplied Protocol is the contract being checked. This scope does not prevent future integrations with API extraction, but those integrations must not redefine the core.
45
+
46
+ ## Reassessment triggers
47
+
48
+ Before publishing competitive claims or major releases, verify current primary documentation and test representative examples. Reevaluate when typing standards improve class-side APIs, checker TypeForm support changes, or adjacent projects add relevant declaration/evolution capabilities.
49
+
50
+ Stipulate earns adoption through demonstrated correctness and error quality. Avoid claims of completeness, unique capability, or stronger guarantees than the evidence supports.
@@ -0,0 +1,100 @@
1
+ # Contract Engine
2
+
3
+ ## Semantic center
4
+
5
+ The engine compares provided declarations against required declarations. Compatibility means each supported required operation is available with compatible call shape, binding, and types, assuming declarations describe actual behavior.
6
+
7
+ One normalization and relation engine powers candidate checks and eventual evolution analysis. Relation context is explicit: metadata conformance and universal contract evolution have different obligations when gradual or unknown types are involved.
8
+
9
+ ## Layers
10
+
11
+ 1. Compile a supported Protocol into immutable `ContractIR`.
12
+ 2. Inspect a candidate into an ephemeral provided-contract view.
13
+ 3. Compare capabilities and types, producing evidence.
14
+ 4. Aggregate a policy-independent `CompatibilityResult`.
15
+ 5. Enforce strict or permissive acceptance and return the original candidate or raise `ContractError`.
16
+
17
+ Later serialization and comparison consume the same IR and relation rules. They are not public 0.1 operations.
18
+
19
+ ## Contract IR
20
+
21
+ ```text
22
+ ContractIR
23
+ declaration identity and diagnostic provenance
24
+ members
25
+ MethodContract: binding, legal calls, parameter types, return type, execution kind
26
+ AttributeContract: read type, write type, storage capability
27
+ PropertyContract: getter, optional setter
28
+ normalized TypeExpr graph
29
+ compilation policy and supported feature set
30
+ ```
31
+
32
+ Candidate evidence and enforcement policy do not enter the requirement IR. Public `Contract[T]` is a typed facade holding one snapshot. Keep source provenance outside the semantic fields used for future serialization.
33
+
34
+ Recursive references use explicit graph identities and a cycle-aware relation context. A cache of visited pairs must distinguish pending from established relations; recursion is not unconditional compatibility. Unsupported recursive forms remain explicit until dedicated support lands.
35
+
36
+ ## Evidence and aggregation
37
+
38
+ Evidence has `PROVEN`, `INCOMPATIBLE`, or `UNKNOWN` status, a stable code and location, expected/actual metadata, provenance, and an optional actionable hint. PROVEN means an obligation about declarations was established, not that a method body was executed.
39
+
40
+ Conjunctive requirements aggregate as follows:
41
+
42
+ | Findings | Result status | Truthiness | Strict acceptance | Permissive acceptance |
43
+ | --- | --- | --- | --- | --- |
44
+ | All obligations established | COMPATIBLE | True | Yes | Yes |
45
+ | At least one incompatible finding, with or without unknowns | INCOMPATIBLE | False | No | No |
46
+ | No incompatibility; unknowns only from the allowlist below | UNKNOWN | False | No | Yes |
47
+ | No incompatibility; any other unknown reason | UNKNOWN | False | No | No |
48
+
49
+ `complete` means every applicable obligation was decided. It is independent of success: a fully analyzed incompatible object is complete. Blocked dependent obligations must remain explicitly unassessed; do not manufacture completeness by dropping them. An empty valid contract is compatible and complete.
50
+
51
+ Disjunctive type relations use three-valued logic: one established branch suffices for an OR, all disproven branches disprove it, otherwise it is unknown. An AND is disproven by any failed obligation, established only when all succeed, otherwise unknown. Apply this inside union and other relation algorithms before aggregating independent member requirements.
52
+
53
+ There is no second public assurance enum or confidence score in 0.1. `status`, `complete`, and detailed evidence suffice.
54
+
55
+ ## Enforcement policy
56
+
57
+ `validate(candidate, strict=True)` and `result.accepted(strict=True)` share the exact same acceptance function. `check()` never applies enforcement policy.
58
+
59
+ Permissive acceptance may tolerate only candidate type unknowns with codes `annotation_missing` and `gradual_type`. Known member presence, binding, signature, and execution-kind checks must still pass. Missing required members, unsupported types, unresolved expressions, unavailable signatures, dynamic members, and inspection failures cannot be waived by `strict=False`.
60
+
61
+ Unknowns retain their original status and provenance after acceptance. A permissive return type is a documented trust boundary comparable to adopting untyped code, not a complete metadata proof. Invalid requirements always raise `ContractDefinitionError` independently of enforcement policy.
62
+
63
+ ## Exceptions
64
+
65
+ `ContractError` means a valid contract rejected the candidate under the requested policy. It includes the result and the findings responsible for rejection, including unknowns rejected by strict policy.
66
+
67
+ `ContractDefinitionError` means the requirement could not be compiled. `check()` does not swallow definition errors or unexpected internal defects. Expected candidate inspection limitations become unknown evidence; process-control exceptions propagate.
68
+
69
+ ## Evolution semantics — later release
70
+
71
+ For old contract O and new contract N, under fully supported, fully static semantics:
72
+
73
+ - Implementers: O is assignable to N. Every implementation meeting O also meets N.
74
+ - Consumers: N is assignable to O. A consumer using O's operations can use N.
75
+
76
+ | Change from old to new | Existing implementers | Existing consumers |
77
+ | --- | --- | --- |
78
+ | Add a required method | Incompatible | Compatible |
79
+ | Remove a required method | Compatible | Incompatible |
80
+ | Widen accepted parameter from int to object | Incompatible | Compatible |
81
+ | Narrow returned value from object to int | Incompatible | Compatible |
82
+ | Add an optional parameter to an existing method | May be incompatible: old implementations need not accept it | Compatible if old calls and results are preserved |
83
+
84
+ These are independent perspectives, not a single “breaking” direction. Member kinds, mutability, and call shapes remain part of the analysis.
85
+
86
+ Python gradual assignability involving Any is not a universal substitutability guarantee. For example, returns `int`, `Any`, and `str` permit pairwise gradual assignments through Any without making int assignable to str. Never infer transitive evolution safety through such evidence. Use the same engine with a universal-guarantee context; return UNKNOWN wherever the guarantee depends on unsupported or gradual assumptions. Independent mismatches can still establish incompatibility.
87
+
88
+ `report.implementers` and `.consumers` are CompatibilityResults. `report.breaking` is True if either direction is INCOMPATIBLE, False only if both are COMPATIBLE, and None otherwise. `report.complete` requires both directions complete. CI fails on incompatible or unknown required directions by default. Report objects have no implicit truthiness; reject it to avoid ambiguous policy decisions. The CLI can explicitly select which direction matters.
89
+
90
+ ## Canonical schema and fingerprints — later release
91
+
92
+ Versioned schema work must specify member ordering, unions, aliases, nominal type identity, generic bindings, recursive references, default presence versus default values, ignored Annotated metadata, and portability before publication.
93
+
94
+ A semantic fingerprint excludes display names, source locations, and irrelevant default values. Callable compatibility depends on default presence; changed default behavior can be reported separately but is not behavioral proof. Preserve nominal identities; never merge unrelated types merely because names match. Process-local or non-portable identities must be rejected for portable snapshots or explicitly marked non-portable, not serialized using unstable repr output.
95
+
96
+ Use an explicit format such as `stipulate-contract-v1:sha256:<digest>`. A fingerprint difference does not imply incompatibility. Loading snapshots must not automatically import or execute arbitrary type references.
97
+
98
+ ## Native implementation boundary
99
+
100
+ The initial core is Python. Normalize Python inspection objects before relation analysis, but retain the runtime identity information needed for correctness. A future native core is justified only by profiling; do not constrain 0.1 around speculative Rust or force premature portable serialization.
@@ -0,0 +1,35 @@
1
+ # Dependency Strategy
2
+
3
+ ## Core
4
+
5
+ Start with standard-library dataclasses, inspect, typing, weakref, and explicit typed internal records. Stipulate owns its IR, type relations, evidence, and enforcement semantics.
6
+
7
+ Use typing_extensions for TypeForm and supported cross-version features. The recorded design probes use 4.15.0; treat that as the initial tested baseline, not proof of the oldest compatible release. Freeze actual package minimums only after the release matrix passes.
8
+
9
+ attrs and typing-inspection remain optional implementation evaluations, not commitments. Adopt them only if conformance experiments demonstrate a meaningful correctness or maintenance benefit. Do not add a dependency because it resembles a small standard-library abstraction.
10
+
11
+ ## Development
12
+
13
+ Use pytest, Hypothesis, Ruff, Pyright strict, and mypy public fixtures. Pin tested checker versions and document required TypeForm settings. The specification is the semantic reference; checker/runtime-library disagreement needs an explanation rather than majority voting.
14
+
15
+ Keep design probes separate from implementation tests. A local fixture dependency is not automatically a production dependency.
16
+
17
+ ## Later CLI
18
+
19
+ Typer and Rich are preferred candidates for an optional stipulate[cli] extra once snapshot and comparison APIs are ready. CLI code consumes the shared contract engine and emits machine-readable reports independently of terminal rendering.
20
+
21
+ No CLI dependency is needed for library validation or the 0.1 API.
22
+
23
+ ## Optional integrations
24
+
25
+ Pydantic is optional and post-1.0. It must not become the assignability engine or change core outcomes based on installation state. Integration value validation needs its own no-hidden-coercion and attribute-access policy.
26
+
27
+ Griffe may be evaluated if later work needs package API extraction. Typeguard and other runtime typing libraries can inform narrow differential experiments but do not define Stipulate's structural assignability semantics.
28
+
29
+ ## Optimization
30
+
31
+ Use hashlib and json for future schema tooling once canonical semantics exist. Do not introduce Rust, PyO3, or native build infrastructure before profiling identifies a material bottleneck. Keep Python introspection on the Python side of any future native boundary.
32
+
33
+ ## Acceptance rule
34
+
35
+ A dependency must demonstrably remove difficult non-differentiating work, improve tested compatibility, or provide a justified optional capability. Record its purpose, supported versions, typing quality, and effect on the package matrix before adoption.