planlens-agent 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 (159) hide show
  1. planlens_agent-0.1.0/.github/ISSUE_TEMPLATE/bug_report.md +17 -0
  2. planlens_agent-0.1.0/.github/workflows/ci.yml +140 -0
  3. planlens_agent-0.1.0/.github/workflows/consumer-demo.yml +115 -0
  4. planlens_agent-0.1.0/.github/workflows/publish.yml +104 -0
  5. planlens_agent-0.1.0/.gitignore +10 -0
  6. planlens_agent-0.1.0/AUTHORS.md +21 -0
  7. planlens_agent-0.1.0/CHANGELOG.md +177 -0
  8. planlens_agent-0.1.0/CONTRIBUTING.md +57 -0
  9. planlens_agent-0.1.0/LICENSE +202 -0
  10. planlens_agent-0.1.0/NOTICE +15 -0
  11. planlens_agent-0.1.0/PKG-INFO +85 -0
  12. planlens_agent-0.1.0/PROVENANCE.md +103 -0
  13. planlens_agent-0.1.0/README.md +196 -0
  14. planlens_agent-0.1.0/README.pypi.md +64 -0
  15. planlens_agent-0.1.0/docs/README.md +20 -0
  16. planlens_agent-0.1.0/docs/acceptance-examples.md +41 -0
  17. planlens_agent-0.1.0/docs/brand/README.md +26 -0
  18. planlens_agent-0.1.0/docs/brand/planlens-mark-dark.svg +6 -0
  19. planlens_agent-0.1.0/docs/brand/planlens-mark-light.svg +6 -0
  20. planlens_agent-0.1.0/docs/brand/planlens-mark-mono-dark.svg +6 -0
  21. planlens_agent-0.1.0/docs/brand/planlens-mark-mono-light.svg +6 -0
  22. planlens_agent-0.1.0/docs/brand/planlens-wordmark-dark.svg +9 -0
  23. planlens_agent-0.1.0/docs/brand/planlens-wordmark-light.svg +9 -0
  24. planlens_agent-0.1.0/docs/brand/planlens-wordmark-mono-dark.svg +9 -0
  25. planlens_agent-0.1.0/docs/brand/planlens-wordmark-mono-light.svg +9 -0
  26. planlens_agent-0.1.0/docs/ci.md +122 -0
  27. planlens_agent-0.1.0/docs/developer-rehearsal.md +79 -0
  28. planlens_agent-0.1.0/docs/evidence.md +49 -0
  29. planlens_agent-0.1.0/docs/inspector.md +110 -0
  30. planlens_agent-0.1.0/docs/integration.md +96 -0
  31. planlens_agent-0.1.0/docs/media/demo-narrow.gif +0 -0
  32. planlens_agent-0.1.0/docs/media/demo-narrow.png +0 -0
  33. planlens_agent-0.1.0/docs/media/demo-transcript.txt +58 -0
  34. planlens_agent-0.1.0/docs/media/demo.gif +0 -0
  35. planlens_agent-0.1.0/docs/media/demo.png +0 -0
  36. planlens_agent-0.1.0/docs/media/inspector-finding-light.png +0 -0
  37. planlens_agent-0.1.0/docs/media/inspector-finding-narrow-light.png +0 -0
  38. planlens_agent-0.1.0/docs/media/inspector-finding-narrow.png +0 -0
  39. planlens_agent-0.1.0/docs/media/inspector-finding.png +0 -0
  40. planlens_agent-0.1.0/docs/media/inspector-light.png +0 -0
  41. planlens_agent-0.1.0/docs/media/inspector.png +0 -0
  42. planlens_agent-0.1.0/docs/media/social-preview.png +0 -0
  43. planlens_agent-0.1.0/docs/naming.md +46 -0
  44. planlens_agent-0.1.0/docs/quickstart.md +213 -0
  45. planlens_agent-0.1.0/docs/rules.md +358 -0
  46. planlens_agent-0.1.0/docs/sarif.md +84 -0
  47. planlens_agent-0.1.0/docs/semantics.md +280 -0
  48. planlens_agent-0.1.0/docs/suites.md +215 -0
  49. planlens_agent-0.1.0/examples/README.md +12 -0
  50. planlens_agent-0.1.0/examples/guarded_runner.py +49 -0
  51. planlens_agent-0.1.0/examples/langgraph_gate/README.md +70 -0
  52. planlens_agent-0.1.0/examples/langgraph_gate/gate.py +195 -0
  53. planlens_agent-0.1.0/examples/langgraph_gate/requirements.in +8 -0
  54. planlens_agent-0.1.0/examples/langgraph_gate/requirements.lock +1233 -0
  55. planlens_agent-0.1.0/examples/langgraph_gate/test_gate.py +313 -0
  56. planlens_agent-0.1.0/examples/sdk_check.py +34 -0
  57. planlens_agent-0.1.0/pyproject.toml +83 -0
  58. planlens_agent-0.1.0/release/NOTES_0.1.0.md +37 -0
  59. planlens_agent-0.1.0/release/PUBLISHING.md +201 -0
  60. planlens_agent-0.1.0/scripts/browser_check.py +382 -0
  61. planlens_agent-0.1.0/scripts/ci_gate.py +304 -0
  62. planlens_agent-0.1.0/scripts/ci_local.py +282 -0
  63. planlens_agent-0.1.0/scripts/docs_check.py +312 -0
  64. planlens_agent-0.1.0/scripts/gen_acceptance_doc.py +66 -0
  65. planlens_agent-0.1.0/scripts/gen_rule_docs.py +66 -0
  66. planlens_agent-0.1.0/scripts/journey.py +259 -0
  67. planlens_agent-0.1.0/scripts/make_demo_media.py +658 -0
  68. planlens_agent-0.1.0/scripts/make_pilot_package.py +108 -0
  69. planlens_agent-0.1.0/scripts/make_review_zip.py +125 -0
  70. planlens_agent-0.1.0/scripts/make_samples.py +162 -0
  71. planlens_agent-0.1.0/scripts/release_check.py +253 -0
  72. planlens_agent-0.1.0/src/planlens_agent/__init__.py +56 -0
  73. planlens_agent-0.1.0/src/planlens_agent/_version.py +1 -0
  74. planlens_agent-0.1.0/src/planlens_agent/approval.py +75 -0
  75. planlens_agent-0.1.0/src/planlens_agent/checker.py +408 -0
  76. planlens_agent-0.1.0/src/planlens_agent/cli.py +479 -0
  77. planlens_agent-0.1.0/src/planlens_agent/compare.py +497 -0
  78. planlens_agent-0.1.0/src/planlens_agent/diagnostics.py +426 -0
  79. planlens_agent-0.1.0/src/planlens_agent/fixtures.py +172 -0
  80. planlens_agent-0.1.0/src/planlens_agent/inspector/__init__.py +681 -0
  81. planlens_agent-0.1.0/src/planlens_agent/inspector/inspector.css +272 -0
  82. planlens_agent-0.1.0/src/planlens_agent/inspector/inspector.js +88 -0
  83. planlens_agent-0.1.0/src/planlens_agent/loading.py +442 -0
  84. planlens_agent-0.1.0/src/planlens_agent/plan.py +371 -0
  85. planlens_agent-0.1.0/src/planlens_agent/policy.py +759 -0
  86. planlens_agent-0.1.0/src/planlens_agent/py.typed +0 -0
  87. planlens_agent-0.1.0/src/planlens_agent/report.py +198 -0
  88. planlens_agent-0.1.0/src/planlens_agent/runner.py +174 -0
  89. planlens_agent-0.1.0/src/planlens_agent/sarif.py +318 -0
  90. planlens_agent-0.1.0/src/planlens_agent/schemas/catalog.v1.schema.json +71 -0
  91. planlens_agent-0.1.0/src/planlens_agent/schemas/contract.v1.schema.json +127 -0
  92. planlens_agent-0.1.0/src/planlens_agent/schemas/fixtures.v1.schema.json +66 -0
  93. planlens_agent-0.1.0/src/planlens_agent/schemas/plan.v1.schema.json +66 -0
  94. planlens_agent-0.1.0/src/planlens_agent/schemas/report.v1.schema.json +289 -0
  95. planlens_agent-0.1.0/src/planlens_agent/schemas/run-diff.v1.schema.json +365 -0
  96. planlens_agent-0.1.0/src/planlens_agent/schemas/run.v1.schema.json +471 -0
  97. planlens_agent-0.1.0/src/planlens_agent/schemas/suite.v1.schema.json +76 -0
  98. planlens_agent-0.1.0/src/planlens_agent/suite.py +691 -0
  99. planlens_agent-0.1.0/src/planlens_agent/templates/release_basic/README.md +102 -0
  100. planlens_agent-0.1.0/src/planlens_agent/templates/release_basic/candidates/v1/expedite.json +39 -0
  101. planlens_agent-0.1.0/src/planlens_agent/templates/release_basic/candidates/v1/hotfix.json +39 -0
  102. planlens_agent-0.1.0/src/planlens_agent/templates/release_basic/candidates/v1/legacy.json +35 -0
  103. planlens_agent-0.1.0/src/planlens_agent/templates/release_basic/candidates/v1/standard-1.json +35 -0
  104. planlens_agent-0.1.0/src/planlens_agent/templates/release_basic/candidates/v1/standard-2.json +35 -0
  105. planlens_agent-0.1.0/src/planlens_agent/templates/release_basic/candidates/v2/expedite.json +39 -0
  106. planlens_agent-0.1.0/src/planlens_agent/templates/release_basic/candidates/v2/hotfix.json +35 -0
  107. planlens_agent-0.1.0/src/planlens_agent/templates/release_basic/candidates/v2/legacy.json +39 -0
  108. planlens_agent-0.1.0/src/planlens_agent/templates/release_basic/candidates/v2/standard-1.json +39 -0
  109. planlens_agent-0.1.0/src/planlens_agent/templates/release_basic/candidates/v2/standard-2.json +39 -0
  110. planlens_agent-0.1.0/src/planlens_agent/templates/release_basic/candidates/v3/expedite.json +39 -0
  111. planlens_agent-0.1.0/src/planlens_agent/templates/release_basic/candidates/v3/hotfix.json +35 -0
  112. planlens_agent-0.1.0/src/planlens_agent/templates/release_basic/candidates/v3/legacy.json +39 -0
  113. planlens_agent-0.1.0/src/planlens_agent/templates/release_basic/candidates/v3/standard-1.json +39 -0
  114. planlens_agent-0.1.0/src/planlens_agent/templates/release_basic/candidates/v3/standard-2.json +39 -0
  115. planlens_agent-0.1.0/src/planlens_agent/templates/release_basic/catalog.toml +36 -0
  116. planlens_agent-0.1.0/src/planlens_agent/templates/release_basic/contract.toml +46 -0
  117. planlens_agent-0.1.0/src/planlens_agent/templates/release_basic/fixtures.toml +33 -0
  118. planlens_agent-0.1.0/src/planlens_agent/templates/release_basic/plans/artifact-mismatch.json +12 -0
  119. planlens_agent-0.1.0/src/planlens_agent/templates/release_basic/plans/reversed-review.json +11 -0
  120. planlens_agent-0.1.0/src/planlens_agent/templates/release_basic/plans/valid-alternate-order.json +11 -0
  121. planlens_agent-0.1.0/src/planlens_agent/templates/release_basic/plans/valid.json +12 -0
  122. planlens_agent-0.1.0/src/planlens_agent/templates/release_basic/suite.toml +33 -0
  123. planlens_agent-0.1.0/src/planlens_agent/view_model.py +323 -0
  124. planlens_agent-0.1.0/tests/acceptance/cases.toml +158 -0
  125. planlens_agent-0.1.0/tests/acceptance/contracts/catalog-mismatch.toml +46 -0
  126. planlens_agent-0.1.0/tests/acceptance/contracts/cyclic.toml +53 -0
  127. planlens_agent-0.1.0/tests/acceptance/contracts/unknown-action.toml +46 -0
  128. planlens_agent-0.1.0/tests/acceptance/contracts/unsupported-rule.toml +53 -0
  129. planlens_agent-0.1.0/tests/acceptance/plans/compound.json +11 -0
  130. planlens_agent-0.1.0/tests/acceptance/plans/duplicate-step-id.json +10 -0
  131. planlens_agent-0.1.0/tests/acceptance/plans/malformed.json +7 -0
  132. planlens_agent-0.1.0/tests/acceptance/plans/policy-override.json +12 -0
  133. planlens_agent-0.1.0/tests/acceptance/plans/reference-before-producer.json +10 -0
  134. planlens_agent-0.1.0/tests/acceptance/plans/unresolved-reference.json +10 -0
  135. planlens_agent-0.1.0/tests/acceptance/plans/unsupported-semantics.json +11 -0
  136. planlens_agent-0.1.0/tests/conftest.py +5 -0
  137. planlens_agent-0.1.0/tests/data/sarif/NOTICE.md +32 -0
  138. planlens_agent-0.1.0/tests/data/sarif/sarif-schema-2.1.0.json +3389 -0
  139. planlens_agent-0.1.0/tests/helpers.py +82 -0
  140. planlens_agent-0.1.0/tests/test_acceptance.py +119 -0
  141. planlens_agent-0.1.0/tests/test_ci_files.py +176 -0
  142. planlens_agent-0.1.0/tests/test_ci_gate.py +755 -0
  143. planlens_agent-0.1.0/tests/test_cli.py +197 -0
  144. planlens_agent-0.1.0/tests/test_compare.py +589 -0
  145. planlens_agent-0.1.0/tests/test_determinism.py +67 -0
  146. planlens_agent-0.1.0/tests/test_docs.py +616 -0
  147. planlens_agent-0.1.0/tests/test_inputs.py +707 -0
  148. planlens_agent-0.1.0/tests/test_inspector.py +757 -0
  149. planlens_agent-0.1.0/tests/test_integrity.py +219 -0
  150. planlens_agent-0.1.0/tests/test_output_protection.py +310 -0
  151. planlens_agent-0.1.0/tests/test_reference_semantics.py +237 -0
  152. planlens_agent-0.1.0/tests/test_release.py +181 -0
  153. planlens_agent-0.1.0/tests/test_rule_docs.py +37 -0
  154. planlens_agent-0.1.0/tests/test_runner.py +248 -0
  155. planlens_agent-0.1.0/tests/test_sarif.py +470 -0
  156. planlens_agent-0.1.0/tests/test_schemas.py +131 -0
  157. planlens_agent-0.1.0/tests/test_semantics.py +139 -0
  158. planlens_agent-0.1.0/tests/test_suite.py +527 -0
  159. planlens_agent-0.1.0/uv.lock +276 -0
@@ -0,0 +1,17 @@
1
+ ---
2
+ name: Bug report
3
+ about: A wrong verdict, a crash or instructions that do not work
4
+ ---
5
+
6
+ **Version:** output of `planlens-agent --version`
7
+
8
+ **Python and operating system:**
9
+
10
+ **Exact command and exit status:**
11
+
12
+ **Smallest catalog, contract and plan that show the problem:**
13
+ <!-- Remove credentials and anything confidential. -->
14
+
15
+ **What you expected, and which rule should or should not have applied:**
16
+
17
+ **Full output:**
@@ -0,0 +1,140 @@
1
+ # Runs the same stages as `python scripts/ci_local.py`. No secrets and no model calls.
2
+ name: CI
3
+
4
+ on:
5
+ push:
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ lint:
13
+ runs-on: ubuntu-latest
14
+ timeout-minutes: 15
15
+ steps:
16
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
17
+ with:
18
+ persist-credentials: false
19
+ - uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
20
+ with:
21
+ version: "0.12.3"
22
+ enable-cache: false
23
+ - run: uv run --no-project --python 3.14 scripts/ci_local.py lint --python 3.14
24
+
25
+ test:
26
+ strategy:
27
+ fail-fast: false
28
+ matrix:
29
+ os: [ubuntu-latest, macos-latest, windows-latest]
30
+ python: ["3.11", "3.12", "3.13", "3.14"]
31
+ runs-on: ${{ matrix.os }}
32
+ timeout-minutes: 20
33
+ steps:
34
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
35
+ with:
36
+ persist-credentials: false
37
+ - uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
38
+ with:
39
+ version: "0.12.3"
40
+ enable-cache: false
41
+ - run: uv run --no-project --python ${{ matrix.python }} scripts/ci_local.py test --python ${{ matrix.python }}
42
+
43
+ package:
44
+ strategy:
45
+ fail-fast: false
46
+ matrix:
47
+ python: ["3.11", "3.14"]
48
+ runs-on: ubuntu-latest
49
+ timeout-minutes: 20
50
+ steps:
51
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
52
+ with:
53
+ persist-credentials: false
54
+ - uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
55
+ with:
56
+ version: "0.12.3"
57
+ enable-cache: false
58
+ - run: uv run --no-project --python ${{ matrix.python }} scripts/ci_local.py package --python ${{ matrix.python }}
59
+
60
+ journey:
61
+ strategy:
62
+ fail-fast: false
63
+ matrix:
64
+ os: [ubuntu-latest, macos-latest, windows-latest]
65
+ runs-on: ${{ matrix.os }}
66
+ timeout-minutes: 15
67
+ steps:
68
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
69
+ with:
70
+ persist-credentials: false
71
+ - uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
72
+ with:
73
+ version: "0.12.3"
74
+ enable-cache: false
75
+ - run: uv run --no-project --python 3.14 scripts/ci_local.py journey --python 3.14 --log journey.log
76
+ - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
77
+ if: always()
78
+ with:
79
+ name: journey-${{ matrix.os }}
80
+ path: journey.log
81
+ if-no-files-found: warn
82
+
83
+ recipe:
84
+ strategy:
85
+ fail-fast: false
86
+ matrix:
87
+ python: ["3.11", "3.14"]
88
+ runs-on: ubuntu-latest
89
+ timeout-minutes: 15
90
+ steps:
91
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
92
+ with:
93
+ persist-credentials: false
94
+ - uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
95
+ with:
96
+ version: "0.12.3"
97
+ enable-cache: false
98
+ - run: uv run --no-project --python ${{ matrix.python }} scripts/ci_local.py recipe --python ${{ matrix.python }} --log recipe-journey.log
99
+ - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
100
+ if: always()
101
+ with:
102
+ name: recipe-journey-${{ matrix.python }}
103
+ path: recipe-journey.log
104
+ if-no-files-found: warn
105
+
106
+ pilot:
107
+ strategy:
108
+ fail-fast: false
109
+ matrix:
110
+ os: [ubuntu-latest, macos-latest, windows-latest]
111
+ python: ["3.11", "3.14"]
112
+ runs-on: ${{ matrix.os }}
113
+ timeout-minutes: 15
114
+ steps:
115
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
116
+ with:
117
+ persist-credentials: false
118
+ - uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
119
+ with:
120
+ version: "0.12.3"
121
+ enable-cache: false
122
+ - run: uv run --no-project --python ${{ matrix.python }} scripts/ci_local.py pilot --python ${{ matrix.python }}
123
+
124
+ docs:
125
+ strategy:
126
+ fail-fast: false
127
+ matrix:
128
+ os: [ubuntu-latest, macos-latest]
129
+ python: ["3.11", "3.14"]
130
+ runs-on: ${{ matrix.os }}
131
+ timeout-minutes: 15
132
+ steps:
133
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
134
+ with:
135
+ persist-credentials: false
136
+ - uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
137
+ with:
138
+ version: "0.12.3"
139
+ enable-cache: false
140
+ - run: uv run --no-project --python ${{ matrix.python }} scripts/ci_local.py docs --python ${{ matrix.python }}
@@ -0,0 +1,115 @@
1
+ # Shows the gate as a consumer would use it. Started by hand only.
2
+ #
3
+ # `reject-demo` and `sarif-demo` FAIL ON PURPOSE: the candidates break the contract, and the
4
+ # gate's failing status is kept. A red run of this workflow is the expected result.
5
+ # Every plan is an authored example. The baselines here are generated inside the job so the
6
+ # demo stands alone; a real baseline is an owner-reviewed file. See docs/ci.md.
7
+ name: Consumer demo
8
+
9
+ on:
10
+ workflow_dispatch:
11
+
12
+ permissions:
13
+ contents: read
14
+
15
+ jobs:
16
+ pass-demo:
17
+ runs-on: ubuntu-latest
18
+ timeout-minutes: 10
19
+ steps:
20
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
21
+ with:
22
+ persist-credentials: false
23
+ - uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
24
+ with:
25
+ version: "0.12.3"
26
+ enable-cache: false
27
+ - name: Install the built wheel
28
+ run: |
29
+ uv build --wheel --out-dir wheel
30
+ uv venv --python 3.14 demo
31
+ uv pip install --python demo/bin/python --no-deps wheel/*.whl
32
+ demo/bin/planlens-agent init release-basic project
33
+ - name: Gate on passing candidates
34
+ working-directory: project
35
+ run: ../demo/bin/planlens-agent suite run suite.toml --plans-dir candidates/v3 --output candidate.run.json
36
+ - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
37
+ if: always()
38
+ with:
39
+ name: pass-demo-run
40
+ path: project/*.run.json
41
+ if-no-files-found: warn
42
+
43
+ reject-demo:
44
+ runs-on: ubuntu-latest
45
+ timeout-minutes: 10
46
+ steps:
47
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
48
+ with:
49
+ persist-credentials: false
50
+ - uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
51
+ with:
52
+ version: "0.12.3"
53
+ enable-cache: false
54
+ - name: Install the built wheel
55
+ run: |
56
+ uv build --wheel --out-dir wheel
57
+ uv venv --python 3.14 demo
58
+ uv pip install --python demo/bin/python --no-deps wheel/*.whl
59
+ demo/bin/planlens-agent init release-basic project
60
+ - name: Create the demonstration baseline
61
+ working-directory: project
62
+ run: ../demo/bin/planlens-agent suite run suite.toml --plans-dir candidates/v3 --output baseline.run.json
63
+ - name: Gate on rejecting candidates (fails on purpose)
64
+ working-directory: project
65
+ run: ../demo/bin/planlens-agent suite run suite.toml --plans-dir candidates/v2 --output candidate.run.json
66
+ - name: Show what changed (also fails, because findings are new)
67
+ if: always()
68
+ working-directory: project
69
+ run: ../demo/bin/planlens-agent suite diff baseline.run.json candidate.run.json --output comparison.json
70
+ - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
71
+ if: always()
72
+ with:
73
+ name: reject-demo-diagnostics
74
+ path: |
75
+ project/*.run.json
76
+ project/comparison.json
77
+ if-no-files-found: warn
78
+
79
+ sarif-demo:
80
+ runs-on: ubuntu-latest
81
+ timeout-minutes: 10
82
+ permissions:
83
+ actions: read # upload-sarif reads this workflow run; needed on private repositories
84
+ contents: read
85
+ security-events: write
86
+ steps:
87
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
88
+ with:
89
+ persist-credentials: false
90
+ - uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
91
+ with:
92
+ version: "0.12.3"
93
+ enable-cache: false
94
+ - name: Install the built wheel
95
+ run: |
96
+ uv build --wheel --out-dir wheel
97
+ uv venv --python 3.14 demo
98
+ uv pip install --python demo/bin/python --no-deps wheel/*.whl
99
+ - name: Check a rejected plan and write SARIF (fails on purpose)
100
+ run: |
101
+ demo/bin/planlens-agent check src/planlens_agent/templates/release_basic/plans/reversed-review.json \
102
+ --contract src/planlens_agent/templates/release_basic/contract.toml \
103
+ --catalog src/planlens_agent/templates/release_basic/catalog.toml \
104
+ --format sarif --output planlens.sarif --source-root .
105
+ - uses: github/codeql-action/upload-sarif@33d7b85da1a04171e211befe2c739303b9a4c066 # v4.39.3
106
+ if: always()
107
+ with:
108
+ sarif_file: planlens.sarif
109
+ category: planlens-agent-demo
110
+ - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
111
+ if: always()
112
+ with:
113
+ name: sarif-demo-log
114
+ path: planlens.sarif
115
+ if-no-files-found: warn
@@ -0,0 +1,104 @@
1
+ # Publishes one checked wheel and sdist to PyPI through Trusted Publishing.
2
+ # Manual only. Run it from the release tag, after the steps in release/PUBLISHING.md.
3
+ name: Publish to PyPI
4
+
5
+ on:
6
+ workflow_dispatch:
7
+ inputs:
8
+ version:
9
+ description: Version to publish, without the leading v
10
+ required: true
11
+ type: string
12
+ commit:
13
+ description: Full commit SHA that the tag and main must both be
14
+ required: true
15
+ type: string
16
+
17
+ permissions:
18
+ contents: read
19
+
20
+ jobs:
21
+ check:
22
+ runs-on: ubuntu-latest
23
+ timeout-minutes: 20
24
+ permissions:
25
+ contents: read
26
+ actions: read
27
+ steps:
28
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
29
+ with:
30
+ fetch-depth: 0
31
+ persist-credentials: false
32
+ - uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
33
+ with:
34
+ version: "0.12.3"
35
+ enable-cache: false
36
+ - name: Stop unless this is the approved tag, commit and main
37
+ env:
38
+ REF: ${{ github.ref }}
39
+ VERSION: ${{ inputs.version }}
40
+ COMMIT: ${{ inputs.commit }}
41
+ run: |
42
+ test "$REF" = "refs/tags/v$VERSION"
43
+ test "$(git rev-parse HEAD)" = "$COMMIT"
44
+ test "$(git rev-parse refs/remotes/origin/main)" = "$COMMIT"
45
+ - name: Stop unless CI passed for this exact commit
46
+ env:
47
+ COMMIT: ${{ inputs.commit }}
48
+ GITHUB_TOKEN: ${{ github.token }}
49
+ run: python3 scripts/ci_gate.py --commit "$COMMIT"
50
+ - name: Build the pair once
51
+ run: uv build --python 3.14 --out-dir release-pair/dist
52
+ - name: Check that pair
53
+ env:
54
+ VERSION: ${{ inputs.version }}
55
+ run: >-
56
+ uv run --no-project --python 3.14 scripts/release_check.py
57
+ --wheel "release-pair/dist/planlens_agent-$VERSION-py3-none-any.whl"
58
+ --sdist "release-pair/dist/planlens_agent-$VERSION.tar.gz"
59
+ --sums release-pair/SHA256SUMS
60
+ --tag "v$VERSION"
61
+ --python "$(uv python find --no-project 3.14)"
62
+ - name: Check the description renders
63
+ run: >-
64
+ uvx --from twine==7.0.0 --with "readme-renderer[md]==46.0"
65
+ twine check --strict release-pair/dist/*
66
+ - name: Record the hashes for the approver
67
+ run: cat release-pair/SHA256SUMS >> "$GITHUB_STEP_SUMMARY"
68
+ - name: Keep the CI gate for the check just before upload
69
+ run: cp scripts/ci_gate.py release-pair/ci_gate.py
70
+ - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
71
+ with:
72
+ name: release-pair
73
+ path: release-pair
74
+ if-no-files-found: error
75
+
76
+ publish:
77
+ needs: check
78
+ runs-on: ubuntu-latest
79
+ timeout-minutes: 15
80
+ environment:
81
+ name: pypi
82
+ url: https://pypi.org/project/planlens-agent/
83
+ permissions:
84
+ actions: read
85
+ id-token: write
86
+ steps:
87
+ - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
88
+ with:
89
+ name: release-pair
90
+ path: release-pair
91
+ - name: Stop unless these are exactly the checked files
92
+ working-directory: release-pair/dist
93
+ run: |
94
+ files=(*)
95
+ test "${#files[@]}" -eq 2
96
+ sha256sum --check --strict ../SHA256SUMS
97
+ - name: Stop unless CI still passes for this exact commit
98
+ env:
99
+ COMMIT: ${{ inputs.commit }}
100
+ GITHUB_TOKEN: ${{ github.token }}
101
+ run: python3 release-pair/ci_gate.py --commit "$COMMIT"
102
+ - uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # v1.14.3
103
+ with:
104
+ packages-dir: release-pair/dist
@@ -0,0 +1,10 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .venv/
4
+ dist/
5
+ build/
6
+ *.egg-info/
7
+ .pytest_cache/
8
+ .mypy_cache/
9
+ .ruff_cache/
10
+ .DS_Store
@@ -0,0 +1,21 @@
1
+ # Authors
2
+
3
+ PlanLens (distributed as `planlens-agent`) is by, in this order:
4
+
5
+ | Author | Role |
6
+ | --- | --- |
7
+ | Nurdaulet Abdrakhman | Project lead and primary maintainer; primary project contact |
8
+ | Daniyal Kozyrev | Co-author and contributor |
9
+
10
+ Nurdaulet Abdrakhman leads the project and is responsible for its maintenance. Contact:
11
+ [LinkedIn](https://www.linkedin.com/in/nurdaulet-abdrakhman-523784375).
12
+
13
+ These names and roles were confirmed by the project owner.
14
+
15
+ Implementation of this product used an AI coding assistant, Claude Code, under the project lead's direction.
16
+
17
+ ## Research artifact
18
+
19
+ This product is separate from the PlanLens research artifact. That repository's `AUTHORS.md` lists Nurdaulet
20
+ Abdrakhman (primary and contact author) and Daniyal Kozyrev (coauthor). That is a statement about the
21
+ research artifact, whose own attribution and copyright are recorded there; see `NOTICE` and `PROVENANCE.md`.
@@ -0,0 +1,177 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 - first public release
4
+
5
+ Changed
6
+
7
+ - Version 0.1.0, with the package maturity classifier `Development Status :: 3 - Alpha`. The
8
+ public API may evolve during 0.x.
9
+ - Installation is documented as `python -m pip install "planlens-agent==0.1.0"`.
10
+ - The package description comes from `README.pypi.md`, because the GitHub README uses relative
11
+ images and links that would break on PyPI.
12
+ - The README opens with a walkthrough of one authored example, built from real package output and
13
+ a real Inspector capture, and the summary now reads "Catch plan errors before execution".
14
+ - The logo is the approved "Planform" mark, with light, dark and one-colour variants.
15
+ - The selected names are recorded in `docs/naming.md`, with PyPI registration pending.
16
+
17
+ Compatibility
18
+
19
+ - The evaluator digest covers `_version.py`, so runs saved by a `0.1.0.dev0` build are
20
+ `not_comparable` (exit 2) with runs from 0.1.0. Regenerate those baselines and review them.
21
+ Strict comparison and the engine-version check on approvals are unchanged.
22
+
23
+ No checker rule, diagnostic meaning, schema or policy behaviour changed from the last development
24
+ build, and no runtime dependency was added.
25
+
26
+ Added
27
+
28
+ - `scripts/release_check.py` checks a built wheel and sdist as one pair, and `release/` holds the
29
+ release notes and publishing procedure.
30
+ - `.github/workflows/publish.yml`, a manual-only PyPI Trusted Publishing workflow.
31
+ `scripts/ci_gate.py` stops it unless GitHub's Actions API shows CI passed for the exact commit.
32
+
33
+ ## 0.1.0.dev0 - unreleased (checkpoint B2)
34
+
35
+ Added
36
+
37
+ - `suite run` and `suite diff`: run developer-supplied candidates through `check()`, save
38
+ an auditable run (`planlens-agent/run/v1`), and compare two runs
39
+ (`planlens-agent/run-diff/v1`). See `docs/suites.md`.
40
+ - Runs record plan content and digests, contract and catalog identity, report and rule
41
+ versions, and an evaluator digest that tells apart builds sharing a version string.
42
+ - `load_suite`, `run_suite`, `load_run`, `compare_runs` in the SDK; schemas for suites, runs
43
+ and comparisons.
44
+ - `candidates/` and `suite.toml` in the `release-basic` template, all authored.
45
+ - `examples/langgraph_gate`: a planner, check, execute-or-reject graph, tested with
46
+ LangGraph 1.2.20. The core still has no runtime dependencies.
47
+ - `.github/workflows/ci.yml` and `consumer-demo.yml`, prepared and not yet run on a hosted
48
+ service; `scripts/ci_local.py` runs the same stages locally; `scripts/journey.py` walks the
49
+ whole journey against an installed command.
50
+
51
+ Fixed
52
+
53
+ - A file name too long for the operating system made `check()` raise, and the CLI report an
54
+ internal error, for plans, contracts and catalogs. It is now an `unreadable` finding, with
55
+ no source location invented. The same fault is fixed in `--source-root`, `init` and
56
+ `regress`.
57
+
58
+ Fixed after independent review of B2 (B2-r2)
59
+
60
+ - LangGraph recipe: a returned state or caller-supplied fields could authorize a later
61
+ invocation whose planner failed, and removing the plan after the check skipped the
62
+ comparison. The graph now accepts only `request`, every invocation starts clean, and
63
+ execution needs a current plan.
64
+ - `load_run`: every declared type is checked before use, so a malformed value is a
65
+ `RunFileError` instead of an uncaught `TypeError`. Booleans and floats are no longer
66
+ accepted as integers, identifiers cannot end in a newline, and findings must agree with the
67
+ run's rule versions.
68
+ - `suite diff`: two runs agreeing on an unsupported `report_schema` are `not_comparable`.
69
+ - `suite diff --output` refuses to replace either input, including through other spellings,
70
+ symlinks and hard links.
71
+
72
+ Fixed after independent review of B2-r2 (B2-r3)
73
+
74
+ - `check`, `inspect` and `suite run --overwrite` could overwrite their own inputs. All of them
75
+ now refuse, with exit 2, an output that is the plan, contract, catalog, suite manifest or a
76
+ candidate in use, including through other spellings, symlinks and hard links.
77
+
78
+ Developer experience
79
+
80
+ - README rebuilt around the journey; quickstart with an owner-defined workflow; evidence page.
81
+ - An authored demo GIF, a static fallback and an inspector screenshot, generated from installed-wheel
82
+ output by `scripts/make_demo_media.py`.
83
+ - `scripts/docs_check.py` and a `docs` CI stage run the copy-and-run blocks exactly as written. Each
84
+ command has its own status, so a failure in the middle of a block is fatal, and the README's
85
+ development command is run from a clean shell.
86
+
87
+ Presentation
88
+
89
+ - PlanLens wordmark, a README built around the first questions a developer asks, a saved diagnosis
90
+ in a collapsed section, a docs index, an examples index and contributor guidance.
91
+ - Terminal media is now a labelled excerpt with a complete transcript beside it.
92
+
93
+ Project details
94
+
95
+ - Owner-confirmed authors, maintainer, copyright holder and contact in `AUTHORS.md`, `NOTICE`, the README
96
+ and package metadata. `CONTRIBUTING.md` is now in the sdist.
97
+
98
+ Fixed on hosted CI
99
+
100
+ - `.gitattributes` keeps LF on every platform and leaves the vendored OASIS schema untouched.
101
+ Windows checkouts had rewritten its line endings.
102
+ - The SARIF demo job has the `actions: read` permission that `upload-sarif` needs on private
103
+ repositories.
104
+
105
+ Unchanged
106
+
107
+ - `check` and `inspect` output: byte-identical to the previous checkpoint's wheel across the
108
+ acceptance cases and bundled plans.
109
+
110
+ ## 0.1.0.dev0 - unreleased (checkpoint A)
111
+
112
+ Not published. Distribution, module and command names are provisional
113
+ (see `docs/naming.md`).
114
+
115
+ Added
116
+
117
+ - Owner-supplied action catalog and contract (`.toml` or `.json`), validated
118
+ together before any plan is read: schema, catalog pin, unknown actions,
119
+ prerequisite cycles, inconsistent or unsatisfiable artifact rules, and
120
+ unsupported rule kinds.
121
+ - Ordered sequential plans with unique step ids and `"<step>.<output>"`
122
+ artifact references.
123
+ - Checks: unknown actions, required actions, prerequisites, reference
124
+ resolution and order, input binding and type, planned artifact identity, and
125
+ attempts by a plan to override policy.
126
+ - One diagnostic model for the SDK, CLI and JSON reports
127
+ (`planlens-agent/report/v1`), with stable rule ids and offline explanations.
128
+ - CLI `planlens-agent` with `check` (exit 0 / 1 / 2), `validate-policy`,
129
+ `regress`, `init`, `rules`, `explain`.
130
+ - `ApprovedPlan` snapshots and a `ReferenceRunner` that dispatches only the
131
+ exact approved snapshot.
132
+ - `release-basic` template, regression fixtures, JSON Schemas.
133
+
134
+ Fixed during the checkpoint A source review
135
+
136
+ - An integer longer than 4,300 digits in a JSON or TOML document made `check()`
137
+ raise `ValueError`; through the CLI it was reported as an internal error with
138
+ no report. It is now a `<doc>/limit` finding.
139
+ - Excessive nesting was reported as `malformed` or `schema` depending on which
140
+ depth check fired first. It is now always `<doc>/limit`.
141
+
142
+ Fixed after the second source review
143
+
144
+ - A validated policy exposed mutable dicts, so clearing an action's inputs made a
145
+ rejected plan pass under the same digest. Catalog and contract are now
146
+ read-only private copies bound to their content; `check(policy=...)` and the
147
+ runner refuse a policy that no longer matches (`PolicyIntegrityError`).
148
+ - The runner re-checked the plan, then dispatched from `approval.plan`, which a
149
+ caller could mutate during dispatch. It now dispatches its own validated
150
+ read-only copy, and `ApprovedPlan` always holds a private copy.
151
+ - A JSON escape for an unpaired surrogate (`"\ud800"`) crashed checking of plans,
152
+ contracts and catalogs. It is now a `<doc>/schema` finding with a location.
153
+ - `contract/unsatisfiable-input` (rule version 2) now detects required actions
154
+ whose inputs cannot be bootstrapped, not only types no action outputs.
155
+ - `uv.lock` is included in the sdist.
156
+
157
+ Added in checkpoint B1
158
+
159
+ - `planlens-agent inspect PLAN --output FILE`: a self-contained HTML report of one
160
+ check, built from an explicit view model (`build_view`, `render_html`).
161
+ - `planlens-agent check --format sarif [--source-root DIR]`: SARIF 2.1.0 export
162
+ (`to_sarif`, `to_sarif_json`). `--output` saves what is printed in this mode;
163
+ text and JSON modes are unchanged.
164
+ - `Policy.catalog_origin` and `Policy.contract_origin`, so a syntax error in a policy
165
+ document can be located in its file.
166
+
167
+ Fixed after the B1 source review
168
+
169
+ - More than 702 distinct artifact references in one report made `build_view` raise
170
+ `IndexError`, so `inspect` gave no report. Group labels now continue past ZZ with no
171
+ limit, and a label stands for one reference across all rules.
172
+ - SARIF export resolved relative paths against the working directory at export time.
173
+ Locations are now fixed when each document is read (`CheckResult.plan_source`,
174
+ `Policy.contract_source`, `Policy.catalog_source`).
175
+ - The diagram's relationship limit is now checked before any of it is built.
176
+ - Raw observed and required data moved behind native disclosure controls, with a compact
177
+ summary from the same structured fields left visible.
@@ -0,0 +1,57 @@
1
+ # Contributing
2
+
3
+ PlanLens is in its 0.x series, and its public API may evolve. You need Git and [uv](https://docs.astral.sh/uv/).
4
+
5
+ ## Set up and test
6
+
7
+ <!-- run prereq -->
8
+ ```sh
9
+ git clone https://github.com/nurdauletabdurahman777-maker/planlens-agent.git
10
+ ```
11
+
12
+ Run everything below from the root of the clone. No virtual environment has to be active: `uv run` creates
13
+ `.venv` and uses it.
14
+
15
+ <!-- run dev contains=" passed" contains="Success: no issues found" -->
16
+ ```sh
17
+ uv run --locked --extra dev pytest tests -q
18
+ uvx ruff@0.17.4 format --check .
19
+ uvx ruff@0.17.4 check .
20
+ uvx mypy@2.4.1 --strict src/planlens_agent
21
+ ```
22
+
23
+ Every CI stage, as CI runs it:
24
+
25
+ ```text
26
+ uv run --no-project --python 3.14 scripts/ci_local.py all --python 3.14
27
+ ```
28
+
29
+ ## What to keep true
30
+
31
+ - The core has no runtime dependencies. Development tools stay out of the wheel.
32
+ - The checker is deterministic and makes no model calls.
33
+ - Every command in a `sh` block in the README, Quickstart or this file must work as written. The `docs` CI stage
34
+ runs them. A command that is meant to fail goes last in its block.
35
+ - Label authored examples as authored. Do not report results that were not observed.
36
+
37
+ ## Regenerate media
38
+
39
+ On macOS with Google Chrome, from the root of the clone:
40
+
41
+ ```text
42
+ uv run --script scripts/make_demo_media.py
43
+ ```
44
+
45
+ This rebuilds `docs/media` and `docs/brand` from the real package. Its tools are used only by that script.
46
+
47
+ ## Report a bug
48
+
49
+ Open an issue, and include:
50
+
51
+ - the output of `planlens-agent --version`, your Python version and operating system;
52
+ - the exact command and its exit status;
53
+ - the smallest catalog, contract and plan that show the problem;
54
+ - what you expected, and the full output.
55
+
56
+ Remove credentials and anything confidential first. A wrong verdict is the most important kind of bug: include
57
+ the plan, and say which rule should or should not have applied.