responsibility-pathway-runtime 0.1.0a2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. responsibility_pathway_runtime-0.1.0a2.dist-info/METADATA +113 -0
  2. responsibility_pathway_runtime-0.1.0a2.dist-info/RECORD +65 -0
  3. responsibility_pathway_runtime-0.1.0a2.dist-info/WHEEL +5 -0
  4. responsibility_pathway_runtime-0.1.0a2.dist-info/entry_points.txt +2 -0
  5. responsibility_pathway_runtime-0.1.0a2.dist-info/licenses/LICENSE +21 -0
  6. responsibility_pathway_runtime-0.1.0a2.dist-info/top_level.txt +1 -0
  7. rpr/__init__.py +36 -0
  8. rpr/_generated_transitions.py +25 -0
  9. rpr/agent_adapters.py +88 -0
  10. rpr/assurance_manifest.py +195 -0
  11. rpr/attempts.py +402 -0
  12. rpr/authority.py +91 -0
  13. rpr/backup.py +126 -0
  14. rpr/candidate_readiness.py +98 -0
  15. rpr/canonical_transition_spec.py +75 -0
  16. rpr/claim_traceability.py +138 -0
  17. rpr/clean_export.py +124 -0
  18. rpr/cli.py +26 -0
  19. rpr/compensation.py +38 -0
  20. rpr/customer_handover.py +189 -0
  21. rpr/delivery_acceptance.py +140 -0
  22. rpr/delivery_acceptance_baseline.py +79 -0
  23. rpr/dependency_inventory.py +77 -0
  24. rpr/diagnostics.py +103 -0
  25. rpr/epistemic_claims.py +181 -0
  26. rpr/evidence.py +53 -0
  27. rpr/executor.py +107 -0
  28. rpr/formal_consistency.py +127 -0
  29. rpr/hash_bundle.py +48 -0
  30. rpr/http_executor.py +144 -0
  31. rpr/identity.py +103 -0
  32. rpr/inspection.py +67 -0
  33. rpr/integration_acceptance_inventory.py +86 -0
  34. rpr/launch_claims.py +49 -0
  35. rpr/lifecycle_acceptance.py +320 -0
  36. rpr/mcp_admission.py +277 -0
  37. rpr/mcp_compatibility.py +95 -0
  38. rpr/mcp_jsonrpc_session.py +136 -0
  39. rpr/mcp_local_subprocess_stdio.py +214 -0
  40. rpr/mcp_retained_evidence.py +194 -0
  41. rpr/mcp_stable_snapshot.py +135 -0
  42. rpr/mcp_stable_transport.py +134 -0
  43. rpr/mcp_stdio_channel.py +144 -0
  44. rpr/mcp_stdio_framing.py +169 -0
  45. rpr/mcp_subprocess_lifecycle.py +147 -0
  46. rpr/mcp_tool_executor.py +188 -0
  47. rpr/message_executor.py +154 -0
  48. rpr/models.py +116 -0
  49. rpr/principal.py +51 -0
  50. rpr/py.typed +0 -0
  51. rpr/rc_execution.py +189 -0
  52. rpr/read_only_connection.py +117 -0
  53. rpr/reconciliation.py +63 -0
  54. rpr/redaction.py +51 -0
  55. rpr/release_audit.py +111 -0
  56. rpr/release_gate.py +63 -0
  57. rpr/repair.py +170 -0
  58. rpr/rpe.py +128 -0
  59. rpr/runtime.py +363 -0
  60. rpr/sbom.py +71 -0
  61. rpr/security_review.py +69 -0
  62. rpr/source_context.py +81 -0
  63. rpr/state_machine.py +17 -0
  64. rpr/storage.py +210 -0
  65. rpr/tenant.py +141 -0
@@ -0,0 +1,113 @@
1
+ Metadata-Version: 2.4
2
+ Name: responsibility-pathway-runtime
3
+ Version: 0.1.0a2
4
+ Summary: A responsibility-pathway runtime for AI agent actions
5
+ Author: Akihisa Ono
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://yutorikomeiji.github.io/responsibility-pathway-runtime/
8
+ Project-URL: Documentation, https://yutorikomeiji.github.io/responsibility-pathway-runtime/
9
+ Project-URL: Repository, https://github.com/YutoriKomeiji/responsibility-pathway-runtime
10
+ Project-URL: Issues, https://github.com/YutoriKomeiji/responsibility-pathway-runtime/issues
11
+ Project-URL: Demo, https://yutorikomeiji.github.io/responsibility-pathway-runtime/demo.html
12
+ Keywords: ai-agents,governance,responsibility,human-in-the-loop,runtime
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Classifier: Topic :: Software Development :: Quality Assurance
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.11
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Dynamic: license-file
25
+
26
+ # Responsibility Pathway Runtime
27
+
28
+ **Govern external actions without losing evidence, recovery, or the human decision point.**
29
+
30
+ Responsibility Pathway Runtime (RPR) is an MIT-licensed Python runtime for applications that need to place an explicit responsibility pathway in front of consequential external actions. It helps a host application preserve actor and authority declarations, execution-attempt continuity, readback evidence, fail-closed ambiguity handling, repair routes, and Human Gate decisions.
31
+
32
+ > **Public alpha source and live demo — 0.1.0a2**
33
+ > Freeze ID: `RPR-CF-2026-08-02-01`
34
+ > Tested final rehearsal profile: Linux, Python 3.11
35
+ > The repository, product site, and browser demo are public. A final tag, GitHub Release, and package-registry distribution have not yet been published.
36
+ > RPR is not a legal-responsibility engine, identity provider, secret manager, production gateway, or guarantee of exactly-once effects across arbitrary remote systems.
37
+
38
+ [Product site](https://yutorikomeiji.github.io/responsibility-pathway-runtime/) · [Live browser demo](https://yutorikomeiji.github.io/responsibility-pathway-runtime/demo.html) · [日本語の入口](docs/ja/README.md) · [Quick Start](docs/en/quick-start.md) · [Product documentation](docs/en/README.md) · [Report an issue](https://github.com/YutoriKomeiji/responsibility-pathway-runtime/issues)
39
+
40
+ ## Why RPR
41
+
42
+ AI agents and automation can execute faster than people can reconstruct what happened. RPR provides a bounded runtime layer where an integrating application can:
43
+
44
+ - declare actors, authority, and the proposed action;
45
+ - evaluate and retain an explicit pathway state;
46
+ - bind operations, attempts, and idempotency identity;
47
+ - require independent readback before completion;
48
+ - stop ambiguous writes as `write_status_unknown` instead of false success;
49
+ - retain Human Gate, repair, resume, reconciliation, and evidence continuity;
50
+ - survive restart without silently repeating unresolved effects.
51
+
52
+ ## Verified in the frozen alpha candidate
53
+
54
+ - pathway registration and authorized state transitions;
55
+ - persistent pathway and execution-attempt stores;
56
+ - Human Gate, repair, resume, and reconciliation boundaries;
57
+ - local-file, allow-listed HTTP, durable outbound-message, and real MCP subprocess paths;
58
+ - HTTP and MCP fault injection;
59
+ - crash/restart continuity and duplicate-dispatch prevention;
60
+ - backup, restore, diagnostics, uninstall, package/CLI residue checks, and customer-data retention;
61
+ - clean wheel and source-distribution installation;
62
+ - two independent byte-for-byte reproducible builds;
63
+ - English-primary and Japanese-parallel product documentation;
64
+ - Lean 4 verification of selected published state-machine invariants;
65
+ - Chromium and Pyodide execution of the CI-built RPR wheel in the public browser demo.
66
+
67
+ ## We need field-test reports for
68
+
69
+ RPR is public so real users can report reproducible environment and integration findings. Please open an Issue for:
70
+
71
+ - Windows, macOS, other Linux distributions, containers, and Python environments beyond the final Linux/Python 3.11 rehearsal;
72
+ - proxy, TLS, enterprise identity, credential handling, remote MCP, and service-specific connectivity;
73
+ - framework, agent, CI/CD, RPA, batch, and application integrations;
74
+ - installation, upgrade, backup/restore, removal, and operational usability;
75
+ - confusing states, missing examples, documentation gaps, and unsupported assumptions.
76
+
77
+ A user report is field evidence for that environment. It does not imply universal production readiness.
78
+
79
+ ## Quick Start
80
+
81
+ Until a package-registry distribution or GitHub Release is published, install from the public repository in a disposable environment:
82
+
83
+ ```bash
84
+ git clone https://github.com/YutoriKomeiji/responsibility-pathway-runtime.git
85
+ cd responsibility-pathway-runtime
86
+ python3.11 -m venv .venv
87
+ . .venv/bin/activate
88
+ python -m pip install --upgrade pip
89
+ python -m pip install -e .
90
+ rpr --help
91
+ ```
92
+
93
+ To inspect the runtime without installing it locally, use the [live browser demo](https://yutorikomeiji.github.io/responsibility-pathway-runtime/demo.html). The demo runs the CI-built RPR wheel in Pyodide with SQLite; only the external payment provider is simulated.
94
+
95
+ The verified candidate artifact hashes are recorded in [`release-evidence/replacement-freeze-2026-08-02.json`](release-evidence/replacement-freeze-2026-08-02.json). Those candidate artifacts are not yet a general package distribution.
96
+
97
+ ## Integration boundary
98
+
99
+ The host application remains responsible for authentication, credential isolation, network controls, bypass prevention, domain-specific authorization, and the independent readback source. RPE integration is optional; RPE absence, malformed output, or unsupported results must not become implicit permission.
100
+
101
+ ## Documentation
102
+
103
+ - [Product, scope, and architecture](docs/en/product-scope-architecture.md)
104
+ - [Installation, operations, and recovery](docs/en/install-operations-recovery.md)
105
+ - [Security, limitations, integration, and API](docs/en/security-integration-api.md)
106
+ - [Verification, known issues, release notes, and UAT](docs/en/verification-release-uat.md)
107
+ - [Support and field testing](SUPPORT.md)
108
+ - [Security reporting](SECURITY.md)
109
+ - [Contributing](CONTRIBUTING.md)
110
+
111
+ ## License
112
+
113
+ RPR is released under the [MIT License](LICENSE). Copyright © 2026 Akihisa Ono.
@@ -0,0 +1,65 @@
1
+ responsibility_pathway_runtime-0.1.0a2.dist-info/licenses/LICENSE,sha256=LOorZGMvZRrYKJ7_pFyNmfvOz0GxAVHDX_S_l3wxuPM,1068
2
+ rpr/__init__.py,sha256=RwGPcjeqfWFUj55KhaxOCRuEu8Im9INhstTGOYyQqS0,2981
3
+ rpr/_generated_transitions.py,sha256=76Ndlgntg1rzibkBOLWFQy6w5k0YBFsJPqgIao0jR_4,1697
4
+ rpr/agent_adapters.py,sha256=bo-M_uCHEa0go0nh2jzw49wJrv3JMyJVsKiHzlUsWVU,3500
5
+ rpr/assurance_manifest.py,sha256=GB3FCNws4lqRgPje5kDb0IwRR52oyODqPBkRjWw7PeE,8700
6
+ rpr/attempts.py,sha256=KVIau_IerQr5Z1KexeouV3FDV0Fa9eGHgfP0lGmklIA,16080
7
+ rpr/authority.py,sha256=g2fCHOO0lN-3lNlL4iOj5JZCQ_o12JMIUItvYOQr590,3932
8
+ rpr/backup.py,sha256=2Dr6ZWaxlczxHN8MnA78VenM3RlPC3eEwOcyQiLCwFw,4359
9
+ rpr/candidate_readiness.py,sha256=x2Ze789xJ-rgTIXCb4fZjg8KUJxhiAxJ1bl-LlSMltY,3657
10
+ rpr/canonical_transition_spec.py,sha256=hypwigmluciw4OxQrDVwC6zbintodr3scS1bDpNYZ5k,2984
11
+ rpr/claim_traceability.py,sha256=PySi0oF5GbGfHPaIiEj0MsJ_IiS-pG3cgcdIWYGR8tg,6761
12
+ rpr/clean_export.py,sha256=gJXqN_Aem2qBkXMJEbTMtczPhMLD7wN0Jngppq4gyRU,4683
13
+ rpr/cli.py,sha256=N3H0Mh8tdaYToo6x57w3m4nuONVpMiUjrMqtNXKaiAA,863
14
+ rpr/compensation.py,sha256=zer6PUVXOv5jIDhUIZIHft3aR5hXRGkamn4GGSUNRl4,1243
15
+ rpr/customer_handover.py,sha256=6Ob7zBbTZKYIzx2hMsWfgTbTBnvKEaa_9Fp0YgwkEp0,9072
16
+ rpr/delivery_acceptance.py,sha256=xcjXNQlbfg6dICMF6dkbN5pPMl_6k5e4r6kCh9gcBbE,5166
17
+ rpr/delivery_acceptance_baseline.py,sha256=-UV3Kqu8eeF-jS_bF0_GqCW3AQUZPbcxaXHfCL7zjIk,2730
18
+ rpr/dependency_inventory.py,sha256=gFJ58jgjoXUNV-WyPiosx4JBXGXZl0kjTGw5Z-Givvw,2676
19
+ rpr/diagnostics.py,sha256=eh4PhXoiW-bXO6x_7Y56chErxKdqMUWXcpMfV3__7HI,4027
20
+ rpr/epistemic_claims.py,sha256=a_bQO8QchO9XGsB6fqTsCKiC_I__OW6HWLsUTSplB-U,7840
21
+ rpr/evidence.py,sha256=3JD6cwuzquBS1khY1dbZTJD8AWbMJFrNU7SfoIfvT3E,2423
22
+ rpr/executor.py,sha256=KnpJfJ72l8DAwFestEcv5YtckHSujRTYQAt2S4nGBAk,4468
23
+ rpr/formal_consistency.py,sha256=LeXzJ85_ccoZXpbTYXLKYkOkRTUu0QTqa1T575GNOcc,4810
24
+ rpr/hash_bundle.py,sha256=T6G8G9ZVuofEL4AX8ac9OibUyMuIzz-t50BcHW9nu8c,1721
25
+ rpr/http_executor.py,sha256=LUpCM81pLorr85l1XJfqHHXn-mUP4vnrv8Oa4OQZciM,7237
26
+ rpr/identity.py,sha256=3t069R-MLc_qPf3pQbbQJ_WzKOIcWozeOfQz4wZPBeQ,4469
27
+ rpr/inspection.py,sha256=liHt9YvdMVCyP4w5Ba659F8Wsk115qIjB-nLrDZlv7c,3390
28
+ rpr/integration_acceptance_inventory.py,sha256=A3UOhB8WFNyBC3IKzkbeaNZOKYfArAJy4Cs-Q_mvifY,3824
29
+ rpr/launch_claims.py,sha256=-uwm9TJR1U4NlchM-L3gw0xCEJ_wT-LZ-mM0jjjLRTk,1875
30
+ rpr/lifecycle_acceptance.py,sha256=O565Bd0NXNsPiusT8f_NRYYs1Ne_kGB2alMd7Y-Sz4o,12575
31
+ rpr/mcp_admission.py,sha256=lDK-xViedg8vh79ugl8ctVJ1kevPfR80qWiL8_HqNqM,10551
32
+ rpr/mcp_compatibility.py,sha256=m2c0MQJ67K3PkRUq-m62tS3gT1cXdgD_3O46IvVsQn8,5174
33
+ rpr/mcp_jsonrpc_session.py,sha256=IoE-56uYeTt62KBiWcG6AW-IafGn0m4U8FatvueUQ8o,5627
34
+ rpr/mcp_local_subprocess_stdio.py,sha256=VGjzkMz3UHIsH7kJRlKdqhZpDFe0hSa6ULYYU-IxZHo,8373
35
+ rpr/mcp_retained_evidence.py,sha256=Orvkexedbt3ifOAojbv91h8ioSr89-p8FS_iwCzxf04,6989
36
+ rpr/mcp_stable_snapshot.py,sha256=6Mk-5CYAUFGAv7yd5M9kUCZsfeo2Yl0Ey87noxhHBAA,5502
37
+ rpr/mcp_stable_transport.py,sha256=HOGQeVP2ckysRxlKnu6qLPka6T2WMK8UuygKwc8H-8Y,4872
38
+ rpr/mcp_stdio_channel.py,sha256=wpqSmIbAkwRYiiMjMjXCsuYp3Ee69wqfCuAsvdf4lhY,5376
39
+ rpr/mcp_stdio_framing.py,sha256=aKScCDcvArJAhA5NLC16_uzo39TsUxfiYIf3_gcizCM,6400
40
+ rpr/mcp_subprocess_lifecycle.py,sha256=flm3TrNeLz4x-HV52-ZHJKTozEHOh81zo9K4ktp7teM,5238
41
+ rpr/mcp_tool_executor.py,sha256=XbjU3A71HqF0WQojPvIKIVur5I4QrLo7uJgNLL9xgJI,7315
42
+ rpr/message_executor.py,sha256=7YLfSXkqmvPcq3WQ8oq0SLFBVwCt_lG5S1wC5OcwObs,7580
43
+ rpr/models.py,sha256=G8kTSyla5t1HWmKjBMWxg_AJ_7rtDYsi2wjSSb4WblA,3556
44
+ rpr/principal.py,sha256=1lOT8Ym2FcW7INRJqHfbKTwWSxHXX86HMiVaqhYEphw,1607
45
+ rpr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
+ rpr/rc_execution.py,sha256=YO3Mj_wO79QW5W_HtbBhuPQr4ahW29ndqHSeHRP3lE4,8634
47
+ rpr/read_only_connection.py,sha256=XgBKOvCibFQtNJ97M8A6dJOw0Rcs4IiPg4AovoNEqpE,4401
48
+ rpr/reconciliation.py,sha256=deou6YeGqaXVKiQisvlb6bL5sFzcFwRSemvM6M0qwGY,2292
49
+ rpr/redaction.py,sha256=Pdq48eprlyxb9BvHVnwmXn9jeJ5BXdUEAPo9xO_Udvw,1916
50
+ rpr/release_audit.py,sha256=enbOK5pfcNfUa2YbhL-38J6TIDGM4J3-SX06pJCzAs8,4344
51
+ rpr/release_gate.py,sha256=Gd219MNz2BrAIAybTyoCpYK-PsES46MByUlmcC1lfl0,2335
52
+ rpr/repair.py,sha256=Z1vW1FOZ-RUBa7hUMC7CrjZcp_qiqMTn4Ua7Ai2TliM,6749
53
+ rpr/rpe.py,sha256=qOY8uql_ZWrJXwvYqKZGKRsRhE_exZY6i7C_GL_EHZ0,5145
54
+ rpr/runtime.py,sha256=zk5Dh_D9hdka_Sc87G4zTiEOOPUdEYz6ODOOJE79hEo,21880
55
+ rpr/sbom.py,sha256=Dj-zjO7be1v2CNJ1_KBhoxFyNlinkr3oUxHgEXjAl8w,2764
56
+ rpr/security_review.py,sha256=JXGSoUauhz-Z-NDDd-RJrjwroCwcBQM_PNO440rPcnI,2616
57
+ rpr/source_context.py,sha256=0leXTlorPZXVFGKjyDEpgnTiynMYU7tlEyr8h1AsDoU,3112
58
+ rpr/state_machine.py,sha256=ulnlef4AC3dpxsSEq8ueXWT_VusyVkwLl6v8TXn3VCA,483
59
+ rpr/storage.py,sha256=nw_1ON27XUNqGUKlSXHZ3PByudjBr5uyjkOv5W4F1Jw,9693
60
+ rpr/tenant.py,sha256=LevzR8eipmRe0NNDQi1feD0Tk2zbRBzxX5lQ51C15VM,6242
61
+ responsibility_pathway_runtime-0.1.0a2.dist-info/METADATA,sha256=c00NvzEtcV00UJkCkLmWfuKB3ufXpZWKZkFb_yOmFsY,6538
62
+ responsibility_pathway_runtime-0.1.0a2.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
63
+ responsibility_pathway_runtime-0.1.0a2.dist-info/entry_points.txt,sha256=Rtm2BOb2RUFT7LRVK3ADREGxPELseAz_dRxMPplULhU,37
64
+ responsibility_pathway_runtime-0.1.0a2.dist-info/top_level.txt,sha256=-MpVZCITUsm3s5OxjrfOYmnLAMxTal0N1KewaSYPJrU,4
65
+ responsibility_pathway_runtime-0.1.0a2.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (83.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ rpr = rpr.cli:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Akihisa Ono
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
rpr/__init__.py ADDED
@@ -0,0 +1,36 @@
1
+ # Copyright (c) 2026 Akihisa Ono
2
+ # SPDX-License-Identifier: MIT
3
+ """Responsibility Pathway Runtime public API."""
4
+
5
+ from .agent_adapters import AgentToolCall, AgentToolOutcome, RprToolBoundary, langgraph_tool_node, openai_function_tool_handler
6
+ from .attempts import AttemptConflictError, ExecutionAttemptRecord, SQLiteExecutionAttemptLedger
7
+ from .authority import AuthorityError
8
+ from .compensation import CompensationPlan, CompensationStatus, NoAutomaticCompensation
9
+ from .executor import ExecutionRequest, ExecutionResult, ExecutionStatus, LocalFileExecutor, ReadbackEvidence
10
+ from .http_executor import HttpMutationExecutor, JsonFieldReadback, ReadbackStrategy
11
+ from .identity import ExternalTokenVerifierResolver, VerifiedClaimsPrincipalResolver, VerifiedTokenClaims
12
+ from .message_executor import DeliveryReceipt, MessageTransport, OutboundMessageExecutor, SQLiteOutbox
13
+ from .models import ActionClass, EnvironmentTrust, PathwayDefinition, PathwayState, RuntimeDecision
14
+ from .principal import Principal, PrincipalError, StaticActorBinding, TrustedPrincipalResolver
15
+ from .reconciliation import ReconciliationResult, ReconciliationStatus, ReconciliationStrategy, reconcile_started_attempt
16
+ from .redaction import EvidenceLimitError, RedactionPolicy
17
+ from .rpe import PythonRpeEvaluator, RestRpeEvaluator, RpeContractError
18
+ from .runtime import EvidenceVerificationResult, RegistrationResult, ResponsibilityPathwayRuntime
19
+ from .source_context import SourceAuthority, SourceContext, SourceContextError
20
+ from .storage import IdempotencyConflictError, SQLiteStore
21
+ from .tenant import SQLiteTenantRegistry, TenantBoundaryError, TenantContext, TenantScopedRuntime
22
+
23
+ __all__ = [
24
+ "ActionClass", "AgentToolCall", "AgentToolOutcome", "AttemptConflictError", "AuthorityError",
25
+ "CompensationPlan", "CompensationStatus", "DeliveryReceipt", "EnvironmentTrust", "EvidenceLimitError",
26
+ "EvidenceVerificationResult", "ExecutionAttemptRecord", "ExecutionRequest", "ExecutionResult", "ExecutionStatus",
27
+ "ExternalTokenVerifierResolver", "HttpMutationExecutor", "IdempotencyConflictError", "JsonFieldReadback",
28
+ "LocalFileExecutor", "MessageTransport", "NoAutomaticCompensation", "OutboundMessageExecutor",
29
+ "PathwayDefinition", "PathwayState", "Principal", "PrincipalError", "PythonRpeEvaluator", "ReadbackEvidence",
30
+ "ReadbackStrategy", "ReconciliationResult", "ReconciliationStatus", "ReconciliationStrategy", "RedactionPolicy",
31
+ "RegistrationResult", "ResponsibilityPathwayRuntime", "RestRpeEvaluator", "RpeContractError", "RprToolBoundary",
32
+ "RuntimeDecision", "SQLiteExecutionAttemptLedger", "SQLiteOutbox", "SQLiteStore", "SQLiteTenantRegistry",
33
+ "SourceAuthority", "SourceContext", "SourceContextError", "StaticActorBinding", "TenantBoundaryError",
34
+ "TenantContext", "TenantScopedRuntime", "TrustedPrincipalResolver", "VerifiedClaimsPrincipalResolver",
35
+ "VerifiedTokenClaims", "langgraph_tool_node", "openai_function_tool_handler", "reconcile_started_attempt",
36
+ ]
@@ -0,0 +1,25 @@
1
+ # Copyright (c) 2026 Akihisa Ono
2
+ # SPDX-License-Identifier: MIT
3
+ # Generated from specs/pathway-state-machine.json. Do not edit manually.
4
+ from __future__ import annotations
5
+
6
+ from .models import PathwayState
7
+
8
+ ALLOWED_TRANSITIONS: dict[PathwayState, frozenset[PathwayState]] = {
9
+ PathwayState.PROPOSED: frozenset({PathwayState.AWAITING_APPROVAL, PathwayState.APPROVED, PathwayState.DENIED}),
10
+ PathwayState.AWAITING_APPROVAL: frozenset({PathwayState.APPROVED, PathwayState.DENIED, PathwayState.HUMAN_GATE}),
11
+ PathwayState.APPROVED: frozenset({PathwayState.RUNNING, PathwayState.HELD, PathwayState.ABORTED}),
12
+ PathwayState.RUNNING: frozenset({PathwayState.COMPLETED, PathwayState.STOPPED, PathwayState.PARTIALLY_COMPLETED, PathwayState.WRITE_STATUS_UNKNOWN, PathwayState.REPAIR_REQUIRED}),
13
+ PathwayState.HELD: frozenset({PathwayState.HUMAN_GATE, PathwayState.APPROVED, PathwayState.ABORTED}),
14
+ PathwayState.HUMAN_GATE: frozenset({PathwayState.APPROVED, PathwayState.DENIED, PathwayState.ABORTED}),
15
+ PathwayState.STOPPED: frozenset({PathwayState.REPAIR_REQUIRED, PathwayState.ABORTED}),
16
+ PathwayState.PARTIALLY_COMPLETED: frozenset({PathwayState.REPAIR_REQUIRED}),
17
+ PathwayState.WRITE_STATUS_UNKNOWN: frozenset({PathwayState.COMPLETED, PathwayState.REPAIR_REQUIRED}),
18
+ PathwayState.REPAIR_REQUIRED: frozenset({PathwayState.READY_TO_RESUME, PathwayState.ABORTED}),
19
+ PathwayState.READY_TO_RESUME: frozenset({PathwayState.RUNNING, PathwayState.ABORTED}),
20
+ PathwayState.COMPLETED: frozenset(),
21
+ PathwayState.DENIED: frozenset(),
22
+ PathwayState.ABORTED: frozenset(),
23
+ }
24
+
25
+ TERMINAL_STATES = frozenset({PathwayState.COMPLETED, PathwayState.DENIED, PathwayState.ABORTED})
rpr/agent_adapters.py ADDED
@@ -0,0 +1,88 @@
1
+ # Copyright (c) 2026 Akihisa Ono
2
+ # SPDX-License-Identifier: MIT
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from dataclasses import dataclass
7
+ from typing import Any, Callable, Mapping
8
+
9
+ from .executor import ExecutionRequest, Executor
10
+ from .runtime import ResponsibilityPathwayRuntime
11
+
12
+
13
+ @dataclass(frozen=True)
14
+ class AgentToolCall:
15
+ tool_name: str
16
+ arguments: Mapping[str, Any]
17
+ call_id: str
18
+
19
+
20
+ @dataclass(frozen=True)
21
+ class AgentToolOutcome:
22
+ allowed: bool
23
+ pathway_id: str
24
+ state: str
25
+ output: Mapping[str, Any]
26
+ reason: str | None = None
27
+
28
+
29
+ class RprToolBoundary:
30
+ """Framework-neutral boundary used by concrete agent-framework adapters."""
31
+
32
+ def __init__(self, runtime: ResponsibilityPathwayRuntime, executor_for: Callable[[str], Executor]) -> None:
33
+ self.runtime = runtime
34
+ self.executor_for = executor_for
35
+
36
+ def invoke(self, *, pathway_id: str, actor: str, call: AgentToolCall) -> AgentToolOutcome:
37
+ request = ExecutionRequest(
38
+ operation_id=call.call_id,
39
+ attempt_id=call.call_id,
40
+ idempotency_key=call.call_id,
41
+ action=call.tool_name,
42
+ parameters=dict(call.arguments),
43
+ )
44
+ result = self.runtime.execute(pathway_id, request, actor=actor, executor=self.executor_for(call.tool_name))
45
+ state = self.runtime.store.get_state(pathway_id).value
46
+ return AgentToolOutcome(
47
+ allowed=result.status.value == "succeeded",
48
+ pathway_id=pathway_id,
49
+ state=state,
50
+ output={
51
+ "status": result.status.value,
52
+ "evidence": dict(result.evidence),
53
+ "readback": None if result.readback is None else {
54
+ "verified": result.readback.verified,
55
+ "observed": dict(result.readback.observed),
56
+ "reason": result.readback.reason,
57
+ },
58
+ },
59
+ reason=result.reason,
60
+ )
61
+
62
+
63
+ def openai_function_tool_handler(boundary: RprToolBoundary, *, pathway_id: str, actor: str, tool_name: str) -> Callable[[str], str]:
64
+ """Return a dependency-free handler suitable for wrapping with Agents SDK `function_tool`.
65
+
66
+ RPR does not import the SDK. The application wraps this callable and may attach SDK tool
67
+ guardrails. Hosted and built-in tools require a different integration boundary.
68
+ """
69
+
70
+ def handler(arguments_json: str) -> str:
71
+ arguments = json.loads(arguments_json)
72
+ call_id = str(arguments.pop("_rpr_call_id"))
73
+ outcome = boundary.invoke(pathway_id=pathway_id, actor=actor, call=AgentToolCall(tool_name, arguments, call_id))
74
+ return json.dumps(outcome.output | {"pathway_id": outcome.pathway_id, "state": outcome.state, "reason": outcome.reason}, ensure_ascii=False)
75
+
76
+ return handler
77
+
78
+
79
+ def langgraph_tool_node(boundary: RprToolBoundary, *, pathway_id: str, actor: str, tool_name: str) -> Callable[[Mapping[str, Any]], Mapping[str, Any]]:
80
+ """Return a node callable usable from a LangGraph `StateGraph` or tool wrapper."""
81
+
82
+ def node(state: Mapping[str, Any]) -> Mapping[str, Any]:
83
+ call_id = str(state["call_id"])
84
+ arguments = dict(state.get("arguments", {}))
85
+ outcome = boundary.invoke(pathway_id=pathway_id, actor=actor, call=AgentToolCall(tool_name, arguments, call_id))
86
+ return dict(state) | {"rpr": {"allowed": outcome.allowed, "state": outcome.state, "output": dict(outcome.output), "reason": outcome.reason}}
87
+
88
+ return node
@@ -0,0 +1,195 @@
1
+ # Copyright (c) 2026 Akihisa Ono
2
+ # SPDX-License-Identifier: MIT
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from pathlib import Path
7
+ from typing import Any, Mapping
8
+
9
+
10
+ class AssuranceManifestError(ValueError):
11
+ """The assurance manifest is malformed or exceeds its declared boundary."""
12
+
13
+
14
+ _ALLOWED_STATUSES = {
15
+ "not_implemented",
16
+ "implemented_unverified",
17
+ "passing",
18
+ "failing",
19
+ "deferred",
20
+ "out_of_scope",
21
+ }
22
+ _EVIDENCE_ORDER = {f"E{level}": level for level in range(6)}
23
+ _REQUIRED_HUMAN_GATES = {
24
+ "repository_publicization",
25
+ "pages_publication",
26
+ "package_release",
27
+ "tag_or_github_release",
28
+ "external_or_live_mcp_connection",
29
+ "credential_use",
30
+ "license_change",
31
+ "claim_escalation_to_e4_or_e5",
32
+ }
33
+ _REQUIRED_NOT_PERMITTED = {
34
+ "full formal verification",
35
+ "legal or regulatory compliance",
36
+ "arbitrary third-party MCP compatibility",
37
+ "live external MCP interoperability",
38
+ "distributed correctness",
39
+ "production readiness",
40
+ "signed non-repudiation",
41
+ "release-complete declaration without authorization",
42
+ }
43
+ _REQUIRED_CLAIM_FIELDS = {
44
+ "claim_id",
45
+ "status",
46
+ "evidence_level",
47
+ "statement",
48
+ "implementation_anchors",
49
+ "test_anchors",
50
+ "retained_evidence",
51
+ "residual_owner",
52
+ "blocked_by",
53
+ "residual_risks",
54
+ }
55
+
56
+
57
+ def load_assurance_manifest(path: str | Path, *, root: str | Path | None = None) -> dict[str, Any]:
58
+ manifest_path = Path(path)
59
+ try:
60
+ payload = json.loads(manifest_path.read_text(encoding="utf-8"))
61
+ except (OSError, UnicodeError, json.JSONDecodeError) as exc:
62
+ raise AssuranceManifestError(f"manifest_load_failed: {type(exc).__name__}: {exc}") from exc
63
+ validate_assurance_manifest(payload, root=manifest_path.parent.parent if root is None else root)
64
+ return payload
65
+
66
+
67
+ def validate_assurance_manifest(payload: Any, *, root: str | Path | None = None) -> None:
68
+ if not isinstance(payload, Mapping):
69
+ raise AssuranceManifestError("manifest_must_be_object")
70
+ if payload.get("schema_version") != 1:
71
+ raise AssuranceManifestError("unsupported_schema_version")
72
+ if payload.get("product") != "Responsibility Pathway Runtime":
73
+ raise AssuranceManifestError("unexpected_product")
74
+ if payload.get("canonical_source") != "YutoriKomeiji/responsibility-pathway-runtime":
75
+ raise AssuranceManifestError("unexpected_canonical_source")
76
+ if payload.get("release_boundary") != "public_alpha_candidate":
77
+ raise AssuranceManifestError("release_boundary_must_be_public_alpha_candidate")
78
+
79
+ human_gates = _string_set(payload.get("human_gate_required_for"), "human_gate_required_for")
80
+ missing_gates = _REQUIRED_HUMAN_GATES - human_gates
81
+ if missing_gates:
82
+ raise AssuranceManifestError(f"missing_human_gates: {sorted(missing_gates)!r}")
83
+
84
+ maximum = payload.get("maximum_current_evidence_level")
85
+ if maximum not in _EVIDENCE_ORDER:
86
+ raise AssuranceManifestError("invalid_maximum_current_evidence_level")
87
+ if _EVIDENCE_ORDER[maximum] > _EVIDENCE_ORDER["E3"]:
88
+ raise AssuranceManifestError("evidence_level_escalation_requires_human_gate")
89
+
90
+ boundary = payload.get("global_claim_boundary")
91
+ if not isinstance(boundary, Mapping):
92
+ raise AssuranceManifestError("global_claim_boundary_must_be_object")
93
+ permitted = boundary.get("permitted")
94
+ if not isinstance(permitted, str) or not permitted.strip():
95
+ raise AssuranceManifestError("global_permitted_wording_required")
96
+ not_permitted = _string_set(payload.get("global_claim_boundary", {}).get("not_permitted"), "global_claim_boundary.not_permitted")
97
+ missing_prohibitions = _REQUIRED_NOT_PERMITTED - not_permitted
98
+ if missing_prohibitions:
99
+ raise AssuranceManifestError(f"missing_claim_prohibitions: {sorted(missing_prohibitions)!r}")
100
+
101
+ source_documents = _string_list(payload.get("source_documents"), "source_documents", allow_empty=False)
102
+ claims = payload.get("claims")
103
+ if not isinstance(claims, list) or not claims:
104
+ raise AssuranceManifestError("claims_must_be_non_empty_list")
105
+
106
+ claim_ids: set[str] = set()
107
+ for index, claim in enumerate(claims):
108
+ _validate_claim(claim, index=index, maximum=maximum, claim_ids=claim_ids)
109
+
110
+ if root is not None:
111
+ root_path = Path(root)
112
+ for relative in source_documents:
113
+ _require_relative_file(root_path, relative, "source_document")
114
+ for claim in claims:
115
+ for relative in claim["implementation_anchors"]:
116
+ _require_relative_file(root_path, relative, f"implementation_anchor:{claim['claim_id']}")
117
+ for relative in claim["test_anchors"]:
118
+ _require_relative_file(root_path, relative, f"test_anchor:{claim['claim_id']}")
119
+
120
+
121
+ def _validate_claim(claim: Any, *, index: int, maximum: str, claim_ids: set[str]) -> None:
122
+ if not isinstance(claim, Mapping):
123
+ raise AssuranceManifestError(f"claim_{index}_must_be_object")
124
+ missing = _REQUIRED_CLAIM_FIELDS - set(claim)
125
+ if missing:
126
+ raise AssuranceManifestError(f"claim_{index}_missing_fields: {sorted(missing)!r}")
127
+
128
+ claim_id = claim.get("claim_id")
129
+ if not isinstance(claim_id, str) or not claim_id.strip():
130
+ raise AssuranceManifestError(f"claim_{index}_invalid_id")
131
+ if claim_id in claim_ids:
132
+ raise AssuranceManifestError(f"duplicate_claim_id: {claim_id}")
133
+ claim_ids.add(claim_id)
134
+
135
+ status = claim.get("status")
136
+ if status not in _ALLOWED_STATUSES:
137
+ raise AssuranceManifestError(f"claim_{claim_id}_invalid_status")
138
+ evidence_level = claim.get("evidence_level")
139
+ if evidence_level not in _EVIDENCE_ORDER:
140
+ raise AssuranceManifestError(f"claim_{claim_id}_invalid_evidence_level")
141
+ if _EVIDENCE_ORDER[evidence_level] > _EVIDENCE_ORDER[maximum]:
142
+ raise AssuranceManifestError(f"claim_{claim_id}_exceeds_manifest_maximum")
143
+ if status == "passing" and _EVIDENCE_ORDER[evidence_level] < _EVIDENCE_ORDER["E2"]:
144
+ raise AssuranceManifestError(f"claim_{claim_id}_passing_without_sufficient_evidence")
145
+
146
+ statement = claim.get("statement")
147
+ if not isinstance(statement, str) or not statement.strip():
148
+ raise AssuranceManifestError(f"claim_{claim_id}_statement_required")
149
+ owner = claim.get("residual_owner")
150
+ if not isinstance(owner, str) or not owner.strip():
151
+ raise AssuranceManifestError(f"claim_{claim_id}_residual_owner_required")
152
+
153
+ implementation = _string_list(claim.get("implementation_anchors"), f"claim_{claim_id}.implementation_anchors", allow_empty=False)
154
+ tests = _string_list(claim.get("test_anchors"), f"claim_{claim_id}.test_anchors", allow_empty=True)
155
+ _string_list(claim.get("retained_evidence"), f"claim_{claim_id}.retained_evidence", allow_empty=True)
156
+ blocked_by = _string_list(claim.get("blocked_by"), f"claim_{claim_id}.blocked_by", allow_empty=True)
157
+ risks = _string_list(claim.get("residual_risks"), f"claim_{claim_id}.residual_risks", allow_empty=False)
158
+
159
+ if status == "passing" and not tests:
160
+ raise AssuranceManifestError(f"claim_{claim_id}_passing_without_test_anchor")
161
+ if status == "implemented_unverified" and not blocked_by:
162
+ raise AssuranceManifestError(f"claim_{claim_id}_unverified_without_blocker")
163
+ if not implementation or not risks:
164
+ raise AssuranceManifestError(f"claim_{claim_id}_missing_assurance_boundary")
165
+
166
+
167
+ def _string_list(value: Any, field: str, *, allow_empty: bool) -> list[str]:
168
+ if not isinstance(value, list):
169
+ raise AssuranceManifestError(f"{field}_must_be_list")
170
+ if not allow_empty and not value:
171
+ raise AssuranceManifestError(f"{field}_must_not_be_empty")
172
+ result: list[str] = []
173
+ for item in value:
174
+ if not isinstance(item, str) or not item.strip():
175
+ raise AssuranceManifestError(f"{field}_contains_invalid_string")
176
+ result.append(item)
177
+ if len(result) != len(set(result)):
178
+ raise AssuranceManifestError(f"{field}_contains_duplicates")
179
+ return result
180
+
181
+
182
+ def _string_set(value: Any, field: str) -> set[str]:
183
+ return set(_string_list(value, field, allow_empty=False))
184
+
185
+
186
+ def _require_relative_file(root: Path, relative: str, field: str) -> None:
187
+ candidate = Path(relative)
188
+ if candidate.is_absolute() or ".." in candidate.parts:
189
+ raise AssuranceManifestError(f"{field}_must_be_relative")
190
+ resolved = (root / candidate).resolve()
191
+ root_resolved = root.resolve()
192
+ if root_resolved != resolved and root_resolved not in resolved.parents:
193
+ raise AssuranceManifestError(f"{field}_escapes_root")
194
+ if not resolved.is_file():
195
+ raise AssuranceManifestError(f"{field}_missing: {relative}")