matrx-mandate-scan 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.
- matrx_mandate_scan-0.1.0/.gitignore +303 -0
- matrx_mandate_scan-0.1.0/CLAUDE.md +91 -0
- matrx_mandate_scan-0.1.0/PKG-INFO +129 -0
- matrx_mandate_scan-0.1.0/README.md +106 -0
- matrx_mandate_scan-0.1.0/matrx_mandate_scan/__init__.py +20 -0
- matrx_mandate_scan-0.1.0/matrx_mandate_scan/__main__.py +4 -0
- matrx_mandate_scan-0.1.0/matrx_mandate_scan/adapters/__init__.py +5 -0
- matrx_mandate_scan-0.1.0/matrx_mandate_scan/adapters/config.py +137 -0
- matrx_mandate_scan-0.1.0/matrx_mandate_scan/adapters/python.py +2045 -0
- matrx_mandate_scan-0.1.0/matrx_mandate_scan/baseline.py +97 -0
- matrx_mandate_scan-0.1.0/matrx_mandate_scan/cli.py +270 -0
- matrx_mandate_scan-0.1.0/matrx_mandate_scan/contract.py +378 -0
- matrx_mandate_scan-0.1.0/matrx_mandate_scan/fixtures/__init__.py +7 -0
- matrx_mandate_scan-0.1.0/matrx_mandate_scan/fixtures/sources.py +375 -0
- matrx_mandate_scan-0.1.0/matrx_mandate_scan/module_index.py +376 -0
- matrx_mandate_scan-0.1.0/matrx_mandate_scan/provider_vocabulary.py +251 -0
- matrx_mandate_scan-0.1.0/matrx_mandate_scan/repo.py +171 -0
- matrx_mandate_scan-0.1.0/matrx_mandate_scan/report.py +154 -0
- matrx_mandate_scan-0.1.0/matrx_mandate_scan/scanner.py +900 -0
- matrx_mandate_scan-0.1.0/matrx_mandate_scan/selftest.py +549 -0
- matrx_mandate_scan-0.1.0/matrx_mandate_scan/transport.py +287 -0
- matrx_mandate_scan-0.1.0/matrx_mandate_scan/walkers.py +243 -0
- matrx_mandate_scan-0.1.0/pyproject.toml +62 -0
- matrx_mandate_scan-0.1.0/tests/test_cli.py +110 -0
- matrx_mandate_scan-0.1.0/tests/test_index_cache.py +146 -0
- matrx_mandate_scan-0.1.0/tests/test_python_adapter.py +193 -0
- matrx_mandate_scan-0.1.0/tests/test_report_payload.py +157 -0
- matrx_mandate_scan-0.1.0/tests/test_revision_truth.py +134 -0
- matrx_mandate_scan-0.1.0/tests/test_walkers.py +91 -0
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
*.pyc
|
|
2
|
+
secrets/
|
|
3
|
+
ignore/
|
|
4
|
+
temp/
|
|
5
|
+
logs/
|
|
6
|
+
# The broad `logs/` rule above is for RUNTIME log output, but it also matched
|
|
7
|
+
# the dashboard's SOURCE directory and silently swallowed an entire feature's
|
|
8
|
+
# files (only the pre-existing index.tsx stayed tracked), breaking the prod
|
|
9
|
+
# Docker build with "Could not resolve ./structured-tab". Re-include the source.
|
|
10
|
+
!apps/dashboard/src/features/logs/
|
|
11
|
+
!apps/dashboard/src/features/logs/**
|
|
12
|
+
todo
|
|
13
|
+
text_notes/
|
|
14
|
+
aidream/secrets/2.env
|
|
15
|
+
automation_matrix/matrix_processing/temp/*
|
|
16
|
+
cd
|
|
17
|
+
# Byte-compiled / optimized / DLL files
|
|
18
|
+
__pycache__/
|
|
19
|
+
*.py[cod]
|
|
20
|
+
*$py.class
|
|
21
|
+
|
|
22
|
+
# C extensions
|
|
23
|
+
*.so
|
|
24
|
+
.venv/
|
|
25
|
+
|
|
26
|
+
# Distribution / packaging
|
|
27
|
+
.Python
|
|
28
|
+
build/
|
|
29
|
+
develop-eggs/
|
|
30
|
+
dist/
|
|
31
|
+
downloads/
|
|
32
|
+
eggs/
|
|
33
|
+
.eggs/
|
|
34
|
+
lib/
|
|
35
|
+
lib64/
|
|
36
|
+
# The blanket lib/ rule above is from the standard Python .gitignore template
|
|
37
|
+
# and was silently swallowing TS source under the SPA `src/lib/` folders.
|
|
38
|
+
# Re-allow them explicitly so frontend builds don't ship without their lib layer.
|
|
39
|
+
!apps/dashboard/src/lib/
|
|
40
|
+
!apps/dashboard/src/lib/**
|
|
41
|
+
!apps/dashboard/src/features/crawler/lib/
|
|
42
|
+
!apps/dashboard/src/features/crawler/lib/**
|
|
43
|
+
!apps/workflow-studio/src/lib/
|
|
44
|
+
!apps/workflow-studio/src/lib/**
|
|
45
|
+
parts/
|
|
46
|
+
sdist/
|
|
47
|
+
var/
|
|
48
|
+
wheels/
|
|
49
|
+
share/python-wheels/
|
|
50
|
+
*.egg-info/
|
|
51
|
+
.installed.cfg
|
|
52
|
+
*.egg
|
|
53
|
+
MANIFEST
|
|
54
|
+
|
|
55
|
+
# PyInstaller
|
|
56
|
+
# Usually these files are written by a python script from a template
|
|
57
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
58
|
+
*.manifest
|
|
59
|
+
*.spec
|
|
60
|
+
|
|
61
|
+
# Installer logs
|
|
62
|
+
pip-log.txt
|
|
63
|
+
pip-delete-this-directory.txt
|
|
64
|
+
|
|
65
|
+
# Unit test / coverage reports
|
|
66
|
+
ai/tests/clean_response.json
|
|
67
|
+
ai/tests/cx_storage_response.json
|
|
68
|
+
ai/tests/execution_test.py
|
|
69
|
+
ai/tests/final_response.json
|
|
70
|
+
htmlcov/
|
|
71
|
+
.tox/
|
|
72
|
+
.nox/
|
|
73
|
+
.coverage
|
|
74
|
+
.coverage.*
|
|
75
|
+
.cache
|
|
76
|
+
nosetests.xml
|
|
77
|
+
coverage.xml
|
|
78
|
+
*.cover
|
|
79
|
+
*.py,cover
|
|
80
|
+
.hypothesis/
|
|
81
|
+
.pytest_cache/
|
|
82
|
+
cover/
|
|
83
|
+
|
|
84
|
+
# Translations
|
|
85
|
+
*.mo
|
|
86
|
+
*.pot
|
|
87
|
+
|
|
88
|
+
# Django stuff:
|
|
89
|
+
*.log
|
|
90
|
+
local_settings.py
|
|
91
|
+
db.sqlite3
|
|
92
|
+
db.sqlite3-journal
|
|
93
|
+
|
|
94
|
+
# Flask stuff:
|
|
95
|
+
instance/
|
|
96
|
+
.webassets-cache
|
|
97
|
+
|
|
98
|
+
# Scrapy stuff:
|
|
99
|
+
.scrapy
|
|
100
|
+
|
|
101
|
+
# Sphinx documentation
|
|
102
|
+
docs/_build/
|
|
103
|
+
|
|
104
|
+
# PyBuilder
|
|
105
|
+
.pybuilder/
|
|
106
|
+
target/
|
|
107
|
+
|
|
108
|
+
# Jupyter Notebook
|
|
109
|
+
.ipynb_checkpoints
|
|
110
|
+
|
|
111
|
+
# IPython
|
|
112
|
+
profile_default/
|
|
113
|
+
ipython_config.py
|
|
114
|
+
|
|
115
|
+
# pyenv
|
|
116
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
117
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
118
|
+
# .python-version
|
|
119
|
+
|
|
120
|
+
# pipenv
|
|
121
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
122
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
123
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
124
|
+
# install all needed dependencies.
|
|
125
|
+
#Pipfile.lock
|
|
126
|
+
|
|
127
|
+
# poetry
|
|
128
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
129
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
130
|
+
# commonly ignored for libraries.
|
|
131
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
132
|
+
|
|
133
|
+
# pdm
|
|
134
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
135
|
+
#pdm.lock
|
|
136
|
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
137
|
+
# in version control.
|
|
138
|
+
# https://pdm.fming.dev/#use-with-ide
|
|
139
|
+
.pdm.toml
|
|
140
|
+
|
|
141
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
142
|
+
__pypackages__/
|
|
143
|
+
|
|
144
|
+
# Celery stuff
|
|
145
|
+
celerybeat-schedule
|
|
146
|
+
celerybeat.pid
|
|
147
|
+
|
|
148
|
+
# SageMath parsed files
|
|
149
|
+
*.sage.py
|
|
150
|
+
|
|
151
|
+
# Environments
|
|
152
|
+
.env
|
|
153
|
+
.env_remote
|
|
154
|
+
.venv
|
|
155
|
+
env/
|
|
156
|
+
venv/
|
|
157
|
+
ENV/
|
|
158
|
+
env.bak/
|
|
159
|
+
venv.bak/
|
|
160
|
+
.env.armanonly
|
|
161
|
+
|
|
162
|
+
# Spyder project settings
|
|
163
|
+
.spyderproject
|
|
164
|
+
.spyproject
|
|
165
|
+
|
|
166
|
+
# Rope project settings
|
|
167
|
+
.ropeproject
|
|
168
|
+
|
|
169
|
+
# mkdocs documentation
|
|
170
|
+
/site
|
|
171
|
+
|
|
172
|
+
# mypy
|
|
173
|
+
.mypy_cache/
|
|
174
|
+
.dmypy.json
|
|
175
|
+
dmypy.json
|
|
176
|
+
|
|
177
|
+
# Pyre type checker
|
|
178
|
+
.pyre/
|
|
179
|
+
|
|
180
|
+
# random armani files
|
|
181
|
+
/armani_dev/secrets/
|
|
182
|
+
/armani/
|
|
183
|
+
/_armani/
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
# pytype static type analyzer
|
|
188
|
+
.pytype/
|
|
189
|
+
|
|
190
|
+
# Cython debug symbols
|
|
191
|
+
cython_debug/
|
|
192
|
+
|
|
193
|
+
.idea/
|
|
194
|
+
.vscode/
|
|
195
|
+
/node_modules/
|
|
196
|
+
|
|
197
|
+
# Frontend pnpm workspace (apps/) — node_modules at the workspace root and any
|
|
198
|
+
# member, plus Vite caches and build output. The unified lockfile (apps/pnpm-lock.yaml)
|
|
199
|
+
# IS committed; everything below is regenerated.
|
|
200
|
+
node_modules/
|
|
201
|
+
apps/**/.vite/
|
|
202
|
+
apps/**/dist/
|
|
203
|
+
.vite/
|
|
204
|
+
|
|
205
|
+
dump.rdb
|
|
206
|
+
|
|
207
|
+
frontend/
|
|
208
|
+
|
|
209
|
+
# AME Temp Files and directory structure
|
|
210
|
+
# Ignore all files in the temp directory and its subdirectories
|
|
211
|
+
/temp/**/*
|
|
212
|
+
/tmp/**/*
|
|
213
|
+
|
|
214
|
+
# Allow .gitkeep files to retain directory structure
|
|
215
|
+
!/temp/**/.gitkeep
|
|
216
|
+
!/tmp/**/.gitkeep
|
|
217
|
+
|
|
218
|
+
# Armani
|
|
219
|
+
.history*
|
|
220
|
+
.history/
|
|
221
|
+
/local_data/
|
|
222
|
+
local_reports_data/
|
|
223
|
+
webscraper/quick_scrapes/temp/
|
|
224
|
+
automation_matrix/ai_apis/fireworks/_dev/*
|
|
225
|
+
automation_matrix/ai_apis/fireworks/_dev/fireworks_sample.py
|
|
226
|
+
*.pdf
|
|
227
|
+
*.flac
|
|
228
|
+
*.mp3
|
|
229
|
+
*.wav
|
|
230
|
+
miniconda.sh
|
|
231
|
+
/database/python_sql/temp_data/
|
|
232
|
+
.history*
|
|
233
|
+
.history/
|
|
234
|
+
.history/
|
|
235
|
+
|
|
236
|
+
_dev/
|
|
237
|
+
/_dev/
|
|
238
|
+
requirements_filtered.txt
|
|
239
|
+
|
|
240
|
+
# matrx-dev-tools backups
|
|
241
|
+
.env-backups/
|
|
242
|
+
# Matrx Ship config (contains API key)
|
|
243
|
+
.matrx-ship.json
|
|
244
|
+
|
|
245
|
+
# Matrx config (contains API keys)
|
|
246
|
+
.matrx.json
|
|
247
|
+
.matrx-tools.conf
|
|
248
|
+
|
|
249
|
+
# Claude Code local worktrees and per-user settings
|
|
250
|
+
.claude/worktrees/
|
|
251
|
+
.worktrees/
|
|
252
|
+
.claude/settings.local.json
|
|
253
|
+
|
|
254
|
+
# Append-only snapshots from matrx_utils.update_history (unbounded; do not commit)
|
|
255
|
+
common/utils/data_in_code/data_history.json
|
|
256
|
+
packages/matrx-utils/matrx_utils/data_in_code/data_history.json
|
|
257
|
+
|
|
258
|
+
# Tool-dispatch debug logs — one file per server start, never committed
|
|
259
|
+
.matrx-debug/
|
|
260
|
+
# Per-definition BEFORE snapshots written by a live migration script. They are
|
|
261
|
+
# the recovery record for one machine's run, not repo content — the durable
|
|
262
|
+
# audit trail is the `metadata.migrations` stamp on the row itself.
|
|
263
|
+
.matrx-migrations/
|
|
264
|
+
|
|
265
|
+
# macOS Finder metadata
|
|
266
|
+
.DS_Store
|
|
267
|
+
**/.DS_Store
|
|
268
|
+
|
|
269
|
+
# Environment files
|
|
270
|
+
.env
|
|
271
|
+
.env.*
|
|
272
|
+
*.env
|
|
273
|
+
*.env.*
|
|
274
|
+
|
|
275
|
+
# Keep safe templates trackable
|
|
276
|
+
!.env.example
|
|
277
|
+
!.env.sample
|
|
278
|
+
!.env.template
|
|
279
|
+
|
|
280
|
+
# Never commit local OAuth client/token artifacts
|
|
281
|
+
credentials.json
|
|
282
|
+
token*.pickle
|
|
283
|
+
token*.json
|
|
284
|
+
tests_trials/rag_tests/kg_export_output/
|
|
285
|
+
|
|
286
|
+
# Pooler-contamination watch output (machine-local evidence, not source)
|
|
287
|
+
db/evidence/
|
|
288
|
+
|
|
289
|
+
# Pooler contamination evidence — machine-local forensic capture, not source
|
|
290
|
+
db/evidence/
|
|
291
|
+
db/mirror/.env.mirror
|
|
292
|
+
supabase/.temp/
|
|
293
|
+
**/supabase/.temp/
|
|
294
|
+
# Packed npm artifacts. Kept locally for a one-time bootstrap publish; never
|
|
295
|
+
# committed (they are large binaries regenerable with `pnpm pack`).
|
|
296
|
+
apps/shared/*/*.tgz
|
|
297
|
+
|
|
298
|
+
# Guard forcing-function scratch packages. These tests plant real files inside
|
|
299
|
+
# the real tree the guard scans (a temp dir would prove nothing) and delete
|
|
300
|
+
# them in teardown — ignoring them keeps the auto-commit tooling from
|
|
301
|
+
# capturing one mid-run.
|
|
302
|
+
_kind_boundary_scratch*/
|
|
303
|
+
_kind_marker_law_scratch*/
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# matrx-mandate-scan — agent notes
|
|
2
|
+
|
|
3
|
+
**Archetype A (library).** Consumers: aidream (`scripts/audit_mandate_wiring.py`,
|
|
4
|
+
`aidream/services/mandates/code_truth.py`, `release.sh`, CI), and — via `uvx` — every
|
|
5
|
+
other Matrx repo's release path. It runs where aidream does not exist, which is the
|
|
6
|
+
whole point.
|
|
7
|
+
|
|
8
|
+
## Hard rules for this package
|
|
9
|
+
|
|
10
|
+
- **Never import `aidream` or `matrx-orm`.** `scripts/check_package_boundaries.py`
|
|
11
|
+
fails the build on it. Submission uses raw asyncpg on purpose (`transport.py`), and
|
|
12
|
+
the SYSTEM-org constant there is a documented mirror of matrx-orm's, not an import.
|
|
13
|
+
- **`contract.py` is FROZEN.** Adding a `reference_type`, a finding code, or a field
|
|
14
|
+
is an amendment recorded in
|
|
15
|
+
`common-docs/projects/mandate-declaration-reporting/REGISTER.md` — never a silent edit.
|
|
16
|
+
A **breaking** amendment bumps `CONTRACT_VERSION` and lane L1's
|
|
17
|
+
`mandate.submit_scan_report(jsonb)` moves in the same change. A purely **additive**
|
|
18
|
+
one (amendment 1, 2026-09-09: `coverage.dirty` / `coverage.head_moved`; amendment 2,
|
|
19
|
+
2026-09-10: the repo-level `coverage.top_level` inventory) does not —
|
|
20
|
+
the door accepts exactly version 1 and stores `coverage` as jsonb wholesale, so a
|
|
21
|
+
bump would make it refuse every report over keys it already accepts. Either way the
|
|
22
|
+
amendment is written down before the code lands.
|
|
23
|
+
- **Never make a command exit non-zero without `--strict`** (D23).
|
|
24
|
+
- **Never widen classification to shape.** A dotted string is a reference because a
|
|
25
|
+
carrier holds it, never because it looks like a key. The moment that slips,
|
|
26
|
+
`consumerId="extend.chat"` becomes a mandate and the inventory is worthless. The
|
|
27
|
+
self-test guards exactly this.
|
|
28
|
+
- **THERE IS EXACTLY ONE KEY RESOLVER, AND IT LIVES HERE** (coordinator ruling,
|
|
29
|
+
2026-09-10): `adapters/python.py::_Resolver`. aidream's
|
|
30
|
+
`scripts/check_mandate_carrier_args.py` is a THIN CALLER of `carrier_sites()` — it
|
|
31
|
+
owns no resolution logic and must never grow any. Two resolvers means the number you
|
|
32
|
+
read depends on which tool printed it, and the two DID disagree: the census certified
|
|
33
|
+
as clean 16 sites the scanner was reporting as `UNRESOLVED_KEY`. A new resolution
|
|
34
|
+
shape goes in `_Resolver`, and both tools get it.
|
|
35
|
+
- **A bypass is a request TARGET, never a mention.** The provider names and hosts live
|
|
36
|
+
in `provider_vocabulary.py`, which is listed in its OWN allowlist beside
|
|
37
|
+
`matrx_ai/providers/**`. A host string counts when it is URL-shaped or sits in a
|
|
38
|
+
request-target position; a host name in a tuple is data, and a URL quoted in a
|
|
39
|
+
docstring is prose. "Any string that names a provider" made this package's own
|
|
40
|
+
vocabulary 13 live `NEW_BYPASS` rows.
|
|
41
|
+
- **Every importable top-level package is scanned or listed as skipped with a reason.**
|
|
42
|
+
`top_level_inventory()` names every top-level directory once. aidream had twelve
|
|
43
|
+
importable packages that were neither, and the report still said `complete`.
|
|
44
|
+
- **The ratchet only goes down.** `baseline.write` refuses to grow; keep it that way.
|
|
45
|
+
- **`repo.py` mirrors `platform.repo`.** An unknown remote is `UNMEASURED`. Never
|
|
46
|
+
infer a slug from a folder name — "ai-matrx" the repo is the `matrx-frontend`
|
|
47
|
+
directory, and guessing gets it backwards.
|
|
48
|
+
- **Nothing about a checkout comes from its DIRECTORY NAME.** The repo root is
|
|
49
|
+
`git rev-parse --show-toplevel`; the slug is the git remote; the root package is what
|
|
50
|
+
the manifests declare, else the registered slug. A worktree, a CI checkout, a fork PR
|
|
51
|
+
and a container build stage all rename the directory, and V-L2 § 6 measured the cost:
|
|
52
|
+
the entire 4,000-file root package silently absent while the report still said
|
|
53
|
+
`complete`.
|
|
54
|
+
- **The revision is read ONCE, at scan start, and the report says whether the tree was
|
|
55
|
+
clean.** A candidate report describes exactly ONE committed tree; `coverage.dirty` /
|
|
56
|
+
`coverage.head_moved` and an `UNMEASURED` finding say so when it does not (V-L2 § 7:
|
|
57
|
+
live rows attributed to a commit that predates the package they scanned). `--revision`
|
|
58
|
+
is a CI-only override and an override that disagrees with HEAD is reported, never
|
|
59
|
+
trusted.
|
|
60
|
+
|
|
61
|
+
## Where the walkers came from
|
|
62
|
+
|
|
63
|
+
`walkers.py` holds the AST walkers that used to be private copies in
|
|
64
|
+
`scripts/audit_mandate_wiring.py` and `aidream/services/mandates/code_truth.py`. Both
|
|
65
|
+
now import from here. Their behavior is byte-for-byte the same (proven by a parity run
|
|
66
|
+
over 11,406 files at the move). Change one and you change both — that is the point.
|
|
67
|
+
|
|
68
|
+
## Proving a change
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
uv run pytest packages/matrx-mandate-scan/tests -q # 71 tests
|
|
72
|
+
uv run matrx-mandate-scan --self-test # 44 checks; runs from a uvx install too
|
|
73
|
+
uv run matrx-mandate-scan scan -o /tmp/scan.json # the whole repo
|
|
74
|
+
uv run pytest aidream/services/mandates/tests/test_code_truth.py -q
|
|
75
|
+
uv run pytest aidream/services/mandates/tests/test_scanner_resolver_agreement.py -q
|
|
76
|
+
python scripts/check_mandate_carrier_args.py --self-test --strict # the thin caller
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Cost.** A cross-module key is only static if the scanner has seen the module that
|
|
80
|
+
declares it, so `build_module_index` reads every python file once before the real pass
|
|
81
|
+
(`module_index.py`). That pre-pass is CACHED per file on `(repo-relative path,
|
|
82
|
+
st_mtime_ns, st_size)` under `<repo>/.cache/matrx-mandate-scan/`. Measured on aidream:
|
|
83
|
+
**cold 62s, warm 34s**, byte-identical payloads. The cache answers only the pre-pass
|
|
84
|
+
question; every reference and finding still comes from reading the file in the real
|
|
85
|
+
pass, a changed file is always re-read, and a cache from another `scanner_version` is
|
|
86
|
+
discarded rather than trusted.
|
|
87
|
+
|
|
88
|
+
A new carrier or a new resolution shape gets a fixture in
|
|
89
|
+
`matrx_mandate_scan/fixtures/sources.py` and a case in `selftest.py` — the pytest suite
|
|
90
|
+
imports those cases, so the two can never disagree. Break the adapter deliberately and
|
|
91
|
+
watch the case go red before you believe it.
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: matrx-mandate-scan
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: The one Mandate reference scanner: finds every mandate carrier, every bypass, and reports contract-v1 JSON to the platform
|
|
5
|
+
Project-URL: Homepage, https://github.com/AI-Matrix-Engine/aidream
|
|
6
|
+
Project-URL: Repository, https://github.com/AI-Matrix-Engine/aidream
|
|
7
|
+
Project-URL: Issues, https://github.com/AI-Matrix-Engine/aidream/issues
|
|
8
|
+
Author-email: Matrx <admin@aimatrx.com>
|
|
9
|
+
Maintainer-email: Matrx <admin@aimatrx.com>
|
|
10
|
+
License: MIT
|
|
11
|
+
Keywords: governance,mandates,matrx,static-analysis
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
18
|
+
Requires-Python: >=3.13
|
|
19
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
20
|
+
Provides-Extra: submit
|
|
21
|
+
Requires-Dist: asyncpg>=0.31.0; extra == 'submit'
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# matrx-mandate-scan
|
|
25
|
+
|
|
26
|
+
The ONE Mandate reference scanner. It finds every place code reaches for
|
|
27
|
+
platform intelligence — through a Mandate carrier or around it — reports the
|
|
28
|
+
result to the database in one frozen contract, and screams (never blocks) when
|
|
29
|
+
something is unresolved, unmeasured, or bypassing the mandate system.
|
|
30
|
+
|
|
31
|
+
Built for the **Mandate Declaration & Usage Reporting** program
|
|
32
|
+
(`common-docs/projects/mandate-declaration-reporting/`), lane L2.
|
|
33
|
+
|
|
34
|
+
## Install / run
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# from any repo, no checkout needed
|
|
38
|
+
uvx --from matrx-mandate-scan==0.1.0 matrx-mandate-scan check
|
|
39
|
+
|
|
40
|
+
# inside the aidream workspace (vendored via [tool.uv.sources])
|
|
41
|
+
uv run matrx-mandate-scan scan --root aidream --root packages/matrx-ai
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Commands
|
|
45
|
+
|
|
46
|
+
| Command | What it does |
|
|
47
|
+
|---|---|
|
|
48
|
+
| `scan` | Contract-v1 JSON on **stdout**, the red human report on **stderr**. |
|
|
49
|
+
| `report` | `scan`, then submit through `mandate.submit_scan_report(jsonb)` and file every red finding into `ops.system_error` (`source_app='mandate-scan'`). |
|
|
50
|
+
| `check` | The release-path command: scan + report + reconcile. |
|
|
51
|
+
| `explain <file:line>` | What the scanner sees at one location, and why. |
|
|
52
|
+
| `--self-test` | The built-in RED→GREEN fixture suite. Runs from a `uvx` install. |
|
|
53
|
+
|
|
54
|
+
**Every command exits 0** unless `--strict` is passed. That is ruling **D23**:
|
|
55
|
+
a mandate check is loud and non-blocking; `--strict` exists for humans and for
|
|
56
|
+
the scheduled remediation task, never for a release script.
|
|
57
|
+
|
|
58
|
+
## What counts as a reference
|
|
59
|
+
|
|
60
|
+
Classification is **by carrier, never by the word or the path**. A dotted
|
|
61
|
+
string is a mandate key only where a carrier puts it — so `consumerId =
|
|
62
|
+
"extend.chat"` is not a reference and never becomes one.
|
|
63
|
+
|
|
64
|
+
Python carriers:
|
|
65
|
+
|
|
66
|
+
- `declare_mandate` / `declare_generated_mandate` / `declare_mandated_agent` → `declaration`
|
|
67
|
+
- `declare_mandate_family(prefix, members=...)` → `family_declaration`, one `constant` per resolvable member, `dynamic_family` when the iterable is computed
|
|
68
|
+
- `resolve_mandate` → `resolution`; `run_mandate` → `execution`
|
|
69
|
+
- `run_mandated(Cls)` / `Cls.run()` → `execution`
|
|
70
|
+
- a `NamedAgent` subclass `mandate_key` (including `type(name, (NamedAgent,), {...})`) → `declaration`
|
|
71
|
+
- `seed_agent_id=<uuid>` inside a `declare_*` → `seed_holder`
|
|
72
|
+
- `@mandate_passthrough` / `MandateKeyParam` → `passthrough`, with the caller attributed when it lives in the same module
|
|
73
|
+
|
|
74
|
+
Config carriers (JSON / YAML / TOML) — the **property name** is the carrier:
|
|
75
|
+
`mandate_key`, `mandateKey`, `defaultMandateKey`, `fallback_mandate_key`.
|
|
76
|
+
Anything else that merely looks key-shaped is `unclassified` and advisory.
|
|
77
|
+
|
|
78
|
+
Keys resolve through literals, module and function constants (UPPER or not),
|
|
79
|
+
attribute constants, f-strings, `+` concatenations, ternaries (both branches
|
|
80
|
+
become real references), tuple/list loop members, aliases, literal-container
|
|
81
|
+
subscripts, and one level of analyzable module-local wrapper function.
|
|
82
|
+
|
|
83
|
+
An argument that resolves to none of those → finding **`UNRESOLVED_KEY`**, plus
|
|
84
|
+
an `unresolved`-flagged reference: D21 says unreachable is a flag, never a
|
|
85
|
+
filter, so nothing is ever dropped from the inventory.
|
|
86
|
+
|
|
87
|
+
## Bypass detection and the ratchet
|
|
88
|
+
|
|
89
|
+
Importing a provider SDK (`anthropic`, `openai`, `groq`, `google.genai`,
|
|
90
|
+
`google.generativeai`, `litellm`, `xai`, `ollama`, `cohere`, `mistralai`) or
|
|
91
|
+
naming a provider host, anywhere outside
|
|
92
|
+
`packages/matrx-ai/matrx_ai/providers/**` and the one D10-approved module
|
|
93
|
+
(`conversation_labeler.py`), is a `bypass` reference. The exact standalone
|
|
94
|
+
RAG default embedding adapter (`packages/matrx-rag/matrx_rag/embeddings.py`) is
|
|
95
|
+
also an approved provider adapter: it is injected through `EmbeddingProvider`,
|
|
96
|
+
does not select a Mandate holder, and is independently ratcheted by
|
|
97
|
+
`scripts/check_raw_llm_clients.py`. No broader `matrx-rag` exemption exists.
|
|
98
|
+
|
|
99
|
+
- in the `--baseline` file → **`CONVERSION_PENDING`** (flag `conversion_pending`)
|
|
100
|
+
- not in it → **`NEW_BYPASS`** (D20: no new ones)
|
|
101
|
+
- a dynamic import that hides its target → **`UNRESOLVED_IMPORT`**
|
|
102
|
+
|
|
103
|
+
`--write-baseline` regenerates the file and **refuses to write a larger one**.
|
|
104
|
+
No entry in the baseline is an approved class; every one is a defect awaiting
|
|
105
|
+
conversion.
|
|
106
|
+
|
|
107
|
+
## Coverage is mandatory output
|
|
108
|
+
|
|
109
|
+
Every file is scanned or listed with a reason (`generated`, `test_fixture`,
|
|
110
|
+
`parse_error`, `unsupported_language`). Any `parse_error` makes the package
|
|
111
|
+
`verification_status = incomplete` and files an `UNMEASURED` finding.
|
|
112
|
+
|
|
113
|
+
## Reference identity
|
|
114
|
+
|
|
115
|
+
`sha256(repo_slug · package_path · file_path · symbol · occurrence_n ·
|
|
116
|
+
reference_type · mandate_key_or_prefix)`.
|
|
117
|
+
|
|
118
|
+
`repo_slug` is always the repo the scan ran in, resolved from
|
|
119
|
+
`git remote get-url origin` through the `platform.repo` mirror in
|
|
120
|
+
`matrx_mandate_scan/repo.py`. **An unknown remote is `UNMEASURED`, never a
|
|
121
|
+
guessed slug** — a folder name is not a repo identity.
|
|
122
|
+
|
|
123
|
+
## Boundaries
|
|
124
|
+
|
|
125
|
+
Per `docs/packages/PACKAGE_DOCTRINE.md`, this package imports **neither
|
|
126
|
+
`aidream` nor `matrx-orm`**. It carries the AST walkers that used to live in
|
|
127
|
+
`scripts/audit_mandate_wiring.py` and
|
|
128
|
+
`aidream/services/mandates/code_truth.py`; those two modules now import them
|
|
129
|
+
from here, so there is exactly one definition of "what a carrier looks like".
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# matrx-mandate-scan
|
|
2
|
+
|
|
3
|
+
The ONE Mandate reference scanner. It finds every place code reaches for
|
|
4
|
+
platform intelligence — through a Mandate carrier or around it — reports the
|
|
5
|
+
result to the database in one frozen contract, and screams (never blocks) when
|
|
6
|
+
something is unresolved, unmeasured, or bypassing the mandate system.
|
|
7
|
+
|
|
8
|
+
Built for the **Mandate Declaration & Usage Reporting** program
|
|
9
|
+
(`common-docs/projects/mandate-declaration-reporting/`), lane L2.
|
|
10
|
+
|
|
11
|
+
## Install / run
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# from any repo, no checkout needed
|
|
15
|
+
uvx --from matrx-mandate-scan==0.1.0 matrx-mandate-scan check
|
|
16
|
+
|
|
17
|
+
# inside the aidream workspace (vendored via [tool.uv.sources])
|
|
18
|
+
uv run matrx-mandate-scan scan --root aidream --root packages/matrx-ai
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Commands
|
|
22
|
+
|
|
23
|
+
| Command | What it does |
|
|
24
|
+
|---|---|
|
|
25
|
+
| `scan` | Contract-v1 JSON on **stdout**, the red human report on **stderr**. |
|
|
26
|
+
| `report` | `scan`, then submit through `mandate.submit_scan_report(jsonb)` and file every red finding into `ops.system_error` (`source_app='mandate-scan'`). |
|
|
27
|
+
| `check` | The release-path command: scan + report + reconcile. |
|
|
28
|
+
| `explain <file:line>` | What the scanner sees at one location, and why. |
|
|
29
|
+
| `--self-test` | The built-in RED→GREEN fixture suite. Runs from a `uvx` install. |
|
|
30
|
+
|
|
31
|
+
**Every command exits 0** unless `--strict` is passed. That is ruling **D23**:
|
|
32
|
+
a mandate check is loud and non-blocking; `--strict` exists for humans and for
|
|
33
|
+
the scheduled remediation task, never for a release script.
|
|
34
|
+
|
|
35
|
+
## What counts as a reference
|
|
36
|
+
|
|
37
|
+
Classification is **by carrier, never by the word or the path**. A dotted
|
|
38
|
+
string is a mandate key only where a carrier puts it — so `consumerId =
|
|
39
|
+
"extend.chat"` is not a reference and never becomes one.
|
|
40
|
+
|
|
41
|
+
Python carriers:
|
|
42
|
+
|
|
43
|
+
- `declare_mandate` / `declare_generated_mandate` / `declare_mandated_agent` → `declaration`
|
|
44
|
+
- `declare_mandate_family(prefix, members=...)` → `family_declaration`, one `constant` per resolvable member, `dynamic_family` when the iterable is computed
|
|
45
|
+
- `resolve_mandate` → `resolution`; `run_mandate` → `execution`
|
|
46
|
+
- `run_mandated(Cls)` / `Cls.run()` → `execution`
|
|
47
|
+
- a `NamedAgent` subclass `mandate_key` (including `type(name, (NamedAgent,), {...})`) → `declaration`
|
|
48
|
+
- `seed_agent_id=<uuid>` inside a `declare_*` → `seed_holder`
|
|
49
|
+
- `@mandate_passthrough` / `MandateKeyParam` → `passthrough`, with the caller attributed when it lives in the same module
|
|
50
|
+
|
|
51
|
+
Config carriers (JSON / YAML / TOML) — the **property name** is the carrier:
|
|
52
|
+
`mandate_key`, `mandateKey`, `defaultMandateKey`, `fallback_mandate_key`.
|
|
53
|
+
Anything else that merely looks key-shaped is `unclassified` and advisory.
|
|
54
|
+
|
|
55
|
+
Keys resolve through literals, module and function constants (UPPER or not),
|
|
56
|
+
attribute constants, f-strings, `+` concatenations, ternaries (both branches
|
|
57
|
+
become real references), tuple/list loop members, aliases, literal-container
|
|
58
|
+
subscripts, and one level of analyzable module-local wrapper function.
|
|
59
|
+
|
|
60
|
+
An argument that resolves to none of those → finding **`UNRESOLVED_KEY`**, plus
|
|
61
|
+
an `unresolved`-flagged reference: D21 says unreachable is a flag, never a
|
|
62
|
+
filter, so nothing is ever dropped from the inventory.
|
|
63
|
+
|
|
64
|
+
## Bypass detection and the ratchet
|
|
65
|
+
|
|
66
|
+
Importing a provider SDK (`anthropic`, `openai`, `groq`, `google.genai`,
|
|
67
|
+
`google.generativeai`, `litellm`, `xai`, `ollama`, `cohere`, `mistralai`) or
|
|
68
|
+
naming a provider host, anywhere outside
|
|
69
|
+
`packages/matrx-ai/matrx_ai/providers/**` and the one D10-approved module
|
|
70
|
+
(`conversation_labeler.py`), is a `bypass` reference. The exact standalone
|
|
71
|
+
RAG default embedding adapter (`packages/matrx-rag/matrx_rag/embeddings.py`) is
|
|
72
|
+
also an approved provider adapter: it is injected through `EmbeddingProvider`,
|
|
73
|
+
does not select a Mandate holder, and is independently ratcheted by
|
|
74
|
+
`scripts/check_raw_llm_clients.py`. No broader `matrx-rag` exemption exists.
|
|
75
|
+
|
|
76
|
+
- in the `--baseline` file → **`CONVERSION_PENDING`** (flag `conversion_pending`)
|
|
77
|
+
- not in it → **`NEW_BYPASS`** (D20: no new ones)
|
|
78
|
+
- a dynamic import that hides its target → **`UNRESOLVED_IMPORT`**
|
|
79
|
+
|
|
80
|
+
`--write-baseline` regenerates the file and **refuses to write a larger one**.
|
|
81
|
+
No entry in the baseline is an approved class; every one is a defect awaiting
|
|
82
|
+
conversion.
|
|
83
|
+
|
|
84
|
+
## Coverage is mandatory output
|
|
85
|
+
|
|
86
|
+
Every file is scanned or listed with a reason (`generated`, `test_fixture`,
|
|
87
|
+
`parse_error`, `unsupported_language`). Any `parse_error` makes the package
|
|
88
|
+
`verification_status = incomplete` and files an `UNMEASURED` finding.
|
|
89
|
+
|
|
90
|
+
## Reference identity
|
|
91
|
+
|
|
92
|
+
`sha256(repo_slug · package_path · file_path · symbol · occurrence_n ·
|
|
93
|
+
reference_type · mandate_key_or_prefix)`.
|
|
94
|
+
|
|
95
|
+
`repo_slug` is always the repo the scan ran in, resolved from
|
|
96
|
+
`git remote get-url origin` through the `platform.repo` mirror in
|
|
97
|
+
`matrx_mandate_scan/repo.py`. **An unknown remote is `UNMEASURED`, never a
|
|
98
|
+
guessed slug** — a folder name is not a repo identity.
|
|
99
|
+
|
|
100
|
+
## Boundaries
|
|
101
|
+
|
|
102
|
+
Per `docs/packages/PACKAGE_DOCTRINE.md`, this package imports **neither
|
|
103
|
+
`aidream` nor `matrx-orm`**. It carries the AST walkers that used to live in
|
|
104
|
+
`scripts/audit_mandate_wiring.py` and
|
|
105
|
+
`aidream/services/mandates/code_truth.py`; those two modules now import them
|
|
106
|
+
from here, so there is exactly one definition of "what a carrier looks like".
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""matrx-mandate-scan — the ONE Mandate reference scanner.
|
|
2
|
+
|
|
3
|
+
Finds every mandate carrier, every dynamic family, every pass-through, and
|
|
4
|
+
every path to intelligence that goes around the mandate system; emits the
|
|
5
|
+
frozen contract-v1 report; submits it through the one DB door; files every red
|
|
6
|
+
finding into the platform's one error system.
|
|
7
|
+
|
|
8
|
+
Laws it is built to (campaign register, 2026-09-09):
|
|
9
|
+
|
|
10
|
+
* **D23 — never block a release.** Every command exits 0 unless ``--strict``.
|
|
11
|
+
* **D20 — no new bypasses; existing ones are a ratchet**, not an approved class.
|
|
12
|
+
* **D21 — unreachable is a flag, never a filter.** Nothing is dropped for being
|
|
13
|
+
unresolved, orphaned or broken.
|
|
14
|
+
* **PACKAGE_DOCTRINE** — this package never imports ``aidream`` or ``matrx-orm``.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from .contract import CONTRACT_VERSION, SCANNER_VERSION, ScanReport, identity_hash
|
|
18
|
+
|
|
19
|
+
__version__ = SCANNER_VERSION
|
|
20
|
+
__all__ = ["CONTRACT_VERSION", "SCANNER_VERSION", "ScanReport", "identity_hash", "__version__"]
|