Releases: QuantmindSSI/CTO-MCP
Release list
v3.6.0
[3.6.0] - 2026-08-20
Gate G4 (Dependency Honesty) gets its mechanical half: hallucinated-
package detection. LLMs invent package names and attackers register them
("slopsquatting"), so an import that does not exist on its registry is
both an incompleteness defect and a supply-chain attack surface - and it
is now detected, not just judged.
Added
verify_dependenciesMCP tool (persona_constitution/dependencies.py):
extracts imports from source (Python via AST including literal-argument
importlib.import_module/__import__; JS/TS via import/export/require
specifiers) or from a unified diff's added lines with new-file line
numbers, classifies the cheap-and-private tiers locally (caller-excluded
globs, Python stdlib incl. a frozen 3.9-floor fallback, Node built-ins,
modules the diff itself provides), and verifies the remainder against
PyPI (PEP 503 simple index) and the npm registry. A curated alias table
resolves the well-known import-name/distribution mismatches
(yaml -> PyYAML, cv2 -> opencv-python, ...) asexists-as.- Network honesty as a contract. This is the package's only
network-touching tool besides the GitHub client, and its advertised
description says so: package names and nothing else leave the machine,
bounded (50 packages/call, 10s timeout, 3 attempts, backoff). A 404 is
missing-> FAIL; timeouts/5xx/429/offline areunverifiable-> REVIEW,
never a silent PASS.scan_codeandreview_patchremain fully
offline. - The reviewing agent's protocol now calls
verify_dependenciesfor
G4's existence half; pinning and intent remain judgement. - 29 hermetic tests: extraction forms, tier ordering (local tiers
provably never query), alias resolution, verdict precedence, retry
behaviour at the single network egress, diff line mapping, and the
tool's boundary validation. The module joins the nightly mutation run.
Scanner accuracy measured by this release build
Adversarial corpus: 24 violations, 13 legitimate samples, 37 total
prose rules only 24/37 (64%)
union (shipped) 37/37 (100%)
Union at or above baseline (37/37 >= 37).
v3.5.0
[3.5.0] - 2026-08-20
The interoperability release: findings speak the industry's language.
Every finding carries a MITRE CWE where a defensible mapping exists, and
the review renders as SARIF 2.1.0 for GitHub code scanning - so the gate's
output lands in the Security tab of every consuming repository, tagged by
weakness class, instead of living only in annotations and logs.
Added
- CWE tagging across all four engines. Deferral prose and markers are
CWE-546 (Suspicious Comment); empty function/loop bodies are CWE-1071
(Empty Code Block); empty catch/except handling is CWE-1069 (Empty
Exception Block); stubs that fake their contract (hardcoded returns,
not-implemented throws, panic()/todo!() stubs) are CWE-684 (Incorrect
Provision of Specified Functionality); unreachable code is CWE-561,
constant conditions are CWE-570/571 selected by actual polarity, and
the Po10 metrics are CWE-1121/1120. Engines attach identical IDs to
byte-identical finding texts, so deduplication can never merge findings
that disagree about their weakness class. Absence ofcweis a
statement - no honest mapping exists (mock/fake/passthrough classes) -
and tests pin both directions. - SARIF 2.1.0 output.
to_sarif()renders a review with stable
ruleIds derived from the constitution failure classes, severity-mapped
levels, real line coordinates, and CWE tags on rules and results.
Skipped files and pre-existing debt contribute nothing: SARIF gates
exactly what the verdict gates. --sarif-file PATHon the CLI (written before stdout output; an
unwritable path is an operational error, exit 3, not a crash) and a
sarif-fileinput on the composite action, which uploads to code
scanning via SHA-pinned codeql-action - skipped automatically for fork
PRs, whose tokens cannot upload. Dogfooded on this repository's own
PR gate.
Scanner accuracy measured by this release build
Adversarial corpus: 24 violations, 13 legitimate samples, 37 total
prose rules only 24/37 (64%)
union (shipped) 37/37 (100%)
Union at or above baseline (37/37 >= 37).
v3.4.0
[3.4.0] - 2026-08-20
The verification-depth release: the protocol boundary is conformance-
tested and fuzzed (and two spec deviations it found are fixed), the
entire first-party package is typed under strict mypy, the detector core
is mutation-tested nightly, and every release now carries the scanner
accuracy its own build measured.
Fixed
- Malformed id-less frames were silenced. JSON-RPC 2.0's own examples
answer{"jsonrpc": "2.0", "method": 1}with an id-null -32600; an
invalid object cannot be trusted to be a notification, because the
missing id may itself be the malformation. Silence is now reserved for
well-formed notifications exactly. - notifications/* with an id attached was silenced. Anything
carrying an id is a request and must be answered; unknown methods now
uniformly produce METHOD_NOT_FOUND and only genuinely id-less frames
are discarded. Found, like the above, by the new fuzz suite's first run. handle_tools_callanswered an unhashable tool name with
INTERNAL_ERROR (it crashed insidedict.get); a caller mistake is now
INVALID_PARAMS. Forced by the type checker during strict-mypy adoption.
Added
- Protocol conformance and fuzz suite
(tests/test_protocol_conformance.py): pins the initialize,
tools/list, and tools/call shapes; 600 seeded mutated frames against
dispatch()under three invariants (never raises; exactly one response
per request, id echoed, exactly one of result/error; silence for
well-formed notifications); byte-level garbage against the stdio loop
proving the transport survives and stdout stays pure JSON frames. - Debug diagnostics:
--debugflag orPERSONA_CONSTITUTION_DEBUG
env enables one stderr line per frame - method, tool, frame/response
sizes, wall-clock cost. Sizes only, never payload content; a test pins
that a scanned secret cannot appear in the diagnostics. - Strict typing, gated: every first-party module fully annotated,
mypy --strictclean (3.9 target; vendored codebase_csi outside the
regime with its symbols guarded at explicit boundaries), pinned mypy
running as its own CI job. GitHub API responses are now shape-checked
at the client boundary instead of trusted. - Nightly mutation testing (
mutation.yml+[tool.mutmut]):
mutmut over the detector core (scanner, logic rules, ast bridge, diff
parser, review engine), driving the existing unittest suite through
pytest. Introduction baseline on logic_rules.py: 107/155 mutants
killed (69%); survivors are the enumerated test gaps to close.
tests/conftest.pyscopes real-repository assertions (release
integrity, wall-clock budgets, subprocess transport) out of the
mutation sandbox where they are meaningless. - Measured accuracy in release notes: the release build's benchmark
summary (corpus size, per-tier and union detection rates) is appended
to the GitHub Release notes and attached as an artifact - the rules
are the product, so the number ships with it.
Scanner accuracy measured by this release build
Adversarial corpus: 24 violations, 13 legitimate samples, 37 total
prose rules only 24/37 (64%)
union (shipped) 37/37 (100%)
Union at or above baseline (37/37 >= 37).
v3.3.1
[3.3.1] - 2026-08-20
Fixed
- The release pipeline's SBOM step used
--outfile; cyclonedx-bom 7.x
spells it--output-file, so the v3.3.0 release build failed before
publishing anything (the version-match, test, benchmark, wheel-content
and twine gates had all passed). The flag is corrected and the tool is
now pinned exactly, for the same reason ruff is: a release pipeline
must not absorb upstream CLI changes as surprises. v3.3.0's tag remains
where it was - tags are immutable here; the fix ships as a new version.