isongraph-ext 0.3.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 (81) hide show
  1. isongraph_ext-0.3.0/LICENSE +21 -0
  2. isongraph_ext-0.3.0/PKG-INFO +144 -0
  3. isongraph_ext-0.3.0/README.md +114 -0
  4. isongraph_ext-0.3.0/pyproject.toml +47 -0
  5. isongraph_ext-0.3.0/setup.cfg +4 -0
  6. isongraph_ext-0.3.0/src/isongraph_ext/__init__.py +3 -0
  7. isongraph_ext-0.3.0/src/isongraph_ext/baselines/REGISTRY.ison +3 -0
  8. isongraph_ext-0.3.0/src/isongraph_ext/baselines/ce9d3b78afd79cbdffdd67546bcb5278dc38be70/MANIFEST.ison +22 -0
  9. isongraph_ext-0.3.0/src/isongraph_ext/baselines/ce9d3b78afd79cbdffdd67546bcb5278dc38be70/domains.ison +8 -0
  10. isongraph_ext-0.3.0/src/isongraph_ext/baselines/ce9d3b78afd79cbdffdd67546bcb5278dc38be70/receipts/cpp.ison +3 -0
  11. isongraph_ext-0.3.0/src/isongraph_ext/baselines/ce9d3b78afd79cbdffdd67546bcb5278dc38be70/receipts/cs.ison +3 -0
  12. isongraph_ext-0.3.0/src/isongraph_ext/baselines/ce9d3b78afd79cbdffdd67546bcb5278dc38be70/receipts/js.ison +3 -0
  13. isongraph_ext-0.3.0/src/isongraph_ext/baselines/ce9d3b78afd79cbdffdd67546bcb5278dc38be70/receipts/python.ison +3 -0
  14. isongraph_ext-0.3.0/src/isongraph_ext/baselines/ce9d3b78afd79cbdffdd67546bcb5278dc38be70/receipts/rust.ison +3 -0
  15. isongraph_ext-0.3.0/src/isongraph_ext/baselines/ce9d3b78afd79cbdffdd67546bcb5278dc38be70/receipts/ts.ison +3 -0
  16. isongraph_ext-0.3.0/src/isongraph_ext/igdm/__init__.py +13 -0
  17. isongraph_ext-0.3.0/src/isongraph_ext/igdm/__main__.py +92 -0
  18. isongraph_ext-0.3.0/src/isongraph_ext/igdm/bind.py +49 -0
  19. isongraph_ext-0.3.0/src/isongraph_ext/igdm/errors.py +12 -0
  20. isongraph_ext-0.3.0/src/isongraph_ext/igdm/payload.py +478 -0
  21. isongraph_ext-0.3.0/src/isongraph_ext/igdm/records.py +121 -0
  22. isongraph_ext-0.3.0/src/isongraph_ext/igdm/verify.py +118 -0
  23. isongraph_ext-0.3.0/src/isongraph_ext/igpv/__init__.py +14 -0
  24. isongraph_ext-0.3.0/src/isongraph_ext/igpv/__main__.py +186 -0
  25. isongraph_ext-0.3.0/src/isongraph_ext/igpv/bind.py +52 -0
  26. isongraph_ext-0.3.0/src/isongraph_ext/igpv/errors.py +14 -0
  27. isongraph_ext-0.3.0/src/isongraph_ext/igpv/lineage.py +100 -0
  28. isongraph_ext-0.3.0/src/isongraph_ext/igpv/locators.py +51 -0
  29. isongraph_ext-0.3.0/src/isongraph_ext/igpv/payload.py +511 -0
  30. isongraph_ext-0.3.0/src/isongraph_ext/igpv/records.py +134 -0
  31. isongraph_ext-0.3.0/src/isongraph_ext/igpv/resolve.py +63 -0
  32. isongraph_ext-0.3.0/src/isongraph_ext/igpv/verify.py +178 -0
  33. isongraph_ext-0.3.0/src/isongraph_ext/igx/__init__.py +15 -0
  34. isongraph_ext-0.3.0/src/isongraph_ext/igx/__main__.py +86 -0
  35. isongraph_ext-0.3.0/src/isongraph_ext/igx/admit.py +95 -0
  36. isongraph_ext-0.3.0/src/isongraph_ext/igx/baselines.py +133 -0
  37. isongraph_ext-0.3.0/src/isongraph_ext/igx/bind.py +57 -0
  38. isongraph_ext-0.3.0/src/isongraph_ext/igx/binding.py +241 -0
  39. isongraph_ext-0.3.0/src/isongraph_ext/igx/digest.py +33 -0
  40. isongraph_ext-0.3.0/src/isongraph_ext/igx/errors.py +14 -0
  41. isongraph_ext-0.3.0/src/isongraph_ext/igx/receipt_rules.py +34 -0
  42. isongraph_ext-0.3.0/src/isongraph_ext/igx/registry.py +10 -0
  43. isongraph_ext-0.3.0/src/isongraph_ext/igx/source.py +84 -0
  44. isongraph_ext-0.3.0/src/isongraph_ext/igx/verify.py +141 -0
  45. isongraph_ext-0.3.0/src/isongraph_ext/igx/versions.py +60 -0
  46. isongraph_ext-0.3.0/src/isongraph_ext/py.typed +0 -0
  47. isongraph_ext-0.3.0/src/isongraph_ext.egg-info/PKG-INFO +144 -0
  48. isongraph_ext-0.3.0/src/isongraph_ext.egg-info/SOURCES.txt +79 -0
  49. isongraph_ext-0.3.0/src/isongraph_ext.egg-info/dependency_links.txt +1 -0
  50. isongraph_ext-0.3.0/src/isongraph_ext.egg-info/requires.txt +6 -0
  51. isongraph_ext-0.3.0/src/isongraph_ext.egg-info/top_level.txt +1 -0
  52. isongraph_ext-0.3.0/tests/test_admit.py +114 -0
  53. isongraph_ext-0.3.0/tests/test_baselines.py +131 -0
  54. isongraph_ext-0.3.0/tests/test_bind.py +93 -0
  55. isongraph_ext-0.3.0/tests/test_binding.py +169 -0
  56. isongraph_ext-0.3.0/tests/test_cli.py +97 -0
  57. isongraph_ext-0.3.0/tests/test_digest.py +34 -0
  58. isongraph_ext-0.3.0/tests/test_examples.py +184 -0
  59. isongraph_ext-0.3.0/tests/test_igdm_cli.py +52 -0
  60. isongraph_ext-0.3.0/tests/test_igdm_payload.py +115 -0
  61. isongraph_ext-0.3.0/tests/test_igdm_records.py +27 -0
  62. isongraph_ext-0.3.0/tests/test_igdm_rules.py +139 -0
  63. isongraph_ext-0.3.0/tests/test_igdm_verify.py +136 -0
  64. isongraph_ext-0.3.0/tests/test_igpv_bind.py +62 -0
  65. isongraph_ext-0.3.0/tests/test_igpv_cli.py +112 -0
  66. isongraph_ext-0.3.0/tests/test_igpv_lineage.py +87 -0
  67. isongraph_ext-0.3.0/tests/test_igpv_locators.py +48 -0
  68. isongraph_ext-0.3.0/tests/test_igpv_payload.py +128 -0
  69. isongraph_ext-0.3.0/tests/test_igpv_records.py +32 -0
  70. isongraph_ext-0.3.0/tests/test_igpv_resolve.py +73 -0
  71. isongraph_ext-0.3.0/tests/test_igpv_rules.py +92 -0
  72. isongraph_ext-0.3.0/tests/test_igpv_verify.py +176 -0
  73. isongraph_ext-0.3.0/tests/test_package.py +38 -0
  74. isongraph_ext-0.3.0/tests/test_packaging.py +54 -0
  75. isongraph_ext-0.3.0/tests/test_registry.py +41 -0
  76. isongraph_ext-0.3.0/tests/test_source.py +91 -0
  77. isongraph_ext-0.3.0/tests/test_vectors.py +138 -0
  78. isongraph_ext-0.3.0/tests/test_vectors_igdm.py +103 -0
  79. isongraph_ext-0.3.0/tests/test_vectors_igpv.py +167 -0
  80. isongraph_ext-0.3.0/tests/test_verify.py +176 -0
  81. isongraph_ext-0.3.0/tests/test_versions.py +38 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mahesh Vaikri
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.
@@ -0,0 +1,144 @@
1
+ Metadata-Version: 2.4
2
+ Name: isongraph-ext
3
+ Version: 0.3.0
4
+ Summary: ISONGraphExt - IGX/1 extension bindings, IGPV/1 provenance and IGDM/1 datamatics with verifiable identity claims over ISONGraph Core
5
+ Author: Mahesh Vaikri
6
+ License-Expression: MIT
7
+ Project-URL: Repository, https://github.com/ISON-format/isongraph-ext
8
+ Project-URL: Issues, https://github.com/ISON-format/isongraph-ext/issues
9
+ Project-URL: Changelog, https://github.com/ISON-format/isongraph-ext/blob/main/CHANGELOG.md
10
+ Project-URL: Specifications, https://github.com/ISON-format/isongraph-ext/tree/main/docs/blueprint
11
+ Project-URL: ISONGraph Core, https://github.com/ISON-format/isongraph
12
+ Keywords: isongraph,ison,graph,provenance,lineage,integrity,verification,conformance
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.12
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: ison-py==1.2.0
25
+ Requires-Dist: ison-graph==1.4.1
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=8; extra == "dev"
28
+ Requires-Dist: build>=1.2; extra == "dev"
29
+ Dynamic: license-file
30
+
31
+ <p align="center">
32
+ <img src="https://raw.githubusercontent.com/ISON-format/isongraph-ext/main/assets/isongraph-banner.png" alt="ISONGraph" width="720">
33
+ </p>
34
+
35
+ <h1 align="center">isongraph-ext</h1>
36
+
37
+ <p align="center">
38
+ <strong>Prove what a graph is, where it came from, and how to show it — without changing the graph.</strong>
39
+ </p>
40
+
41
+ <p align="center">
42
+ <a href="https://github.com/ISON-format/isongraph-ext/actions/workflows/ci.yml"><img src="https://github.com/ISON-format/isongraph-ext/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
43
+ <img src="https://img.shields.io/badge/license-MIT-yellow.svg" alt="MIT License">
44
+ <img src="https://img.shields.io/badge/python-3.12%2B-blue.svg" alt="Python 3.12+">
45
+ <img src="https://img.shields.io/badge/status-alpha-orange.svg" alt="Alpha">
46
+ </p>
47
+
48
+ [ISONGraph](https://github.com/ISON-format/isongraph) stores a graph as a compact, token-efficient file. That file deliberately says nothing about **who made it**, **where its facts came from**, or **how a viewer should draw it**. `isongraph-ext` answers those three questions with small **companion files that sit next to the graph** and are tied to its exact bytes by SHA-256. The graph itself is never modified, and everything works offline.
49
+
50
+ ```text
51
+ graph.ison the ordinary ISONGraph; Core reads it exactly as before
52
+ |-- graph.igx.ison IGX/1 binding "is this the graph I was promised?"
53
+ |-- graph.igpv.ison IGPV/1 provenance "where did this come from?"
54
+ `-- graph.igdm.ison IGDM/1 datamatics "how should a viewer present it?"
55
+ ```
56
+
57
+ Each companion is optional and independent. A consumer that knows none of them still has the whole graph.
58
+
59
+ ## Install
60
+
61
+ ```bash
62
+ pip install isongraph-ext
63
+ ```
64
+
65
+ Python 3.12+. Pure Python. The only dependencies are `ison-graph==1.4.1` and `ison-py==1.2.0`, pinned exactly, because the package verifies against the Core baseline it was measured with.
66
+
67
+ ## Try it
68
+
69
+ Bind a graph to its bytes, verify it, then change one byte:
70
+
71
+ ```python
72
+ from ison_graph import ISONGraph
73
+ from isongraph_ext import igx
74
+
75
+ g = ISONGraph()
76
+ g.add_node("person", "ada", name="Ada")
77
+ g.add_node("person", "grace", name="Grace")
78
+ g.add_edge("knows", ("person", "ada"), ("person", "grace"))
79
+ data = g.to_ison().encode("utf-8")
80
+
81
+ binding = igx.bind(data, serialization_profile="ison-v1", producer_port="python", identity_claim="artifact")
82
+ result, decision = igx.verify_and_admit(binding, data)
83
+ print("admitted:", decision.admitted, "| steps:", ", ".join(result.steps_passed))
84
+
85
+ try:
86
+ igx.verify(binding, data + b"\n# edited")
87
+ except igx.IGXError as e:
88
+ print("tampered:", e.code, "at", e.step)
89
+ ```
90
+
91
+ ```text
92
+ admitted: True | steps: V0, V1, V2, V3, V4, V5
93
+ tampered: SOURCE_BINDING_MISMATCH at V4
94
+ ```
95
+
96
+ Verification is a fixed sequence of numbered steps, and every failure names the step and a stable error code.
97
+
98
+ ## Command line
99
+
100
+ ```bash
101
+ python -m isongraph_ext.igx verify graph.ison graph.igx.ison # exit 0 ok, 1 invalid, 64 usage
102
+ python -m isongraph_ext.igx admit graph.ison graph.igx.ison # exit 0 admitted, 2 denied
103
+ python -m isongraph_ext.igpv verify graph.ison graph.igx.ison graph.igpv.ison [--source SHA256=PATH]
104
+ python -m isongraph_ext.igpv origins <graph-sha256> graph.igpv.ison --node person ada
105
+ python -m isongraph_ext.igdm verify graph.ison graph.igx.ison graph.igdm.ison
106
+ ```
107
+
108
+ Output is itself ISON, so receipts can quote it verbatim.
109
+
110
+ ## What you get
111
+
112
+ | Capability | What it does |
113
+ |---|---|
114
+ | **IGX/1** binding | Pins the exact bytes, the Core version they were written with and an identity claim (`none`, `artifact`, `producer_bound`). Unknown capabilities are reported or refused, never silently ignored. |
115
+ | **IGPV/1** provenance | Attributes nodes and edges to source documents, with byte or line spans checked against the real bytes, and records derivation lineage: *this node stands for those nodes in an earlier graph*. |
116
+ | **IGDM/1** datamatics | Renderer-neutral presentation **intent**: semantic roles, emphasis, badges, groups, layout hints and accessibility text. Never colours, fonts or coordinates. |
117
+
118
+ ## Built to be checked
119
+
120
+ - **Byte-exact.** Companion files are canonical by construction: one graph, one companion, one set of bytes, one SHA-256.
121
+ - **Specified before coded.** Frozen specifications for IGX/1, IGPV/1 and IGDM/1 live in the [repository](https://github.com/ISON-format/isongraph-ext/tree/main/docs/blueprint); the code follows them, never the reverse.
122
+ - **Conformance vectors.** 156 byte-exact vectors and about 450 tests are replayed in CI on every change.
123
+ - **Pinned to a measured Core.** The package embeds the Core baseline it was verified against, plus Core's conformance receipts, so identity claims are checkable rather than asserted.
124
+ - **Hostile-input safe.** Parsing is bounded by explicit size and row budgets; verification reports the first failing step instead of guessing.
125
+
126
+ ## Examples
127
+
128
+ Four runnable demonstrations (a non-software provenance graph, a supply-chain presentation graph, a minimal generic SVG adapter and a Core-only consumer) are in the [examples folder](https://github.com/ISON-format/isongraph-ext/tree/main/examples) of the repository.
129
+
130
+ ## Status and limits
131
+
132
+ This is an **early-stage (alpha)** release. Know what it does not do:
133
+
134
+ - A verified binding proves **reproducibility and consistency, not authorship**; `producer_port` is a checked claim, not authentication.
135
+ - Provenance proves origin and lineage, **not that an extracted statement is true**.
136
+ - The cross-port identity claim and lossy producer-bound admission are reserved. Revision, delta, projection and DAG capabilities are not implemented.
137
+ - IGDM/1 carries presentation **intent only** and renders nothing.
138
+ - Python reference implementation only. Verification is an offline cost: roughly 5 seconds for a 10,000-node graph with a capability.
139
+
140
+ ## Links
141
+
142
+ [Source and issues](https://github.com/ISON-format/isongraph-ext) · [Changelog](https://github.com/ISON-format/isongraph-ext/blob/main/CHANGELOG.md) · [Security policy](https://github.com/ISON-format/isongraph-ext/blob/main/SECURITY.md) · [ISONGraph Core](https://github.com/ISON-format/isongraph)
143
+
144
+ MIT — Copyright (c) 2026 Mahesh Vaikri.
@@ -0,0 +1,114 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/ISON-format/isongraph-ext/main/assets/isongraph-banner.png" alt="ISONGraph" width="720">
3
+ </p>
4
+
5
+ <h1 align="center">isongraph-ext</h1>
6
+
7
+ <p align="center">
8
+ <strong>Prove what a graph is, where it came from, and how to show it — without changing the graph.</strong>
9
+ </p>
10
+
11
+ <p align="center">
12
+ <a href="https://github.com/ISON-format/isongraph-ext/actions/workflows/ci.yml"><img src="https://github.com/ISON-format/isongraph-ext/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
13
+ <img src="https://img.shields.io/badge/license-MIT-yellow.svg" alt="MIT License">
14
+ <img src="https://img.shields.io/badge/python-3.12%2B-blue.svg" alt="Python 3.12+">
15
+ <img src="https://img.shields.io/badge/status-alpha-orange.svg" alt="Alpha">
16
+ </p>
17
+
18
+ [ISONGraph](https://github.com/ISON-format/isongraph) stores a graph as a compact, token-efficient file. That file deliberately says nothing about **who made it**, **where its facts came from**, or **how a viewer should draw it**. `isongraph-ext` answers those three questions with small **companion files that sit next to the graph** and are tied to its exact bytes by SHA-256. The graph itself is never modified, and everything works offline.
19
+
20
+ ```text
21
+ graph.ison the ordinary ISONGraph; Core reads it exactly as before
22
+ |-- graph.igx.ison IGX/1 binding "is this the graph I was promised?"
23
+ |-- graph.igpv.ison IGPV/1 provenance "where did this come from?"
24
+ `-- graph.igdm.ison IGDM/1 datamatics "how should a viewer present it?"
25
+ ```
26
+
27
+ Each companion is optional and independent. A consumer that knows none of them still has the whole graph.
28
+
29
+ ## Install
30
+
31
+ ```bash
32
+ pip install isongraph-ext
33
+ ```
34
+
35
+ Python 3.12+. Pure Python. The only dependencies are `ison-graph==1.4.1` and `ison-py==1.2.0`, pinned exactly, because the package verifies against the Core baseline it was measured with.
36
+
37
+ ## Try it
38
+
39
+ Bind a graph to its bytes, verify it, then change one byte:
40
+
41
+ ```python
42
+ from ison_graph import ISONGraph
43
+ from isongraph_ext import igx
44
+
45
+ g = ISONGraph()
46
+ g.add_node("person", "ada", name="Ada")
47
+ g.add_node("person", "grace", name="Grace")
48
+ g.add_edge("knows", ("person", "ada"), ("person", "grace"))
49
+ data = g.to_ison().encode("utf-8")
50
+
51
+ binding = igx.bind(data, serialization_profile="ison-v1", producer_port="python", identity_claim="artifact")
52
+ result, decision = igx.verify_and_admit(binding, data)
53
+ print("admitted:", decision.admitted, "| steps:", ", ".join(result.steps_passed))
54
+
55
+ try:
56
+ igx.verify(binding, data + b"\n# edited")
57
+ except igx.IGXError as e:
58
+ print("tampered:", e.code, "at", e.step)
59
+ ```
60
+
61
+ ```text
62
+ admitted: True | steps: V0, V1, V2, V3, V4, V5
63
+ tampered: SOURCE_BINDING_MISMATCH at V4
64
+ ```
65
+
66
+ Verification is a fixed sequence of numbered steps, and every failure names the step and a stable error code.
67
+
68
+ ## Command line
69
+
70
+ ```bash
71
+ python -m isongraph_ext.igx verify graph.ison graph.igx.ison # exit 0 ok, 1 invalid, 64 usage
72
+ python -m isongraph_ext.igx admit graph.ison graph.igx.ison # exit 0 admitted, 2 denied
73
+ python -m isongraph_ext.igpv verify graph.ison graph.igx.ison graph.igpv.ison [--source SHA256=PATH]
74
+ python -m isongraph_ext.igpv origins <graph-sha256> graph.igpv.ison --node person ada
75
+ python -m isongraph_ext.igdm verify graph.ison graph.igx.ison graph.igdm.ison
76
+ ```
77
+
78
+ Output is itself ISON, so receipts can quote it verbatim.
79
+
80
+ ## What you get
81
+
82
+ | Capability | What it does |
83
+ |---|---|
84
+ | **IGX/1** binding | Pins the exact bytes, the Core version they were written with and an identity claim (`none`, `artifact`, `producer_bound`). Unknown capabilities are reported or refused, never silently ignored. |
85
+ | **IGPV/1** provenance | Attributes nodes and edges to source documents, with byte or line spans checked against the real bytes, and records derivation lineage: *this node stands for those nodes in an earlier graph*. |
86
+ | **IGDM/1** datamatics | Renderer-neutral presentation **intent**: semantic roles, emphasis, badges, groups, layout hints and accessibility text. Never colours, fonts or coordinates. |
87
+
88
+ ## Built to be checked
89
+
90
+ - **Byte-exact.** Companion files are canonical by construction: one graph, one companion, one set of bytes, one SHA-256.
91
+ - **Specified before coded.** Frozen specifications for IGX/1, IGPV/1 and IGDM/1 live in the [repository](https://github.com/ISON-format/isongraph-ext/tree/main/docs/blueprint); the code follows them, never the reverse.
92
+ - **Conformance vectors.** 156 byte-exact vectors and about 450 tests are replayed in CI on every change.
93
+ - **Pinned to a measured Core.** The package embeds the Core baseline it was verified against, plus Core's conformance receipts, so identity claims are checkable rather than asserted.
94
+ - **Hostile-input safe.** Parsing is bounded by explicit size and row budgets; verification reports the first failing step instead of guessing.
95
+
96
+ ## Examples
97
+
98
+ Four runnable demonstrations (a non-software provenance graph, a supply-chain presentation graph, a minimal generic SVG adapter and a Core-only consumer) are in the [examples folder](https://github.com/ISON-format/isongraph-ext/tree/main/examples) of the repository.
99
+
100
+ ## Status and limits
101
+
102
+ This is an **early-stage (alpha)** release. Know what it does not do:
103
+
104
+ - A verified binding proves **reproducibility and consistency, not authorship**; `producer_port` is a checked claim, not authentication.
105
+ - Provenance proves origin and lineage, **not that an extracted statement is true**.
106
+ - The cross-port identity claim and lossy producer-bound admission are reserved. Revision, delta, projection and DAG capabilities are not implemented.
107
+ - IGDM/1 carries presentation **intent only** and renders nothing.
108
+ - Python reference implementation only. Verification is an offline cost: roughly 5 seconds for a 10,000-node graph with a capability.
109
+
110
+ ## Links
111
+
112
+ [Source and issues](https://github.com/ISON-format/isongraph-ext) · [Changelog](https://github.com/ISON-format/isongraph-ext/blob/main/CHANGELOG.md) · [Security policy](https://github.com/ISON-format/isongraph-ext/blob/main/SECURITY.md) · [ISONGraph Core](https://github.com/ISON-format/isongraph)
113
+
114
+ MIT — Copyright (c) 2026 Mahesh Vaikri.
@@ -0,0 +1,47 @@
1
+ [build-system]
2
+ requires = ["setuptools>=69", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "isongraph-ext"
7
+ version = "0.3.0"
8
+ description = "ISONGraphExt - IGX/1 extension bindings, IGPV/1 provenance and IGDM/1 datamatics with verifiable identity claims over ISONGraph Core"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ authors = [{name = "Mahesh Vaikri"}]
13
+ requires-python = ">=3.12"
14
+ # Exact pins: the reference runtime IS the implementation the Core baseline was measured with (17 §3, §4 V0).
15
+ dependencies = ["ison-py==1.2.0", "ison-graph==1.4.1"]
16
+ keywords = ["isongraph", "ison", "graph", "provenance", "lineage", "integrity", "verification", "conformance"]
17
+ classifiers = [
18
+ "Development Status :: 3 - Alpha",
19
+ "Intended Audience :: Developers",
20
+ "Operating System :: OS Independent",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3 :: Only",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Topic :: Software Development :: Libraries :: Python Modules",
25
+ "Typing :: Typed",
26
+ ]
27
+
28
+ [project.optional-dependencies]
29
+ dev = ["pytest>=8", "build>=1.2"]
30
+
31
+ [project.urls]
32
+ Repository = "https://github.com/ISON-format/isongraph-ext"
33
+ Issues = "https://github.com/ISON-format/isongraph-ext/issues"
34
+ Changelog = "https://github.com/ISON-format/isongraph-ext/blob/main/CHANGELOG.md"
35
+ Specifications = "https://github.com/ISON-format/isongraph-ext/tree/main/docs/blueprint"
36
+ "ISONGraph Core" = "https://github.com/ISON-format/isongraph"
37
+
38
+ [tool.setuptools.packages.find]
39
+ where = ["src"]
40
+
41
+ [tool.setuptools.package-data]
42
+ isongraph_ext = ["py.typed", "baselines/REGISTRY.ison", "baselines/*/MANIFEST.ison", "baselines/*/domains.ison", "baselines/*/receipts/*.ison"]
43
+
44
+ [tool.pytest.ini_options]
45
+ testpaths = ["tests"]
46
+ addopts = "-q --tb=short"
47
+ pythonpath = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ """ISONGraphExt - extension bindings, provenance and datamatics over ISONGraph Core (IGX/1, IGPV/1, IGDM/1)."""
2
+
3
+ __version__ = "0.3.0"
@@ -0,0 +1,3 @@
1
+ table.baselines
2
+ adopted core_commit retired
3
+ 2026-11-05 ce9d3b78afd79cbdffdd67546bcb5278dc38be70 false
@@ -0,0 +1,22 @@
1
+ meta.baseline
2
+ canonical_writer_dist canonical_writer_dist_version core_commit core_format core_runtime_dist core_runtime_dist_version core_semantic_spec core_vector_corpus_commit core_vector_corpus_digest core_vector_corpus_version core_version
3
+ ison-py 1.2.0 ce9d3b78afd79cbdffdd67546bcb5278dc38be70 isongraph ison-graph 1.4.1 ISONGraph-Semantic/2-draft f88af8bd29680e7b6e7716585be936d5738eb55f 1d1a6648abeeadece24b43a163949d02241911706866236cc32bd6b61745bcb0 1 1.4.1
4
+
5
+ table.core_runtime
6
+ module sha256
7
+ ison_graph/__init__.py 2a13a36d63d85e766df961aae2d52550c2e9c52f60a5ee46560ddce4a301ece4
8
+ ison_graph/multigraph.py 6d4e874a75f43d8914422bf2006f995a6334bfe4fe9eb5552c0f2f31fb4ff3e6
9
+ ison_graph/query.py d0c34fa8649de066049a1670ccc00f8af28029c2ed7374256b9fb9a978423cd4
10
+ ison_graph/schema.py 06f82dc13eb02794b11d0386c8f8090b0f9a5d2f48be839e828703e2e5e2d1b4
11
+ ison_graph/structural.py ffa53c3edd5dc76e6e7db20b74473f59bb6b329b09479445699eeba59e2232c7
12
+ ison_graph/viz.py e62949eb91c9a3fe4be3972de94baddf7f41f034f5c61db51ceb8bcb4ca9b6d6
13
+
14
+ table.files
15
+ path sha256
16
+ "domains.ison" 6d9db34ceedd5c1309060bc2dfeddcdd302b6664737bfe904c14391870254897
17
+ receipts/cpp.ison b330dc23e4d882c71942d035d1848f03841f932345c823f93b560c86f40e83a8
18
+ receipts/cs.ison f37d41566cf69c3e6b933483946bc8559c8ceb160c2d6d4ea36caab8f94ccfc7
19
+ receipts/js.ison acbe2104736148bf19c0d93649781b9c142066bec4fe1ab0b6fdc116abc39ed6
20
+ receipts/python.ison cece1259ac61172a1d519b5ad31cef8b29ff3e466f629f4cb72b4f34fdda9ac0
21
+ receipts/rust.ison 6dd9c2dcf5407f598233f6c3f21bf831a02f141a509ff45b112729ae35690040
22
+ receipts/ts.ison 393ba7e64e6c2be3606f2e8b03124dd2ff0cef33d069f38c6cb0b075dec268c4
@@ -0,0 +1,8 @@
1
+ table.domains
2
+ port tag
3
+ js binary64-inexact-int
4
+ js integral-float-collapse
5
+ js multigraph-document-accepted
6
+ ts binary64-inexact-int
7
+ ts integral-float-collapse
8
+ ts multigraph-document-accepted
@@ -0,0 +1,3 @@
1
+ meta.core_conformance_receipt
2
+ canonicalized core_commit core_format core_version corpus_commit corpus_digest corpus_version defect lossy pass port port_version posture rejected_as_expected semantic_spec todo total
3
+ 0 ce9d3b78afd79cbdffdd67546bcb5278dc38be70 isongraph 1.4.1 f88af8bd29680e7b6e7716585be936d5738eb55f 1d1a6648abeeadece24b43a163949d02241911706866236cc32bd6b61745bcb0 1 0 0 0 cpp 1.4.1 PARTIAL 0 ISONGraph-Semantic/2-draft 32 32
@@ -0,0 +1,3 @@
1
+ meta.core_conformance_receipt
2
+ canonicalized core_commit core_format core_version corpus_commit corpus_digest corpus_version defect lossy pass port port_version posture rejected_as_expected semantic_spec todo total
3
+ 0 ce9d3b78afd79cbdffdd67546bcb5278dc38be70 isongraph 1.4.1 f88af8bd29680e7b6e7716585be936d5738eb55f 1d1a6648abeeadece24b43a163949d02241911706866236cc32bd6b61745bcb0 1 0 0 0 cs 1.4.1 PARTIAL 0 ISONGraph-Semantic/2-draft 32 32
@@ -0,0 +1,3 @@
1
+ meta.core_conformance_receipt
2
+ canonicalized core_commit core_format core_version corpus_commit corpus_digest corpus_version defect lossy pass port port_version posture rejected_as_expected semantic_spec todo total
3
+ 6 ce9d3b78afd79cbdffdd67546bcb5278dc38be70 isongraph 1.4.1 f88af8bd29680e7b6e7716585be936d5738eb55f 1d1a6648abeeadece24b43a163949d02241911706866236cc32bd6b61745bcb0 1 1 4 16 js 1.4.1 KNOWN_DEFECT 5 ISONGraph-Semantic/2-draft 0 32
@@ -0,0 +1,3 @@
1
+ meta.core_conformance_receipt
2
+ canonicalized core_commit core_format core_version corpus_commit corpus_digest corpus_version defect lossy pass port port_version posture rejected_as_expected semantic_spec todo total
3
+ 7 ce9d3b78afd79cbdffdd67546bcb5278dc38be70 isongraph 1.4.1 f88af8bd29680e7b6e7716585be936d5738eb55f 1d1a6648abeeadece24b43a163949d02241911706866236cc32bd6b61745bcb0 1 0 0 19 python 1.4.1 FULL 6 ISONGraph-Semantic/2-draft 0 32
@@ -0,0 +1,3 @@
1
+ meta.core_conformance_receipt
2
+ canonicalized core_commit core_format core_version corpus_commit corpus_digest corpus_version defect lossy pass port port_version posture rejected_as_expected semantic_spec todo total
3
+ 0 ce9d3b78afd79cbdffdd67546bcb5278dc38be70 isongraph 1.4.1 f88af8bd29680e7b6e7716585be936d5738eb55f 1d1a6648abeeadece24b43a163949d02241911706866236cc32bd6b61745bcb0 1 0 0 0 rust 1.4.1 PARTIAL 0 ISONGraph-Semantic/2-draft 32 32
@@ -0,0 +1,3 @@
1
+ meta.core_conformance_receipt
2
+ canonicalized core_commit core_format core_version corpus_commit corpus_digest corpus_version defect lossy pass port port_version posture rejected_as_expected semantic_spec todo total
3
+ 6 ce9d3b78afd79cbdffdd67546bcb5278dc38be70 isongraph 1.4.1 f88af8bd29680e7b6e7716585be936d5738eb55f 1d1a6648abeeadece24b43a163949d02241911706866236cc32bd6b61745bcb0 1 1 4 16 ts 1.4.1 KNOWN_DEFECT 5 ISONGraph-Semantic/2-draft 0 32
@@ -0,0 +1,13 @@
1
+ """IGDM/1 Datamatics (19-IGDM1-DESIGN.md)."""
2
+
3
+ from ..igpv.records import EdgeAddress, NodeRef
4
+ from ..igx.registry import DEFAULT_REGISTRY
5
+ from .bind import bind, verify_and_admit
6
+ from .errors import IGDMError
7
+ from .payload import DatamaticsPayload, check_references, unrecognized_roles
8
+ from .records import DEFAULT_LIMITS, EdgeHints, Group, LayoutHints, Limits, Member, NodeHints
9
+ from .verify import DatamaticsVerification, verify
10
+
11
+ __all__ = ["IGDMError", "DEFAULT_LIMITS", "EdgeHints", "Group", "LayoutHints", "Limits", "Member", "NodeHints", "EdgeAddress", "NodeRef",
12
+ "DEFAULT_REGISTRY", "DatamaticsPayload", "check_references", "unrecognized_roles", "DatamaticsVerification", "verify",
13
+ "bind", "verify_and_admit"]
@@ -0,0 +1,92 @@
1
+ """CLI (19 §4): verify -> 0/1/2, 64 on usage; one canonical ISON document per response."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import sys
7
+ from collections.abc import Mapping
8
+ from pathlib import Path
9
+
10
+ from ison_parser import Block, Document, dumps_canonical
11
+
12
+ from ..igx.admit import AdmissionPolicy
13
+ from ..igx.binding import ExtensionBinding
14
+ from ..igx.errors import IGXError
15
+ from .bind import verify_and_admit
16
+ from .errors import IGDMError
17
+
18
+ EX_USAGE = 64 # BSD sysexits: never collides with 2 (admission denied) or 1 (invalid binding/payload)
19
+
20
+
21
+ class _Parser(argparse.ArgumentParser):
22
+ def error(self, message: str) -> None: # type: ignore[override]
23
+ self.print_usage(sys.stderr)
24
+ sys.stderr.write(f"error: {message}\n")
25
+ raise SystemExit(EX_USAGE)
26
+
27
+
28
+ def _utf8_streams() -> None:
29
+ """Output is UTF-8, LF-terminated ISON regardless of console locale or platform (same rule as the igx CLI)."""
30
+ for stream in (sys.stdout, sys.stderr):
31
+ reconfigure = getattr(stream, "reconfigure", None)
32
+ if reconfigure is not None:
33
+ reconfigure(encoding="utf-8", errors="strict", newline="\n")
34
+
35
+
36
+ def _meta(name: str, row: dict) -> Block:
37
+ return Block("meta", name, list(row), [row])
38
+
39
+
40
+ def _emit(blocks: list[Block]) -> None:
41
+ sys.stdout.write(dumps_canonical(Document(blocks=blocks)) + "\n")
42
+
43
+
44
+ def _joined(items) -> str | None:
45
+ items = list(items)
46
+ return ",".join(items) if items else None
47
+
48
+
49
+ def _kv(m: Mapping) -> str | None:
50
+ return _joined(f"{k}={v}" for k, v in m.items())
51
+
52
+
53
+ def main(argv: list[str]) -> int:
54
+ _utf8_streams()
55
+ ap = _Parser(prog="python -m isongraph_ext.igdm")
56
+ sub = ap.add_subparsers(dest="cmd", required=True)
57
+ v = sub.add_parser("verify")
58
+ v.add_argument("graph", type=Path)
59
+ v.add_argument("binding", type=Path)
60
+ v.add_argument("payload", type=Path)
61
+ v.add_argument("--allow-retired", action="store_true")
62
+ a = ap.parse_args(argv)
63
+ try:
64
+ graph, binding_bytes, payload_bytes = a.graph.read_bytes(), a.binding.read_bytes(), a.payload.read_bytes()
65
+ except OSError as e:
66
+ ap.print_usage(sys.stderr)
67
+ sys.stderr.write(f"error: {e}\n")
68
+ return EX_USAGE
69
+ try:
70
+ binding = ExtensionBinding.from_ison(binding_bytes)
71
+ result, dm, decision = verify_and_admit(payload_bytes, binding, graph, policy=AdmissionPolicy(allow_retired_baselines=a.allow_retired))
72
+ except (IGXError, IGDMError) as e:
73
+ _emit([_meta("error", {"code": e.code, "field": e.field, "detail": e.detail, "step": e.step})])
74
+ return 1
75
+ _emit([
76
+ _meta("verification", {
77
+ "binding_digest": result.binding_digest, "semantic_verification": result.semantic_verification,
78
+ "source_canonical": result.source_canonical, "source_semantic_eligibility": result.source_semantic_eligibility,
79
+ "source_semantic_reason": result.source_semantic_reason, "steps_passed": _joined(result.steps_passed),
80
+ "unrecognized_optional": _joined(c.extension for c in result.unrecognized_optional)}),
81
+ _meta("datamatics", {
82
+ "payload_sha256": dm.payload_sha256, "binding_digest": dm.binding_digest, "target_artifact_sha256": dm.target_artifact_sha256,
83
+ "object_resolution": dm.object_resolution, "unrecognized_roles": _joined(dm.unrecognized_roles),
84
+ "counts": _kv(dm.counts), "steps_passed": _joined(dm.steps_passed)}),
85
+ _meta("admission", {"admitted": decision.admitted, "code": decision.code, "step": decision.step,
86
+ "receipt_posture": decision.receipt_posture, "reasons": _joined(decision.reasons)}),
87
+ ])
88
+ return 0 if decision.admitted else 2
89
+
90
+
91
+ if __name__ == "__main__":
92
+ sys.exit(main(sys.argv[1:]))
@@ -0,0 +1,49 @@
1
+ """Producer path and trustworthy consumer path (19 §4), mirroring igpv.bind."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Mapping, Sequence
6
+
7
+ from ..igx.admit import DEFAULT_POLICY, AdmissionPolicy, AdmissionResult, admit
8
+ from ..igx.baselines import BASELINES, DEFAULT_BASELINE, Baseline
9
+ from ..igx.bind import bind as igx_bind
10
+ from ..igx.binding import Capability, Consumer, ExtensionBinding
11
+ from ..igx.digest import sha256_hex
12
+ from ..igx.registry import DEFAULT_REGISTRY, CapabilityRegistry
13
+ from ..igx.source import as_bytes
14
+ from ..igx.verify import VerificationResult
15
+ from . import records as R
16
+ from .errors import IGDMError
17
+ from .payload import DatamaticsPayload
18
+ from .verify import DatamaticsVerification, verify
19
+
20
+
21
+ def bind(target: str | bytes, payload: DatamaticsPayload, *, requirement: str = "REQUIRED", serialization_profile: str,
22
+ producer_port: str, identity_claim: str, capabilities: Sequence[Capability] = (), consumer: Consumer | None = None,
23
+ baseline: Baseline = DEFAULT_BASELINE, registry: CapabilityRegistry = DEFAULT_REGISTRY,
24
+ policy: AdmissionPolicy = DEFAULT_POLICY, limits: R.Limits = R.DEFAULT_LIMITS) -> ExtensionBinding:
25
+ if requirement not in ("REQUIRED", "OPTIONAL"):
26
+ raise IGDMError("MALFORMED_DATAMATICS", "table.capabilities.igdm.requirement", "REQUIRED or OPTIONAL", "D1")
27
+ if any(c.extension == R.CAPABILITY for c in capabilities):
28
+ raise IGDMError("MALFORMED_DATAMATICS", "table.capabilities.igdm", "bind() adds the igdm row itself; do not pass one", "D1")
29
+ payload.check()
30
+ data = as_bytes(target)
31
+ actual = sha256_hex(data)
32
+ if payload.target_artifact_sha256 != actual:
33
+ raise IGDMError("TARGET_BINDING_MISMATCH", "meta.igdm.target_artifact_sha256", f"target bytes hash to {actual}", "D2")
34
+ if payload.target_serialization_profile != serialization_profile:
35
+ raise IGDMError("TARGET_BINDING_MISMATCH", "meta.igdm.target_serialization_profile",
36
+ f"{payload.target_serialization_profile} != {serialization_profile}", "D2")
37
+ caps = tuple(capabilities) + (Capability(R.CAPABILITY, R.CAPABILITY_RANGE, requirement, payload.digest),)
38
+ binding = igx_bind(data, serialization_profile=serialization_profile, producer_port=producer_port, identity_claim=identity_claim,
39
+ capabilities=caps, consumer=consumer, baseline=baseline, registry=registry, policy=policy)
40
+ verify(payload, binding, data, limits=limits, baselines={**BASELINES, baseline.core_commit: baseline}, registry=registry)
41
+ return binding
42
+
43
+
44
+ def verify_and_admit(payload: str | bytes | DatamaticsPayload, binding: ExtensionBinding, target: str | bytes, *,
45
+ limits: R.Limits = R.DEFAULT_LIMITS, baselines: Mapping[str, Baseline] = BASELINES,
46
+ registry: CapabilityRegistry = DEFAULT_REGISTRY, policy: AdmissionPolicy = DEFAULT_POLICY
47
+ ) -> tuple[VerificationResult, DatamaticsVerification, AdmissionResult]:
48
+ result, dm = verify(payload, binding, target, limits=limits, baselines=baselines, registry=registry)
49
+ return result, dm, admit(binding, result, policy=policy, baselines=baselines)
@@ -0,0 +1,12 @@
1
+ """The one exception type IGDM/1 raises (19 §3.1). Admission denials are the binding's results, not exceptions."""
2
+
3
+ from __future__ import annotations
4
+
5
+
6
+ class IGDMError(Exception):
7
+ def __init__(self, code: str, field: str, detail: str, step: str) -> None:
8
+ super().__init__(f"{step} {code} {field}: {detail}")
9
+ self.code = code
10
+ self.field = field
11
+ self.detail = detail
12
+ self.step = step