patchr 0.1.0__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 (116) hide show
  1. apps/__init__.py +2 -0
  2. apps/api/__init__.py +2 -0
  3. apps/api/main.py +652 -0
  4. apps/benchmarks/__init__.py +1 -0
  5. apps/benchmarks/main.py +20 -0
  6. apps/sandbox/__init__.py +1 -0
  7. apps/sandbox/main.py +20 -0
  8. apps/worker/__init__.py +2 -0
  9. apps/worker/main.py +15 -0
  10. apps/worker/verify.py +14 -0
  11. patchr/__init__.py +12 -0
  12. patchr/sdk/__init__.py +20 -0
  13. patchr/sdk/client.py +12 -0
  14. patchr-0.1.0.dist-info/METADATA +137 -0
  15. patchr-0.1.0.dist-info/RECORD +116 -0
  16. patchr-0.1.0.dist-info/WHEEL +5 -0
  17. patchr-0.1.0.dist-info/entry_points.txt +5 -0
  18. patchr-0.1.0.dist-info/licenses/LICENSE +17 -0
  19. patchr-0.1.0.dist-info/top_level.txt +3 -0
  20. picux/__init__.py +6 -0
  21. picux/agents/__init__.py +5 -0
  22. picux/agents/registry.py +204 -0
  23. picux/api/__init__.py +5 -0
  24. picux/api/service.py +5075 -0
  25. picux/audit/__init__.py +31 -0
  26. picux/audit/activity.py +97 -0
  27. picux/audit/observability.py +55 -0
  28. picux/audit/verification/__init__.py +21 -0
  29. picux/audit/verification/ledger.py +633 -0
  30. picux/benchmarks/__init__.py +5 -0
  31. picux/benchmarks/local.py +286 -0
  32. picux/config.py +140 -0
  33. picux/contracts/__init__.py +22 -0
  34. picux/contracts/handshake.py +122 -0
  35. picux/contracts/integration.py +385 -0
  36. picux/contracts/openapi.py +187 -0
  37. picux/contracts/protocol_map.py +152 -0
  38. picux/contracts/routes.py +980 -0
  39. picux/contracts/schema_catalog.py +125 -0
  40. picux/core/__init__.py +17 -0
  41. picux/core/models.py +148 -0
  42. picux/core/router.py +131 -0
  43. picux/core/runtime.py +42 -0
  44. picux/core/state_machine.py +38 -0
  45. picux/domains/__init__.py +2 -0
  46. picux/domains/bridge/HostRun.py +1104 -0
  47. picux/domains/bridge/__init__.py +6 -0
  48. picux/domains/bridge/engine.py +345 -0
  49. picux/domains/hunt/__init__.py +6 -0
  50. picux/domains/hunt/engine.py +307 -0
  51. picux/domains/hunt/models.py +88 -0
  52. picux/domains/pay/__init__.py +16 -0
  53. picux/domains/pay/adapters.py +607 -0
  54. picux/domains/pay/engine.py +950 -0
  55. picux/domains/pay/models.py +95 -0
  56. picux/domains/proxy/__init__.py +5 -0
  57. picux/domains/proxy/engine.py +466 -0
  58. picux/domains/resolve/__init__.py +5 -0
  59. picux/domains/resolve/engine.py +546 -0
  60. picux/orchestrator/__init__.py +3 -0
  61. picux/orchestrator/engine.py +2840 -0
  62. picux/portals/__init__.py +17 -0
  63. picux/portals/templates.py +272 -0
  64. picux/protocols/__init__.py +1 -0
  65. picux/protocols/a2a/__init__.py +6 -0
  66. picux/protocols/a2a/client.py +51 -0
  67. picux/protocols/a2a/envelope.py +132 -0
  68. picux/protocols/mcp/__init__.py +7 -0
  69. picux/protocols/mcp/client.py +69 -0
  70. picux/protocols/mcp/contract.py +67 -0
  71. picux/protocols/mcp/server.py +76 -0
  72. picux/sandbox/__init__.py +6 -0
  73. picux/sandbox/midnight_arbitrage.py +215 -0
  74. picux/sandbox/models.py +90 -0
  75. picux/sdk/__init__.py +13 -0
  76. picux/sdk/client.py +768 -0
  77. picux/sdk/external.py +245 -0
  78. picux/security/__init__.py +18 -0
  79. picux/security/auth.py +86 -0
  80. picux/security/config_validator.py +58 -0
  81. picux/security/policy.py +158 -0
  82. picux/security/secrets.py +144 -0
  83. picux/signals/__init__.py +1 -0
  84. picux/signals/community/__init__.py +24 -0
  85. picux/signals/community/adapters/__init__.py +7 -0
  86. picux/signals/community/adapters/reddit.py +37 -0
  87. picux/signals/community/adapters/shopify.py +23 -0
  88. picux/signals/community/adapters/web.py +23 -0
  89. picux/signals/community/disambiguation.py +51 -0
  90. picux/signals/community/intake.py +227 -0
  91. picux/signals/community/models.py +102 -0
  92. picux/signals/community/rules.py +91 -0
  93. picux/signals/community/scoring.py +64 -0
  94. picux/storage/__init__.py +41 -0
  95. picux/storage/agents.py +50 -0
  96. picux/storage/cases.py +440 -0
  97. picux/storage/channels.py +476 -0
  98. picux/storage/connectors.py +411 -0
  99. picux/storage/envelopes.py +137 -0
  100. picux/storage/escrows.py +168 -0
  101. picux/storage/events.py +989 -0
  102. picux/storage/keyspace.py +60 -0
  103. picux/storage/mandates.py +107 -0
  104. picux/storage/portals.py +222 -0
  105. picux/storage/postgres.py +2049 -0
  106. picux/storage/providers.py +148 -0
  107. picux/storage/proxy.py +231 -0
  108. picux/storage/receipts.py +131 -0
  109. picux/storage/signals.py +147 -0
  110. picux/storage/tasks.py +179 -0
  111. picux/tools/__init__.py +11 -0
  112. picux/tools/shared.py +2048 -0
  113. picux/verification/__init__.py +5 -0
  114. picux/verification/rollout.py +183 -0
  115. picux/workflows/__init__.py +5 -0
  116. picux/workflows/templates.py +74 -0
@@ -0,0 +1,5 @@
1
+ """Verification and rollout gates."""
2
+
3
+ from .rollout import RolloutGate, RolloutReport, RolloutVerifier
4
+
5
+ __all__ = ["RolloutGate", "RolloutReport", "RolloutVerifier"]
@@ -0,0 +1,183 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from datetime import datetime, timezone
5
+ from typing import Any
6
+
7
+ from picux.api import PicuxApiService
8
+ from picux.config import PicuxSettings
9
+ from picux.core import Domain, ProtocolTask, ProtocolTaskStatus
10
+ from picux.domains.pay import PayDomain
11
+ from picux.security import validateProductionReady
12
+ from picux.storage import Keyspace, PicuxPostgresStore
13
+
14
+
15
+ @dataclass(frozen=True)
16
+ class RolloutGate:
17
+ name: str
18
+ ok: bool
19
+ detail: dict[str, Any]
20
+
21
+ def toMap(self) -> dict[str, Any]:
22
+ return {"name": self.name, "ok": self.ok, "detail": self.detail}
23
+
24
+
25
+ @dataclass(frozen=True)
26
+ class RolloutReport:
27
+ ok: bool
28
+ gates: tuple[RolloutGate, ...]
29
+
30
+ def toMap(self) -> dict[str, Any]:
31
+ return {"ok": self.ok, "gates": [gate.toMap() for gate in self.gates]}
32
+
33
+
34
+ class RolloutVerifier:
35
+ """Runs deterministic rollout gates that do not require live providers."""
36
+
37
+ def __init__(self, *, service: PicuxApiService | None = None, store: PicuxPostgresStore | None = None) -> None:
38
+ self.service = service or PicuxApiService(pay=PayDomain(verifier=self._verifier, clock=self._clock))
39
+ self.store = store or PicuxPostgresStore("", ensure=False)
40
+
41
+ def verify(self, *, settings: PicuxSettings | None = None) -> RolloutReport:
42
+ settings = settings or PicuxSettings.fromEnv({"PICUX_ENV": "local"})
43
+ gates = (
44
+ self.apiContractGate(),
45
+ self.externalIntegrationGate(),
46
+ self.postgresDurableGate(),
47
+ self.redisNamespaceGate(),
48
+ self.productionFailClosedGate(settings),
49
+ self.endToEndContractGate(),
50
+ )
51
+ return RolloutReport(ok=all(gate.ok for gate in gates), gates=gates)
52
+
53
+ def apiContractGate(self) -> RolloutGate:
54
+ checks = [
55
+ self.service.handle("GET", "/healthz")[0] == 200,
56
+ self.service.handle("GET", "/runtime")[0] == 200,
57
+ self.service.handle("POST", "/v1/tasks", {"goal": "find vendor arbitrage"})[1].get("ok") is True,
58
+ self.service.handle("GET", "/v1/signals/community/entities")[1].get("ok") is True,
59
+ ]
60
+ return RolloutGate("apiContract", all(checks), {"checks": checks})
61
+
62
+ def externalIntegrationGate(self) -> RolloutGate:
63
+ status, result = self.service.handle(
64
+ "POST",
65
+ "/v1/tasks",
66
+ {"userId": "external_1", "channel": "external", "goal": "settle mandate after proof"},
67
+ )
68
+ ok = status == 200 and result.get("ok") is True and result["task"]["channel"] == "external"
69
+ return RolloutGate("externalIntegration", ok, {"status": status, "task": result.get("task", {})})
70
+
71
+ def postgresDurableGate(self) -> RolloutGate:
72
+ task = ProtocolTask(
73
+ taskId="task_rollout_probe",
74
+ userId="user_rollout",
75
+ domain=Domain.HUNT,
76
+ status=ProtocolTaskStatus.PENDING,
77
+ channel="verification",
78
+ )
79
+ result = self.store.durableWriteReadCheck(task)
80
+ ok = bool(result.get("ok") or result.get("skipped"))
81
+ return RolloutGate("postgresDurable", ok, result)
82
+
83
+ def redisNamespaceGate(self) -> RolloutGate:
84
+ plan = Keyspace().migrationReadPlan("task", "task_rollout_probe")
85
+ readKeys = plan["readKeys"]
86
+ ok = plan["writeKey"] == "picux:v1:task:task_rollout_probe" and readKeys[0] == plan["writeKey"]
87
+ return RolloutGate("redisNamespaceMigration", ok, plan)
88
+
89
+ def productionFailClosedGate(self, settings: PicuxSettings) -> RolloutGate:
90
+ readiness = validateProductionReady(settings)
91
+ if settings.prod:
92
+ ok = not readiness.ok and bool(readiness.issues)
93
+ else:
94
+ prodSettings = PicuxSettings.fromEnv({"PICUX_ENV": "production"})
95
+ prodReadiness = validateProductionReady(prodSettings)
96
+ ok = not prodReadiness.ok and bool(prodReadiness.issues)
97
+ readiness = prodReadiness
98
+ return RolloutGate("productionFailClosed", ok, readiness.toMap())
99
+
100
+ def endToEndContractGate(self) -> RolloutGate:
101
+ signalStatus, signal = self.service.handle(
102
+ "POST",
103
+ "/v1/signals/community/launch-task",
104
+ {
105
+ "userId": "external_1",
106
+ "targetDomain": "resolve",
107
+ "approved": True,
108
+ "signal": {
109
+ "source": {"platform": "reddit", "community": "agents"},
110
+ "text": "Picux Protocol request needs resolve proof before settlement",
111
+ "query": "Picux Protocol",
112
+ },
113
+ },
114
+ )
115
+ task = signal.get("task", {})
116
+ resolveStatus, resolved = self.service.handle(
117
+ "POST",
118
+ f"/v1/tasks/{task.get('taskId', '')}/resolve",
119
+ {"text": "Duplicate charge and overcharge $20 were found", "provider": "vendorA"},
120
+ )
121
+ mandate = self._mandate()
122
+ verifyStatus, verified = self.service.handle("POST", "/v1/mandates/mandate_rollout/verify", mandate)
123
+ settleStatus, settled = self.service.handle(
124
+ "POST",
125
+ "/v1/pay/settle",
126
+ {
127
+ "mandate": mandate,
128
+ "request": {
129
+ "taskId": task.get("taskId", ""),
130
+ "vendorId": "vendorA",
131
+ "amount": {"amount": 80, "currency": "USD"},
132
+ "pov": {"povId": "pov_rollout", "rules": ["inventoryVerified", "priceArbitrage20"]},
133
+ },
134
+ },
135
+ )
136
+ receiptId = str(settled.get("receipt", {}).get("receiptId", "") or "")
137
+ receiptStatus, receipt = self.service.handle("GET", f"/v1/receipts/{receiptId}")
138
+ ok = all(
139
+ (
140
+ signalStatus == 200,
141
+ resolveStatus == 200,
142
+ verifyStatus == 200,
143
+ settleStatus == 200,
144
+ receiptStatus == 200,
145
+ signal.get("ok") is True,
146
+ resolved.get("ok") is True,
147
+ verified.get("ok") is True,
148
+ settled.get("ok") is True,
149
+ settled.get("receipt", {}).get("status") == "settled",
150
+ receipt.get("receipt", {}).get("receiptId") == receiptId,
151
+ )
152
+ )
153
+ return RolloutGate(
154
+ "endToEndContract",
155
+ ok,
156
+ {
157
+ "taskId": task.get("taskId", ""),
158
+ "receiptId": receiptId,
159
+ "statuses": [signalStatus, resolveStatus, verifyStatus, settleStatus, receiptStatus],
160
+ },
161
+ )
162
+
163
+ @staticmethod
164
+ def _clock() -> datetime:
165
+ return datetime(2026, 5, 9, 12, 0, tzinfo=timezone.utc)
166
+
167
+ @staticmethod
168
+ def _verifier(payload: dict[str, Any], signature: str, publicKey: str) -> bool:
169
+ return payload.get("mandateId") == "mandate_rollout" and signature == "rolloutSig" and publicKey == "rolloutPub"
170
+
171
+ @staticmethod
172
+ def _mandate() -> dict[str, Any]:
173
+ return {
174
+ "mandateId": "mandate_rollout",
175
+ "issuer": {"entityId": "tenant_rollout", "publicKey": "rolloutPub"},
176
+ "validUntil": "2099-01-01T00:00:00Z",
177
+ "constraints": {
178
+ "maxSpend": {"amount": 100.0, "currency": "USD"},
179
+ "allowedVendors": ["vendorA"],
180
+ "resolveRules": ["inventoryVerified", "priceArbitrage20"],
181
+ },
182
+ "signature": "rolloutSig",
183
+ }
@@ -0,0 +1,5 @@
1
+ """Use-case-first workflow template packaging."""
2
+
3
+ from .templates import getWorkflowTemplate, workflowTemplates
4
+
5
+ __all__ = ["getWorkflowTemplate", "workflowTemplates"]
@@ -0,0 +1,74 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Any
5
+
6
+
7
+ @dataclass(frozen=True)
8
+ class WorkflowTemplate:
9
+ templateId: str
10
+ name: str
11
+ domain: str
12
+ entryPoint: str
13
+ tagline: str
14
+ inputHints: tuple[str, ...]
15
+ outputs: tuple[str, ...]
16
+ proof: str
17
+
18
+ def toMap(self) -> dict[str, Any]:
19
+ return {
20
+ "templateId": self.templateId,
21
+ "name": self.name,
22
+ "domain": self.domain,
23
+ "entryPoint": self.entryPoint,
24
+ "tagline": self.tagline,
25
+ "inputHints": list(self.inputHints),
26
+ "outputs": list(self.outputs),
27
+ "proof": self.proof,
28
+ }
29
+
30
+
31
+ TEMPLATES: tuple[WorkflowTemplate, ...] = (
32
+ WorkflowTemplate(
33
+ "findBestFit",
34
+ "Find my best-fit options",
35
+ "hunt",
36
+ "/v1/hunt/discover",
37
+ "Unify fragmented discovery, rank options, and suggest the next best action.",
38
+ ("criteria", "offers", "sources"),
39
+ ("rankedOptions", "selectedOption", "nextBestAction", "proofCard"),
40
+ "Source-bound HUNT proof card backed by a proof pack.",
41
+ ),
42
+ WorkflowTemplate(
43
+ "auditDisputedClaim",
44
+ "Audit this disputed claim",
45
+ "resolve",
46
+ "/v1/workflows/templates/auditDisputedClaim/run",
47
+ "Turn a messy claim, dispute, audit trail, or migration-trust case into a reviewable evidence map.",
48
+ ("claim", "documents", "agentClaims", "counterparty", "profile"),
49
+ ("evidenceMap", "typedEvidence", "sourceClasses", "fraudIndicators", "caseOpsTimeline", "nextAction", "proofCard"),
50
+ "Resolve proof card with evidence status, confidence, open questions, and escalation guidance.",
51
+ ),
52
+ WorkflowTemplate(
53
+ "coordinateHumanProcess",
54
+ "Coordinate this human process end-to-end",
55
+ "proxy",
56
+ "/v1/proxy/missions",
57
+ "Coordinate people, messages, documents, status, and verified follow-through.",
58
+ ("task", "actors", "documents", "channels", "proofReq"),
59
+ ("mission", "route", "status", "humanProof", "proofCard"),
60
+ "Proxy proof card backed by mission state and human completion proof.",
61
+ ),
62
+ )
63
+
64
+
65
+ def workflowTemplates() -> dict[str, Any]:
66
+ return {"ok": True, "templates": [item.toMap() for item in TEMPLATES], "count": len(TEMPLATES)}
67
+
68
+
69
+ def getWorkflowTemplate(templateId: str) -> dict[str, Any]:
70
+ requested = str(templateId or "")
71
+ match = next((item for item in TEMPLATES if item.templateId == requested), None)
72
+ if not match:
73
+ return {"ok": False, "error": "workflowTemplateNotFound", "templateId": requested}
74
+ return {"ok": True, "template": match.toMap()}