Skip to content

[spark-compete] fix(cli): name installed + registry modules in 'Unknown module target' install error#737

Closed
4gjnbzb4zf-sudo wants to merge 1 commit into
vibeforge1111:masterfrom
4gjnbzb4zf-sudo:sentinel/actionable-error/unknown-install-target-listing
Closed

[spark-compete] fix(cli): name installed + registry modules in 'Unknown module target' install error#737
4gjnbzb4zf-sudo wants to merge 1 commit into
vibeforge1111:masterfrom
4gjnbzb4zf-sudo:sentinel/actionable-error/unknown-install-target-listing

Conversation

@4gjnbzb4zf-sudo

@4gjnbzb4zf-sudo 4gjnbzb4zf-sudo commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

{
"schema": "spark-compete-hotfix-v1",
"event": "spark-compete-first-event",
"submission_mode": "public_repo_pr",
"submission_target_url": "#737",
"team": {
"name": "SparkThisUp",
"members": ["ValHallaBuilder", "Baz707", "DanFireDash"],
"github_accounts": ["4gjnbzb4zf-sudo"],
"llm_device_holder": "ValHallaBuilder",
"device_holder_github": "4gjnbzb4zf-sudo"
},
"target_repo": {
"id": "vibeforge1111/spark-cli",
"source": "https://github.com/vibeforge1111/spark-cli",
"owner_surface": "spark-cli"
},
"issue": {
"type": "usage_friction",
"severity": "low",
"title": "resolve_install_target's 'Unknown module target' error omits installed/registry modules and the acceptable target shapes",
"actual_behavior": "src/spark_cli/cli.py:4537 raises SystemExit(f"Unknown module target: {target}") when spark install <name> falls through every branch of resolve_install_target (installed dict, registry definition, git source, local path). The message names only the typed-but-unresolved argument and says nothing about (1) which modules are currently installed, (2) which modules the local registry definition knows about, or (3) the two alternative target shapes the function supports (git URL or local directory containing spark.toml). An operator who typed a near-miss has to leave the shell to run spark list and read the registry file before they can recover.",
"expected_behavior": "The same SystemExit names the installed modules, the registry-known modules (deduplicated against the installed set), and the two alternative target shapes (git URL with documented prefix list + .git suffix + owner/repo shorthand; local directory with spark.toml manifest). Pure-correct lookup paths (where the typed name DOES resolve via modules/registry/git/local) stay byte-identical -- the new message text only fires when SystemExit was already going to fire. The empty-registry edge case (no installed modules, no registry entries) prints a clear 'No modules are installed yet.' line plus the alternative shapes, so a fresh operator running spark install typo before any setup also gets a recovery path.",
"repro_steps": [
"gh pr checkout ",
"PYTHONPATH=src python -m unittest tests.test_cli.SparkCliTests.test_unknown_install_target_message_lists_installed_and_registry -> ok. Case A asserts the message names installed and registry-known modules separately (no double-listing); Case B asserts the empty-registry edge case prints 'No modules are installed yet.' and does NOT print the 'Registry-known modules:' line.",
"Manual: PYTHONPATH=src python -c "from spark_cli.cli import _unknown_install_target_message; print(_unknown_install_target_message('typo', {'spark-cli': 1}, {'modules': {'spark-character': {}}}))" -> 'Unknown module target: typo. Installed modules: spark-cli. Registry-known modules: spark-character. Or pass a git URL (https://, git@, .git suffix, or owner/repo shorthand) or a local directory containing a spark.toml manifest.'",
"Pure-hit paths unchanged: resolve_install_target still returns the correct Module when the target resolves via modules dict (L4508), registry definition (L4511-L4521), git source (L4527-L4530), or local manifest directory (L4531-L4536). The new message text only fires when the function was already going to SystemExit."
],
"affected_workflow": "spark install -- when the operator's typed target falls through every branch, the actionable-error fallback now tells them which modules they can install by short name (installed + registry) and which two alternative shapes the function accepts (git URL or local manifest path) without leaving the shell."
},
"evidence": {
"safe_links_only": true,
"before_after_proof": "One SystemExit site at src/spark_cli/cli.py:4537. Before: raise SystemExit(f"Unknown module target: {target}"). After: raise SystemExit(_unknown_install_target_message(target, modules, registry)) where the helper assembles the message from in-scope data: installed module names (sorted), registry-known names (deduplicated against installed, sorted), an empty-state line, and a one-line description of the two alternative target shapes. Diff: 1 file modified for the fix (22 changed lines around resolve_install_target and a new _unknown_install_target_message helper), 1 test file (37 insertions in tests/test_cli.py for two regression cases). The pure-hit return paths at L4508/L4511-L4521/L4527-L4530/L4531-L4536 are byte-identical.",
"links": ["https://github.com//pull/737"],
"forbidden": ["pdf","zip","exe","unknown downloads","shortened links","archives","binaries","tokens","browser cookies","wallet material","raw logs","raw conversations","raw memory","raw patches","private repo maps","private scoring details"]
},
"proposed_fix": {
"approach": "Extract the SystemExit message into a small _unknown_install_target_message(target, modules, registry) helper next to resolve_install_target. The helper assembles the message from in-scope data: the installed module names (sorted, from the modules dict already in scope), the registry-known names (sorted, from registry.get('modules') already in scope at L4510, deduplicated against the installed set), an empty-state line when the registry is empty, and a one-line description of the two alternative target shapes (git URL with the documented prefix list + .git suffix + owner/repo shorthand; local directory containing a spark.toml manifest). The fix is additive, narrowly scoped to the message text, and changes nothing on the four pure-hit return paths.",
"files_expected": ["src/spark_cli/cli.py", "tests/test_cli.py"],
"tests_or_smoke": "PYTHONPATH=src python -m unittest tests.test_cli.SparkCliTests.test_unknown_install_target_message_lists_installed_and_registry -> ok. The new test asserts (Case A) the message names installed and registry-known modules separately without double-listing when one name appears in both, and (Case B) the empty-registry edge case prints 'No modules are installed yet.' and does NOT print the 'Registry-known modules:' line. Pre-existing tests that exercise resolve_install_target's pure-hit paths are unaffected -- the helper only changes the SystemExit message text."
},
"pr": {
"branch": "sentinel/actionable-error/unknown-install-target-listing",
"title_prefix": "[spark-compete]",
"author_github": "4gjnbzb4zf-sudo",
"body_must_include": ["packet","team","pr_author","repo","actual_behavior","expected_behavior","repro_steps","before_after_proof","tests_or_smoke","duplicate_notes","risk_notes","review_claim"],
"url": "#737"
},
"review_claim": {
"impact_claim": "low",
"evidence_types": ["redacted_terminal_excerpt"],
"duplicate_notes": "Pre-flight gh pr list --repo vibeforge1111/spark-cli --search 'resolve_install_target OR Unknown module target' --state all returned a cluster of sibling-named PRs that are scope-disjoint from this one. PR #511 modifies resolve_installed_target_modules + resolve_start_modules (the Unknown installed module message on the spark logs/spark start path -- different function name, different surface). PR #516 names known bundles in the Unknown bundle message (different surface). PR #518 lists valid choices in setup-wizard 'Unknown X' prompts (different surface). PR #347 validates registry module names against path traversal (registry write path, not the install resolve path). PR #277 catches load_module crashes on missing/malformed spark.toml (different concern). None of those PRs touch resolve_install_target's SystemExit message at L4537. This entry extends the sibling actionable-error pattern to the install resolve-target fallback that no other PR touches.",
"risk_notes": "Local scope: one file changed for the fix, plus one regression test with two cases. The four pure-hit return paths in resolve_install_target are byte-identical. The new helper is a pure-text assembler with no I/O and no side effects -- it reads only the in-scope modules dict and the registry definition that the caller already loaded at L4510. No new module-level constant, no new import.",
"review_state_requested": "pr_review"
}
}

@4gjnbzb4zf-sudo

Copy link
Copy Markdown
Contributor Author

QA write-up — for reviewer eyes

TL;DR. resolve_install_target in src/spark_cli/cli.py raises SystemExit(f"Unknown module target: {target}") at L4537 when spark install <name> falls through every branch (installed dict, registry definition, git source, local path). The message names only the typed-but-unresolved argument and tells the operator nothing about (1) which modules they have installed, (2) which modules the registry knows about, or (3) the two alternative target shapes the function supports. This change extracts the message into a _unknown_install_target_message(target, modules, registry) helper that assembles a recoverable error from data already in scope. Pure-hit lookup paths are byte-identical.

Before

candidate = Path(target)
if candidate.exists():
    manifest_path = candidate / "spark.toml"
    if not manifest_path.exists():
        raise SystemExit(f"{candidate} does not contain spark.toml")
    return load_module(candidate)
raise SystemExit(f"Unknown module target: {target}")
$ spark install typoed-name
Unknown module target: typoed-name

After

candidate = Path(target)
if candidate.exists():
    manifest_path = candidate / "spark.toml"
    if not manifest_path.exists():
        raise SystemExit(f"{candidate} does not contain spark.toml")
    return load_module(candidate)
raise SystemExit(_unknown_install_target_message(target, modules, registry))


def _unknown_install_target_message(
    target: str, modules: dict[str, Module], registry: dict[str, Any]
) -> str:
    installed_names = sorted(modules.keys()) if modules else []
    registry_modules = registry.get("modules") if isinstance(registry.get("modules"), dict) else {}
    registry_names = sorted(name for name in registry_modules.keys() if name not in modules)
    parts = [f"Unknown module target: {target}."]
    if installed_names:
        parts.append("Installed modules: " + ", ".join(installed_names) + ".")
    else:
        parts.append("No modules are installed yet.")
    if registry_names:
        parts.append("Registry-known modules: " + ", ".join(registry_names) + ".")
    parts.append(
        "Or pass a git URL (https://, git@, .git suffix, or owner/repo shorthand) "
        "or a local directory containing a spark.toml manifest."
    )
    return " ".join(parts)
$ spark install typoed-name
Unknown module target: typoed-name. Installed modules: spark-cli,
spark-telegram-bot. Registry-known modules: spark-character,
spark-researcher. Or pass a git URL (https://, git@, .git suffix, or
owner/repo shorthand) or a local directory containing a spark.toml
manifest.
$ spark install typoed-name   # fresh machine, nothing installed
Unknown module target: typoed-name. No modules are installed yet. Or
pass a git URL (https://, git@, .git suffix, or owner/repo shorthand)
or a local directory containing a spark.toml manifest.

Smoke

$ PYTHONPATH=src python3 -m unittest tests.test_cli.SparkCliTests.test_unknown_install_target_message_lists_installed_and_registry
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

The test covers two cases: (Case A) the message names installed and registry-known modules separately without double-listing when one name appears in both; (Case B) the empty-registry edge case prints No modules are installed yet. and does NOT print the Registry-known modules: line.

Scope

  • 1 file changed for the fix: src/spark_cli/cli.py (22 changed lines around resolve_install_target and the new _unknown_install_target_message helper).
  • 1 test file: tests/test_cli.py (37 insertions, 1 new regression test with two cases).
  • git diff --stat origin/master -> 2 files, 58 insertions, 1 deletion.
  • The four pure-hit return paths in resolve_install_target (L4508 modules dict, L4511-L4521 registry, L4527-L4530 git source, L4531-L4536 local manifest) are byte-identical. The helper only changes the SystemExit message text.

Disjoint with sibling PRs

gh pr list --repo vibeforge1111/spark-cli --search "resolve_install_target OR Unknown module target" --state all returns sibling-named PRs that all address a different surface. PR #511 modifies resolve_installed_target_modules + resolve_start_modules (the Unknown installed module message on spark logs/spark start -- different function, different surface). PR #516 names known bundles in Unknown bundle (different surface). PR #518 lists valid choices in setup-wizard prompts (different surface). PR #347 validates registry module names against path traversal (registry write path). PR #277 catches load_module crashes on missing/malformed spark.toml (different concern). None touch resolve_install_target's SystemExit at L4537.

@vibeforge1111

Copy link
Copy Markdown
Owner

R24 cleanup: this source PR has received R24 leaderboard credit and is represented in the shipped/adopted release path by spark-cli#754. Thanks for the contribution; closing this PR to keep the review queue clean.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants