sourcecode 0.33.0__tar.gz → 0.34.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.
Files changed (142) hide show
  1. {sourcecode-0.33.0 → sourcecode-0.34.0}/PKG-INFO +1 -1
  2. {sourcecode-0.33.0 → sourcecode-0.34.0}/pyproject.toml +1 -1
  3. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/__init__.py +1 -1
  4. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/ast_extractor.py +48 -3
  5. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/cli.py +28 -9
  6. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/relevance_scorer.py +40 -6
  7. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/serializer.py +288 -53
  8. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_ast_extractor.py +4 -2
  9. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_contract_pipeline.py +17 -14
  10. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_integration.py +9 -7
  11. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_integration_detection.py +4 -4
  12. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_integration_lqn.py +4 -3
  13. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_integration_metrics.py +2 -2
  14. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_integration_multistack.py +2 -2
  15. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_integration_universal.py +3 -3
  16. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_pipeline_integrity.py +7 -7
  17. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_real_projects.py +4 -4
  18. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_signal_hierarchy.py +6 -6
  19. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_summarizer.py +4 -4
  20. {sourcecode-0.33.0 → sourcecode-0.34.0}/.agents/skills/source-command-gsd-join-discord/SKILL.md +0 -0
  21. {sourcecode-0.33.0 → sourcecode-0.34.0}/.agents/skills/source-command-gsd-review-backlog/SKILL.md +0 -0
  22. {sourcecode-0.33.0 → sourcecode-0.34.0}/.agents/skills/source-command-gsd-workstreams/SKILL.md +0 -0
  23. {sourcecode-0.33.0 → sourcecode-0.34.0}/.gitignore +0 -0
  24. {sourcecode-0.33.0 → sourcecode-0.34.0}/.ruff.toml +0 -0
  25. {sourcecode-0.33.0 → sourcecode-0.34.0}/CONTRIBUTING.md +0 -0
  26. {sourcecode-0.33.0 → sourcecode-0.34.0}/LICENSE +0 -0
  27. {sourcecode-0.33.0 → sourcecode-0.34.0}/README.md +0 -0
  28. {sourcecode-0.33.0 → sourcecode-0.34.0}/SECURITY.md +0 -0
  29. {sourcecode-0.33.0 → sourcecode-0.34.0}/docs/privacy.md +0 -0
  30. {sourcecode-0.33.0 → sourcecode-0.34.0}/docs/schema.md +0 -0
  31. {sourcecode-0.33.0 → sourcecode-0.34.0}/raw +0 -0
  32. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/architecture_analyzer.py +0 -0
  33. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/architecture_summary.py +0 -0
  34. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/classifier.py +0 -0
  35. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/code_notes_analyzer.py +0 -0
  36. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/confidence_analyzer.py +0 -0
  37. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/context_summarizer.py +0 -0
  38. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/contract_model.py +0 -0
  39. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/contract_pipeline.py +0 -0
  40. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/coverage_parser.py +0 -0
  41. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/dependency_analyzer.py +0 -0
  42. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/__init__.py +0 -0
  43. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/base.py +0 -0
  44. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/csproj_parser.py +0 -0
  45. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/dart.py +0 -0
  46. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/dotnet.py +0 -0
  47. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/elixir.py +0 -0
  48. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/go.py +0 -0
  49. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/heuristic.py +0 -0
  50. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/hybrid.py +0 -0
  51. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/java.py +0 -0
  52. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
  53. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/nodejs.py +0 -0
  54. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/parsers.py +0 -0
  55. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/php.py +0 -0
  56. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/project.py +0 -0
  57. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/python.py +0 -0
  58. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/ruby.py +0 -0
  59. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/rust.py +0 -0
  60. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/systems.py +0 -0
  61. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/terraform.py +0 -0
  62. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/detectors/tooling.py +0 -0
  63. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/doc_analyzer.py +0 -0
  64. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/entrypoint_classifier.py +0 -0
  65. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/env_analyzer.py +0 -0
  66. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/file_classifier.py +0 -0
  67. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/git_analyzer.py +0 -0
  68. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/graph_analyzer.py +0 -0
  69. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/metrics_analyzer.py +0 -0
  70. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/prepare_context.py +0 -0
  71. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/redactor.py +0 -0
  72. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/runtime_classifier.py +0 -0
  73. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/scanner.py +0 -0
  74. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/schema.py +0 -0
  75. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/semantic_analyzer.py +0 -0
  76. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/summarizer.py +0 -0
  77. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/telemetry/__init__.py +0 -0
  78. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/telemetry/config.py +0 -0
  79. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/telemetry/consent.py +0 -0
  80. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/telemetry/events.py +0 -0
  81. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/telemetry/filters.py +0 -0
  82. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/telemetry/transport.py +0 -0
  83. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/tree_utils.py +0 -0
  84. {sourcecode-0.33.0 → sourcecode-0.34.0}/src/sourcecode/workspace.py +0 -0
  85. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/__init__.py +0 -0
  86. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/conftest.py +0 -0
  87. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/coverage.xml +0 -0
  88. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/fastapi_app/pyproject.toml +0 -0
  89. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/fastapi_app/src/main.py +0 -0
  90. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/go_service/cmd/api/main.go +0 -0
  91. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/go_service/go.mod +0 -0
  92. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/jacoco.xml +0 -0
  93. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/lcov.info +0 -0
  94. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/nextjs_app/app/page.tsx +0 -0
  95. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/nextjs_app/package.json +0 -0
  96. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/nextjs_app/pnpm-lock.yaml +0 -0
  97. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/pnpm_monorepo/apps/web/app/page.tsx +0 -0
  98. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/pnpm_monorepo/apps/web/package.json +0 -0
  99. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/pnpm_monorepo/packages/api/main.py +0 -0
  100. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/pnpm_monorepo/packages/api/pyproject.toml +0 -0
  101. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/fixtures/pnpm_monorepo/pnpm-workspace.yaml +0 -0
  102. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_architecture_analyzer.py +0 -0
  103. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_architecture_summary.py +0 -0
  104. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_classifier.py +0 -0
  105. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_cli.py +0 -0
  106. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_code_notes_analyzer.py +0 -0
  107. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_coverage_parser.py +0 -0
  108. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_cross_consistency.py +0 -0
  109. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_dependency_analyzer_node_python.py +0 -0
  110. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_dependency_analyzer_polyglot.py +0 -0
  111. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_dependency_schema.py +0 -0
  112. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_detector_dotnet.py +0 -0
  113. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_detector_go_rust_java.py +0 -0
  114. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_detector_nodejs.py +0 -0
  115. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_detector_php_ruby_dart.py +0 -0
  116. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_detector_python.py +0 -0
  117. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_detector_universal_managed.py +0 -0
  118. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_detector_universal_systems.py +0 -0
  119. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_detectors_base.py +0 -0
  120. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_doc_analyzer_jsdom.py +0 -0
  121. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_doc_analyzer_python.py +0 -0
  122. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_graph_analyzer_polyglot.py +0 -0
  123. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_graph_analyzer_python_node.py +0 -0
  124. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_graph_schema.py +0 -0
  125. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_hybrid_inference.py +0 -0
  126. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_integration_dependencies.py +0 -0
  127. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_integration_docs.py +0 -0
  128. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_integration_graph_modules.py +0 -0
  129. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_integration_semantics.py +0 -0
  130. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_metrics_analyzer.py +0 -0
  131. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_packaging.py +0 -0
  132. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_phase1_improvements.py +0 -0
  133. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_redactor.py +0 -0
  134. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_scanner.py +0 -0
  135. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_schema.py +0 -0
  136. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_schema_normalization.py +0 -0
  137. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_semantic_analyzer_node.py +0 -0
  138. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_semantic_analyzer_python.py +0 -0
  139. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_semantic_import_resolution.py +0 -0
  140. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_semantic_schema.py +0 -0
  141. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_telemetry.py +0 -0
  142. {sourcecode-0.33.0 → sourcecode-0.34.0}/tests/test_workspace_analyzer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 0.33.0
3
+ Version: 0.34.0
4
4
  Summary: Deterministic codebase context for AI coding agents
5
5
  License: Apache License
6
6
  Version 2.0, January 2004
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sourcecode"
7
- version = "0.33.0"
7
+ version = "0.34.0"
8
8
  description = "Deterministic codebase context for AI coding agents"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -1,3 +1,3 @@
1
1
  """sourcecode — Deterministic codebase context maps for AI coding agents."""
2
2
 
3
- __version__ = "0.33.0"
3
+ __version__ = "0.34.0"
@@ -13,6 +13,7 @@ Install tree-sitter for best TS/JS results:
13
13
 
14
14
  import ast
15
15
  import re
16
+ import sys
16
17
  from pathlib import Path
17
18
  from typing import Any, Iterator, Optional
18
19
 
@@ -31,6 +32,45 @@ from sourcecode.contract_model import (
31
32
 
32
33
  _MAX_FILE_SIZE = 200_000 # bytes — skip files larger than this
33
34
 
35
+ # Python stdlib module names — used to filter noise from import lists.
36
+ # sys.stdlib_module_names is available in Python 3.10+; fall back to a
37
+ # curated set for 3.9 compatibility.
38
+ if hasattr(sys, "stdlib_module_names"):
39
+ _PY_STDLIB: frozenset[str] = sys.stdlib_module_names # type: ignore[attr-defined]
40
+ else:
41
+ _PY_STDLIB: frozenset[str] = frozenset({ # type: ignore[no-redef]
42
+ "__future__", "_thread", "abc", "aifc", "argparse", "array", "ast",
43
+ "asynchat", "asyncio", "asyncore", "atexit", "audioop", "base64",
44
+ "bdb", "binascii", "binhex", "bisect", "builtins", "bz2", "calendar",
45
+ "cgi", "cgitb", "chunk", "cmath", "cmd", "code", "codecs", "codeop",
46
+ "collections", "colorsys", "compileall", "concurrent", "configparser",
47
+ "contextlib", "contextvars", "copy", "copyreg", "cProfile", "csv",
48
+ "ctypes", "curses", "dataclasses", "datetime", "dbm", "decimal",
49
+ "difflib", "dis", "doctest", "email", "encodings", "enum", "errno",
50
+ "faulthandler", "fcntl", "filecmp", "fileinput", "fnmatch", "fractions",
51
+ "ftplib", "functools", "gc", "getopt", "getpass", "gettext", "glob",
52
+ "grp", "gzip", "hashlib", "heapq", "hmac", "html", "http", "idlelib",
53
+ "imaplib", "importlib", "inspect", "io", "ipaddress", "itertools",
54
+ "json", "keyword", "lib2to3", "linecache", "locale", "logging", "lzma",
55
+ "mailbox", "marshal", "math", "mimetypes", "mmap", "modulefinder",
56
+ "multiprocessing", "netrc", "nntplib", "numbers", "operator", "optparse",
57
+ "os", "pathlib", "pdb", "pickle", "pickletools", "pipes", "pkgutil",
58
+ "platform", "plistlib", "poplib", "posix", "posixpath", "pprint",
59
+ "profile", "pstats", "pty", "pwd", "py_compile", "pyclbr", "pydoc",
60
+ "queue", "quopri", "random", "re", "readline", "reprlib", "resource",
61
+ "rlcompleter", "runpy", "sched", "secrets", "select", "selectors",
62
+ "shelve", "shlex", "shutil", "signal", "site", "smtpd", "smtplib",
63
+ "sndhdr", "socket", "socketserver", "sqlite3", "ssl", "stat",
64
+ "statistics", "string", "stringprep", "struct", "subprocess", "sunau",
65
+ "symtable", "sys", "sysconfig", "syslog", "tabnanny", "tarfile",
66
+ "tempfile", "termios", "test", "textwrap", "threading", "time",
67
+ "timeit", "tkinter", "token", "tokenize", "tomllib", "trace",
68
+ "traceback", "tracemalloc", "tty", "types", "typing", "unicodedata",
69
+ "unittest", "urllib", "uuid", "venv", "warnings", "wave", "weakref",
70
+ "webbrowser", "wsgiref", "xml", "xmlrpc", "zipapp", "zipfile",
71
+ "zipimport", "zlib", "zoneinfo",
72
+ })
73
+
34
74
  _LANGUAGE_MAP: dict[str, str] = {
35
75
  ".py": "python",
36
76
  ".ts": "typescript",
@@ -729,9 +769,10 @@ def _py_signature(node: ast.FunctionDef | ast.AsyncFunctionDef) -> str:
729
769
  sig += f" -> {ast.unparse(node.returns)}"
730
770
  except Exception:
731
771
  pass
732
- # Truncate runaway signatures (e.g. typer.Option() defaults)
733
- if len(sig) > 300:
734
- sig = sig[:297] + "..."
772
+ # Keep full signature serializer applies per-mode compression.
773
+ # Hard cap at 2000 to prevent pathological cases.
774
+ if len(sig) > 2000:
775
+ sig = sig[:1997] + "..."
735
776
  return sig
736
777
 
737
778
 
@@ -840,6 +881,10 @@ def _extract_python(path: str, source: str) -> FileContract:
840
881
  if exported or name in all_names:
841
882
  exports.append(ExportRecord(name=name, kind="class"))
842
883
 
884
+ # Filter stdlib from imports — they add noise without signal for agents
885
+ _stdlib_roots = {m.split(".")[0] for m in _PY_STDLIB}
886
+ imports = [i for i in imports if i.source.split(".")[0] not in _stdlib_roots]
887
+
843
888
  deps = sorted({
844
889
  imp.source.split(".")[0]
845
890
  for imp in imports
@@ -516,11 +516,13 @@ def main(
516
516
  "contract",
517
517
  "--mode",
518
518
  help=(
519
- "Output mode: contract (default) | hybrid | raw. "
520
- "contract: per-file semantic contracts — exports, signatures, types, imports. No bodies. "
519
+ "Output mode: contract|minimal (default) | standard | deep | hybrid | raw. "
520
+ "contract/minimal: minimal per-file contracts — exports, signatures, deps. Smallest output. "
521
+ "standard: full per-file detail with imports, relevance scores, extraction method. "
522
+ "deep: standard + optional analysis sections (deps, env, git). "
521
523
  "hybrid: contracts + compact bodies for top-ranked files. "
522
524
  "raw: legacy project-level analysis (stacks, entry points, dependencies). "
523
- "contract mode is the recommended default for AI coding agents."
525
+ "contract/minimal is the recommended default for AI coding agents."
524
526
  ),
525
527
  ),
526
528
  max_symbols: Optional[int] = typer.Option(
@@ -587,7 +589,7 @@ def main(
587
589
  _t0 = time.monotonic()
588
590
 
589
591
  # Validate new flag choices
590
- _MODE_CHOICES = ("contract", "hybrid", "raw")
592
+ _MODE_CHOICES = ("contract", "minimal", "standard", "deep", "hybrid", "raw")
591
593
  if mode not in _MODE_CHOICES:
592
594
  typer.echo(
593
595
  f"Error: invalid value '{mode}' for --mode. Valid options: {', '.join(_MODE_CHOICES)}",
@@ -631,6 +633,13 @@ def main(
631
633
  typer.echo(f"Error: '{target}' is not a directory.", err=True)
632
634
  raise typer.Exit(code=1)
633
635
 
636
+ # Normalize mode aliases
637
+ _CONTRACT_MODES = frozenset({"contract", "minimal", "standard", "deep", "hybrid"})
638
+ if mode == "minimal":
639
+ mode = "contract" # minimal is the canonical default contract rendering
640
+ elif mode not in _CONTRACT_MODES and mode != "raw":
641
+ mode = "contract" # unknown → safe default
642
+
634
643
  # Legacy flags imply raw mode unless --mode was explicitly overridden.
635
644
  # These flags produce standard_view-only output sections not in contract_view.
636
645
  # Preserves backward compat: callers using any legacy flag get their previous format.
@@ -639,9 +648,17 @@ def main(
639
648
  compact or agent or tree or format == "yaml" or trace_pipeline
640
649
  or docs or semantics or graph_modules or full_metrics or architecture
641
650
  )
642
- if mode == "contract" and _legacy_flags_active:
651
+ if mode in ("contract", "standard", "deep") and _legacy_flags_active:
643
652
  mode = "raw"
644
653
 
654
+ # Map mode to contract_view depth
655
+ _CONTRACT_DEPTH = {
656
+ "contract": "minimal",
657
+ "standard": "standard",
658
+ "deep": "deep",
659
+ "hybrid": "minimal", # hybrid adds bodies via pipeline, minimal header
660
+ }
661
+
645
662
  # --- Import analysis modules ---
646
663
  from dataclasses import asdict, replace
647
664
 
@@ -1226,8 +1243,9 @@ def main(
1226
1243
  ))
1227
1244
  sm = _replace(sm, pipeline_trace=_trace.build_trace())
1228
1245
 
1229
- # Contract pipeline — runs for mode=contract|hybrid (skip for raw)
1230
- if mode in ("contract", "hybrid"):
1246
+ # Contract pipeline — runs for mode=contract|standard|deep|hybrid (skip for raw)
1247
+ _is_contract_mode = mode in ("contract", "standard", "deep", "hybrid")
1248
+ if _is_contract_mode:
1231
1249
  from sourcecode.contract_pipeline import ContractPipeline
1232
1250
  _cp = ContractPipeline()
1233
1251
  _contracts, _contract_summary = _cp.run(
@@ -1249,9 +1267,10 @@ def main(
1249
1267
  typer.echo(f"[contract] {len(_contracts)} files extracted ({_contract_summary.method_breakdown})", err=True)
1250
1268
 
1251
1269
  # 4. Serialize
1252
- if mode in ("contract", "hybrid"):
1270
+ if _is_contract_mode:
1253
1271
  from sourcecode.serializer import contract_view as _contract_view
1254
- data = _contract_view(sm, emit_graph=emit_graph)
1272
+ _depth = _CONTRACT_DEPTH.get(mode, "minimal")
1273
+ data = _contract_view(sm, emit_graph=emit_graph, depth=_depth)
1255
1274
  if not no_redact:
1256
1275
  data = redact_dict(data)
1257
1276
  content = json.dumps(data, indent=2, ensure_ascii=False)
@@ -82,8 +82,30 @@ _AUXILIARY_DIR_PATTERNS: list[re.Pattern[str]] = [
82
82
  re.compile(r"(?:^|/)scripts?(?:/|$)"),
83
83
  re.compile(r"(?:^|/)tools?(?:/|$)"),
84
84
  re.compile(r"(?:^|/)ci(?:/|$)"),
85
+ re.compile(r"(?:^|/)migrations?(?:/|$)"),
86
+ re.compile(r"(?:^|/)generated?(?:/|$)"),
87
+ re.compile(r"(?:^|/)storybook(?:/|$)"),
88
+ re.compile(r"(?:^|/)stories(?:/|$)"),
85
89
  ]
86
90
 
91
+ # Test file patterns — scored low, excluded from default contract output
92
+ _TEST_FILE_PATTERNS: tuple[str, ...] = (
93
+ "_test.", ".test.", ".spec.", "test_", "conftest", "_spec.",
94
+ )
95
+ _TEST_DIR_MARKERS: frozenset[str] = frozenset({
96
+ "/test/", "/tests/", "/spec/", "/specs/", "/__tests__/", "/__mocks__/",
97
+ })
98
+
99
+ # Config/tooling filenames that are low runtime-relevance
100
+ _LOW_RUNTIME_STEMS: frozenset[str] = frozenset({
101
+ "setup", "setup.cfg", "pyproject", "package", "package-lock",
102
+ "yarn.lock", "pnpm-lock", "composer", "gemfile", "podfile",
103
+ "dockerfile", "docker-compose", "makefile", "rakefile",
104
+ "gruntfile", "gulpfile", "webpack.config", "vite.config",
105
+ "rollup.config", "babel.config", "jest.config", "vitest.config",
106
+ "tsconfig", "jsconfig", ".eslintrc", ".prettierrc", ".editorconfig",
107
+ })
108
+
87
109
  _HIGH_VALUE_SUFFIXES: frozenset[str] = frozenset({
88
110
  ".py", ".ts", ".tsx", ".js", ".jsx", ".mjs",
89
111
  ".go", ".java", ".kt", ".rs", ".rb", ".cs",
@@ -114,7 +136,7 @@ class RelevanceScorer:
114
136
 
115
137
  base = 0.3
116
138
 
117
- # Package role boost
139
+ # Package role boost — runtime code scores high, tooling/docs low
118
140
  role = self._package_role(norm)
119
141
  role_boost = {
120
142
  "runtime_core": 0.4,
@@ -124,10 +146,10 @@ class RelevanceScorer:
124
146
  "composition_layer": 0.2,
125
147
  "plugin_package": 0.15,
126
148
  "infrastructure_layer": 0.15,
127
- "tooling_layer": -0.1,
128
- "docs_layer": -0.15,
129
- "test_layer": 0.05,
130
- "benchmark_layer": -0.2,
149
+ "tooling_layer": -0.15,
150
+ "docs_layer": -0.25,
151
+ "test_layer": -0.1,
152
+ "benchmark_layer": -0.25,
131
153
  }.get(role, 0.0)
132
154
  base += role_boost
133
155
 
@@ -141,7 +163,19 @@ class RelevanceScorer:
141
163
  if stem in _ENTRYPOINT_STEMS:
142
164
  base += 0.15
143
165
 
144
- # Penalize auxiliary dirs
166
+ # Test file penalty — tests are useful for coverage but not for
167
+ # understanding architecture or editing production code
168
+ fname = Path(norm).name.lower()
169
+ if (any(m in f"/{norm}/" for m in _TEST_DIR_MARKERS)
170
+ or any(fname.startswith(p.strip(".")) or p in fname
171
+ for p in _TEST_FILE_PATTERNS)):
172
+ base -= 0.25
173
+
174
+ # Config/tooling filename penalty
175
+ if stem.lower() in _LOW_RUNTIME_STEMS:
176
+ base -= 0.2
177
+
178
+ # Auxiliary dir penalty
145
179
  if self._is_auxiliary(norm):
146
180
  base -= 0.2
147
181