A Shipmoor finding is not a style nit. Every rule in the catalog targets a high-confidence failure mode of generated code: the things a coding agent gets wrong that a linter, a type checker, and a tired reviewer all let through. This page covers what those failure modes are, how severity is assigned, and how to use shipmoor rules and shipmoor explain to go from a finding to a fix.
The failure modes
The headline classes, in the order reviewers hit them:
| Failure mode | What it means |
|---|---|
| Phantom import | The code references a package or local module that isn’t in the manifest, the lockfile, or the project. |
| Hallucinated API | A function, method, endpoint, or local symbol is called even though it doesn’t exist. |
| Stub path | A handler returns success while the real persistence, payment, or side effect is missing. |
The full catalog organizes its rules into five categories:
- Phantom imports / dependencies. The agent invented a package, mis-spelled one, or used one without declaring it.
python.phantom_import,typescript.phantom_dependency,javascript.phantom_dependency,go.phantom_import. - Placeholder logic. Empty bodies,
pass/ ellipsis, constant returns,throw new Error("not implemented"),panic("TODO").*.placeholder.*. - Trust suppression.
anyat public boundaries,as any,@ts-ignore: code that bypasses the type system so a generated change compiles without satisfying the contract.*.trust.*. - Quality signals. Bare
except, mutable default arguments, ignored errors on side-effecting calls,console.log/fmt.Printleft in production code, oversized functions.*.quality.*,*.error.*,*.debug.*,*.structure.*. - Control flow. Unreachable code after a
returnorthrow.*.control_flow.*.
Shipmoor 0.4.0 ships 30 rules across Python, TypeScript, JavaScript, and Go. List them all, with severities, in one command:
shipmoor rules
shipmoor rules --json
Phantom-import subtypes
The phantom-import rules classify every finding by subtype, so a reviewer can tell at a glance whether the agent invented something or just forgot a manifest entry:
| Subtype | What it means |
|---|---|
hallucinated_package | No such package exists on the public registry. Often a real agent hallucination. |
missing_manifest_entry | The package exists on the registry, but the project never declared it. |
broken_relative_path | The import is local, but the target file does not exist on disk. |
unresolved_local_module | The import looks local but doesn’t match any module under the project’s source roots. |
The subtype appears in the human message and in JSON under finding.subtype. The optional registry lookup behind hallucinated_package is the Community CLI’s only outbound network call. Disable it with SHIPMOOR_OFFLINE=1, and those findings fall back to missing_manifest_entry, marked unverified.
How severity is assigned
Severity is set per defect class and held consistent across languages. A hallucinated import is high whether it’s Python or Go, because the code cannot run as authored in either:
| Defect class | Severity | Why |
|---|---|---|
| Hallucinated import or dependency | high | Code cannot run as authored; strong signal of agent failure. |
| Placeholder body in non-test, non-interface code | medium | Strong review signal, but some legitimate stubs exist. |
| Ignored error from a side-effecting call | medium | Reviewer-actionable, conservative default. |
| Trust suppression at a boundary or via ignore directives | medium | A defensible signal that safety checks were bypassed. |
| Bare except / catch-all that discards failures | low | Common pattern with high context sensitivity. |
| Debug output left in source | low | Usually cosmetic and easy to clean up. |
A few rules sit outside the shared classes. A Python syntax error is critical (the file can’t even be analyzed), and a placeholder panic("TODO") in Go is high. You can override any rule’s severity, or disable a rule entirely, in .shipmoor.yaml. See Gating & policy.
Explaining a finding
Every finding carries a stable ID. Ask Shipmoor for the why, the root cause, and the fix, either by rule or by finding ID from a JSON report:
shipmoor explain phantom_import
shipmoor explain SHM-b00b9982e581ed39 --from shipmoor.json
✗ high · phantom import python.phantom_import
app.py:3 · SHM-b00b9982e581ed39 · confidence high · phantom_dependency
────────────────────────────────────────────────────────
why
Local module 'imaginary_shipmoor_package' is referenced but no file matches under PYTHONPATH.
root cause
No matching local module file could be resolved from project paths.
fix
→ 'imaginary_shipmoor_package' looks local but does not resolve from project module paths.
Add the file, fix PYTHONPATH, or remove the import.
evidence
import_name: imaginary_shipmoor_package
registry_lookup: not_applicable
After any --json or --sarif run that produced findings, the scan prints the exact shipmoor explain command for one of them; copy it to drill in. Agents use the same loop: the shipmoor-fix skill feeds explain output back to the agent as repair guidance.
What Shipmoor deliberately doesn’t flag
Style, formatting, dependency vulnerabilities, and general SAST are other tools’ jobs (ruff, ESLint, pip-audit, semgrep, CodeQL). Shipmoor stays focused on the question those tools don’t answer: is this generated change real, grounded, and implemented?
Next
- Output formats & exit codes: JSON, SARIF, and the CI contract.
- Gating & policy:
--fail-on, severity overrides, and baselines. - Rule catalog: every rule, by language and class.
- Claim Check: beyond structure: did the change do what the task asked?