tiergraph 0.1.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 (119) hide show
  1. tiergraph-0.1.0/.github/workflows/ci.yml +87 -0
  2. tiergraph-0.1.0/.github/workflows/publish.yml +55 -0
  3. tiergraph-0.1.0/.gitignore +13 -0
  4. tiergraph-0.1.0/.pre-commit-config.yaml +32 -0
  5. tiergraph-0.1.0/CHANGELOG.md +21 -0
  6. tiergraph-0.1.0/CONTRIBUTING.md +75 -0
  7. tiergraph-0.1.0/LICENSE +24 -0
  8. tiergraph-0.1.0/Makefile +59 -0
  9. tiergraph-0.1.0/PKG-INFO +160 -0
  10. tiergraph-0.1.0/README.md +127 -0
  11. tiergraph-0.1.0/RELEASING.md +95 -0
  12. tiergraph-0.1.0/SECURITY.md +27 -0
  13. tiergraph-0.1.0/docs/README.md +39 -0
  14. tiergraph-0.1.0/docs/concepts.md +138 -0
  15. tiergraph-0.1.0/docs/contributing-docs.md +13 -0
  16. tiergraph-0.1.0/docs/format.md +43 -0
  17. tiergraph-0.1.0/docs/getting-started.md +224 -0
  18. tiergraph-0.1.0/docs/guide/construction.md +142 -0
  19. tiergraph-0.1.0/docs/guide/folding.md +218 -0
  20. tiergraph-0.1.0/docs/guide/profiles.md +139 -0
  21. tiergraph-0.1.0/docs/guide/recognize-and-act.md +234 -0
  22. tiergraph-0.1.0/docs/guide/selection-and-traversal.md +219 -0
  23. tiergraph-0.1.0/docs/guide/serialization.md +146 -0
  24. tiergraph-0.1.0/docs/guide/span-views.md +21 -0
  25. tiergraph-0.1.0/docs/guide/timing.md +144 -0
  26. tiergraph-0.1.0/docs/manifest.json +74 -0
  27. tiergraph-0.1.0/docs/reference/api.md +3969 -0
  28. tiergraph-0.1.0/docs/reference/cli.md +436 -0
  29. tiergraph-0.1.0/examples/__init__.py +1 -0
  30. tiergraph-0.1.0/examples/caption_alignment.py +64 -0
  31. tiergraph-0.1.0/examples/critical_path.py +101 -0
  32. tiergraph-0.1.0/examples/json_document.py +39 -0
  33. tiergraph-0.1.0/examples/mix_paths.py +511 -0
  34. tiergraph-0.1.0/examples/mixing.py +208 -0
  35. tiergraph-0.1.0/examples/text_segmentation.py +111 -0
  36. tiergraph-0.1.0/pyproject.toml +77 -0
  37. tiergraph-0.1.0/schema/tiergraph.schema.json +893 -0
  38. tiergraph-0.1.0/schema/tiergraph.schema.sha256 +5 -0
  39. tiergraph-0.1.0/scripts/__init__.py +1 -0
  40. tiergraph-0.1.0/scripts/check_documented.py +46 -0
  41. tiergraph-0.1.0/scripts/check_tracked_clean.py +70 -0
  42. tiergraph-0.1.0/scripts/generate_docs.py +467 -0
  43. tiergraph-0.1.0/scripts/generate_schema.py +100 -0
  44. tiergraph-0.1.0/src/tiergraph/__init__.py +325 -0
  45. tiergraph-0.1.0/src/tiergraph/__main__.py +6 -0
  46. tiergraph-0.1.0/src/tiergraph/action.py +492 -0
  47. tiergraph-0.1.0/src/tiergraph/build.py +838 -0
  48. tiergraph-0.1.0/src/tiergraph/cli/__init__.py +804 -0
  49. tiergraph-0.1.0/src/tiergraph/clock.py +680 -0
  50. tiergraph-0.1.0/src/tiergraph/core.py +1586 -0
  51. tiergraph-0.1.0/src/tiergraph/fold.py +831 -0
  52. tiergraph-0.1.0/src/tiergraph/grammar.py +1286 -0
  53. tiergraph-0.1.0/src/tiergraph/inspect.py +41 -0
  54. tiergraph-0.1.0/src/tiergraph/machine.py +1417 -0
  55. tiergraph-0.1.0/src/tiergraph/machine_codec.py +106 -0
  56. tiergraph-0.1.0/src/tiergraph/path.py +497 -0
  57. tiergraph-0.1.0/src/tiergraph/py.typed +0 -0
  58. tiergraph-0.1.0/src/tiergraph/root.py +222 -0
  59. tiergraph-0.1.0/src/tiergraph/schema.py +537 -0
  60. tiergraph-0.1.0/src/tiergraph/selection.py +364 -0
  61. tiergraph-0.1.0/src/tiergraph/selection_query.py +277 -0
  62. tiergraph-0.1.0/src/tiergraph/semiring.py +660 -0
  63. tiergraph-0.1.0/src/tiergraph/spanview.py +491 -0
  64. tiergraph-0.1.0/src/tiergraph/traversal.py +634 -0
  65. tiergraph-0.1.0/src/tiergraph/value.py +481 -0
  66. tiergraph-0.1.0/src/tiergraph/wire.py +626 -0
  67. tiergraph-0.1.0/src/tiergraph_dot/__init__.py +979 -0
  68. tiergraph-0.1.0/src/tiergraph_dot/py.typed +0 -0
  69. tiergraph-0.1.0/tests/__init__.py +1 -0
  70. tiergraph-0.1.0/tests/conformance/__init__.py +1 -0
  71. tiergraph-0.1.0/tests/conformance/action.py +89 -0
  72. tiergraph-0.1.0/tests/conformance/declared_schema_codec_divergences.py +55 -0
  73. tiergraph-0.1.0/tests/conformance/fold.py +302 -0
  74. tiergraph-0.1.0/tests/conformance/kernel.py +237 -0
  75. tiergraph-0.1.0/tests/conformance/machine.py +570 -0
  76. tiergraph-0.1.0/tests/conformance/recognition.py +66 -0
  77. tiergraph-0.1.0/tests/conformance/schema.py +33 -0
  78. tiergraph-0.1.0/tests/conformance/schema_codec.py +327 -0
  79. tiergraph-0.1.0/tests/conformance/selection.py +323 -0
  80. tiergraph-0.1.0/tests/conformance/traversal.py +248 -0
  81. tiergraph-0.1.0/tests/conformance/wire.py +74 -0
  82. tiergraph-0.1.0/tests/semiring_laws.py +175 -0
  83. tiergraph-0.1.0/tests/test_action.py +472 -0
  84. tiergraph-0.1.0/tests/test_alignment_witness.py +359 -0
  85. tiergraph-0.1.0/tests/test_alternation_witness.py +566 -0
  86. tiergraph-0.1.0/tests/test_boundary_witness.py +247 -0
  87. tiergraph-0.1.0/tests/test_build.py +785 -0
  88. tiergraph-0.1.0/tests/test_cli.py +1761 -0
  89. tiergraph-0.1.0/tests/test_clock.py +1026 -0
  90. tiergraph-0.1.0/tests/test_core.py +1200 -0
  91. tiergraph-0.1.0/tests/test_docs.py +308 -0
  92. tiergraph-0.1.0/tests/test_dot.py +2009 -0
  93. tiergraph-0.1.0/tests/test_examples.py +43 -0
  94. tiergraph-0.1.0/tests/test_external_reference_witness.py +361 -0
  95. tiergraph-0.1.0/tests/test_fold.py +762 -0
  96. tiergraph-0.1.0/tests/test_fold_witness.py +416 -0
  97. tiergraph-0.1.0/tests/test_grammar.py +709 -0
  98. tiergraph-0.1.0/tests/test_inspect.py +50 -0
  99. tiergraph-0.1.0/tests/test_machine.py +1016 -0
  100. tiergraph-0.1.0/tests/test_machine_codec.py +173 -0
  101. tiergraph-0.1.0/tests/test_mix_paths.py +426 -0
  102. tiergraph-0.1.0/tests/test_ordered_containment.py +384 -0
  103. tiergraph-0.1.0/tests/test_ordered_polyadic_traversal.py +293 -0
  104. tiergraph-0.1.0/tests/test_package.py +35 -0
  105. tiergraph-0.1.0/tests/test_path.py +381 -0
  106. tiergraph-0.1.0/tests/test_path_alternation.py +373 -0
  107. tiergraph-0.1.0/tests/test_polyadic_relations.py +430 -0
  108. tiergraph-0.1.0/tests/test_publishability_guards.py +71 -0
  109. tiergraph-0.1.0/tests/test_root.py +383 -0
  110. tiergraph-0.1.0/tests/test_schema.py +457 -0
  111. tiergraph-0.1.0/tests/test_schema_codec_conformance.py +259 -0
  112. tiergraph-0.1.0/tests/test_selection.py +164 -0
  113. tiergraph-0.1.0/tests/test_semiring.py +421 -0
  114. tiergraph-0.1.0/tests/test_semiring_law_discrimination.py +208 -0
  115. tiergraph-0.1.0/tests/test_spanview.py +538 -0
  116. tiergraph-0.1.0/tests/test_text_domain.py +244 -0
  117. tiergraph-0.1.0/tests/test_traversal.py +52 -0
  118. tiergraph-0.1.0/tests/test_value.py +441 -0
  119. tiergraph-0.1.0/tests/test_wire.py +784 -0
@@ -0,0 +1,87 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+
9
+ concurrency:
10
+ group: ci-${{ github.ref }}
11
+ cancel-in-progress: true
12
+
13
+ permissions:
14
+ contents: read
15
+
16
+ jobs:
17
+ test-python-313:
18
+ name: test (Python 3.13)
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@v5
22
+ # Only run the 3.13 compatibility suite when code changes; a docs- or
23
+ # metadata-only change cannot affect it, and the job still reports success
24
+ # so a required check does not hang.
25
+ - uses: dorny/paths-filter@v3
26
+ id: changes
27
+ with:
28
+ filters: |
29
+ code:
30
+ - 'src/**'
31
+ - 'tests/**'
32
+ - 'examples/**'
33
+ - 'scripts/**'
34
+ - 'pyproject.toml'
35
+ - '.github/workflows/ci.yml'
36
+ - if: steps.changes.outputs.code == 'true'
37
+ uses: actions/setup-python@v6
38
+ with:
39
+ python-version: "3.13"
40
+ cache: pip
41
+ cache-dependency-path: pyproject.toml
42
+ - if: steps.changes.outputs.code == 'true'
43
+ run: python -m pip install --upgrade pip
44
+ - if: steps.changes.outputs.code == 'true'
45
+ run: python -m pip install -e ".[test]"
46
+ # The documentation gate type-checks doc code fences with mypy (a dev-tooling
47
+ # concern pinned to the 3.12 environment) and is covered by the full make check job.
48
+ - if: steps.changes.outputs.code == 'true'
49
+ run: python -m pytest --deselect tests/test_docs.py::test_documentation_gate_is_current
50
+ - if: steps.changes.outputs.code != 'true'
51
+ run: echo "No code changed; skipping the 3.13 compatibility suite."
52
+
53
+ check:
54
+ runs-on: ubuntu-latest
55
+ steps:
56
+ - uses: actions/checkout@v5
57
+ # The full gate runs whenever code or gate-checked docs change. A change
58
+ # confined to inert files -- the release workflow, release notes, the
59
+ # license -- skips it, and the job still reports success so the required
60
+ # check does not hang. Anything under src, tests, docs, examples, scripts,
61
+ # or the build files keeps docs currency and code gated.
62
+ - uses: dorny/paths-filter@v3
63
+ id: changes
64
+ with:
65
+ filters: |
66
+ gated:
67
+ - 'src/**'
68
+ - 'tests/**'
69
+ - 'examples/**'
70
+ - 'scripts/**'
71
+ - 'docs/**'
72
+ - 'pyproject.toml'
73
+ - 'Makefile'
74
+ - 'README.md'
75
+ - '.github/workflows/ci.yml'
76
+ - if: steps.changes.outputs.gated == 'true'
77
+ uses: actions/setup-python@v6
78
+ with:
79
+ python-version: "3.13"
80
+ cache: pip
81
+ cache-dependency-path: pyproject.toml
82
+ # make check builds its own environment, so CI runs the same path as a
83
+ # developer rather than a parallel one that can drift.
84
+ - if: steps.changes.outputs.gated == 'true'
85
+ run: make check
86
+ - if: steps.changes.outputs.gated != 'true'
87
+ run: echo "Only inert files changed (workflow or release notes); skipping the full gate."
@@ -0,0 +1,55 @@
1
+ name: Publish
2
+
3
+ # Build once, then publish via PyPI Trusted Publishing (OIDC) -- no API tokens.
4
+ # Cut a GitHub Release (tag vX.Y.Z) to publish to PyPI.
5
+ #
6
+ # One-time setup (see RELEASING.md):
7
+ # - PyPI: add a Trusted Publisher (project tiergraph, this repo, workflow
8
+ # publish.yml, environment "pypi").
9
+ # - GitHub: create environment "pypi" (Settings > Environments).
10
+
11
+ on:
12
+ release:
13
+ types: [published]
14
+
15
+ permissions:
16
+ contents: read
17
+
18
+ jobs:
19
+ build:
20
+ name: build sdist + wheel
21
+ runs-on: ubuntu-latest
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+ - uses: actions/setup-python@v7
25
+ with:
26
+ python-version: "3.12"
27
+ - run: python -m pip install --upgrade pip build
28
+ - run: python -m build
29
+ - name: Verify version matches release tag
30
+ env:
31
+ TAG: ${{ github.event.release.tag_name }}
32
+ run: |
33
+ VERSION=$(PYTHONPATH=src python -c "import tiergraph; print(tiergraph.__version__)")
34
+ echo "tiergraph.__version__=$VERSION release tag=$TAG"
35
+ test "$VERSION" = "${TAG#v}"
36
+ - uses: actions/upload-artifact@v4
37
+ with:
38
+ name: dist
39
+ path: dist/
40
+
41
+ publish-pypi:
42
+ name: publish to PyPI
43
+ needs: build
44
+ runs-on: ubuntu-latest
45
+ environment:
46
+ name: pypi
47
+ url: https://pypi.org/p/tiergraph
48
+ permissions:
49
+ id-token: write
50
+ steps:
51
+ - uses: actions/download-artifact@v4
52
+ with:
53
+ name: dist
54
+ path: dist/
55
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,13 @@
1
+ untracked/
2
+
3
+ __pycache__/
4
+ *.py[cod]
5
+ .coverage
6
+ .hypothesis/
7
+ .mypy_cache/
8
+ .pytest_cache/
9
+ .ruff_cache/
10
+ build/
11
+ dist/
12
+ *.egg-info/
13
+ .venv/
@@ -0,0 +1,32 @@
1
+ minimum_pre_commit_version: "3.0.0"
2
+
3
+ repos:
4
+ - repo: https://github.com/pre-commit/pre-commit-hooks
5
+ rev: v6.0.0
6
+ hooks:
7
+ - id: trailing-whitespace
8
+ - id: end-of-file-fixer
9
+ - id: check-yaml
10
+ - id: check-toml
11
+ - id: check-merge-conflict
12
+ - id: check-added-large-files
13
+
14
+ - repo: https://github.com/astral-sh/ruff-pre-commit
15
+ rev: v0.16.1
16
+ hooks:
17
+ - id: ruff-check
18
+ args: ["--fix"]
19
+ - id: ruff-format
20
+
21
+ - repo: local
22
+ hooks:
23
+ - id: tracked-clean
24
+ name: tracked files carry nothing local
25
+ entry: python scripts/check_tracked_clean.py
26
+ language: system
27
+ pass_filenames: false
28
+ - id: documented
29
+ name: public names carry a docstring
30
+ entry: python scripts/check_documented.py
31
+ language: system
32
+ pass_filenames: false
@@ -0,0 +1,21 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.1.0] - 2026-08-23
9
+
10
+ ### Added
11
+
12
+ - Immutable ordered-tier graphs with declared namespaces, typed attributes, item and boundary references, and simple, bipartite, and polyadic relations.
13
+ - A checked opcode `Program` and build machine for declaring and populating graphs, with bounded repetition, execution traces, and unrolling to an immutable `Graph`.
14
+ - Semiring folds over finite dependency DAGs, including exact min- and max-plus carriers and the `PATH` semiring's tied best-path provenance and capped n-best ranked witnesses.
15
+ - Clock profiles for structural refinement and physical timing, including `ClockProfile.from_position_values`, optional shared-boundary collapse, and the `is_structural` capability flag.
16
+ - Deterministic span projections through `tiergraph.spanview`, with text, JSON, JSON Lines, and HTML emitters, plus `tiergraph_dot.dumps_spans` visualization.
17
+ - Deterministic Graphviz DOT rendering through `tiergraph_dot.dumps`, including `DotPresentation` hooks and structural-clock occupied-spine placement and relation rendering.
18
+ - TG-PATH canonical addressing for structural and durable items and boundaries, profile-owned alternatives, kind checks, and typed refusals with offender details.
19
+ - Canonical selection, bounded bipartite walks, ordered polyadic traversal, and ordered containment queries that preserve declared incidence and child order where applicable.
20
+
21
+ [0.1.0]: https://github.com/lenzo-ka/tiergraph/releases/tag/v0.1.0
@@ -0,0 +1,75 @@
1
+ # Contributing to tiergraph
2
+
3
+ Thank you for contributing to tiergraph. This project is alpha software, so a
4
+ small, well-tested change is especially valuable.
5
+
6
+ ## Set up a development environment
7
+
8
+ tiergraph requires Python 3.12 or later. Development is pinned to Python 3.12,
9
+ the supported floor, so newer Python features do not enter the codebase
10
+ accidentally. From the repository root, create the isolated development
11
+ environment and install the project with its development dependencies:
12
+
13
+ ```console
14
+ make venv
15
+ ```
16
+
17
+ By default, this uses `python3.12` and creates `.venv`. You can override the
18
+ interpreter with `PYTHON=/path/to/python3.12` or the environment directory with
19
+ `VENV=/path/to/venv`.
20
+
21
+ ## Check a change
22
+
23
+ Run the same full gate used by CI:
24
+
25
+ ```console
26
+ make check
27
+ ```
28
+
29
+ The gate runs Ruff linting and formatting checks, strict mypy checks, pytest,
30
+ the test suite in separate processes with hash seeds 0, 12345, and 999, JSON
31
+ Schema currency checks, documentation currency checks, the tracked-file hygiene
32
+ check, and the public-docstring check. Coverage is measured only for the shipped
33
+ `tiergraph` and `tiergraph_dot` packages and must remain at 100% branch coverage.
34
+
35
+ The repository also provides a pre-commit configuration. After installing
36
+ `pre-commit` separately, enable it in your checkout with:
37
+
38
+ ```console
39
+ pre-commit install
40
+ pre-commit run --all-files
41
+ ```
42
+
43
+ Those hooks apply basic file checks and Ruff, then run the tracked-file hygiene
44
+ and public-docstring checks. They complement rather than replace `make check`.
45
+
46
+ ## Documentation
47
+
48
+ Reader documentation lives in `README.md` and `docs/`. Every page under `docs/`
49
+ must be registered in `docs/manifest.json`. Generated sections and references
50
+ must be refreshed with `make docs`; `make docs-check` (implemented as
51
+ `scripts/generate_docs.py --check`) verifies that committed output matches a
52
+ fresh deterministic render. See [Contributing documentation](docs/contributing-docs.md)
53
+ for the rules governing pages, generated output, executable examples, and export
54
+ lists.
55
+
56
+ ## What is accepted
57
+
58
+ Changes should keep `make check` green, use US English, contain no AI or tool
59
+ attribution, and preserve compatibility through additive changes where possible.
60
+ Because the project is pre-1.0, an incompatible change may still be necessary;
61
+ make its effect explicit and keep it as narrow as practical. See the
62
+ [stability policy](README.md#stability).
63
+
64
+ ## Releases
65
+
66
+ Releases are a maintainer operation. The package version has a single source of
67
+ truth in `src/tiergraph/__init__.py`. Before release, maintainers run the full
68
+ gate, build the distribution, verify the import reports the intended version,
69
+ and wait for CI to pass. A GitHub Release whose `vX.Y.Z` tag matches the package
70
+ version triggers the publish workflow; it builds the sdist and wheel and uploads
71
+ them to PyPI through trusted publishing. PyPI releases cannot be overwritten.
72
+
73
+ The complete operator checklist, including initial trusted-publisher setup,
74
+ artifact checks, tagging, publication, and verification, is in
75
+ [RELEASING.md](RELEASING.md).
@@ -0,0 +1,24 @@
1
+ BSD 2-Clause License
2
+
3
+ Copyright (c) 2026 Kevin Lenzo
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,59 @@
1
+ VENV ?= .venv
2
+ # Pin development to the supported floor so newer-only features cannot slip in.
3
+ PYTHON ?= python3.12
4
+ VENV_PYTHON := $(VENV)/bin/python
5
+
6
+ .PHONY: venv lint format-check types test determinism-seed determinism schema schema-check docs docs-check tracked-clean documented check
7
+
8
+ # Development happens in an isolated environment: a shared interpreter drags in
9
+ # packages this project does not depend on, and they surface as type errors in
10
+ # other people's stubs.
11
+ venv: $(VENV)/bin/python
12
+
13
+ $(VENV)/bin/python:
14
+ @$(PYTHON) -m venv $(VENV)
15
+ @$(VENV)/bin/pip install --quiet --upgrade pip
16
+ @$(VENV)/bin/pip install --quiet -e ".[dev]"
17
+
18
+ lint:
19
+ @$(VENV_PYTHON) -m ruff check .
20
+
21
+ format-check:
22
+ @$(VENV_PYTHON) -m ruff format --check .
23
+
24
+ types:
25
+ @$(VENV_PYTHON) -m mypy
26
+
27
+ test:
28
+ @$(VENV_PYTHON) -m pytest --cov=tiergraph --cov=tiergraph_dot --cov-report=term-missing
29
+
30
+ # Separate processes: interpreter hash state is fixed at startup and cannot be
31
+ # changed honestly inside one run.
32
+ determinism-seed:
33
+ @test -n "$(HASH_SEED)" || (echo "HASH_SEED is required" >&2; exit 2)
34
+ @PYTHONHASHSEED=$(HASH_SEED) $(VENV_PYTHON) -m pytest
35
+
36
+ determinism:
37
+ @for seed in 0 12345 999; do \
38
+ $(MAKE) --no-print-directory determinism-seed HASH_SEED=$$seed || exit $$?; \
39
+ done
40
+
41
+ tracked-clean:
42
+ @$(VENV_PYTHON) scripts/check_tracked_clean.py
43
+
44
+ documented:
45
+ @$(VENV_PYTHON) scripts/check_documented.py
46
+
47
+ schema:
48
+ @$(VENV_PYTHON) scripts/generate_schema.py
49
+
50
+ schema-check:
51
+ @$(VENV_PYTHON) scripts/generate_schema.py --check
52
+
53
+ docs:
54
+ @$(VENV_PYTHON) scripts/generate_docs.py
55
+
56
+ docs-check:
57
+ @$(VENV_PYTHON) scripts/generate_docs.py --check
58
+
59
+ check: venv lint format-check types test determinism schema-check docs-check tracked-clean documented
@@ -0,0 +1,160 @@
1
+ Metadata-Version: 2.5
2
+ Name: tiergraph
3
+ Version: 0.1.0
4
+ Summary: Ordered tiers, declared relations, and an algebra over them
5
+ Project-URL: Homepage, https://github.com/lenzo-ka/tiergraph
6
+ Project-URL: Repository, https://github.com/lenzo-ka/tiergraph
7
+ Author: Kevin Lenzo
8
+ License-Expression: BSD-2-Clause
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Classifier: Programming Language :: Python :: 3.13
13
+ Classifier: Typing :: Typed
14
+ Requires-Python: >=3.12
15
+ Provides-Extra: dev
16
+ Requires-Dist: hatchling>=1.27; extra == 'dev'
17
+ Requires-Dist: hypothesis>=6.100; extra == 'dev'
18
+ Requires-Dist: jsonschema>=4.26; extra == 'dev'
19
+ Requires-Dist: mypy>=1.11; extra == 'dev'
20
+ Requires-Dist: pydantic>=2.9; extra == 'dev'
21
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
22
+ Requires-Dist: pytest>=8.0; extra == 'dev'
23
+ Requires-Dist: ruff>=0.16; extra == 'dev'
24
+ Provides-Extra: lint
25
+ Requires-Dist: mypy>=1.11; extra == 'lint'
26
+ Requires-Dist: ruff>=0.16; extra == 'lint'
27
+ Provides-Extra: test
28
+ Requires-Dist: hypothesis>=6.100; extra == 'test'
29
+ Requires-Dist: jsonschema>=4.26; extra == 'test'
30
+ Requires-Dist: pytest-cov>=5.0; extra == 'test'
31
+ Requires-Dist: pytest>=8.0; extra == 'test'
32
+ Description-Content-Type: text/markdown
33
+
34
+ # tiergraph
35
+
36
+ *Ordered tiers, declared relations, and an algebra over them*
37
+
38
+ tiergraph holds parallel ordered sequences and the declared links between them
39
+ as one immutable graph, checked when it is built. Every view — selection,
40
+ traversal, containment, timing, folds — is computed from that one graph, so no
41
+ view can disagree with the store.
42
+
43
+ The shape is the track view of an audio or video editor: rows of items, ordered
44
+ within a row, aligned across rows, with links between rows. Aligned annotations
45
+ over a signal have it; so do layered timelines and structured documents whose
46
+ parts reference each other.
47
+
48
+ You have this problem already if:
49
+
50
+ - you can construct a state your own code treats as invalid;
51
+ - you keep a derived index beside the store and must remember to update both; or
52
+ - your serialized format breaks when you add a field.
53
+
54
+ The package requires Python 3.12 or later. A PyPI release is not yet available;
55
+ install it from a source checkout:
56
+
57
+ ```console
58
+ git clone https://github.com/lenzo-ka/tiergraph.git
59
+ cd tiergraph
60
+ python -m pip install .
61
+ tiergraph --version
62
+ ```
63
+
64
+ ## See an alignment
65
+
66
+ This caption graph links each word to its phones. Select `cat`, walk the declared
67
+ alignment, and the answer is visible in the input:
68
+
69
+ ```python
70
+ from tiergraph import ItemSelector, Walk, WalkDirection, select
71
+ from tiergraph.build import document
72
+
73
+ builder = document("https://example.com/captions", prefix="caption")
74
+ words = builder.tier(
75
+ "words",
76
+ ("a", "cat", "sat"),
77
+ item_type="word",
78
+ membership="word-membership",
79
+ )
80
+ phones = builder.tier(
81
+ "phones",
82
+ ("AH", "K", "AE", "T", "S", "AE-2", "T-2"),
83
+ item_type="phone",
84
+ membership="phone-membership",
85
+ )
86
+ aligns = builder.link(
87
+ "aligns",
88
+ words,
89
+ phones,
90
+ ((0, 0), (1, 1), (1, 2), (1, 3), (2, 4), (2, 5), (2, 6)),
91
+ acyclic=True,
92
+ )
93
+ graph = builder.build()
94
+
95
+ cat = select(graph, (ItemSelector(graph, words.ref(1)),))
96
+ reached = Walk(cat, aligns.name, WalkDirection.FORWARD).evaluate().nodes
97
+ assert [node.reference for node in reached.nodes] == [
98
+ phones.ref(1),
99
+ phones.ref(2),
100
+ phones.ref(3),
101
+ ]
102
+ ```
103
+
104
+ The complete runnable example keeps the displayed phone labels separate from
105
+ their durable ids and prints `['K', 'AE', 'T']`; see
106
+ [`examples/caption_alignment.py`](examples/caption_alignment.py).
107
+
108
+ The model learned from Paul Hertz's Delta representation and the heterogeneous
109
+ relation graphs (HRGs) of the Festival Speech Synthesis System. tiergraph keeps
110
+ their emphasis on explicit tiered structure while defining a typed, immutable
111
+ model and a versioned interchange format.
112
+
113
+ Downstream migration (ipakit). ipakit is migrating onto tiergraph: Form's timed representation — units, intervals, positional lookup, and DOT rendering — is authoritative on the tiergraph library via a containment projection, with graph-independent identity hashing. The remaining backend subsystem graphs (such as pronunciation/CMU, mora, pinyin, gesture, and rewrite) and their JSON wire are still on ipakit's embedded graph engine and are being migrated to the library; when that completes the embedded engine is removed.
114
+
115
+ ## What you can do with it
116
+
117
+ - Build a graph directly, or record an ordered edit stream as a `Program` and run
118
+ it — see [construction](docs/guide/construction.md).
119
+ - Select and traverse the structure, including ordered containment — see
120
+ [selection and traversal](docs/guide/selection-and-traversal.md).
121
+ - Fold a dependency graph with a semiring to measure or recognize it — see
122
+ [folding](docs/guide/folding.md) and [recognize and act](docs/guide/recognize-and-act.md).
123
+ - Attach a clock profile and resolve physical timing — see [timing](docs/guide/timing.md).
124
+ - Serialize to canonical JSON or render Graphviz DOT — see
125
+ [serialization](docs/guide/serialization.md).
126
+ - Project segmentation graphs into deterministic span views for JSON, JSON Lines,
127
+ text, HTML, or DOT — see [span views](docs/guide/span-views.md).
128
+
129
+ ## Documentation
130
+
131
+ Start with the [documentation map](docs/README.md), then
132
+ [concepts](docs/concepts.md) for the data model and [getting
133
+ started](docs/getting-started.md) for a worked walkthrough. The [API
134
+ reference](docs/reference/api.md) covers every top-level export; the [CLI
135
+ reference](docs/reference/cli.md) is generated from the parser.
136
+
137
+ The companion `tiergraph_dot` package renders a graph as deterministic Graphviz
138
+ DOT and ships in the same distribution:
139
+
140
+ ```python
141
+ import tiergraph_dot
142
+
143
+ dot = tiergraph_dot.dumps(graph)
144
+ ```
145
+
146
+ ## Stability
147
+
148
+ tiergraph 0.1.x is alpha software. The public Python API may change before 1.0;
149
+ where possible, changes will be additive, but compatibility is not yet promised.
150
+ The JSON wire format, construction machine format, and span-view JSON format
151
+ carry explicit version stamps so a reader can identify the format it receives.
152
+ A format stamp identifies a contract; it does not imply that every version can
153
+ read or migrate every older format.
154
+
155
+ After 1.0, the intended policy is to announce a deprecated public Python API in
156
+ a minor release, retain it with a warning for at least one subsequent minor
157
+ release, and remove it only in a later release. Security, correctness, or
158
+ otherwise impractical compatibility constraints may require a faster change,
159
+ which will be documented in the release. This is an intended post-1.0 policy,
160
+ not a compatibility promise for the current alpha series.
@@ -0,0 +1,127 @@
1
+ # tiergraph
2
+
3
+ *Ordered tiers, declared relations, and an algebra over them*
4
+
5
+ tiergraph holds parallel ordered sequences and the declared links between them
6
+ as one immutable graph, checked when it is built. Every view — selection,
7
+ traversal, containment, timing, folds — is computed from that one graph, so no
8
+ view can disagree with the store.
9
+
10
+ The shape is the track view of an audio or video editor: rows of items, ordered
11
+ within a row, aligned across rows, with links between rows. Aligned annotations
12
+ over a signal have it; so do layered timelines and structured documents whose
13
+ parts reference each other.
14
+
15
+ You have this problem already if:
16
+
17
+ - you can construct a state your own code treats as invalid;
18
+ - you keep a derived index beside the store and must remember to update both; or
19
+ - your serialized format breaks when you add a field.
20
+
21
+ The package requires Python 3.12 or later. A PyPI release is not yet available;
22
+ install it from a source checkout:
23
+
24
+ ```console
25
+ git clone https://github.com/lenzo-ka/tiergraph.git
26
+ cd tiergraph
27
+ python -m pip install .
28
+ tiergraph --version
29
+ ```
30
+
31
+ ## See an alignment
32
+
33
+ This caption graph links each word to its phones. Select `cat`, walk the declared
34
+ alignment, and the answer is visible in the input:
35
+
36
+ ```python
37
+ from tiergraph import ItemSelector, Walk, WalkDirection, select
38
+ from tiergraph.build import document
39
+
40
+ builder = document("https://example.com/captions", prefix="caption")
41
+ words = builder.tier(
42
+ "words",
43
+ ("a", "cat", "sat"),
44
+ item_type="word",
45
+ membership="word-membership",
46
+ )
47
+ phones = builder.tier(
48
+ "phones",
49
+ ("AH", "K", "AE", "T", "S", "AE-2", "T-2"),
50
+ item_type="phone",
51
+ membership="phone-membership",
52
+ )
53
+ aligns = builder.link(
54
+ "aligns",
55
+ words,
56
+ phones,
57
+ ((0, 0), (1, 1), (1, 2), (1, 3), (2, 4), (2, 5), (2, 6)),
58
+ acyclic=True,
59
+ )
60
+ graph = builder.build()
61
+
62
+ cat = select(graph, (ItemSelector(graph, words.ref(1)),))
63
+ reached = Walk(cat, aligns.name, WalkDirection.FORWARD).evaluate().nodes
64
+ assert [node.reference for node in reached.nodes] == [
65
+ phones.ref(1),
66
+ phones.ref(2),
67
+ phones.ref(3),
68
+ ]
69
+ ```
70
+
71
+ The complete runnable example keeps the displayed phone labels separate from
72
+ their durable ids and prints `['K', 'AE', 'T']`; see
73
+ [`examples/caption_alignment.py`](examples/caption_alignment.py).
74
+
75
+ The model learned from Paul Hertz's Delta representation and the heterogeneous
76
+ relation graphs (HRGs) of the Festival Speech Synthesis System. tiergraph keeps
77
+ their emphasis on explicit tiered structure while defining a typed, immutable
78
+ model and a versioned interchange format.
79
+
80
+ Downstream migration (ipakit). ipakit is migrating onto tiergraph: Form's timed representation — units, intervals, positional lookup, and DOT rendering — is authoritative on the tiergraph library via a containment projection, with graph-independent identity hashing. The remaining backend subsystem graphs (such as pronunciation/CMU, mora, pinyin, gesture, and rewrite) and their JSON wire are still on ipakit's embedded graph engine and are being migrated to the library; when that completes the embedded engine is removed.
81
+
82
+ ## What you can do with it
83
+
84
+ - Build a graph directly, or record an ordered edit stream as a `Program` and run
85
+ it — see [construction](docs/guide/construction.md).
86
+ - Select and traverse the structure, including ordered containment — see
87
+ [selection and traversal](docs/guide/selection-and-traversal.md).
88
+ - Fold a dependency graph with a semiring to measure or recognize it — see
89
+ [folding](docs/guide/folding.md) and [recognize and act](docs/guide/recognize-and-act.md).
90
+ - Attach a clock profile and resolve physical timing — see [timing](docs/guide/timing.md).
91
+ - Serialize to canonical JSON or render Graphviz DOT — see
92
+ [serialization](docs/guide/serialization.md).
93
+ - Project segmentation graphs into deterministic span views for JSON, JSON Lines,
94
+ text, HTML, or DOT — see [span views](docs/guide/span-views.md).
95
+
96
+ ## Documentation
97
+
98
+ Start with the [documentation map](docs/README.md), then
99
+ [concepts](docs/concepts.md) for the data model and [getting
100
+ started](docs/getting-started.md) for a worked walkthrough. The [API
101
+ reference](docs/reference/api.md) covers every top-level export; the [CLI
102
+ reference](docs/reference/cli.md) is generated from the parser.
103
+
104
+ The companion `tiergraph_dot` package renders a graph as deterministic Graphviz
105
+ DOT and ships in the same distribution:
106
+
107
+ ```python
108
+ import tiergraph_dot
109
+
110
+ dot = tiergraph_dot.dumps(graph)
111
+ ```
112
+
113
+ ## Stability
114
+
115
+ tiergraph 0.1.x is alpha software. The public Python API may change before 1.0;
116
+ where possible, changes will be additive, but compatibility is not yet promised.
117
+ The JSON wire format, construction machine format, and span-view JSON format
118
+ carry explicit version stamps so a reader can identify the format it receives.
119
+ A format stamp identifies a contract; it does not imply that every version can
120
+ read or migrate every older format.
121
+
122
+ After 1.0, the intended policy is to announce a deprecated public Python API in
123
+ a minor release, retain it with a warning for at least one subsequent minor
124
+ release, and remove it only in a later release. Security, correctness, or
125
+ otherwise impractical compatibility constraints may require a faster change,
126
+ which will be documented in the release. This is an intended post-1.0 policy,
127
+ not a compatibility promise for the current alpha series.