openframe-core 3.0.1__tar.gz → 3.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.
- {openframe_core-3.0.1 → openframe_core-3.2.0}/.github/CHANGELOG.md +71 -6
- {openframe_core-3.0.1 → openframe_core-3.2.0}/PKG-INFO +8 -18
- {openframe_core-3.0.1 → openframe_core-3.2.0}/README.md +6 -16
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/code/getting-started/index.md +5 -3
- openframe_core-3.2.0/docs/code/modules/health.md +46 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/code/modules/index.md +4 -5
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/code/modules/plugins.md +3 -3
- openframe_core-3.2.0/docs/code/modules/ports.md +428 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/code/modules/runtime.md +1 -1
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/developer-guide/explore.md +7 -9
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/developer-guide/how-it-works.md +6 -6
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/developer-guide/local-dev.md +1 -1
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/developer-guide/quick-start/index.md +5 -5
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/index.md +1 -1
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/architecture/adrs/adr-006-unified-port-lifecycle.md +83 -1
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/architecture/capability-taxonomy.md +19 -3
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/architecture/design-decisions.md +41 -17
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/architecture/package-journey/adapter-lifecycle.md +1 -1
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/architecture/package-journey/template-wiring.md +2 -2
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/architecture/system-architecture.md +44 -28
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/infrastructure/networking.md +1 -1
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/operations/runbooks/adapter-connection-failure.md +2 -2
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/operations/runbooks/queue-consumer-stuck.md +1 -1
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/overview/glossary.md +6 -6
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/overview/roadmap.md +13 -3
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/overview/system-overview.md +20 -21
- {openframe_core-3.0.1 → openframe_core-3.2.0}/mkdocs.yml +0 -1
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/exceptions/base.py +1 -1
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/inbound/command.py +1 -1
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/inbound/context.py +4 -4
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/inbound/query.py +1 -1
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/inbound/usecase.py +2 -2
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/plugins/__init__.py +3 -3
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/plugins/registry.py +12 -12
- openframe_core-3.2.0/openframe/core/ports/__init__.py +64 -0
- {openframe_core-3.0.1/openframe/core/contracts → openframe_core-3.2.0/openframe/core/ports}/capability.py +2 -2
- {openframe_core-3.0.1/openframe/core/contracts → openframe_core-3.2.0/openframe/core/ports}/context.py +6 -6
- {openframe_core-3.0.1/openframe/core/contracts → openframe_core-3.2.0/openframe/core/ports}/health.py +6 -6
- {openframe_core-3.0.1/openframe/core/contracts → openframe_core-3.2.0/openframe/core/ports}/identity.py +7 -7
- {openframe_core-3.0.1/openframe/core/contracts → openframe_core-3.2.0/openframe/core/ports}/lifecycle.py +7 -7
- openframe_core-3.2.0/openframe/core/ports/outbound/__init__.py +40 -0
- {openframe_core-3.0.1/openframe/core/ports → openframe_core-3.2.0/openframe/core/ports/outbound}/consumer.py +6 -6
- {openframe_core-3.0.1/openframe/core/ports → openframe_core-3.2.0/openframe/core/ports/outbound}/producer.py +6 -6
- {openframe_core-3.0.1/openframe/core/ports → openframe_core-3.2.0/openframe/core/ports/outbound}/repository.py +6 -6
- {openframe_core-3.0.1/openframe/core/contracts → openframe_core-3.2.0/openframe/core/ports}/port.py +8 -8
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/runtime/bootstrap.py +7 -7
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/testing/__init__.py +26 -2
- openframe_core-3.2.0/openframe/core/testing/contracts/__init__.py +44 -0
- openframe_core-3.2.0/openframe/core/testing/contracts/inbound.py +221 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/testing/contracts/lifecycle.py +8 -8
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/testing/contracts/port.py +6 -6
- openframe_core-3.2.0/openframe/core/testing/fakes/__init__.py +36 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/testing/fakes/consumer.py +2 -2
- openframe_core-3.2.0/openframe/core/testing/fakes/inbound.py +256 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/testing/fakes/producer.py +2 -2
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/testing/fakes/repository.py +3 -3
- {openframe_core-3.0.1 → openframe_core-3.2.0}/pyproject.toml +2 -2
- {openframe_core-3.0.1 → openframe_core-3.2.0}/tests/test_inbound.py +1 -1
- openframe_core-3.2.0/tests/test_inbound_contracts.py +164 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/tests/test_plugins.py +1 -1
- {openframe_core-3.0.1 → openframe_core-3.2.0}/tests/test_ports.py +11 -3
- openframe_core-3.0.1/tests/test_contracts.py → openframe_core-3.2.0/tests/test_ports_primitives.py +6 -4
- {openframe_core-3.0.1 → openframe_core-3.2.0}/tests/test_runtime.py +1 -1
- {openframe_core-3.0.1 → openframe_core-3.2.0}/tests/test_testing_fakes.py +2 -2
- openframe_core-3.0.1/docs/code/modules/contracts.md +0 -219
- openframe_core-3.0.1/docs/code/modules/health.md +0 -41
- openframe_core-3.0.1/docs/code/modules/ports.md +0 -224
- openframe_core-3.0.1/openframe/core/contracts/__init__.py +0 -61
- openframe_core-3.0.1/openframe/core/ports/__init__.py +0 -32
- openframe_core-3.0.1/openframe/core/testing/contracts/__init__.py +0 -25
- openframe_core-3.0.1/openframe/core/testing/fakes/__init__.py +0 -22
- {openframe_core-3.0.1 → openframe_core-3.2.0}/.github/requirements/docs.txt +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/.github/requirements/test.txt +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/.github/workflows/app-test.yml +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/.github/workflows/auto-docs.yml +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/.github/workflows/python-build.yml +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/.gitignore +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/.vscode/settings.json +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/LICENSE +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/assets/images/banner.png +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/assets/images/favicon.png +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/assets/images/logo-dark.png +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/assets/images/logo-light.png +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/assets/javascripts/extra.js +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/assets/stylesheets/extra.css +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/code/cicd/pipeline.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/code/modules/config.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/code/modules/exceptions.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/code/modules/inbound.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/code/modules/middleware.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/code/modules/telemetry.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/code/modules/testing.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/code/modules/tracing.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/developer-guide/debugging.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/developer-guide/first-change.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/architecture/adrs/adr-001-namespace.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/architecture/adrs/adr-002-hexagonal.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/architecture/adrs/adr-003-async.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/architecture/adrs/adr-004-pydantic.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/architecture/adrs/adr-005-middleware.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/architecture/adrs/index.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/architecture/component-lifecycle.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/architecture/data-flows.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/architecture/error-taxonomy.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/architecture/package-journey/error-propagation.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/architecture/package-journey/index.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/architecture/package-journey/tracing-flow.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/deployment/cicd.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/deployment/environments.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/deployment/secrets-and-config.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/infrastructure/platform.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/infrastructure/storage.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/operations/index.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/operations/monitoring.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/operations/runbooks/modal-cold-start-spike.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/operations/runbooks/postgres-pool-exhausted.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/operations/runbooks/redis-connection-lost.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/docs/technical/operations/runbooks/telemetry-export-failing.md +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/__init__.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/__init__.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/config/__init__.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/config/settings.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/exceptions/__init__.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/exceptions/adapter.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/exceptions/codes.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/exceptions/plugin.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/inbound/__init__.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/middleware/__init__.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/middleware/telemetry.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/middleware/types.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/runtime/__init__.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/telemetry/__init__.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/telemetry/setup.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/testing/contracts/consumer.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/testing/contracts/producer.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/testing/contracts/repository.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/testing/fixtures.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/tracing/__init__.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/tracing/propagation.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/core/tracing/proxy.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/openframe/py.typed +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/tests/conftest.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/tests/test_config.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/tests/test_exceptions.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/tests/test_middleware.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/tests/test_middleware_types.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/tests/test_record_error.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/tests/test_shutdown_telemetry.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/tests/test_telemetry_sidecar.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/tests/test_tracing.py +0 -0
- {openframe_core-3.0.1 → openframe_core-3.2.0}/tests/test_tracing_propagation.py +0 -0
|
@@ -18,12 +18,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
18
18
|
as the default starting point and frame the other two as explicit alternatives
|
|
19
19
|
with stated conditions. Tracked in the roadmap.
|
|
20
20
|
|
|
21
|
-
- **`contracts/` five-module depth** — the `capability → context → health →
|
|
22
|
-
identity → lifecycle → port` chain is clean today. The risk is a sixth or
|
|
23
|
-
seventh module that doesn't stay within the single-concept-per-file rule or
|
|
24
|
-
that imports from non-adjacent layers. Consolidate before expanding if either
|
|
25
|
-
signal appears.
|
|
26
|
-
|
|
27
21
|
### Added
|
|
28
22
|
|
|
29
23
|
- **`openframe.core.telemetry.shutdown_telemetry()`** — flushes and shuts
|
|
@@ -64,6 +58,77 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
64
58
|
|
|
65
59
|
---
|
|
66
60
|
|
|
61
|
+
## v3.2.0
|
|
62
|
+
|
|
63
|
+
### Added
|
|
64
|
+
|
|
65
|
+
- `openframe.core.testing.fakes.inbound` — three in-memory test
|
|
66
|
+
doubles for the inbound contracts: `EchoUseCase`,
|
|
67
|
+
`SpyCommandHandler`, `SpyQueryHandler`. Mirror of the outbound
|
|
68
|
+
fakes (`InMemoryRepository`, `FakeProducer`, `FakeConsumer`).
|
|
69
|
+
- `openframe.core.testing.contracts.inbound` — three inheritable
|
|
70
|
+
pytest base classes: `UseCaseContractTests`,
|
|
71
|
+
`CommandHandlerContractTests`, `QueryHandlerContractTests`.
|
|
72
|
+
Any application service or validation-framework service
|
|
73
|
+
implementing these protocols can prove conformance by inheriting
|
|
74
|
+
the relevant class.
|
|
75
|
+
- All six new names exported from `openframe.core.testing`
|
|
76
|
+
top-level for consistent import ergonomics.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## v3.1.0
|
|
81
|
+
|
|
82
|
+
### Breaking changes
|
|
83
|
+
|
|
84
|
+
#### openframe.core.contracts → openframe.core.ports
|
|
85
|
+
|
|
86
|
+
The openframe.core.contracts module has been merged into
|
|
87
|
+
openframe.core.ports and no longer exists. All names previously
|
|
88
|
+
importable from openframe.core.contracts are now importable from
|
|
89
|
+
openframe.core.ports:
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
# Before (< v3.1.0)
|
|
93
|
+
from openframe.core.contracts import BasePort, Capability, PluginHealth
|
|
94
|
+
|
|
95
|
+
# After (v3.1.0+)
|
|
96
|
+
from openframe.core.ports import BasePort, Capability, PluginHealth
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
No compatibility shim is provided at the old path.
|
|
100
|
+
|
|
101
|
+
`openframe.core.ports` now exports both the port primitives
|
|
102
|
+
(BasePort, Capability, Identity, Lifecycle, PluginStatus,
|
|
103
|
+
PluginHealth, PluginContext, PrincipalContext, TenantContext)
|
|
104
|
+
and the outbound protocols (BaseRepository, BaseProducer,
|
|
105
|
+
BaseConsumer) from a single unified module.
|
|
106
|
+
|
|
107
|
+
#### BaseRepository, BaseProducer, BaseConsumer moved to ports/outbound/
|
|
108
|
+
|
|
109
|
+
The three capability-specific outbound port protocols have moved
|
|
110
|
+
into the ports/outbound/ sub-module to mirror the existing
|
|
111
|
+
inbound/ sub-module on the driven side of the hexagon.
|
|
112
|
+
The public API is unchanged — import from openframe.core.ports
|
|
113
|
+
as before:
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
from openframe.core.ports import BaseRepository # unchanged
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The explicit sub-module path is now:
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
from openframe.core.ports.outbound import BaseRepository
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Future outbound capability protocols (BaseSecretsProvider,
|
|
126
|
+
BaseObjectStore, BaseFeatureFlagProvider from openframe-infra)
|
|
127
|
+
will be added to openframe/core/ports/outbound/ as the
|
|
128
|
+
ecosystem grows.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
67
132
|
## [3.0.0] — 2026-07-07
|
|
68
133
|
|
|
69
134
|
### Architecture scorecard
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openframe-core
|
|
3
|
-
Version: 3.0
|
|
4
|
-
Summary: OpenFrame Microservice Suite - platform kernel.
|
|
3
|
+
Version: 3.2.0
|
|
4
|
+
Summary: OpenFrame Microservice Suite - platform kernel. Port contracts, testing utilities, plugin registry, and composition root.
|
|
5
5
|
Project-URL: Homepage, https://github.com/Furious-Meteors/openframe-core
|
|
6
6
|
Project-URL: Documentation, https://furious-meteors.github.io/openframe-core/
|
|
7
7
|
Project-URL: Repository, https://github.com/Furious-Meteors/openframe-core
|
|
@@ -73,24 +73,15 @@ Description-Content-Type: text/markdown
|
|
|
73
73
|
<a href="https://github.com/Furious-Meteors/openframe-core/blob/production/.github/CHANGELOG.md">Changelog</a>
|
|
74
74
|
</p>
|
|
75
75
|
|
|
76
|
-
---
|
|
77
|
-
|
|
78
76
|
`openframe-core` is the foundation package of the OpenFrame Microservice Development Suite. It defines the structural contracts, telemetry primitives, and shared utilities that every other package in the ecosystem depends on.
|
|
79
77
|
|
|
80
|
-
Every package in the OpenFrame ecosystem pins `openframe-core>=3.0,<4`. The major version is the stability contract for the entire ecosystem.
|
|
81
|
-
|
|
82
|
-
> **v3.0.0 is a breaking redesign.** The old hardcoded, lifecycle-free ports, the standalone `HealthCheck` protocol, and the separate `OpenFramePlugin` protocol are gone. They are replaced by a single unified contract layer built on `BasePort` (`Identity` + `Lifecycle`), and the error hierarchy is consolidated under a single `OpenFrameError` root. See [ADR-006](https://furious-meteors.github.io/openframe-core/technical/architecture/adrs/adr-006-unified-port-lifecycle/) and the [Changelog](.github/CHANGELOG.md) for the full migration guide.
|
|
83
|
-
|
|
84
|
-
---
|
|
85
|
-
|
|
86
78
|
## What's inside
|
|
87
79
|
|
|
88
80
|
| Module | Exports |
|
|
89
81
|
|---|---|
|
|
90
|
-
| `openframe.core.
|
|
82
|
+
| `openframe.core.ports` | `BasePort` · `Identity` · `Lifecycle` · `Capability` · `PluginStatus` · `PluginHealth` · `PluginContext` · `PrincipalContext` · `TenantContext` · `BaseRepository[T]` · `BaseProducer[T]` · `BaseConsumer[T]` |
|
|
91
83
|
| `openframe.core.exceptions` | `OpenFrameError` (root) · `ErrorCode` · `Severity` · `AdapterError` (+5) · `PluginError` (+4, incl. `AmbiguousCapabilityError`) |
|
|
92
84
|
| `openframe.core.config` | `BaseAdapterSettings` — Pydantic `BaseSettings` subclass all adapters inherit |
|
|
93
|
-
| `openframe.core.ports` | `BaseRepository[T]` · `BaseProducer[T]` · `BaseConsumer[T]` — `BasePort` + domain methods (outbound side) |
|
|
94
85
|
| `openframe.core.inbound` | `UseCase[TIn, TOut]` · `CommandHandler[TIn]` · `QueryHandler[TIn, TOut]` · `RequestContext` (driving side) |
|
|
95
86
|
| `openframe.core.plugins` | `PluginRegistry` — explicit registration, ordered init, LIFO shutdown, capability lookup |
|
|
96
87
|
| `openframe.core.runtime` | `ApplicationBootstrap` — optional composition-root base class |
|
|
@@ -169,8 +160,7 @@ settings = PostgresSettings()
|
|
|
169
160
|
Every port is a `BasePort`: `Identity` (`name`/`version`/`capability`) + `Lifecycle` (`initialize`/`shutdown`/`health`) plus its own domain methods. Adapters satisfy it structurally — no inheritance required.
|
|
170
161
|
|
|
171
162
|
```python
|
|
172
|
-
from openframe.core.
|
|
173
|
-
from openframe.core.ports import BaseRepository
|
|
163
|
+
from openframe.core.ports import Capability, PluginContext, PluginHealth, PluginStatus, BaseRepository
|
|
174
164
|
|
|
175
165
|
class PostgresItemRepository:
|
|
176
166
|
# Identity
|
|
@@ -200,7 +190,7 @@ assert isinstance(PostgresItemRepository(), BaseRepository) # True
|
|
|
200
190
|
A "plugin" is just a registered `BasePort`. The registry initializes in order, shuts down LIFO, and looks up by the typed `Capability` enum:
|
|
201
191
|
|
|
202
192
|
```python
|
|
203
|
-
from openframe.core.
|
|
193
|
+
from openframe.core.ports import Capability
|
|
204
194
|
from openframe.core.plugins import PluginRegistry
|
|
205
195
|
|
|
206
196
|
registry = PluginRegistry()
|
|
@@ -218,7 +208,7 @@ await registry.shutdown_all() # reverse order; never raises
|
|
|
218
208
|
### Runtime — optional composition root
|
|
219
209
|
|
|
220
210
|
```python
|
|
221
|
-
from openframe.core.
|
|
211
|
+
from openframe.core.ports import Capability
|
|
222
212
|
from openframe.core.runtime import ApplicationBootstrap
|
|
223
213
|
|
|
224
214
|
class MyServiceBootstrap(ApplicationBootstrap):
|
|
@@ -356,11 +346,11 @@ pip install -e ".[dev]"
|
|
|
356
346
|
pytest tests/ -v
|
|
357
347
|
```
|
|
358
348
|
|
|
359
|
-
|
|
349
|
+
301 tests. All run in under 1 second — no network calls, no external services.
|
|
360
350
|
|
|
361
351
|
```bash
|
|
362
352
|
# Smoke test
|
|
363
|
-
python -c "from openframe.core.
|
|
353
|
+
python -c "from openframe.core.ports import BasePort; print('openframe-core OK')"
|
|
364
354
|
```
|
|
365
355
|
|
|
366
356
|
---
|
|
@@ -17,24 +17,15 @@
|
|
|
17
17
|
<a href="https://github.com/Furious-Meteors/openframe-core/blob/production/.github/CHANGELOG.md">Changelog</a>
|
|
18
18
|
</p>
|
|
19
19
|
|
|
20
|
-
---
|
|
21
|
-
|
|
22
20
|
`openframe-core` is the foundation package of the OpenFrame Microservice Development Suite. It defines the structural contracts, telemetry primitives, and shared utilities that every other package in the ecosystem depends on.
|
|
23
21
|
|
|
24
|
-
Every package in the OpenFrame ecosystem pins `openframe-core>=3.0,<4`. The major version is the stability contract for the entire ecosystem.
|
|
25
|
-
|
|
26
|
-
> **v3.0.0 is a breaking redesign.** The old hardcoded, lifecycle-free ports, the standalone `HealthCheck` protocol, and the separate `OpenFramePlugin` protocol are gone. They are replaced by a single unified contract layer built on `BasePort` (`Identity` + `Lifecycle`), and the error hierarchy is consolidated under a single `OpenFrameError` root. See [ADR-006](https://furious-meteors.github.io/openframe-core/technical/architecture/adrs/adr-006-unified-port-lifecycle/) and the [Changelog](.github/CHANGELOG.md) for the full migration guide.
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
22
|
## What's inside
|
|
31
23
|
|
|
32
24
|
| Module | Exports |
|
|
33
25
|
|---|---|
|
|
34
|
-
| `openframe.core.
|
|
26
|
+
| `openframe.core.ports` | `BasePort` · `Identity` · `Lifecycle` · `Capability` · `PluginStatus` · `PluginHealth` · `PluginContext` · `PrincipalContext` · `TenantContext` · `BaseRepository[T]` · `BaseProducer[T]` · `BaseConsumer[T]` |
|
|
35
27
|
| `openframe.core.exceptions` | `OpenFrameError` (root) · `ErrorCode` · `Severity` · `AdapterError` (+5) · `PluginError` (+4, incl. `AmbiguousCapabilityError`) |
|
|
36
28
|
| `openframe.core.config` | `BaseAdapterSettings` — Pydantic `BaseSettings` subclass all adapters inherit |
|
|
37
|
-
| `openframe.core.ports` | `BaseRepository[T]` · `BaseProducer[T]` · `BaseConsumer[T]` — `BasePort` + domain methods (outbound side) |
|
|
38
29
|
| `openframe.core.inbound` | `UseCase[TIn, TOut]` · `CommandHandler[TIn]` · `QueryHandler[TIn, TOut]` · `RequestContext` (driving side) |
|
|
39
30
|
| `openframe.core.plugins` | `PluginRegistry` — explicit registration, ordered init, LIFO shutdown, capability lookup |
|
|
40
31
|
| `openframe.core.runtime` | `ApplicationBootstrap` — optional composition-root base class |
|
|
@@ -113,8 +104,7 @@ settings = PostgresSettings()
|
|
|
113
104
|
Every port is a `BasePort`: `Identity` (`name`/`version`/`capability`) + `Lifecycle` (`initialize`/`shutdown`/`health`) plus its own domain methods. Adapters satisfy it structurally — no inheritance required.
|
|
114
105
|
|
|
115
106
|
```python
|
|
116
|
-
from openframe.core.
|
|
117
|
-
from openframe.core.ports import BaseRepository
|
|
107
|
+
from openframe.core.ports import Capability, PluginContext, PluginHealth, PluginStatus, BaseRepository
|
|
118
108
|
|
|
119
109
|
class PostgresItemRepository:
|
|
120
110
|
# Identity
|
|
@@ -144,7 +134,7 @@ assert isinstance(PostgresItemRepository(), BaseRepository) # True
|
|
|
144
134
|
A "plugin" is just a registered `BasePort`. The registry initializes in order, shuts down LIFO, and looks up by the typed `Capability` enum:
|
|
145
135
|
|
|
146
136
|
```python
|
|
147
|
-
from openframe.core.
|
|
137
|
+
from openframe.core.ports import Capability
|
|
148
138
|
from openframe.core.plugins import PluginRegistry
|
|
149
139
|
|
|
150
140
|
registry = PluginRegistry()
|
|
@@ -162,7 +152,7 @@ await registry.shutdown_all() # reverse order; never raises
|
|
|
162
152
|
### Runtime — optional composition root
|
|
163
153
|
|
|
164
154
|
```python
|
|
165
|
-
from openframe.core.
|
|
155
|
+
from openframe.core.ports import Capability
|
|
166
156
|
from openframe.core.runtime import ApplicationBootstrap
|
|
167
157
|
|
|
168
158
|
class MyServiceBootstrap(ApplicationBootstrap):
|
|
@@ -300,11 +290,11 @@ pip install -e ".[dev]"
|
|
|
300
290
|
pytest tests/ -v
|
|
301
291
|
```
|
|
302
292
|
|
|
303
|
-
|
|
293
|
+
301 tests. All run in under 1 second — no network calls, no external services.
|
|
304
294
|
|
|
305
295
|
```bash
|
|
306
296
|
# Smoke test
|
|
307
|
-
python -c "from openframe.core.
|
|
297
|
+
python -c "from openframe.core.ports import BasePort; print('openframe-core OK')"
|
|
308
298
|
```
|
|
309
299
|
|
|
310
300
|
---
|
|
@@ -23,8 +23,10 @@ pip install openframe-core
|
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
25
|
python -c "
|
|
26
|
-
from openframe.core.
|
|
27
|
-
|
|
26
|
+
from openframe.core.ports import (
|
|
27
|
+
BasePort, Capability, PluginHealth, PluginStatus,
|
|
28
|
+
BaseRepository, BaseProducer, BaseConsumer,
|
|
29
|
+
)
|
|
28
30
|
from openframe.core.exceptions import OpenFrameError, AdapterError
|
|
29
31
|
from openframe.core.inbound import UseCase, RequestContext
|
|
30
32
|
from openframe.core.plugins import PluginRegistry
|
|
@@ -67,7 +69,7 @@ export OPENFRAME_ENV="dev"
|
|
|
67
69
|
```python
|
|
68
70
|
from contextlib import asynccontextmanager
|
|
69
71
|
from fastapi import FastAPI
|
|
70
|
-
from openframe.core.
|
|
72
|
+
from openframe.core.ports import Capability
|
|
71
73
|
from openframe.core.plugins import PluginRegistry
|
|
72
74
|
from openframe.core.telemetry import setup_telemetry, record_lifecycle_event
|
|
73
75
|
from openframe.core.middleware import TelemetryMiddleware
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Health
|
|
2
|
+
|
|
3
|
+
Health is part of the unified `Lifecycle` contract in `openframe.core.ports`. Every `BasePort` implements a single `health()` method that returns a rich `PluginHealth` snapshot — there is no separate health protocol.
|
|
4
|
+
|
|
5
|
+
```python
|
|
6
|
+
from openframe.core.ports import Lifecycle, PluginHealth, PluginStatus
|
|
7
|
+
|
|
8
|
+
async def health(self) -> PluginHealth:
|
|
9
|
+
try:
|
|
10
|
+
await self._pool.fetchval("SELECT 1")
|
|
11
|
+
return PluginHealth(status=PluginStatus.READY)
|
|
12
|
+
except Exception as exc:
|
|
13
|
+
return PluginHealth(
|
|
14
|
+
status=PluginStatus.UNAVAILABLE,
|
|
15
|
+
message=str(exc),
|
|
16
|
+
)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
`Lifecycle.health()` is the single canonical health primitive. Liveness vs. readiness granularity — or any other reporting distinction an adapter needs — is expressed through `PluginStatus` and `PluginHealth.details`, not through separate methods:
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
# Minimal
|
|
23
|
+
PluginHealth(status=PluginStatus.READY)
|
|
24
|
+
|
|
25
|
+
# With detail
|
|
26
|
+
PluginHealth(
|
|
27
|
+
status=PluginStatus.READY,
|
|
28
|
+
details={"ping_ms": 2.1, "schema_ok": True},
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# Degraded
|
|
32
|
+
PluginHealth(
|
|
33
|
+
status=PluginStatus.DEGRADED,
|
|
34
|
+
message="replica lag 5s",
|
|
35
|
+
details={"lag_s": 5},
|
|
36
|
+
)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`PluginRegistry` calls `health()` on every registered port to build a live snapshot — see [`PluginRegistry.health_all()`](plugins.md).
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## See Also
|
|
44
|
+
|
|
45
|
+
- [ports module](ports.md) — `Lifecycle`, `PluginHealth`, `PluginStatus`, `BasePort`
|
|
46
|
+
- [ADR-006](../../technical/architecture/adrs/adr-006-unified-port-lifecycle.md) — full design rationale
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
# Modules
|
|
2
2
|
|
|
3
|
-
`openframe-core` v3.
|
|
3
|
+
`openframe-core` v3.1.0 contains ten modules, organised into three tiers: foundation, contract layer, and application modules. Each page documents every public class, method, and function with parameters, return types, and what it raises.
|
|
4
4
|
|
|
5
5
|
| Module | Import path | What it provides |
|
|
6
6
|
|---|---|---|
|
|
7
7
|
| [exceptions](exceptions.md) | `openframe.core.exceptions` | `OpenFrameError` (root) · `ErrorCode` · `Severity` · `AdapterError` (+5) · `PluginError` (+4, incl. `AmbiguousCapabilityError`) |
|
|
8
8
|
| [config](config.md) | `openframe.core.config` | `BaseAdapterSettings` |
|
|
9
|
-
| [
|
|
10
|
-
| [ports](ports.md) | `openframe.core.ports` | `BaseRepository[T]` · `BaseProducer[T]` · `BaseConsumer[T]` — `BasePort` + domain methods |
|
|
9
|
+
| [ports](ports.md) | `openframe.core.ports` | `Identity` · `Lifecycle` · `BasePort` · `Capability` · `PluginStatus` · `PluginHealth` · `PluginContext` · `PrincipalContext` · `TenantContext` · `BaseRepository[T]` · `BaseProducer[T]` · `BaseConsumer[T]` |
|
|
11
10
|
| [inbound](inbound.md) | `openframe.core.inbound` | `UseCase[TIn, TOut]` · `CommandHandler[TIn]` · `QueryHandler[TIn, TOut]` · `RequestContext` |
|
|
12
11
|
| [telemetry](telemetry.md) | `openframe.core.telemetry` | `setup_telemetry` · `get_tracer` · `get_meter` · `record_lifecycle_event` · `record_error` |
|
|
13
12
|
| [tracing](tracing.md) | `openframe.core.tracing` | `TracingProxy` |
|
|
@@ -16,5 +15,5 @@
|
|
|
16
15
|
| [runtime](runtime.md) | `openframe.core.runtime` | `ApplicationBootstrap` |
|
|
17
16
|
| [testing](testing.md) | `openframe.core.testing` | `InMemoryRepository` · `FakeProducer` · `FakeConsumer` · contract test base classes |
|
|
18
17
|
|
|
19
|
-
!!! note "health module removed in v3.0.0"
|
|
20
|
-
The `openframe.core.health` module and `HealthCheck` protocol were removed in v3.0.0. Health is now part of the unified `Lifecycle` contract in `openframe.core.
|
|
18
|
+
!!! note "health module removed in v3.0.0; contracts merged into ports in v3.1.0"
|
|
19
|
+
The `openframe.core.health` module and `HealthCheck` protocol were removed in v3.0.0. Health is now part of the unified `Lifecycle` contract in `openframe.core.ports` (`Lifecycle.health() -> PluginHealth`). In v3.1.0, `openframe.core.contracts` was merged into `openframe.core.ports`, and the outbound protocols (`BaseRepository`, `BaseProducer`, `BaseConsumer`) moved into an internal `ports/outbound/` sub-module mirroring `openframe.core.inbound` on the driving side — the public import path (`from openframe.core.ports import ...`) is unaffected. No compatibility shim exists at the old `openframe.core.contracts` path. See the [ports module](ports.md) and [ADR-006](../../technical/architecture/adrs/adr-006-unified-port-lifecycle.md).
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
```python
|
|
12
12
|
from openframe.core.plugins import PluginRegistry
|
|
13
|
-
from openframe.core.
|
|
13
|
+
from openframe.core.ports import Capability
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
---
|
|
@@ -119,7 +119,7 @@ Return all registered ports for the given `Capability`. Returns an empty list wh
|
|
|
119
119
|
|
|
120
120
|
```python
|
|
121
121
|
from openframe.core.plugins import PluginRegistry
|
|
122
|
-
from openframe.core.
|
|
122
|
+
from openframe.core.ports import Capability
|
|
123
123
|
|
|
124
124
|
registry = PluginRegistry()
|
|
125
125
|
|
|
@@ -154,7 +154,7 @@ primary, replica = registry.get_all(Capability.PERSISTENCE)
|
|
|
154
154
|
|
|
155
155
|
```python
|
|
156
156
|
from openframe.core.runtime import ApplicationBootstrap
|
|
157
|
-
from openframe.core.
|
|
157
|
+
from openframe.core.ports import Capability
|
|
158
158
|
|
|
159
159
|
class MyApp(ApplicationBootstrap):
|
|
160
160
|
def configure(self) -> None:
|