Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
6bf551e
chore(plan): detailed plan for nopt-backed npm package identity (#195)
ViperJuice Aug 26, 2026
14db5d7
chore(plan): revision 2 after board review (#195)
ViperJuice Aug 26, 2026
c8f1aaa
chore(plan): revision 3 -- narrow and fail closed (#195)
ViperJuice Aug 27, 2026
f93caa8
chore(plan): revision 4 -- allowlist instead of denylist (#195)
ViperJuice Aug 27, 2026
5d6a650
chore(plan): revision 5 -- self-test failure must refuse, not fall ba…
ViperJuice Aug 27, 2026
9a8419d
chore(plan): revision 6 -- final, implement from this (#195)
ViperJuice Aug 27, 2026
56055f3
feat(parser): add _npm_resolve.js -- npm's own parser as an identity …
ViperJuice Aug 27, 2026
13ffa17
feat(parser): add NpmResolver -- tri-state identity with a persistent…
ViperJuice Aug 27, 2026
2946bcf
refactor(parser)!: env and cwd are required identity inputs (#195)
ViperJuice Aug 27, 2026
81255cb
test(parser): parametrize the npm identity suite over both paths (#195)
ViperJuice Aug 27, 2026
ab6060a
test(parser): resolver contract -- gates, tri-state, drift, lifecycle…
ViperJuice Aug 27, 2026
e7c7891
build(parser): ship _npm_resolve.js and prove it in install-smoke (#195)
ViperJuice Aug 27, 2026
16abc3c
fix(parser): never memoise a refusal the child did not survive (#195)
ViperJuice Aug 27, 2026
913c831
test(parser): hermetic three-way differential corpus (#195)
ViperJuice Aug 27, 2026
3762b0c
docs(parser): CHANGELOG and README for npm identity via npm's parser …
ViperJuice Aug 27, 2026
9faed7a
feat(health): report npm identity resolver state in gateway.health (#…
ViperJuice Aug 27, 2026
8c12fb1
docs(parser): the disabled-resolver WARNING names the restart require…
ViperJuice Aug 27, 2026
6c46c66
Merge remote-tracking branch 'origin/main' into fix/195-nopt-npm-iden…
ViperJuice Aug 27, 2026
e384975
fix(parser): refuse a package operand that starts with a dash (#195)
ViperJuice Aug 27, 2026
9a06553
fix(parser): four board must-fixes on the diff (#195)
ViperJuice Aug 27, 2026
eac8027
fix(parser): locate npm in the prefix layout; refuse an npm we cannot…
ViperJuice Aug 27, 2026
ffd90c1
fix(parser): install family is a package LIST; a spaced spec must not…
ViperJuice Aug 27, 2026
1b3c363
fix(parser): close the three board follow-ups (#195)
ViperJuice Aug 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
713 changes: 713 additions & 0 deletions .consiliency/notes/differential_npm_corpus.py

Large diffs are not rendered by default.

173 changes: 114 additions & 59 deletions .consiliency/notes/mutate.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,96 +26,118 @@
MUTATIONS = [
(
"uvx --python reclassified value -> boolean",
VC, "append",
VC,
"append",
'_UVX_VALUE_FLAGS = _UVX_VALUE_FLAGS - {"--python"}\n'
'_UVX_BOOLEAN_FLAGS = _UVX_BOOLEAN_FLAGS | {"--python"}\n',
"tests/test_version_checker.py::TestValueFlagCollisions"
"::test_uvx_python_version_is_not_the_package",
),
(
"uvx --with reclassified value -> boolean",
VC, "append",
VC,
"append",
'_UVX_VALUE_FLAGS = _UVX_VALUE_FLAGS - {"--with"}\n'
'_UVX_BOOLEAN_FLAGS = _UVX_BOOLEAN_FLAGS | {"--with"}\n',
"tests/test_version_checker.py::TestValueFlagCollisions"
"::test_uvx_with_dependency_is_not_the_package",
),
(
"pip --index-url reclassified value -> boolean",
VC, "append",
VC,
"append",
'_PIP_VALUE_FLAGS = _PIP_VALUE_FLAGS - {"--index-url"}\n'
'_PIP_BOOLEAN_FLAGS = _PIP_BOOLEAN_FLAGS | {"--index-url"}\n',
"tests/test_version_checker.py::TestValueFlagCollisions"
"::test_pip_index_url_is_not_the_package",
),
(
"cargo --features reclassified value -> boolean",
VC, "append",
VC,
"append",
'_CARGO_VALUE_FLAGS = _CARGO_VALUE_FLAGS - {"--features"}\n'
'_CARGO_BOOLEAN_FLAGS = _CARGO_BOOLEAN_FLAGS | {"--features"}\n',
"tests/test_version_checker.py::TestValueFlagCollisions"
"::test_cargo_features_is_not_the_crate",
),
(
"docker --env-file reclassified value -> boolean",
VC, "append",
VC,
"append",
'_DOCKER_VALUE_FLAGS = _DOCKER_VALUE_FLAGS - {"--env-file"}\n'
'_DOCKER_BOOLEAN_FLAGS = _DOCKER_BOOLEAN_FLAGS | {"--env-file"}\n',
"tests/test_version_checker.py::TestValueFlagCollisions"
"::test_docker_env_file_is_not_the_image",
),
(
"docker --mount reclassified value -> boolean",
VC, "append",
VC,
"append",
'_DOCKER_VALUE_FLAGS = _DOCKER_VALUE_FLAGS - {"--mount"}\n'
'_DOCKER_BOOLEAN_FLAGS = _DOCKER_BOOLEAN_FLAGS | {"--mount"}\n',
"tests/test_version_checker.py::TestValueFlagCollisions"
"::test_docker_mount_spec_is_not_the_image",
),
(
"npm --package no longer known-positive (pre-fix skip)",
VC, "append",
VC,
"append",
"_NPM_POSITIVE_FLAGS = frozenset()\n",
"tests/test_version_checker.py::TestValueFlagCollisions"
"::test_npm_exec_package_flag_names_the_package",
),
(
"npm repeated --package no longer refuses (returns the first)",
VC, "replace",
(" return packages[0] if len(set(packages)) == 1 else None\n",
" return packages[0]\n"),
VC,
"replace",
(
" return packages[0] if len(set(packages)) == 1 else None\n",
" return packages[0]\n",
),
"tests/test_version_checker.py::TestValueFlagCollisions"
"::test_npm_repeated_package_flags_refuse",
),
(
"fail-closed default removed (unlisted flag skipped again)",
VC, "replace",
(' return arg.startswith("-") and arg != "-" and "=" not in arg\n',
" return False\n"),
VC,
"replace",
(
' return arg.startswith("-") and arg != "-" and "=" not in arg\n',
" return False\n",
),
"tests/test_version_checker.py::TestValueFlagsFailClosed"
"::test_uvx_unlisted_flag_refuses",
),
(
"fail-closed default removed -- docker arm",
VC, "replace",
(' return arg.startswith("-") and arg != "-" and "=" not in arg\n',
" return False\n"),
VC,
"replace",
(
' return arg.startswith("-") and arg != "-" and "=" not in arg\n',
" return False\n",
),
"tests/test_version_checker.py::TestValueFlagsFailClosed"
"::test_docker_unlisted_flag_refuses",
),
(
"fail-closed default removed -- update_server no-probe consequence",
VC, "replace",
(' return arg.startswith("-") and arg != "-" and "=" not in arg\n',
" return False\n"),
VC,
"replace",
(
' return arg.startswith("-") and arg != "-" and "=" not in arg\n',
" return False\n",
),
"tests/test_tools.py::TestUpdateServerVersionRepair"
"::test_update_server_never_probes_an_unclassifiable_flag_form",
),
(
"`--flag=value` no longer treated as self-delimiting",
VC, "replace",
(' return arg.startswith("-") and arg != "-" and "=" not in arg\n',
' return arg.startswith("-") and arg != "-"\n'),
VC,
"replace",
(
' return arg.startswith("-") and arg != "-" and "=" not in arg\n',
' return arg.startswith("-") and arg != "-"\n',
),
"tests/test_version_checker.py::TestValueFlagsFailClosed"
"::test_unlisted_flag_with_attached_value_is_self_delimiting",
),
Expand All @@ -126,30 +148,38 @@
# proof that does not exist.
(
"PEP 508 normalization removed",
VC, "replace",
(" return match.group(1) if match else requirement\n",
" return requirement\n"),
VC,
"replace",
(
" return match.group(1) if match else requirement\n",
" return requirement\n",
),
"tests/test_version_checker.py::TestKnownPositiveValueFlags"
"::test_from_value_is_normalized_to_its_pep508_base_name",
),
(
"PEP 508 applied to URLs too (git+https identity destroyed)",
VC, "replace",
(" return match.group(1) if match else requirement\n",
' return requirement.split("/")[0]\n'),
VC,
"replace",
(
" return match.group(1) if match else requirement\n",
' return requirement.split("/")[0]\n',
),
"tests/test_version_checker.py::TestKnownPositiveValueFlags"
"::test_from_url_value_keeps_the_whole_url_as_identity",
),
(
"docker `-it` combined short boolean removed",
VC, "append",
VC,
"append",
'_DOCKER_BOOLEAN_FLAGS = _DOCKER_BOOLEAN_FLAGS - {"-it"}\n',
"tests/test_version_checker.py::TestKnownPositiveValueFlags"
"::test_docker_combined_short_booleans_still_find_image",
),
(
"uvx --from downgraded known-positive -> value flag",
VC, "append",
VC,
"append",
"_UVX_POSITIVE_FLAGS = frozenset()\n"
'_UVX_VALUE_FLAGS = _UVX_VALUE_FLAGS | {"--from"}\n',
"tests/test_version_checker.py::TestKnownPositiveValueFlags"
Expand All @@ -160,42 +190,50 @@
# the half that was actually broken. `--from`'s classification is NOT
# observable through this form -- see the test's docstring.
"uvx --python reclassified -> README pin form misidentified as 3.12",
VC, "append",
VC,
"append",
'_UVX_VALUE_FLAGS = _UVX_VALUE_FLAGS - {"--python"}\n'
'_UVX_BOOLEAN_FLAGS = _UVX_BOOLEAN_FLAGS | {"--python"}\n',
"tests/test_version_checker.py::TestKnownPositiveValueFlags"
"::test_readme_documented_pin_form_resolves_to_the_package",
),
(
"uvx --quiet reclassified boolean -> value (rejected design)",
VC, "append",
VC,
"append",
'_UVX_BOOLEAN_FLAGS = _UVX_BOOLEAN_FLAGS - {"--quiet"}\n'
'_UVX_VALUE_FLAGS = _UVX_VALUE_FLAGS | {"--quiet"}\n',
"tests/test_version_checker.py::TestKnownPositiveValueFlags"
"::test_uvx_boolean_flag_still_finds_package",
),
(
"uvx positional normalized too (inline pin lost)",
VC, "replace",
(' return ("pypi", _pep508_base_name(raw) '
"if from_positive_flag else raw)\n",
' return ("pypi", _pep508_base_name(raw))\n'),
VC,
"replace",
(
' return ("pypi", _pep508_base_name(raw) '
"if from_positive_flag else raw)\n",
' return ("pypi", _pep508_base_name(raw))\n',
),
"tests/test_version_checker.py::TestKnownPositiveValueFlags"
"::test_positional_uvx_token_is_left_raw",
),
(
"uvx pin detection un-shared (back to independent scan)",
HD, "replace",
(" raw, _from_flag = _uvx_package_arg(args)\n"
' if raw is not None and "==" in raw:\n'
' _, _, version = raw.partition("==")\n'
" return version or None\n",
" for arg in args:\n"
' if arg.startswith("-"):\n'
" continue\n"
' if "==" in arg:\n'
' _, _, version = arg.partition("==")\n'
" return version or None\n"),
HD,
"replace",
(
" raw, _from_flag = _uvx_package_arg(args)\n"
' if raw is not None and "==" in raw:\n'
' _, _, version = raw.partition("==")\n'
" return version or None\n",
" for arg in args:\n"
' if arg.startswith("-"):\n'
" continue\n"
' if "==" in arg:\n'
' _, _, version = arg.partition("==")\n'
" return version or None\n",
),
"tests/test_tools.py::TestUpdateServerVersionRepair"
"::test_detect_effective_version_pin_matrix",
),
Expand All @@ -208,9 +246,11 @@ def purge() -> None:


PY = str(REPO / ".venv/bin/python")
ENV = {**__import__("os").environ,
"PYTHONDONTWRITEBYTECODE": "1",
"PYTHONPATH": str(MUT / "src")}
ENV = {
**__import__("os").environ,
"PYTHONDONTWRITEBYTECODE": "1",
"PYTHONPATH": str(MUT / "src"),
}


def check_provenance() -> None:
Expand All @@ -221,7 +261,10 @@ def check_provenance() -> None:
"""
proc = subprocess.run(
[PY, "-c", "import pmcp.manifest.version_checker as m; print(m.__file__)"],
cwd=MUT, capture_output=True, text=True, env=ENV,
cwd=MUT,
capture_output=True,
text=True,
env=ENV,
)
resolved = proc.stdout.strip()
expected = str(MUT / "src/pmcp/manifest/version_checker.py")
Expand All @@ -237,11 +280,19 @@ def run(node: str) -> tuple[bool, str]:
purge()
proc = subprocess.run(
[PY, "-m", "pytest", node, "-q", "-p", "no:randomly", "--no-header", "-x"],
cwd=MUT, capture_output=True, text=True, env=ENV,
cwd=MUT,
capture_output=True,
text=True,
env=ENV,
)
tail = [ln for ln in proc.stdout.splitlines()
if ln.startswith(("FAILED", "ERROR", "assert", "E "))
or " passed" in ln or " failed" in ln or " error" in ln]
tail = [
ln
for ln in proc.stdout.splitlines()
if ln.startswith(("FAILED", "ERROR", "assert", "E "))
or " passed" in ln
or " failed" in ln
or " error" in ln
]
return proc.returncode == 0, " | ".join(tail[-3:])[:260]


Expand Down Expand Up @@ -279,8 +330,10 @@ def main() -> int:
old, new = payload
text = originals[path]
if old not in text:
print(f" SKIP {label}\n (anchor not found -- mutation "
f"did not apply, treat as UNPROVEN)")
print(
f" SKIP {label}\n (anchor not found -- mutation "
f"did not apply, treat as UNPROVEN)"
)
survivors.append((label, node, "anchor not found"))
continue
path.write_text(text.replace(old, new, 1))
Expand All @@ -300,8 +353,10 @@ def main() -> int:
print()
print("=" * 78)
if survivors:
print(f"{len(survivors)} SURVIVING MUTANT(S) -- these tests do not pin "
"what they claim:")
print(
f"{len(survivors)} SURVIVING MUTANT(S) -- these tests do not pin "
"what they claim:"
)
for label, node, detail in survivors:
print(f" - {label}\n {node}\n {detail}")
return 1
Expand Down
6 changes: 4 additions & 2 deletions .consiliency/notes/verify_tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,10 @@ def main() -> int:
# value and positive flags must take a value; boolean must not.
expected = kind in ("value", "positive")
if takes != expected and (tool, flag) in JUSTIFIED_ARITY:
print(f" ARITY-OK {tool:6s} {kind:8s} {flag:24s} "
f"{JUSTIFIED_ARITY[(tool, flag)]}")
print(
f" ARITY-OK {tool:6s} {kind:8s} {flag:24s} "
f"{JUSTIFIED_ARITY[(tool, flag)]}"
)
elif takes != expected:
mismatches.append(
f"{tool} {kind:8s} {flag:24s} "
Expand Down
Loading
Loading