pgc-domains 2.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. pgc_domains-2.0.0/LICENSE +67 -0
  2. pgc_domains-2.0.0/NOTICE +11 -0
  3. pgc_domains-2.0.0/PKG-INFO +169 -0
  4. pgc_domains-2.0.0/README.md +144 -0
  5. pgc_domains-2.0.0/ai_governance/implementation/__init__.py +0 -0
  6. pgc_domains-2.0.0/ai_governance/implementation/capability_transforms/__init__.py +0 -0
  7. pgc_domains-2.0.0/ai_governance/implementation/capability_transforms/atoms/__init__.py +0 -0
  8. pgc_domains-2.0.0/ai_governance/implementation/capability_transforms/atoms/ct_pure_check_quota_available_v0.py +64 -0
  9. pgc_domains-2.0.0/ai_governance/implementation/capability_transforms/atoms/ct_pure_check_training_status_v0.py +51 -0
  10. pgc_domains-2.0.0/ai_governance/implementation/capability_transforms/atoms/ct_pure_evaluate_inactivity_v0.py +96 -0
  11. pgc_domains-2.0.0/blockchain/implementation/__init__.py +0 -0
  12. pgc_domains-2.0.0/blockchain/implementation/capability_transforms/__init__.py +0 -0
  13. pgc_domains-2.0.0/blockchain/implementation/capability_transforms/atoms/__init__.py +0 -0
  14. pgc_domains-2.0.0/blockchain/implementation/capability_transforms/atoms/ct_pure_derive_wallet_address_v0.py +96 -0
  15. pgc_domains-2.0.0/book_library_mgmt/implementation/__init__.py +0 -0
  16. pgc_domains-2.0.0/book_library_mgmt/implementation/capability_transforms/__init__.py +0 -0
  17. pgc_domains-2.0.0/book_library_mgmt/implementation/capability_transforms/atoms/__init__.py +0 -0
  18. pgc_domains-2.0.0/book_library_mgmt/implementation/capability_transforms/atoms/ct_pure_form_book_identity_key_v0.py +96 -0
  19. pgc_domains-2.0.0/book_library_mgmt/implementation/capability_transforms/atoms/ct_pure_form_work_identity_key_v0.py +77 -0
  20. pgc_domains-2.0.0/book_library_mgmt/implementation/capability_transforms/atoms/ct_pure_group_records_v0.py +72 -0
  21. pgc_domains-2.0.0/book_library_mgmt/implementation/capability_transforms/atoms/ct_pure_select_records_v0.py +65 -0
  22. pgc_domains-2.0.0/pgc_domains.egg-info/PKG-INFO +169 -0
  23. pgc_domains-2.0.0/pgc_domains.egg-info/SOURCES.txt +26 -0
  24. pgc_domains-2.0.0/pgc_domains.egg-info/dependency_links.txt +1 -0
  25. pgc_domains-2.0.0/pgc_domains.egg-info/requires.txt +2 -0
  26. pgc_domains-2.0.0/pgc_domains.egg-info/top_level.txt +3 -0
  27. pgc_domains-2.0.0/pyproject.toml +61 -0
  28. pgc_domains-2.0.0/setup.cfg +4 -0
@@ -0,0 +1,67 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ Copyright 2026 Bhash Ganti aka Bachi
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
18
+
19
+
20
+ ------------------------
21
+ FULL LICENSE TEXT BELOW
22
+ ------------------------
23
+
24
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
25
+
26
+ 1. Definitions.
27
+ "License" shall mean the terms and conditions for use, reproduction,
28
+ and distribution as defined by Sections 1 through 9 of this document.
29
+ "Licensor" shall mean the copyright owner.
30
+ "Legal Entity" shall mean the union of the acting entity and all other
31
+ entities that control, are controlled by, or are under common control.
32
+ "You" shall mean an individual or Legal Entity exercising permissions.
33
+ "Source" form shall mean the preferred form for making modifications.
34
+ "Object" form shall mean any form resulting from mechanical transformation.
35
+ "Work" shall mean the work of authorship.
36
+ "Derivative Works" shall mean any work based on the Work.
37
+ "Contribution" shall mean any work intentionally submitted.
38
+ "Contributor" shall mean Licensor and any individual submitting Contributions.
39
+
40
+ 2. Grant of Copyright License.
41
+ Each Contributor grants You a perpetual, worldwide, non-exclusive,
42
+ no-charge, royalty-free copyright license.
43
+
44
+ 3. Grant of Patent License.
45
+ Each Contributor grants a patent license to make, use, sell, etc.
46
+
47
+ 4. Redistribution.
48
+ You may reproduce and distribute copies provided that:
49
+ - You include a copy of this License
50
+ - You retain notices
51
+ - You state modifications
52
+ - You include NOTICE file if present
53
+
54
+ 5. Submission of Contributions.
55
+ Contributions are under this License unless stated otherwise.
56
+
57
+ 6. Trademarks.
58
+ This License does not grant trademark rights.
59
+
60
+ 7. Disclaimer of Warranty.
61
+ Provided "AS IS", without warranties.
62
+
63
+ 8. Limitation of Liability.
64
+ No liability for damages.
65
+
66
+ 9. Accepting Warranty or Additional Liability.
67
+ You may offer support/warranty on your own behalf only.
@@ -0,0 +1,11 @@
1
+ PGS — Protocol-Governed Systems
2
+ Copyright 2026 Bhash Ganti aka Bachi
3
+
4
+ This project introduces a protocol-first execution model in which:
5
+
6
+ - Behavior is declared in protocol artifacts
7
+ - Execution is performed by a deterministic runtime
8
+ - Capability implementations are bound at compile time
9
+ - Governance is enforced through invariants and assertions
10
+
11
+ Extensibility is achieved by declaration, not refactor.
@@ -0,0 +1,169 @@
1
+ Metadata-Version: 2.4
2
+ Name: pgc-domains
3
+ Version: 2.0.0
4
+ Summary: PGC business domains — the capability implementations the composed reference snapshot binds at execution
5
+ Author-email: Bhash Ganti <bachipeachy@gmail.com>
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://omnibachi.org/
8
+ Project-URL: Repository, https://github.com/protocol-governed-computing/business_domains
9
+ Project-URL: Standard, https://doi.org/10.5281/zenodo.22150616
10
+ Keywords: protocol-governed-computing,pgc,business-domain,capability-transforms
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Operating System :: OS Independent
18
+ Requires-Python: >=3.10
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ License-File: NOTICE
22
+ Requires-Dist: pgc-runtime>=2.0.0
23
+ Requires-Dist: pycryptodome
24
+ Dynamic: license-file
25
+
26
+ # business_domains
27
+
28
+ **Real business work, declared as governed protocol.**
29
+
30
+ Registering a participant, cataloguing a book, licensing an AI agent — work that would be worth
31
+ doing whether or not this platform existed. Each domain here is a directory of declarations: a
32
+ workflow graph, the contracts its nodes name, the intents that admit a request, the events it
33
+ announces, the store it writes to. No domain implements admission, routing, persistence, auditing
34
+ or refusal. It declares them, and the platform enforces what it declared.
35
+
36
+ > **New here?** Start with [`ARCHITECTURE.md`](ARCHITECTURE.md) — what this repository is, what it
37
+ > owns, and a hands-on walkthrough. For the whole picture, see the
38
+ > [organization profile](https://github.com/protocol-governed-computing).
39
+
40
+ ---
41
+
42
+ ## The domains
43
+
44
+ | Domain | Subdomains | What it does |
45
+ |---|---|---|
46
+ | **`blockchain`** | `identity`, `wallet` | Register a participant, then accept or reject them — keeping a durable record of what they registered with. An accepted person is then given exactly one wallet, whose creation is recorded as a moment on its own trail. Reachable over HTTP and the command line, with a web client. |
47
+ | **`book_library_mgmt`** | `catalog` | Register works, editions and physical copies; retire and reinstate them; update bibliographic information; search. Ten workflows — the largest surface here — of which six announce the business moments they complete. |
48
+ | **`ai_governance`** | `agent_governance`, `ai_licensing` | Admit or deny an AI agent's action; provision, deny and reclaim licences. Two subdomains sharing one namespace. |
49
+
50
+ A **domain is a namespace**; a **subdomain is a division within it**. `ai_governance` is the case
51
+ that makes the distinction concrete — two subdomains, one compiled domain, neither a fork of the
52
+ other.
53
+
54
+ Maturity differs, and it is stated rather than implied. `blockchain::identity` is functionally
55
+ complete; two of its validated criteria are not exercised, and both wait on a function that does not
56
+ exist yet — a timed test, and the transaction half of the wallet claim. `blockchain::wallet` is
57
+ delivered and validated, and it is the domain that demonstrates **consulting** another subdomain's
58
+ records without writing them. `book_library_mgmt` now announces: six of its ten acts emit the moments
59
+ they complete, from the ending that completes them. `ai_governance` carries no change dossier —
60
+ deliberately — and is the least exercised.
61
+
62
+ **The wallet is also where a defect and its repair are on the record.** Its validation once read 7/9
63
+ because the suite registered the same people identity's suite registers, so a shared data root left
64
+ the unverified-person criterion testing someone already accepted. The suite now seeds people of its
65
+ own. Both blockchain suites run into one data root, because a domain has one place its records live.
66
+
67
+ ## Where this sits
68
+
69
+ ```
70
+ software_governance conformance_workloads business_domains
71
+ what is GOVERNED what PROVES the guarantee what is DONE ← here
72
+ └──────────────────────────┼──────────────────────────┘
73
+
74
+ compiler → assembler
75
+
76
+ ┌────────▼────────┐
77
+ │ sealed snapshot │
78
+ └────┬───────┬────┘
79
+ ▼ ▼
80
+ runtime inspector
81
+ ```
82
+
83
+ A domain is compiled **against** an already-compiled governance surface. Governance is never edited
84
+ to admit a domain — compiling one leaves the platform's identity unchanged. A domain declares its
85
+ own sources in its own build manifest, so adding one is a sibling directory and nothing upstream is
86
+ touched.
87
+
88
+ ## Run one
89
+
90
+ ```bash
91
+ ./blockchain/client/serve.sh # http://localhost:8000
92
+ ```
93
+
94
+ Register a name and contact address, then verify that address — accepting or rejecting it. The same
95
+ path without the browser:
96
+
97
+ ```bash
98
+ curl -s -X POST http://localhost:8000/blockchain -H 'Content-Type: application/json' \
99
+ -d '{"operation":"blockchain.register_actor",
100
+ "params":{"name":"Ada","contact_address":"ada@example.com"}}'
101
+ ```
102
+
103
+ ```json
104
+ { "outcome": "SUCCESS", "result_class": "SUCCESS",
105
+ "result": { "contact_address": "ada@example.com",
106
+ "occurrence": "ACTOR_REGISTERED_UNVERIFIED", "sequence_number": 1 },
107
+ "evidence": [ "trace:traces/blockchain/WF_REGISTER_ACTOR_V0/…" ] }
108
+ ```
109
+
110
+ Accepting an unknown address returns a governed `NOT_FOUND` without writing anything; registering
111
+ twice succeeds twice and advances the sequence, because registration is idempotent **by
112
+ declaration**. Every response points at the trace for that exact run.
113
+
114
+ To run a workflow directly against the sealed snapshot, without any web surface:
115
+
116
+ ```bash
117
+ cd ../protocol_runtime
118
+ ./run.sh run --wf blockchain::WF_REGISTER_ACTOR_V0 \
119
+ --payload ../business_domains/blockchain/testbed/identity/test_payloads/01_register_actor.json \
120
+ --data-root /tmp/pgc_instance
121
+ ```
122
+
123
+ ## Layout
124
+
125
+ ```
126
+ blockchain/
127
+ registry/identity/ workflows · intents · contracts · events · actors ·
128
+ storage structure · runtime bindings · transport contracts
129
+ client/ web client, HTTP binding table, composition launcher
130
+ cr_dossiers/ the governed record of each change, with its baseline pin
131
+ testbed/ payloads, including ones that must be refused
132
+
133
+ book_library_mgmt/ same shape; subdomain `catalog`; plus implementation/ transforms
134
+ ai_governance/ same shape; two subdomains in one namespace
135
+ ```
136
+
137
+ ## A change to a domain is itself governed
138
+
139
+ Each domain carries **change dossiers** — the record of a change from the business problem as stated
140
+ (P0) through to the authoring mandate (P8), each phase admissible before the next may be authored.
141
+ Every dossier pins the baseline it was approved against, and that pin stays historical: a completed
142
+ change is never re-pinned forward.
143
+
144
+ A change need not author anything. One dossier here produces a **two-line diff** — a defect
145
+ correction, fully evidenced, every phase admissible. A lifecycle that can only describe creation
146
+ cannot describe maintenance.
147
+
148
+ ## What this repository is not
149
+
150
+ - **Not the platform.** The governance surface is `software_governance`; the runtime that executes
151
+ these domains is `protocol_runtime`, and it contains no knowledge of any domain here.
152
+ - **Not a set of examples.** Conformance workloads (`conformance_workloads`) exist to prove a
153
+ guarantee; these exist because the work is worth doing. That both compile by the identical path,
154
+ with no privilege on either side, is the claim.
155
+ - **Not a place for platform mechanisms.** When a domain needs something neutral the substrate
156
+ lacks, the substrate gains it — a domain that compensates with a private rule produces a promise
157
+ stated nowhere and copied everywhere.
158
+
159
+ ## Rules
160
+
161
+ - A domain declares; it does not implement admission, routing, persistence or auditing.
162
+ - No import of the compiler, the assembler, the runtime, or another domain. Implementations are
163
+ leaves; cross-domain reference happens through compiled identity.
164
+ - Capability transforms are pure and deterministic. Every effect is a declared capability.
165
+ - All references are by fully-qualified identity, resolved at compile time. No short names.
166
+
167
+ ## License
168
+
169
+ Apache-2.0. See [`LICENSE`](LICENSE) and [`NOTICE`](NOTICE).
@@ -0,0 +1,144 @@
1
+ # business_domains
2
+
3
+ **Real business work, declared as governed protocol.**
4
+
5
+ Registering a participant, cataloguing a book, licensing an AI agent — work that would be worth
6
+ doing whether or not this platform existed. Each domain here is a directory of declarations: a
7
+ workflow graph, the contracts its nodes name, the intents that admit a request, the events it
8
+ announces, the store it writes to. No domain implements admission, routing, persistence, auditing
9
+ or refusal. It declares them, and the platform enforces what it declared.
10
+
11
+ > **New here?** Start with [`ARCHITECTURE.md`](ARCHITECTURE.md) — what this repository is, what it
12
+ > owns, and a hands-on walkthrough. For the whole picture, see the
13
+ > [organization profile](https://github.com/protocol-governed-computing).
14
+
15
+ ---
16
+
17
+ ## The domains
18
+
19
+ | Domain | Subdomains | What it does |
20
+ |---|---|---|
21
+ | **`blockchain`** | `identity`, `wallet` | Register a participant, then accept or reject them — keeping a durable record of what they registered with. An accepted person is then given exactly one wallet, whose creation is recorded as a moment on its own trail. Reachable over HTTP and the command line, with a web client. |
22
+ | **`book_library_mgmt`** | `catalog` | Register works, editions and physical copies; retire and reinstate them; update bibliographic information; search. Ten workflows — the largest surface here — of which six announce the business moments they complete. |
23
+ | **`ai_governance`** | `agent_governance`, `ai_licensing` | Admit or deny an AI agent's action; provision, deny and reclaim licences. Two subdomains sharing one namespace. |
24
+
25
+ A **domain is a namespace**; a **subdomain is a division within it**. `ai_governance` is the case
26
+ that makes the distinction concrete — two subdomains, one compiled domain, neither a fork of the
27
+ other.
28
+
29
+ Maturity differs, and it is stated rather than implied. `blockchain::identity` is functionally
30
+ complete; two of its validated criteria are not exercised, and both wait on a function that does not
31
+ exist yet — a timed test, and the transaction half of the wallet claim. `blockchain::wallet` is
32
+ delivered and validated, and it is the domain that demonstrates **consulting** another subdomain's
33
+ records without writing them. `book_library_mgmt` now announces: six of its ten acts emit the moments
34
+ they complete, from the ending that completes them. `ai_governance` carries no change dossier —
35
+ deliberately — and is the least exercised.
36
+
37
+ **The wallet is also where a defect and its repair are on the record.** Its validation once read 7/9
38
+ because the suite registered the same people identity's suite registers, so a shared data root left
39
+ the unverified-person criterion testing someone already accepted. The suite now seeds people of its
40
+ own. Both blockchain suites run into one data root, because a domain has one place its records live.
41
+
42
+ ## Where this sits
43
+
44
+ ```
45
+ software_governance conformance_workloads business_domains
46
+ what is GOVERNED what PROVES the guarantee what is DONE ← here
47
+ └──────────────────────────┼──────────────────────────┘
48
+
49
+ compiler → assembler
50
+
51
+ ┌────────▼────────┐
52
+ │ sealed snapshot │
53
+ └────┬───────┬────┘
54
+ ▼ ▼
55
+ runtime inspector
56
+ ```
57
+
58
+ A domain is compiled **against** an already-compiled governance surface. Governance is never edited
59
+ to admit a domain — compiling one leaves the platform's identity unchanged. A domain declares its
60
+ own sources in its own build manifest, so adding one is a sibling directory and nothing upstream is
61
+ touched.
62
+
63
+ ## Run one
64
+
65
+ ```bash
66
+ ./blockchain/client/serve.sh # http://localhost:8000
67
+ ```
68
+
69
+ Register a name and contact address, then verify that address — accepting or rejecting it. The same
70
+ path without the browser:
71
+
72
+ ```bash
73
+ curl -s -X POST http://localhost:8000/blockchain -H 'Content-Type: application/json' \
74
+ -d '{"operation":"blockchain.register_actor",
75
+ "params":{"name":"Ada","contact_address":"ada@example.com"}}'
76
+ ```
77
+
78
+ ```json
79
+ { "outcome": "SUCCESS", "result_class": "SUCCESS",
80
+ "result": { "contact_address": "ada@example.com",
81
+ "occurrence": "ACTOR_REGISTERED_UNVERIFIED", "sequence_number": 1 },
82
+ "evidence": [ "trace:traces/blockchain/WF_REGISTER_ACTOR_V0/…" ] }
83
+ ```
84
+
85
+ Accepting an unknown address returns a governed `NOT_FOUND` without writing anything; registering
86
+ twice succeeds twice and advances the sequence, because registration is idempotent **by
87
+ declaration**. Every response points at the trace for that exact run.
88
+
89
+ To run a workflow directly against the sealed snapshot, without any web surface:
90
+
91
+ ```bash
92
+ cd ../protocol_runtime
93
+ ./run.sh run --wf blockchain::WF_REGISTER_ACTOR_V0 \
94
+ --payload ../business_domains/blockchain/testbed/identity/test_payloads/01_register_actor.json \
95
+ --data-root /tmp/pgc_instance
96
+ ```
97
+
98
+ ## Layout
99
+
100
+ ```
101
+ blockchain/
102
+ registry/identity/ workflows · intents · contracts · events · actors ·
103
+ storage structure · runtime bindings · transport contracts
104
+ client/ web client, HTTP binding table, composition launcher
105
+ cr_dossiers/ the governed record of each change, with its baseline pin
106
+ testbed/ payloads, including ones that must be refused
107
+
108
+ book_library_mgmt/ same shape; subdomain `catalog`; plus implementation/ transforms
109
+ ai_governance/ same shape; two subdomains in one namespace
110
+ ```
111
+
112
+ ## A change to a domain is itself governed
113
+
114
+ Each domain carries **change dossiers** — the record of a change from the business problem as stated
115
+ (P0) through to the authoring mandate (P8), each phase admissible before the next may be authored.
116
+ Every dossier pins the baseline it was approved against, and that pin stays historical: a completed
117
+ change is never re-pinned forward.
118
+
119
+ A change need not author anything. One dossier here produces a **two-line diff** — a defect
120
+ correction, fully evidenced, every phase admissible. A lifecycle that can only describe creation
121
+ cannot describe maintenance.
122
+
123
+ ## What this repository is not
124
+
125
+ - **Not the platform.** The governance surface is `software_governance`; the runtime that executes
126
+ these domains is `protocol_runtime`, and it contains no knowledge of any domain here.
127
+ - **Not a set of examples.** Conformance workloads (`conformance_workloads`) exist to prove a
128
+ guarantee; these exist because the work is worth doing. That both compile by the identical path,
129
+ with no privilege on either side, is the claim.
130
+ - **Not a place for platform mechanisms.** When a domain needs something neutral the substrate
131
+ lacks, the substrate gains it — a domain that compensates with a private rule produces a promise
132
+ stated nowhere and copied everywhere.
133
+
134
+ ## Rules
135
+
136
+ - A domain declares; it does not implement admission, routing, persistence or auditing.
137
+ - No import of the compiler, the assembler, the runtime, or another domain. Implementations are
138
+ leaves; cross-domain reference happens through compiled identity.
139
+ - Capability transforms are pure and deterministic. Every effect is a declared capability.
140
+ - All references are by fully-qualified identity, resolved at compile time. No short names.
141
+
142
+ ## License
143
+
144
+ Apache-2.0. See [`LICENSE`](LICENSE) and [`NOTICE`](NOTICE).
@@ -0,0 +1,64 @@
1
+ """
2
+ CT_PURE_CHECK_QUOTA_AVAILABLE_V0
3
+
4
+ Pure Capability Transform (Atom)
5
+
6
+ Purpose:
7
+ Determine whether license quota remains under a declared cap.
8
+
9
+ Implementation:
10
+ - Compares assigned_count against quota
11
+ - Raises CTExecutionError when the cap is reached — the protocol's VIOLATION signal
12
+ for a validating CT; returns the remaining count otherwise
13
+
14
+ Purity Class: ct_pure
15
+ """
16
+
17
+ from typing import Any, Dict
18
+
19
+ from runtime.ct_executor import CTExecutionError
20
+
21
+
22
+ def _require_int(inputs: Dict[str, Any], key: str) -> int:
23
+ if key not in inputs:
24
+ raise CTExecutionError(
25
+ f"CT_PURE_CHECK_QUOTA_AVAILABLE_V0: missing required input '{key}'"
26
+ )
27
+ value = inputs[key]
28
+ # bool is a subclass of int — reject it explicitly rather than silently coercing.
29
+ if isinstance(value, bool) or not isinstance(value, int):
30
+ raise CTExecutionError(
31
+ f"CT_PURE_CHECK_QUOTA_AVAILABLE_V0: '{key}' must be an int, "
32
+ f"got {type(value).__name__}"
33
+ )
34
+ if value < 0:
35
+ raise CTExecutionError(
36
+ f"CT_PURE_CHECK_QUOTA_AVAILABLE_V0: '{key}' must be non-negative, got {value}"
37
+ )
38
+ return value
39
+
40
+
41
+ def execute(inputs: Dict[str, Any], context: Any = None) -> Dict[str, Any]:
42
+ """
43
+ Execute CT_PURE_CHECK_QUOTA_AVAILABLE_V0.
44
+
45
+ Inputs:
46
+ assigned_count (int): Licenses currently assigned
47
+ quota (int): Declared license cap
48
+
49
+ Outputs:
50
+ quota_available (bool): True when assigned_count is below quota
51
+ remaining (int): Licenses remaining under the cap, floored at zero
52
+ """
53
+ assigned_count = _require_int(inputs, "assigned_count")
54
+ quota = _require_int(inputs, "quota")
55
+
56
+ remaining = quota - assigned_count
57
+
58
+ if remaining <= 0:
59
+ raise CTExecutionError(
60
+ f"CT_PURE_CHECK_QUOTA_AVAILABLE_V0: license cap reached "
61
+ f"(assigned_count={assigned_count}, quota={quota})"
62
+ )
63
+
64
+ return {"result_status": "SUCCESS", "quota_available": True, "remaining": remaining}
@@ -0,0 +1,51 @@
1
+ """
2
+ CT_PURE_CHECK_TRAINING_STATUS_V0
3
+
4
+ Pure Capability Transform (Atom)
5
+
6
+ Purpose:
7
+ Evaluate whether an employee has completed the training required for AI license
8
+ provisioning.
9
+
10
+ Implementation:
11
+ - Reads the declared training_completed fact
12
+ - Raises CTExecutionError when training is incomplete — the protocol's VIOLATION
13
+ signal for a validating CT; returns the eligibility flag otherwise
14
+
15
+ Purity Class: ct_pure
16
+ """
17
+
18
+ from typing import Any, Dict
19
+
20
+ from runtime.ct_executor import CTExecutionError
21
+
22
+
23
+ def execute(inputs: Dict[str, Any], context: Any = None) -> Dict[str, Any]:
24
+ """
25
+ Execute CT_PURE_CHECK_TRAINING_STATUS_V0.
26
+
27
+ Inputs:
28
+ training_completed (bool): Whether required training is complete
29
+
30
+ Outputs:
31
+ training_eligible (bool): True when training is complete
32
+ """
33
+ if "training_completed" not in inputs:
34
+ raise CTExecutionError(
35
+ "CT_PURE_CHECK_TRAINING_STATUS_V0: missing required input 'training_completed'"
36
+ )
37
+
38
+ training_completed = inputs["training_completed"]
39
+
40
+ if not isinstance(training_completed, bool):
41
+ raise CTExecutionError(
42
+ "CT_PURE_CHECK_TRAINING_STATUS_V0: 'training_completed' must be a bool, "
43
+ f"got {type(training_completed).__name__}"
44
+ )
45
+
46
+ if not training_completed:
47
+ raise CTExecutionError(
48
+ "CT_PURE_CHECK_TRAINING_STATUS_V0: required training is not complete"
49
+ )
50
+
51
+ return {"result_status": "SUCCESS", "training_eligible": True}
@@ -0,0 +1,96 @@
1
+ """
2
+ CT_PURE_EVALUATE_INACTIVITY_V0
3
+
4
+ Pure Capability Transform (Atom)
5
+
6
+ Purpose:
7
+ Evaluate whether a license has been dormant past its reclamation threshold.
8
+
9
+ Implementation:
10
+ - Parses last_active_date and evaluation_date as ISO-8601
11
+ - Computes whole days elapsed between them
12
+ - Compares against threshold_days
13
+ - Raises CTExecutionError when the license is still active — the protocol's VIOLATION
14
+ signal for a validating CT; returns the dormancy verdict otherwise
15
+
16
+ evaluation_date is a declared input, never a clock read: a pure CT that consulted the
17
+ system clock would be non-deterministic and its trace unreplayable.
18
+
19
+ Purity Class: ct_pure
20
+ """
21
+
22
+ from datetime import date, datetime
23
+ from typing import Any, Dict
24
+
25
+ from runtime.ct_executor import CTExecutionError
26
+
27
+
28
+ def _parse_iso_date(inputs: Dict[str, Any], key: str) -> date:
29
+ if key not in inputs:
30
+ raise CTExecutionError(
31
+ f"CT_PURE_EVALUATE_INACTIVITY_V0: missing required input '{key}'"
32
+ )
33
+ raw = inputs[key]
34
+ if not isinstance(raw, str):
35
+ raise CTExecutionError(
36
+ f"CT_PURE_EVALUATE_INACTIVITY_V0: '{key}' must be an ISO-8601 string, "
37
+ f"got {type(raw).__name__}"
38
+ )
39
+ # Accept both date and date-time forms; a trailing Z is ISO-8601 but not accepted by
40
+ # fromisoformat before 3.11, so normalize it.
41
+ normalized = raw[:-1] + "+00:00" if raw.endswith("Z") else raw
42
+ try:
43
+ return datetime.fromisoformat(normalized).date()
44
+ except ValueError:
45
+ raise CTExecutionError(
46
+ f"CT_PURE_EVALUATE_INACTIVITY_V0: '{key}' is not a valid ISO-8601 date: {raw!r}"
47
+ ) from None
48
+
49
+
50
+ def execute(inputs: Dict[str, Any], context: Any = None) -> Dict[str, Any]:
51
+ """
52
+ Execute CT_PURE_EVALUATE_INACTIVITY_V0.
53
+
54
+ Inputs:
55
+ last_active_date (str): ISO-8601 date/date-time of last recorded activity
56
+ evaluation_date (str): ISO-8601 date/date-time the evaluation is made as of
57
+ threshold_days (int): Inactivity threshold in days
58
+
59
+ Outputs:
60
+ is_inactive (bool): True when days_inactive >= threshold_days
61
+ days_inactive (int): Whole days elapsed between the two dates
62
+ """
63
+ last_active = _parse_iso_date(inputs, "last_active_date")
64
+ evaluated_on = _parse_iso_date(inputs, "evaluation_date")
65
+
66
+ if "threshold_days" not in inputs:
67
+ raise CTExecutionError(
68
+ "CT_PURE_EVALUATE_INACTIVITY_V0: missing required input 'threshold_days'"
69
+ )
70
+ threshold_days = inputs["threshold_days"]
71
+ if isinstance(threshold_days, bool) or not isinstance(threshold_days, int):
72
+ raise CTExecutionError(
73
+ "CT_PURE_EVALUATE_INACTIVITY_V0: 'threshold_days' must be an int, "
74
+ f"got {type(threshold_days).__name__}"
75
+ )
76
+ if threshold_days < 0:
77
+ raise CTExecutionError(
78
+ f"CT_PURE_EVALUATE_INACTIVITY_V0: 'threshold_days' must be non-negative, "
79
+ f"got {threshold_days}"
80
+ )
81
+
82
+ if evaluated_on < last_active:
83
+ raise CTExecutionError(
84
+ "CT_PURE_EVALUATE_INACTIVITY_V0: 'evaluation_date' precedes 'last_active_date' "
85
+ f"({evaluated_on.isoformat()} < {last_active.isoformat()})"
86
+ )
87
+
88
+ days_inactive = (evaluated_on - last_active).days
89
+
90
+ if days_inactive < threshold_days:
91
+ raise CTExecutionError(
92
+ f"CT_PURE_EVALUATE_INACTIVITY_V0: license is still active "
93
+ f"(days_inactive={days_inactive} < threshold_days={threshold_days})"
94
+ )
95
+
96
+ return {"result_status": "SUCCESS", "is_inactive": True, "days_inactive": days_inactive}