plm-engine-core 0.1.0a0__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.
- plm_engine_core-0.1.0a0/PKG-INFO +179 -0
- plm_engine_core-0.1.0a0/README.md +162 -0
- plm_engine_core-0.1.0a0/plm_engine_core/__init__.py +24 -0
- plm_engine_core-0.1.0a0/plm_engine_core/agent_runtime/__init__.py +31 -0
- plm_engine_core-0.1.0a0/plm_engine_core/agent_runtime/dispatcher.py +343 -0
- plm_engine_core-0.1.0a0/plm_engine_core/agent_runtime/selector.py +154 -0
- plm_engine_core-0.1.0a0/plm_engine_core/cli/__init__.py +64 -0
- plm_engine_core-0.1.0a0/plm_engine_core/cli/__main__.py +15 -0
- plm_engine_core-0.1.0a0/plm_engine_core/cli/auth.py +125 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/__init__.py +52 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/_lint_fixtures/__init__.py +16 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/_lint_fixtures/violation_demo.py +28 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/capability_registry/__init__.py +45 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/capability_registry/errors.py +71 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/capability_registry/registry.py +403 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/connectors/__init__.py +53 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/connectors/dispatcher.py +148 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/connectors/runtime.py +214 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/dispatch.py +180 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/hitl/__init__.py +45 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/hitl/errors.py +74 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/hitl/gate.py +555 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/hitl/sql_store.py +380 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/identity/__init__.py +46 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/identity/middleware.py +349 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/identity/provider.py +249 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/identity/system_identity.py +92 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/identity/telemetry.py +146 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/knowledge/__init__.py +79 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/knowledge/curation_index.py +119 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/knowledge/envelope.py +358 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/knowledge/runtime.py +205 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/policies/__init__.py +74 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/policies/authorization.py +192 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/policies/autonomy_gating.py +273 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/policies/base.py +174 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/policies/cost_budget.py +490 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/policies/rate_limit.py +369 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/retry_policy.py +288 -0
- plm_engine_core-0.1.0a0/plm_engine_core/control_plane/run_task_tracker.py +262 -0
- plm_engine_core-0.1.0a0/plm_engine_core/mcp/__init__.py +63 -0
- plm_engine_core-0.1.0a0/plm_engine_core/mcp/asgi.py +195 -0
- plm_engine_core-0.1.0a0/plm_engine_core/mcp/errors.py +41 -0
- plm_engine_core-0.1.0a0/plm_engine_core/mcp/manifest.py +170 -0
- plm_engine_core-0.1.0a0/plm_engine_core/mcp/openapi.py +605 -0
- plm_engine_core-0.1.0a0/plm_engine_core/mcp/server.py +219 -0
- plm_engine_core-0.1.0a0/plm_engine_core/mcp/tools.py +544 -0
- plm_engine_core-0.1.0a0/plm_engine_core/studio/__init__.py +11 -0
- plm_engine_core-0.1.0a0/plm_engine_core/studio/readers/__init__.py +25 -0
- plm_engine_core-0.1.0a0/plm_engine_core/studio/readers/mcrc_v1.py +221 -0
- plm_engine_core-0.1.0a0/plm_engine_core.egg-info/PKG-INFO +179 -0
- plm_engine_core-0.1.0a0/plm_engine_core.egg-info/SOURCES.txt +81 -0
- plm_engine_core-0.1.0a0/plm_engine_core.egg-info/dependency_links.txt +1 -0
- plm_engine_core-0.1.0a0/plm_engine_core.egg-info/entry_points.txt +2 -0
- plm_engine_core-0.1.0a0/plm_engine_core.egg-info/requires.txt +9 -0
- plm_engine_core-0.1.0a0/plm_engine_core.egg-info/top_level.txt +1 -0
- plm_engine_core-0.1.0a0/pyproject.toml +118 -0
- plm_engine_core-0.1.0a0/setup.cfg +4 -0
- plm_engine_core-0.1.0a0/tests/test_authorization_policy.py +352 -0
- plm_engine_core-0.1.0a0/tests/test_autonomy_gating_policy.py +491 -0
- plm_engine_core-0.1.0a0/tests/test_capability_registry.py +462 -0
- plm_engine_core-0.1.0a0/tests/test_cli_auth.py +248 -0
- plm_engine_core-0.1.0a0/tests/test_connector_dispatcher.py +374 -0
- plm_engine_core-0.1.0a0/tests/test_cost_budget_policy.py +386 -0
- plm_engine_core-0.1.0a0/tests/test_error_code_mirror.py +135 -0
- plm_engine_core-0.1.0a0/tests/test_hitl_gate.py +517 -0
- plm_engine_core-0.1.0a0/tests/test_identity_middleware.py +435 -0
- plm_engine_core-0.1.0a0/tests/test_identity_provider.py +286 -0
- plm_engine_core-0.1.0a0/tests/test_import_linter.py +216 -0
- plm_engine_core-0.1.0a0/tests/test_imports.py +130 -0
- plm_engine_core-0.1.0a0/tests/test_knowledge_curation_index.py +73 -0
- plm_engine_core-0.1.0a0/tests/test_knowledge_envelope.py +278 -0
- plm_engine_core-0.1.0a0/tests/test_knowledge_runtime_adapter.py +198 -0
- plm_engine_core-0.1.0a0/tests/test_mcp_asgi.py +181 -0
- plm_engine_core-0.1.0a0/tests/test_mcp_server.py +400 -0
- plm_engine_core-0.1.0a0/tests/test_mcrc_v1_reader.py +74 -0
- plm_engine_core-0.1.0a0/tests/test_openapi.py +238 -0
- plm_engine_core-0.1.0a0/tests/test_policy_pipeline_order.py +549 -0
- plm_engine_core-0.1.0a0/tests/test_rate_limit_policy.py +430 -0
- plm_engine_core-0.1.0a0/tests/test_retry_policy.py +236 -0
- plm_engine_core-0.1.0a0/tests/test_run_task_tracker.py +359 -0
- plm_engine_core-0.1.0a0/tests/test_skill_selector.py +319 -0
- plm_engine_core-0.1.0a0/tests/test_system_identity.py +111 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: plm-engine-core
|
|
3
|
+
Version: 0.1.0a0
|
|
4
|
+
Summary: TracePulse PLM Engine Core — control_plane (governance, autonomy, HITL, run lifecycle, trace propagation) + agent_runtime (selector, dispatcher, retry, escalation). US-CR.1 scaffold; behaviour lands in US-CR.0+. Internal one-way import contract: control_plane MUST NOT import from agent_runtime (mechanical enforcement in US-CR.2).
|
|
5
|
+
Author: TracePulse
|
|
6
|
+
License: Proprietary
|
|
7
|
+
Requires-Python: >=3.12
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: plm-shared
|
|
10
|
+
Requires-Dist: PyJWT<3,>=2.8
|
|
11
|
+
Provides-Extra: test
|
|
12
|
+
Requires-Dist: pytest; extra == "test"
|
|
13
|
+
Requires-Dist: pytest-asyncio; extra == "test"
|
|
14
|
+
Requires-Dist: fastapi; extra == "test"
|
|
15
|
+
Requires-Dist: httpx; extra == "test"
|
|
16
|
+
Requires-Dist: import-linter<3,>=2.0; extra == "test"
|
|
17
|
+
|
|
18
|
+
# plm-engine-core
|
|
19
|
+
|
|
20
|
+
TracePulse PLM Engine Core package. Lives next to `plm-shared` in the
|
|
21
|
+
monorepo; shipped editable for Wave 1 (`pip install -e ../plm-engine-core`),
|
|
22
|
+
internal PyPI publication deferred to Wave 5.
|
|
23
|
+
|
|
24
|
+
US-CR.1 ships this package as **empty scaffolding**. Every other
|
|
25
|
+
US-CR.* story in FTR-607 lands its implementation inside the two
|
|
26
|
+
sub-packages declared here, on top of contracts published by
|
|
27
|
+
`plm-shared` (US-W1.0).
|
|
28
|
+
|
|
29
|
+
## Internal layout
|
|
30
|
+
|
|
31
|
+
| Sub-package | Owns | Stories landing here |
|
|
32
|
+
|------------------|----------------------------------------------------------------|-----------------------------------------------|
|
|
33
|
+
| `control_plane/` | governance, autonomy, HITL, run lifecycle, trace propagation | CR.0, CR.3, CR.4, CR.5, CR.6, CR.10, CR.13 |
|
|
34
|
+
| `agent_runtime/` | selector, dispatcher, retry, escalation | CR.10, CR.11 |
|
|
35
|
+
|
|
36
|
+
The split implements target architecture invariant **#5** — *execution
|
|
37
|
+
separated from expertise* — and decision **D-LOCKED-13**. The physical
|
|
38
|
+
repo split is deferred to V1.1; Wave 1 delivers the **logical**
|
|
39
|
+
boundary.
|
|
40
|
+
|
|
41
|
+
## One-way import contract
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
control_plane ─────► plm_shared.* (frozen contracts)
|
|
45
|
+
agent_runtime ─────► plm_shared.* (frozen contracts)
|
|
46
|
+
agent_runtime ─────► control_plane (asks for verdicts)
|
|
47
|
+
control_plane ──╳──► agent_runtime (FORBIDDEN)
|
|
48
|
+
plm_engine_core ─╳──► plm_accelerators (FORBIDDEN)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`control_plane` decides *what is allowed*; `agent_runtime` asks
|
|
52
|
+
*how do I run this*. Reversing the dependency (control_plane reading
|
|
53
|
+
runtime state) couples policy to execution and breaks the V1.1 repo
|
|
54
|
+
split. **plm-engine-core MUST NOT import from the Workbench /
|
|
55
|
+
Accelerators** package; reversing this absorption would dissolve
|
|
56
|
+
the platform / product-line boundary (anti-pattern #8).
|
|
57
|
+
|
|
58
|
+
**Mechanical enforcement (US-CR.2 / Conv F sub-story 3):** two
|
|
59
|
+
`import-linter` contracts in `pyproject.toml` fail CI on any
|
|
60
|
+
violation:
|
|
61
|
+
|
|
62
|
+
| Contract | Source | Forbidden |
|
|
63
|
+
|-----------------------------------------------------------|------------------------------|---------------------------------|
|
|
64
|
+
| `control_plane-must-not-depend-on-agent_runtime` | `plm_engine_core.control_plane` | `plm_engine_core.agent_runtime` |
|
|
65
|
+
| `plm_engine_core-must-not-depend-on-workbench` | `plm_engine_core` | `plm_accelerators` |
|
|
66
|
+
|
|
67
|
+
`if TYPE_CHECKING:` imports across the boundary are **blocked by
|
|
68
|
+
default** (CR.2 AC-6) — TYPE_CHECKING leakage is the most common
|
|
69
|
+
way the boundary erodes silently. `tests/` lives outside the
|
|
70
|
+
package and is naturally excluded.
|
|
71
|
+
|
|
72
|
+
The CR.1-era by-convention guard in `tests/test_imports.py` STAYS
|
|
73
|
+
alongside the mechanical contract. Both fire if either rule trips
|
|
74
|
+
— belt-and-braces protection if the linter contract has to be
|
|
75
|
+
relaxed for a transient reason.
|
|
76
|
+
|
|
77
|
+
### Negative-fixture toggling test
|
|
78
|
+
|
|
79
|
+
A permanent sandbox lives at
|
|
80
|
+
`plm_engine_core/control_plane/_lint_fixtures/violation_demo.py`.
|
|
81
|
+
The `tests/test_import_linter.py::test_negative_fixture_trips_*`
|
|
82
|
+
tests (gated by `RUN_LINTER_NEGATIVE=1`) materialise a temporary
|
|
83
|
+
sibling file with an offending import, run `lint-imports`, assert
|
|
84
|
+
the contract trips with the right name + file:line, then delete
|
|
85
|
+
the temp file and verify the clean state passes again. Run with:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
RUN_LINTER_NEGATIVE=1 pytest tests/test_import_linter.py -v
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Exemption process
|
|
92
|
+
|
|
93
|
+
Genuine exceptions go through an ADR signed off by the
|
|
94
|
+
architecture team. ADRs live under
|
|
95
|
+
[`02_App/plm-engine-core/docs/adr/`](docs/adr/). Each ADR records
|
|
96
|
+
the contract relaxed, the scope of the relaxation
|
|
97
|
+
(typically a specific `ignore_imports` entry on one contract),
|
|
98
|
+
the rationale, and the cross-link to D-LOCKED-13 + invariant #5.
|
|
99
|
+
The contract / `ignore_imports` edit MUST cite the ADR file path
|
|
100
|
+
in a comment so a future reader finds the authority for the
|
|
101
|
+
exemption.
|
|
102
|
+
|
|
103
|
+
### Known limitations
|
|
104
|
+
|
|
105
|
+
- **Transitive imports via `plm-shared` are not caught** (CR.2 §9 +
|
|
106
|
+
Edge cases). A control_plane file importing a plm-shared helper
|
|
107
|
+
that itself transitively imports agent_runtime is invisible to
|
|
108
|
+
the contract. Intentional — limits blast radius of a single
|
|
109
|
+
PR's contract scope.
|
|
110
|
+
- **Dynamic imports (`importlib`, string-based) are not caught**.
|
|
111
|
+
Static analysis only.
|
|
112
|
+
- **The contracts are scoped to plm-engine-core**. Cross-product-
|
|
113
|
+
line contracts (e.g. `agent_runtime → connectors`,
|
|
114
|
+
`agent_runtime → workbench`) land with Epic 6 / Epic 8.
|
|
115
|
+
|
|
116
|
+
## `with_system_identity` allowlist (CR.2 Decision #24)
|
|
117
|
+
|
|
118
|
+
`plm_engine_core.control_plane.identity.with_system_identity` is a
|
|
119
|
+
context manager that binds an `actor_kind="system"` identity for
|
|
120
|
+
in-process callers without an inbound JWT (cron, BackgroundTask,
|
|
121
|
+
GC). It bypasses JWT validation by design and MUST NOT be invoked
|
|
122
|
+
from arbitrary call sites.
|
|
123
|
+
|
|
124
|
+
The path-based BL6 guardrail in
|
|
125
|
+
[`02_App/backend/scripts/architecture_guardrails.py`](../backend/scripts/architecture_guardrails.py)
|
|
126
|
+
restricts the importer set. Initial allowlist:
|
|
127
|
+
|
|
128
|
+
- `plm_engine_core/control_plane/identity/system_identity.py` — defining module.
|
|
129
|
+
- `plm_engine_core/control_plane/identity/__init__.py` — re-export site.
|
|
130
|
+
- `plm_engine_core/cli/` — `plm-cli` future subcommands may bind a
|
|
131
|
+
system identity for offline operations.
|
|
132
|
+
- `tests/` — fixtures may import freely.
|
|
133
|
+
|
|
134
|
+
Adding a new module to the allowlist requires an ADR.
|
|
135
|
+
|
|
136
|
+
## Install (developer)
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
cd 02_App/backend
|
|
140
|
+
pip install -e ../plm-engine-core
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
The editable install puts `plm_engine_core.*` on the sys.path of the
|
|
144
|
+
backend venv. Like `plm-shared`, **`pip install` MUST run from
|
|
145
|
+
`02_App/backend/`** because pip resolves `-e ../plm-engine-core`
|
|
146
|
+
relative to the invocation CWD.
|
|
147
|
+
|
|
148
|
+
## Tests
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
cd 02_App/plm-engine-core
|
|
152
|
+
python -m pytest tests/ -v
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
The smoke test verifies:
|
|
156
|
+
- Both sub-packages import cleanly.
|
|
157
|
+
- `__all__` placeholders match the documented public surface.
|
|
158
|
+
- No `control_plane` module imports from `agent_runtime` (one-way
|
|
159
|
+
contract guard, AC-10).
|
|
160
|
+
- No business logic has snuck in beyond `__init__.py` files (AC-9
|
|
161
|
+
scope-creep guard).
|
|
162
|
+
|
|
163
|
+
## CI
|
|
164
|
+
|
|
165
|
+
`.github/workflows/test.yml` runs a `plm-engine-core-tests` job
|
|
166
|
+
mirroring `plm-shared-tests` — editable-install + pytest on every
|
|
167
|
+
push to `main` / `FTR575-Codebase-Split` and on every PR touching
|
|
168
|
+
`02_App/**`.
|
|
169
|
+
|
|
170
|
+
## Status
|
|
171
|
+
|
|
172
|
+
- **US-CR.1**: scaffold (Conv E close `822c415`). Ships placeholders only.
|
|
173
|
+
- **US-CR.0** (Wave 1 Conv E + Conv F): `IdentityMiddleware`,
|
|
174
|
+
`Hs256JwtIdentityProvider`, `with_system_identity`, `audit_log`
|
|
175
|
+
migration 0013, and `plm-cli auth issue-token` all land. 16/16 ACs
|
|
176
|
+
covered; story closed Conv F (3/3 PRs).
|
|
177
|
+
- **US-CR.2** (Wave 1 Conv F): two import-linter Forbidden contracts +
|
|
178
|
+
permanent negative-fixture toggling test + BL6 path-based guardrail
|
|
179
|
+
for `with_system_identity` + ADR exemption process.
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# plm-engine-core
|
|
2
|
+
|
|
3
|
+
TracePulse PLM Engine Core package. Lives next to `plm-shared` in the
|
|
4
|
+
monorepo; shipped editable for Wave 1 (`pip install -e ../plm-engine-core`),
|
|
5
|
+
internal PyPI publication deferred to Wave 5.
|
|
6
|
+
|
|
7
|
+
US-CR.1 ships this package as **empty scaffolding**. Every other
|
|
8
|
+
US-CR.* story in FTR-607 lands its implementation inside the two
|
|
9
|
+
sub-packages declared here, on top of contracts published by
|
|
10
|
+
`plm-shared` (US-W1.0).
|
|
11
|
+
|
|
12
|
+
## Internal layout
|
|
13
|
+
|
|
14
|
+
| Sub-package | Owns | Stories landing here |
|
|
15
|
+
|------------------|----------------------------------------------------------------|-----------------------------------------------|
|
|
16
|
+
| `control_plane/` | governance, autonomy, HITL, run lifecycle, trace propagation | CR.0, CR.3, CR.4, CR.5, CR.6, CR.10, CR.13 |
|
|
17
|
+
| `agent_runtime/` | selector, dispatcher, retry, escalation | CR.10, CR.11 |
|
|
18
|
+
|
|
19
|
+
The split implements target architecture invariant **#5** — *execution
|
|
20
|
+
separated from expertise* — and decision **D-LOCKED-13**. The physical
|
|
21
|
+
repo split is deferred to V1.1; Wave 1 delivers the **logical**
|
|
22
|
+
boundary.
|
|
23
|
+
|
|
24
|
+
## One-way import contract
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
control_plane ─────► plm_shared.* (frozen contracts)
|
|
28
|
+
agent_runtime ─────► plm_shared.* (frozen contracts)
|
|
29
|
+
agent_runtime ─────► control_plane (asks for verdicts)
|
|
30
|
+
control_plane ──╳──► agent_runtime (FORBIDDEN)
|
|
31
|
+
plm_engine_core ─╳──► plm_accelerators (FORBIDDEN)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`control_plane` decides *what is allowed*; `agent_runtime` asks
|
|
35
|
+
*how do I run this*. Reversing the dependency (control_plane reading
|
|
36
|
+
runtime state) couples policy to execution and breaks the V1.1 repo
|
|
37
|
+
split. **plm-engine-core MUST NOT import from the Workbench /
|
|
38
|
+
Accelerators** package; reversing this absorption would dissolve
|
|
39
|
+
the platform / product-line boundary (anti-pattern #8).
|
|
40
|
+
|
|
41
|
+
**Mechanical enforcement (US-CR.2 / Conv F sub-story 3):** two
|
|
42
|
+
`import-linter` contracts in `pyproject.toml` fail CI on any
|
|
43
|
+
violation:
|
|
44
|
+
|
|
45
|
+
| Contract | Source | Forbidden |
|
|
46
|
+
|-----------------------------------------------------------|------------------------------|---------------------------------|
|
|
47
|
+
| `control_plane-must-not-depend-on-agent_runtime` | `plm_engine_core.control_plane` | `plm_engine_core.agent_runtime` |
|
|
48
|
+
| `plm_engine_core-must-not-depend-on-workbench` | `plm_engine_core` | `plm_accelerators` |
|
|
49
|
+
|
|
50
|
+
`if TYPE_CHECKING:` imports across the boundary are **blocked by
|
|
51
|
+
default** (CR.2 AC-6) — TYPE_CHECKING leakage is the most common
|
|
52
|
+
way the boundary erodes silently. `tests/` lives outside the
|
|
53
|
+
package and is naturally excluded.
|
|
54
|
+
|
|
55
|
+
The CR.1-era by-convention guard in `tests/test_imports.py` STAYS
|
|
56
|
+
alongside the mechanical contract. Both fire if either rule trips
|
|
57
|
+
— belt-and-braces protection if the linter contract has to be
|
|
58
|
+
relaxed for a transient reason.
|
|
59
|
+
|
|
60
|
+
### Negative-fixture toggling test
|
|
61
|
+
|
|
62
|
+
A permanent sandbox lives at
|
|
63
|
+
`plm_engine_core/control_plane/_lint_fixtures/violation_demo.py`.
|
|
64
|
+
The `tests/test_import_linter.py::test_negative_fixture_trips_*`
|
|
65
|
+
tests (gated by `RUN_LINTER_NEGATIVE=1`) materialise a temporary
|
|
66
|
+
sibling file with an offending import, run `lint-imports`, assert
|
|
67
|
+
the contract trips with the right name + file:line, then delete
|
|
68
|
+
the temp file and verify the clean state passes again. Run with:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
RUN_LINTER_NEGATIVE=1 pytest tests/test_import_linter.py -v
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Exemption process
|
|
75
|
+
|
|
76
|
+
Genuine exceptions go through an ADR signed off by the
|
|
77
|
+
architecture team. ADRs live under
|
|
78
|
+
[`02_App/plm-engine-core/docs/adr/`](docs/adr/). Each ADR records
|
|
79
|
+
the contract relaxed, the scope of the relaxation
|
|
80
|
+
(typically a specific `ignore_imports` entry on one contract),
|
|
81
|
+
the rationale, and the cross-link to D-LOCKED-13 + invariant #5.
|
|
82
|
+
The contract / `ignore_imports` edit MUST cite the ADR file path
|
|
83
|
+
in a comment so a future reader finds the authority for the
|
|
84
|
+
exemption.
|
|
85
|
+
|
|
86
|
+
### Known limitations
|
|
87
|
+
|
|
88
|
+
- **Transitive imports via `plm-shared` are not caught** (CR.2 §9 +
|
|
89
|
+
Edge cases). A control_plane file importing a plm-shared helper
|
|
90
|
+
that itself transitively imports agent_runtime is invisible to
|
|
91
|
+
the contract. Intentional — limits blast radius of a single
|
|
92
|
+
PR's contract scope.
|
|
93
|
+
- **Dynamic imports (`importlib`, string-based) are not caught**.
|
|
94
|
+
Static analysis only.
|
|
95
|
+
- **The contracts are scoped to plm-engine-core**. Cross-product-
|
|
96
|
+
line contracts (e.g. `agent_runtime → connectors`,
|
|
97
|
+
`agent_runtime → workbench`) land with Epic 6 / Epic 8.
|
|
98
|
+
|
|
99
|
+
## `with_system_identity` allowlist (CR.2 Decision #24)
|
|
100
|
+
|
|
101
|
+
`plm_engine_core.control_plane.identity.with_system_identity` is a
|
|
102
|
+
context manager that binds an `actor_kind="system"` identity for
|
|
103
|
+
in-process callers without an inbound JWT (cron, BackgroundTask,
|
|
104
|
+
GC). It bypasses JWT validation by design and MUST NOT be invoked
|
|
105
|
+
from arbitrary call sites.
|
|
106
|
+
|
|
107
|
+
The path-based BL6 guardrail in
|
|
108
|
+
[`02_App/backend/scripts/architecture_guardrails.py`](../backend/scripts/architecture_guardrails.py)
|
|
109
|
+
restricts the importer set. Initial allowlist:
|
|
110
|
+
|
|
111
|
+
- `plm_engine_core/control_plane/identity/system_identity.py` — defining module.
|
|
112
|
+
- `plm_engine_core/control_plane/identity/__init__.py` — re-export site.
|
|
113
|
+
- `plm_engine_core/cli/` — `plm-cli` future subcommands may bind a
|
|
114
|
+
system identity for offline operations.
|
|
115
|
+
- `tests/` — fixtures may import freely.
|
|
116
|
+
|
|
117
|
+
Adding a new module to the allowlist requires an ADR.
|
|
118
|
+
|
|
119
|
+
## Install (developer)
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
cd 02_App/backend
|
|
123
|
+
pip install -e ../plm-engine-core
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The editable install puts `plm_engine_core.*` on the sys.path of the
|
|
127
|
+
backend venv. Like `plm-shared`, **`pip install` MUST run from
|
|
128
|
+
`02_App/backend/`** because pip resolves `-e ../plm-engine-core`
|
|
129
|
+
relative to the invocation CWD.
|
|
130
|
+
|
|
131
|
+
## Tests
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
cd 02_App/plm-engine-core
|
|
135
|
+
python -m pytest tests/ -v
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
The smoke test verifies:
|
|
139
|
+
- Both sub-packages import cleanly.
|
|
140
|
+
- `__all__` placeholders match the documented public surface.
|
|
141
|
+
- No `control_plane` module imports from `agent_runtime` (one-way
|
|
142
|
+
contract guard, AC-10).
|
|
143
|
+
- No business logic has snuck in beyond `__init__.py` files (AC-9
|
|
144
|
+
scope-creep guard).
|
|
145
|
+
|
|
146
|
+
## CI
|
|
147
|
+
|
|
148
|
+
`.github/workflows/test.yml` runs a `plm-engine-core-tests` job
|
|
149
|
+
mirroring `plm-shared-tests` — editable-install + pytest on every
|
|
150
|
+
push to `main` / `FTR575-Codebase-Split` and on every PR touching
|
|
151
|
+
`02_App/**`.
|
|
152
|
+
|
|
153
|
+
## Status
|
|
154
|
+
|
|
155
|
+
- **US-CR.1**: scaffold (Conv E close `822c415`). Ships placeholders only.
|
|
156
|
+
- **US-CR.0** (Wave 1 Conv E + Conv F): `IdentityMiddleware`,
|
|
157
|
+
`Hs256JwtIdentityProvider`, `with_system_identity`, `audit_log`
|
|
158
|
+
migration 0013, and `plm-cli auth issue-token` all land. 16/16 ACs
|
|
159
|
+
covered; story closed Conv F (3/3 PRs).
|
|
160
|
+
- **US-CR.2** (Wave 1 Conv F): two import-linter Forbidden contracts +
|
|
161
|
+
permanent negative-fixture toggling test + BL6 path-based guardrail
|
|
162
|
+
for `with_system_identity` + ADR exemption process.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""plm-engine-core — TracePulse PLM Engine Core package (US-CR.1 scaffold).
|
|
2
|
+
|
|
3
|
+
Internally split into two sub-packages aligned with target architecture
|
|
4
|
+
invariant #5 ("execution separated from expertise") and decision
|
|
5
|
+
D-LOCKED-13:
|
|
6
|
+
|
|
7
|
+
* `control_plane/` — governance, autonomy, HITL, run lifecycle,
|
|
8
|
+
trace propagation. Owns *what is allowed*.
|
|
9
|
+
* `agent_runtime/` — selector, dispatcher, retry, escalation.
|
|
10
|
+
Owns *how skills execute*.
|
|
11
|
+
|
|
12
|
+
One-way import contract: `control_plane` MUST NOT import from
|
|
13
|
+
`agent_runtime`. Mechanical enforcement (import-linter rule) lands
|
|
14
|
+
in US-CR.2; until then the rule is documented in README and observed
|
|
15
|
+
by convention.
|
|
16
|
+
|
|
17
|
+
US-CR.1 ships this scaffold deliberately empty — every other US-CR.*
|
|
18
|
+
story (CR.0 identity middleware, CR.2 boundary lint, CR.3-6 policies,
|
|
19
|
+
CR.7 MCP server, CR.8 OpenAPI, CR.9 federated manifest, CR.10 selector,
|
|
20
|
+
CR.11 retry, CR.12 capability registry, CR.13 HITL) lands its
|
|
21
|
+
implementation inside these clear, enforceable internal boundaries
|
|
22
|
+
from day one.
|
|
23
|
+
"""
|
|
24
|
+
__version__ = "0.1.0-alpha"
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""plm_engine_core.agent_runtime — selector + dispatcher + retry +
|
|
2
|
+
escalation (US-CR.1 scaffold).
|
|
3
|
+
|
|
4
|
+
Owns *how skills execute*: skill selection, Kernel dispatch, retry
|
|
5
|
+
orchestration on transient failures, escalation when retries
|
|
6
|
+
exhaust. Downstream stories land here:
|
|
7
|
+
|
|
8
|
+
* US-CR.10 — skill selector → Kernel dispatch loopback (runtime side).
|
|
9
|
+
* US-CR.11 — externalised RetryPolicy module.
|
|
10
|
+
|
|
11
|
+
`agent_runtime` may import from `plm_shared.*` (frozen contracts) and
|
|
12
|
+
from `plm_engine_core.control_plane` is **forbidden** by the one-way
|
|
13
|
+
import rule. Decisions about what is allowed live in `control_plane`;
|
|
14
|
+
the runtime asks control_plane for verdicts but does not depend on
|
|
15
|
+
its internals.
|
|
16
|
+
|
|
17
|
+
The `__all__` placeholders below name the public surface downstream
|
|
18
|
+
stories will populate. Importing any of them today raises
|
|
19
|
+
`ImportError` because the modules don't exist yet — placeholder
|
|
20
|
+
list is the contract, not a runtime shim.
|
|
21
|
+
"""
|
|
22
|
+
__all__ = [
|
|
23
|
+
# US-CR.10 — skill selection from a tenant + capability scope.
|
|
24
|
+
"selector",
|
|
25
|
+
# Kernel dispatch loop (runtime side of US-CR.10).
|
|
26
|
+
"dispatcher",
|
|
27
|
+
# US-CR.11 — externalised retry policy (taxonomy-aware).
|
|
28
|
+
"retry",
|
|
29
|
+
# Escalation when retries exhaust or autonomy gate denies.
|
|
30
|
+
"escalation",
|
|
31
|
+
]
|