sourcecode 5.8.30__py3-none-any.whl → 5.8.31__py3-none-any.whl

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.

Potentially problematic release.


This version of sourcecode might be problematic. Click here for more details.

sourcecode/__init__.py CHANGED
@@ -4,4 +4,4 @@ ASK Engine is the product. ``ask`` is the canonical CLI command; ``sourcecode``
4
4
  the legacy compatibility alias and the Python/PyPI package name. See
5
5
  docs/PRODUCT_IDENTITY.md (normative)."""
6
6
 
7
- __version__ = "5.8.30"
7
+ __version__ = "5.8.31"
@@ -1,5 +1,5 @@
1
1
  """Generated at build time by hatch_build.py. Do not edit (AUD-592-D04)."""
2
2
 
3
- BUILD_COMMIT = 'ab3d2c7736790a32306bd4b1df906f54bb72f5a6'
3
+ BUILD_COMMIT = '32e9b630f9276e5e481a33f0232c3a7876cd5751'
4
4
  CLOSURE_PROVENANCE = {'Window': {'commit': '', 'status': 'uncited'}, '`AUD-588-F05`': {'commit': '470e4a4', 'status': 'present'}, '`AUD-590-B01` / `B-01`, `F-01`': {'commit': '', 'status': 'uncited'}, '`AUD-590-B02` / `B-02`, `F-02`': {'commit': '', 'status': 'uncited'}, '`AUD-590-B03` / `B-03`, `F-03`': {'commit': '', 'status': 'uncited'}, '`AUD-590-B04` / `B-04`, `F-04`': {'commit': '', 'status': 'uncited'}, '`AUD-590-R01` / `R-01`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A01` / `A-1`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A02` / `A-2`, `A-4`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A03` / `A-3`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A05` / `A-5`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A06` / `A-6`, `A-7`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A08` / `A-8`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A09` / `A-9`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A10` / `A-10`': {'commit': '', 'status': 'uncited'}, '`AUD-592-A02` / `A-1` second half, `§12.5`': {'commit': '63f3d61', 'status': 'present'}, '`AUD-592-B01` / `B-8`': {'commit': '8329614', 'status': 'present'}, '`AUD-592-D01` / `D-1`': {'commit': '0f8e03f', 'status': 'present'}, '`AUD-592-D02` / `D-2`': {'commit': '1d3db4d', 'status': 'present'}, '`AUD-592-D03` / `D-3`': {'commit': 'f28fe40', 'status': 'present'}, '`AUD-592-R01` / `A-1`': {'commit': '216025f', 'status': 'present'}, '`AUD-592-R02` / `N-4`, reopens `AUD-513-N04`': {'commit': 'ec3050d', 'status': 'present'}, '`AUD-593-N01` / `N-01`': {'commit': 'dd6a706', 'status': 'present'}, '`AUD-593-N02` / `N-02`': {'commit': 'f539787', 'status': 'present'}, '`AUD-593-N03` / `N-03`': {'commit': '1dd0b1c', 'status': 'present'}, '`AUD-593-N05` / `N-05`': {'commit': 'aa89388', 'status': 'present'}, '`AUD-593-N06` / `N-06`': {'commit': 'aa584a6', 'status': 'present'}, '`AUD-594-N04` / `D-5`, disclosure half of `B-3`': {'commit': 'a0060b7', 'status': 'present'}, '`AUD-594-X01` / `A-1`, residual of `AUD-593-N03`': {'commit': 'dd222b9', 'status': 'present'}, '`AUD-594-X02` / `A-1` second half': {'commit': '1193937', 'status': 'present'}, '`AUD-594-X03` / `X-03`, residual of `AUD-593-N01`': {'commit': 'e89e8f0', 'status': 'present'}, '`AUD-594-X04`': {'commit': '05b8cc9', 'status': 'present'}, '`AUD-595-A02` / `N-5`, advisory half of `AUD-588-B11`': {'commit': '3e15227', 'status': 'present'}, '`AUD-595-A03` / `B-6` exit-code half': {'commit': 'ab7285f', 'status': 'present'}, '`AUD-595-A05`': {'commit': 'e0b3d10', 'status': 'present'}, '`AUD-595-A07`, narrow half of `AUD-592-A02`': {'commit': 'cc15177', 'status': 'present'}, '`AUD-595-B01` / §B': {'commit': 'b77a1ad', 'status': 'present'}, '`AUD-595-Q01`': {'commit': '91a6566', 'status': 'present'}, '`AUD-596-A01` / `ASK-DET-001`': {'commit': 'fa508b4', 'status': 'present'}, '`AUD-596-A02` / `ASK-SELF-001`': {'commit': '4dfadc8', 'status': 'present'}, '`AUD-596-A03` / `ASK-C1-001`': {'commit': 'bffa3a6', 'status': 'present'}, '`AUD-596-A04` / `ASK-UX-003` + `ASK-UX-004`': {'commit': 'f0aac3c', 'status': 'present'}, '`AUD-596-B01` / `B-01`, harder witness for `BUG-6`': {'commit': '567d09d', 'status': 'present'}, '`AUD-596-B02` / `B-02`, class residual of `R2`': {'commit': '', 'status': 'uncited'}, '`AUD-596-B03` / `B-03`': {'commit': 'a8cb814', 'status': 'present'}, '`AUD-596-B06` / `B-06`': {'commit': '8107927', 'status': 'present'}, '`AUD-596-B07` / `B-07`, class residual of `AUD-592-R02`': {'commit': 'e060485', 'status': 'present'}, '`AUD-596-B09` / `B-09`': {'commit': '5b8146c', 'status': 'present'}, '`AUD-596-B10` / `B-10`': {'commit': '5cb994d', 'status': 'present'}, '`AUD-596-B16` / `B-16`': {'commit': '1507f69', 'status': 'present'}, '`AUD-596-D01` / `B-13` + `B-14`': {'commit': '0b1bdf0', 'status': 'present'}, '`AUD-596-D02` / `B-08`, residual of `AUD-594-N04`': {'commit': 'e7f73c3', 'status': 'present'}, '`AUD-596-D03` / `ASK-AGT-001`': {'commit': '8c46967', 'status': 'present'}, '`AUD-596-D04` / `B-18`': {'commit': '040f027', 'status': 'present'}, '`AUD-596-D05` / `B-19`': {'commit': 'fd2bf68', 'status': 'present'}, '`AUD-596-D06` / `B-20`': {'commit': '784cd83', 'status': 'present'}, '`AUD-596-D07` / `B-17`, half refuted': {'commit': 'c3ff822', 'status': 'present'}, '`AUD-596-D08` / `B-22`, class residual of `AUD-591-A06`': {'commit': 'b396c6a', 'status': 'present'}, '`AUD-596-D09` / `B-23`, surviving half of `B26`': {'commit': 'fd3d63f', 'status': 'present'}, '`AUD-596-D10` / `B-29`': {'commit': '', 'status': 'uncited'}, '`AUD-596-D11` / `ASK-UX-005`': {'commit': 'f4b4f77', 'status': 'present'}, '`AUD-596-D12` — six hints that send the reader back to the error': {'commit': '498df44', 'status': 'present'}, '`AUD-596-D13` / `B-28`': {'commit': '1014c72', 'status': 'present'}, '`AUD-596-D14` / `B-15`, narrow half of `B20`': {'commit': '10f2827', 'status': 'present'}, '`AUD-596-R01` / `B-05`': {'commit': '', 'status': 'uncited'}, '`AUD-596-X01` / `ASK-GATE-001`, gating half of `B24`': {'commit': 'e59c655', 'status': 'present'}, '`AUD-596-X02` / `ASK-UX-001` + `ASK-UX-002` + `B-21`': {'commit': 'f6ebf50', 'status': 'present'}, '`AUD-597-A01` / `ASK-UX-001` + `N-01`': {'commit': 'f8cf061', 'status': 'present'}, '`AUD-597-A02` / `ASK-UX-008` + `ASK-DOC-002`': {'commit': '9d47a4c', 'status': 'present'}, '`AUD-597-A03` / `ASK-DET-001`': {'commit': '4c7622a', 'status': 'present'}, '`AUD-597-A04` / `ASK-LEDGER-001`': {'commit': '46fb870', 'status': 'present'}, '`AUD-597-D01` / `B-04`': {'commit': '1094e6a', 'status': 'present'}, '`AUD-597-D02` / `ASK-DOC-001`': {'commit': 'ecb1bb7', 'status': 'present'}, '`AUD-597-D03` / `N-06`': {'commit': '9784333', 'status': 'present'}, '`AUD-597-D04` / `N-05`': {'commit': 'e51c087', 'status': 'present'}, '`AUD-597-D05` / `N-04`, fourth appearance of `C4-27`': {'commit': '9cccc15', 'status': 'present'}, '`AUD-597-D06` / `ASK-CLI-001`': {'commit': '178aa6d', 'status': 'present'}, '`AUD-597-D07` / `N-03`': {'commit': '9245e35', 'status': 'present'}, '`AUD-597-R01` / `ASK-PERF-001`': {'commit': '6910054', 'status': 'present'}, '`AUD-597-R02` / `ASK-ENC-001`': {'commit': 'ce6dac1', 'status': 'present'}, '`AUD-597-R03` / `ASK-UX-002`': {'commit': 'c57e50b', 'status': 'present'}, '`AUD-597-X01` / `ASK-BUILD-001` + `ASK-META-001` / `B-12`': {'commit': '354338b', 'status': 'present'}, '`AUD-598-B01` / `ASK-META-001`': {'commit': 'b2f7c65', 'status': 'present'}, '`AUD-598-B02` / `ASK-UX-002`': {'commit': '56a4bf7', 'status': 'present'}, '`AUD-598-B03` / `B-11`': {'commit': 'c63cb24', 'status': 'present'}, '`AUD-598-B04` / `N-02`': {'commit': '187937f', 'status': 'present'}, '`AUD-598-R01` / `ASK-PERF-002`': {'commit': '', 'status': 'uncited'}, '`AUD-598-X01` / `N-01` + `B-13` + `B-14` + `B-29` + `N-06`': {'commit': '6f2f5a4', 'status': 'present'}, '`AUD-600-B01` / `P-01`': {'commit': '366ffed', 'status': 'present'}, '`AUD-600-B02` / `P-02` + `ASK-PACK-002`': {'commit': '2a814c3', 'status': 'present'}, '`AUD-600-B03` / `ASK-PACK-001`': {'commit': '452f2a0', 'status': 'present'}, '`AUD-600-D01`': {'commit': '1224e1b', 'status': 'present'}, '`AUD-600-D02`': {'commit': 'eab8172', 'status': 'present'}, '`AUD-600-R01` / `R-01`': {'commit': '88add64', 'status': 'present'}, '`AUD-601-B01` / `N-02`, 5th round': {'commit': '', 'status': 'uncited'}, '`AUD-601-B02` / `ASK-PACK-004`': {'commit': '', 'status': 'uncited'}, '`AUD-601-D01` / `N-01`, `ASK-UX-001`, 5th round': {'commit': '', 'status': 'uncited'}, '`AUD-601-D02` / `B-13`, `B-14`, 5th round': {'commit': '', 'status': 'uncited'}, '`AUD-601-M01` / `B-26`, `B-27` retracted': {'commit': '', 'status': 'uncited'}, '`AUD-601-R01` / `R-02`': {'commit': '', 'status': 'uncited'}, '`B-3`': {'commit': '773268d', 'status': 'present'}, '`B-6`': {'commit': '17c6e06', 'status': 'present'}, '`B-8`': {'commit': '8329614', 'status': 'present'}, '`BUG-3` / `443b345`': {'commit': '', 'status': 'uncited'}, '`BUG-4a` / `AUD-588-B11` residual': {'commit': '24b4185', 'status': 'present'}, '`BUG-4b` / `AUD-588-B11` residual': {'commit': '0376350', 'status': 'present'}, '`E-39`, class residual of `AUD-593-N06`': {'commit': '25fc11f', 'status': 'present'}, '`N-5`': {'commit': 'c68083f', 'status': 'present'}, '`N-7`': {'commit': '082e9de', 'status': 'present'}, '`R-1`': {'commit': '424fb1c', 'status': 'present'}, '`R-2`': {'commit': '5158b92', 'status': 'present'}, '`R-3`': {'commit': '88aec04', 'status': 'present'}, '`R-4`': {'commit': '04fd04f', 'status': 'present'}}
5
5
  CLOSURE_COVERAGE = {'closed_rows': 113, 'present': 88, 'absent': 0, 'unresolved': 0, 'uncited': 25, 'unknown': 0}
@@ -25,7 +25,7 @@ checkout by `52bcc36` and `f89ae18`, with focused regression batteries passing;
25
25
  artefact verification remains pending. The pack's `--since` timing is additional evidence
26
26
  for `AUD-604-P01`, not a duplicate performance finding.
27
27
 
28
- **Current `5.8.30` queue:** artefact verification for `AUD-604-R01`; the two `AUD-605`
28
+ **Current `5.8.31` queue:** artefact verification for `AUD-604-R01`; the two `AUD-605`
29
29
  fixes are included in this release and await release-artefact verification.
30
30
 
31
31
  **External `5.8.28` audit received, 2026-08-26 - `AUD-604`.**
@@ -46,13 +46,13 @@ CLI commands — impact, endpoints, spring-audit, explain, … each a pro
46
46
  The key idea: the extraction is **content-addressed**. Commands reuse the parse cache and,
47
47
  where their analysed scope matches, the shared Canonical IR; `ask cache model` names what a
48
48
  warm buys for each command rather than implying that every projection costs the same. In
49
- 5.8.30, `validation` enters through that shared CIR and `data-exposure` reuses one semantic
49
+ 5.8.31, `validation` enters through that shared CIR and `data-exposure` reuses one semantic
50
50
  model across all declared label seeds. (The extraction and consumption contract is fixed in
51
51
  the architecture ADRs 0001–0004 under `docs/architecture/`.)
52
52
 
53
53
  The current external pack audit intake is tracked in
54
54
  [`AUDIT-2026-08-26-EXTERNAL-5.8.28-PACK.md`](AUDIT-2026-08-26-EXTERNAL-5.8.28-PACK.md);
55
- the two pack fixes are included in release 5.8.30, with release-artifact verification
55
+ the two pack fixes are included in release 5.8.31, with release-artifact verification
56
56
  remaining for detached execution and pack evidence.
57
57
 
58
58
  ---
@@ -183,7 +183,7 @@ pipx install sourcecode # isolated install, no venv needed
183
183
 
184
184
  # Verify
185
185
  ask version
186
- # ask 5.8.30
186
+ # ask 5.8.31
187
187
  ```
188
188
 
189
189
  Requires Python 3.9+.
sourcecode/cache.py CHANGED
@@ -82,6 +82,12 @@ CORE_SCHEMA_VERSION: str = "1"
82
82
  ANALYZER_CACHE_VERSION: str = "1"
83
83
 
84
84
 
85
+ def _user_home() -> Path:
86
+ """Honor an explicit HOME override before Windows' USERPROFILE fallback."""
87
+ configured = os.environ.get("HOME")
88
+ return Path(configured) if configured else Path.home()
89
+
90
+
85
91
  def analyzer_fingerprint() -> str:
86
92
  """Content hash of the analysis code, memoised for the process.
87
93
 
@@ -325,7 +331,7 @@ def cache_dir(repo_root: Path) -> Path:
325
331
  Override the base via ``SOURCECODE_CACHE_DIR``.
326
332
  """
327
333
  env_base = os.environ.get("SOURCECODE_CACHE_DIR", "")
328
- base: Path = Path(env_base) if env_base else Path.home() / ".sourcecode" / "cache"
334
+ base: Path = Path(env_base) if env_base else _user_home() / ".sourcecode" / "cache"
329
335
  return base / repo_id(repo_root)
330
336
 
331
337
 
sourcecode/cli.py CHANGED
@@ -3415,7 +3415,6 @@ COMMANDS_WITHOUT_PROGRESS: "frozenset[str]" = frozenset({
3415
3415
  "baseline trend", # same command under the group name
3416
3416
  "regress", # reads two named JSON files; analyses no repository
3417
3417
  "pack list", # fixed local catalog
3418
- "pack assessment", # child progress is captured for aggregate JSON
3419
3418
  "pack gate", # child progress is captured for aggregate JSON
3420
3419
  })
3421
3420
 
@@ -4332,6 +4331,11 @@ def pack_assessment_cmd(
4332
4331
  help="Deployment artefact for posture evidence (repeatable: k8s, Compose, Dockerfile, WebLogic, dotenv or launch script).",
4333
4332
  ),
4334
4333
  compact: bool = typer.Option(False, "--compact", help="Keep component reports bounded where supported."),
4334
+ only: Optional[str] = typer.Option(
4335
+ None,
4336
+ "--only",
4337
+ help="Comma-separated assessment components to run; audit-report requires risk.",
4338
+ ),
4335
4339
  output_dir: Optional[Path] = typer.Option(
4336
4340
  None,
4337
4341
  "--output-dir",
@@ -4340,13 +4344,14 @@ def pack_assessment_cmd(
4340
4344
  format: str = _format_option(help="Output format: json, yaml or markdown."),
4341
4345
  copy: bool = _copy_option(),
4342
4346
  output_path: Optional[Path] = _output_option(),
4347
+ progress_mode: Optional[str] = _progress_option(),
4343
4348
  ) -> None:
4344
4349
  """Modernization and Risk Assessment pack.
4345
4350
 
4346
4351
  Composes existing commands into one consumable report. Individual commands
4347
4352
  remain available and are the source of truth for every artifact.
4348
4353
  """
4349
- from sourcecode.packs import render_assessment_markdown, run_assessment
4354
+ from sourcecode.packs import assessment_components, render_assessment_markdown, run_assessment
4350
4355
 
4351
4356
  root = _admit_path(path)
4352
4357
  if profile and deployment:
@@ -4357,10 +4362,16 @@ def pack_assessment_cmd(
4357
4362
  )
4358
4363
  raise typer.Exit(code=2)
4359
4364
  _enforce_format("pack-assessment", format)
4365
+ try:
4366
+ selected_components = assessment_components(only.split(",") if only is not None else None)
4367
+ except ValueError as exc:
4368
+ _emit_error_json(INVALID_INPUT_CODE, str(exc))
4369
+ raise typer.Exit(code=2)
4360
4370
  _progress = Progress().start("pack assessment")
4361
4371
  try:
4362
4372
  data = run_assessment(
4363
4373
  root, profile=profile, deployment=deployment, compact=compact, output_dir=output_dir,
4374
+ selected_components=selected_components,
4364
4375
  progress=lambda done, total, component: _progress.work(
4365
4376
  done, total, stage=f"pack assessment: {component}",
4366
4377
  unit="components", estimate=False,
@@ -4390,7 +4401,12 @@ def pack_assessment_cmd(
4390
4401
  @pack_app.command("gate")
4391
4402
  def pack_gate_cmd(
4392
4403
  path: Path = typer.Argument(Path("."), help="Repository path (default: current directory)."),
4393
- since: str = typer.Option(..., "--since", help="Git ref used as the comparison base."),
4404
+ since: Optional[str] = typer.Option(None, "--since", help="Local Git ref used as the comparison base."),
4405
+ pr: Optional[int] = typer.Option(
4406
+ None,
4407
+ "--pr",
4408
+ help="GitHub pull request number; resolves changed files and requires its base commit locally.",
4409
+ ),
4394
4410
  profile: Optional[str] = typer.Option(None, "--profile", help="Profile set used for posture evidence."),
4395
4411
  compact: bool = typer.Option(False, "--compact", help="Omit component payload bodies from the aggregate."),
4396
4412
  allow_unverified: bool = typer.Option(False, "--allow-unverified", help="Allow an unverified component to exit 0."),
@@ -4416,7 +4432,37 @@ def pack_gate_cmd(
4416
4432
  from sourcecode.packs import run_gate
4417
4433
 
4418
4434
  root = _admit_path(path, exit_code=2)
4419
- data = run_gate(root, since=since, profile=profile, allow_unverified=allow_unverified, compact=compact, output_dir=output_dir)
4435
+ if since is not None and pr is not None:
4436
+ _emit_error_json(
4437
+ INVALID_INPUT_CODE,
4438
+ "--since and --pr describe mutually exclusive comparison bases.",
4439
+ hint="Use --since REF for a local comparison or --pr NUMBER for GitHub pull-request mode.",
4440
+ )
4441
+ raise typer.Exit(code=2)
4442
+ if since is None and pr is None:
4443
+ _emit_error_json(
4444
+ INVALID_INPUT_CODE,
4445
+ "pack gate requires --since REF or --pr NUMBER.",
4446
+ hint="Use --since origin/main, or --pr 123 when the GitHub base commit is available locally.",
4447
+ )
4448
+ raise typer.Exit(code=2)
4449
+ comparison_ref = since
4450
+ if pr is not None:
4451
+ try:
4452
+ from sourcecode.github_diff import pull_request_base_ref
4453
+
4454
+ comparison_ref, _description = pull_request_base_ref(root, pr)
4455
+ except Exception as exc:
4456
+ from sourcecode.github_diff import GitHubDiffError
4457
+
4458
+ if isinstance(exc, GitHubDiffError):
4459
+ _emit_error_json(INVALID_INPUT_CODE, str(exc), pr=pr)
4460
+ raise typer.Exit(code=2)
4461
+ raise
4462
+ data = run_gate(
4463
+ root, since=comparison_ref or "", pr=pr, profile=profile,
4464
+ allow_unverified=allow_unverified, compact=compact, output_dir=output_dir,
4465
+ )
4420
4466
  if format in {"github-actions", "gitlab"}:
4421
4467
  from sourcecode.ci_output import render_pack_gate_github_actions, render_pack_gate_gitlab
4422
4468
  output = (render_pack_gate_github_actions(data)
@@ -18682,7 +18728,6 @@ def cache_warm_cmd(
18682
18728
  this command reports. Cache ~/.sourcecode/cache and ~/.sourcecode between jobs,
18683
18729
  or budget the cold run explicitly.
18684
18730
  """
18685
- import shutil as _shutil
18686
18731
  import subprocess as _sub
18687
18732
  import time as _warm_time
18688
18733
  # Warm exactly the path given. Resolving up to the enclosing git root warmed
@@ -18714,7 +18759,11 @@ def cache_warm_cmd(
18714
18759
  f"(scoped to {target}; the enclosing git repository is {_git_root} — "
18715
18760
  "git-derived signals are computed within the scope above)"
18716
18761
  )
18717
- _sc_bin = _shutil.which("sourcecode") or sys.argv[0]
18762
+ # Launch the worker through this interpreter rather than resolving a second
18763
+ # console script from PATH. A stale global script can otherwise warm one
18764
+ # package installation while the caller reads another one, leaving a view
18765
+ # apparently fresh even though its cache entry was never written.
18766
+ _sc_bin = [sys.executable, "-m", "sourcecode"]
18718
18767
 
18719
18768
  # AUD-600-R01: which views a warm builds is `cache_model`'s fact, not a pair
18720
18769
  # of literals here. The warm used to run one child with `--compact` and an
@@ -18763,7 +18812,7 @@ def cache_warm_cmd(
18763
18812
  # stderr: the line above says it started, the spinner says it is still going.
18764
18813
  _warmed_ids: list[str] = []
18765
18814
  for _view in _selected:
18766
- cmd = [_sc_bin, str(target), *_warm_view_flags(_view.id)]
18815
+ cmd = [*_sc_bin, str(target), *_warm_view_flags(_view.id)]
18767
18816
  _prog = Progress()
18768
18817
  _prog.start(f"running full analysis ({_view.id} view)")
18769
18818
  try:
sourcecode/envelope.py CHANGED
@@ -81,7 +81,7 @@ def _tree_state(target: Path) -> "tuple[str, str, str]":
81
81
  return "", "", ""
82
82
  # Git for Windows emits forward slashes while Path resolves to native
83
83
  # separators. Restore the platform-native spelling for this path contract.
84
- root = str(Path(root))
84
+ root = portable_path(Path(root))
85
85
  prefix = _git(["rev-parse", "--show-prefix"], target)
86
86
  head = _git(["rev-parse", "HEAD"], target) or "no-commit"
87
87
  dirty = _git(["status", "--porcelain"], target)
sourcecode/github_diff.py CHANGED
@@ -1,6 +1,7 @@
1
1
  """Optional GitHub CLI adapter for obtaining a pull-request file list."""
2
2
  from __future__ import annotations
3
3
 
4
+ import json
4
5
  import subprocess
5
6
  from pathlib import Path
6
7
 
@@ -32,3 +33,53 @@ def pull_request_files(root: Path, number: int) -> tuple[list[str], str]:
32
33
  )
33
34
  paths = [line.strip() for line in result.stdout.splitlines() if line.strip()]
34
35
  return paths, f"gh pr diff {number} --name-only"
36
+
37
+
38
+ def pull_request_base_ref(root: Path, number: int) -> tuple[str, str]:
39
+ """Return the exact local comparison commit for a GitHub pull request.
40
+
41
+ The gate's posture component compares two repository states, unlike
42
+ `pr-impact`, which only needs GitHub's changed-file list. Resolve the base
43
+ SHA through `gh`, then require that the checkout actually has that object;
44
+ a missing base is an actionable CI checkout problem, not a reason to compare
45
+ against an arbitrary branch name.
46
+ """
47
+ if number < 1:
48
+ raise GitHubDiffError("pull request number must be a positive integer")
49
+ command = ["gh", "pr", "view", str(number), "--json", "baseRefName,baseRefOid"]
50
+ try:
51
+ result = subprocess.run(
52
+ command, cwd=root, capture_output=True, text=True, check=False,
53
+ )
54
+ except FileNotFoundError as exc:
55
+ raise GitHubDiffError(
56
+ "GitHub PR mode requires the `gh` CLI; install it or use --since"
57
+ ) from exc
58
+ except OSError as exc:
59
+ raise GitHubDiffError(f"could not start `gh`: {exc}") from exc
60
+ if result.returncode != 0:
61
+ detail = result.stderr.strip() or "GitHub CLI returned a non-zero status"
62
+ raise GitHubDiffError(
63
+ f"could not read pull request #{number}: {detail}. "
64
+ "Check `gh auth status` and the repository remote."
65
+ )
66
+ try:
67
+ payload = json.loads(result.stdout)
68
+ except json.JSONDecodeError as exc:
69
+ raise GitHubDiffError("GitHub CLI returned invalid pull-request metadata") from exc
70
+ base_oid = payload.get("baseRefOid")
71
+ base_name = payload.get("baseRefName")
72
+ if not isinstance(base_oid, str) or not base_oid:
73
+ raise GitHubDiffError("GitHub pull-request metadata did not include baseRefOid")
74
+ check = subprocess.run(
75
+ ["git", "cat-file", "-e", f"{base_oid}^{{commit}}"],
76
+ cwd=root, capture_output=True, text=True, check=False,
77
+ )
78
+ if check.returncode != 0:
79
+ label = base_name if isinstance(base_name, str) and base_name else base_oid
80
+ raise GitHubDiffError(
81
+ f"pull request #{number} base {label} ({base_oid}) is not present in this checkout. "
82
+ "Fetch the base commit first (for GitHub Actions, use actions/checkout with fetch-depth: 0), "
83
+ "or use --since with an available local ref."
84
+ )
85
+ return base_oid, f"gh pr view {number} base {base_name or base_oid} ({base_oid})"
sourcecode/license.py CHANGED
@@ -89,11 +89,20 @@ if _SUPABASE_URL != _DEFAULT_SUPABASE_URL:
89
89
  # which case prompts point to the documented Pro plans instead of a placeholder link.
90
90
  _PURCHASE_URL: str = os.environ.get("SOURCECODE_PURCHASE_URL", "").strip()
91
91
 
92
+
93
+ def _user_home() -> Path:
94
+ """Honor HOME overrides used by isolated subprocesses on every host."""
95
+ configured = os.environ.get("HOME") or os.environ.get("USERPROFILE")
96
+ if configured:
97
+ return Path(configured)
98
+ return Path.home()
99
+
100
+
92
101
  # Config home: ~/.ask is canonical (product = ASK Engine). The legacy ~/.sourcecode
93
102
  # stays READABLE so no existing user loses their license — reads prefer ~/.ask and
94
103
  # fall back to ~/.sourcecode; writes always land in ~/.ask. Backward-compatible.
95
- _LICENSE_DIR: Path = Path.home() / ".ask"
96
- _LEGACY_LICENSE_DIR: Path = Path.home() / ".sourcecode"
104
+ _LICENSE_DIR: Path = _user_home() / ".ask"
105
+ _LEGACY_LICENSE_DIR: Path = _user_home() / ".sourcecode"
97
106
  _LICENSE_FILE: Path = _LICENSE_DIR / "license.json"
98
107
  _DELTA_RUNS_FILE: Path = _LICENSE_DIR / "delta_runs.json"
99
108
 
sourcecode/mcp_nudge.py CHANGED
@@ -18,11 +18,21 @@ Exit code of the calling command is unaffected.
18
18
  """
19
19
  from __future__ import annotations
20
20
 
21
+ import os
21
22
  import sys
22
23
  from pathlib import Path
23
24
 
25
+
26
+ def _home_dir() -> Path:
27
+ """Resolve the configured home even in minimal Windows subprocess envs."""
28
+ configured = os.environ.get("HOME") or os.environ.get("USERPROFILE")
29
+ if configured:
30
+ return Path(configured)
31
+ return Path.home()
32
+
33
+
24
34
  # Stable path used as a session-level "already shown" sentinel.
25
- _FLAG: Path = Path.home() / ".sourcecode" / "nudge_shown"
35
+ _FLAG: Path = _home_dir() / ".sourcecode" / "nudge_shown"
26
36
 
27
37
  _MSG = (
28
38
  "→ Claude Desktop detected. "
@@ -3008,6 +3008,10 @@ def _scan_file(
3008
3008
  *,
3009
3009
  declared_types: "Optional[frozenset[str]]" = None,
3010
3010
  ) -> list[MigrationFinding]:
3011
+ # Findings are a portable payload contract. Callers may have obtained the
3012
+ # relative path with ``str(Path)`` on Windows, but the same repository file
3013
+ # must retain one identity across hosts and subprocess boundaries.
3014
+ rel_path = rel_path.replace("\\", "/")
3011
3015
  findings: list[MigrationFinding] = []
3012
3016
  type_deprecated = _primary_type_is_deprecated(source)
3013
3017
 
sourcecode/packs.py CHANGED
@@ -24,7 +24,7 @@ import sys
24
24
  import tempfile
25
25
  import time
26
26
  from pathlib import Path
27
- from typing import Any, Callable, Optional
27
+ from typing import Any, Callable, Optional, Sequence
28
28
 
29
29
  from sourcecode import pack_manifest
30
30
  from sourcecode.partial_contract import PARTIAL_EXIT_CODE
@@ -306,6 +306,47 @@ def pack_non_coverage(pack: str) -> dict[str, Any]:
306
306
  }
307
307
 
308
308
 
309
+ def assessment_components(selected: "Optional[Sequence[str]]" = None) -> list[str]:
310
+ """Return requested assessment components in declared execution order."""
311
+ declared = list(PACKS["assessment"]["commands"])
312
+ if selected is None:
313
+ return declared
314
+ requested = [name.strip() for name in selected if name and name.strip()]
315
+ if not requested:
316
+ raise ValueError("--only requires at least one assessment component")
317
+ unknown = sorted(set(requested) - set(declared))
318
+ if unknown:
319
+ raise ValueError(
320
+ "unknown assessment component(s): " + ", ".join(unknown) + ". "
321
+ "Choose from: " + ", ".join(declared)
322
+ )
323
+ if len(set(requested)) != len(requested):
324
+ raise ValueError("--only must not name an assessment component more than once")
325
+ if "audit-report" in requested and "risk" not in requested:
326
+ raise ValueError("audit-report requires risk in --only")
327
+ return [name for name in declared if name in requested]
328
+
329
+
330
+ def _assessment_non_coverage(commands: list[str]) -> dict[str, Any]:
331
+ """Add caller-selected omissions to the pack's normal coverage declaration."""
332
+ block = pack_non_coverage("assessment")
333
+ omitted = [name for name in PACKS["assessment"]["commands"] if name not in commands]
334
+ if not omitted:
335
+ return block
336
+ items = list(block.get("items") or [])
337
+ items.append({
338
+ "id": "NC-PACK-SELECTION",
339
+ "surface": "pack assessment",
340
+ "not_covered": "Assessment components omitted by --only: " + ", ".join(omitted) + ".",
341
+ "why": (
342
+ "The caller selected a bounded component subset. Silence from an omitted "
343
+ "component is not evidence about its subject."
344
+ ),
345
+ "instead": "Re-run ask pack assessment <repo> without --only, or name the component explicitly.",
346
+ })
347
+ return {**block, "items": items}
348
+
349
+
309
350
  #: What `--compact` keeps from each component, as dotted paths into that
310
351
  #: component's own payload.
311
352
  #:
@@ -772,18 +813,20 @@ def run_assessment(root: Path, *, profile: Optional[str] = None,
772
813
  deployment: Optional[list[Path]] = None,
773
814
  compact: bool = False,
774
815
  output_dir: Optional[Path] = None,
775
- progress: Optional[Callable[[int, int, str], None]] = None) -> dict[str, Any]:
816
+ progress: Optional[Callable[[int, int, str], None]] = None,
817
+ selected_components: "Optional[Sequence[str]]" = None) -> dict[str, Any]:
776
818
  """Build the assessment pack from existing analysis commands."""
777
819
  no_write = _no_write_substitution("assessment", output_dir)
778
820
  if no_write is not None:
779
821
  output_dir = None
780
- commands = ["migrate-check", "posture", "endpoints", "spring-audit", "risk"]
822
+ commands = assessment_components(selected_components)
823
+ analysis_commands = [command for command in commands if command != "audit-report"]
781
824
  results: dict[str, Any] = {}
782
825
  artifacts: dict[str, Optional[str]] = {}
783
826
  with tempfile.TemporaryDirectory(prefix="ask-assessment-") as temp:
784
827
  temp_root = Path(temp)
785
- total_components = len(commands) + 1 # the aggregate audit-report is a component too
786
- for index, command in enumerate(commands, start=1):
828
+ total_components = len(commands)
829
+ for index, command in enumerate(analysis_commands, start=1):
787
830
  if progress:
788
831
  progress(index, total_components, command)
789
832
  extra: list[str] = []
@@ -801,21 +844,22 @@ def run_assessment(root: Path, *, profile: Optional[str] = None,
801
844
  # that is not bounded by construction.
802
845
  artifacts[command] = _write_artifact(output_dir, command, _carrier(result))
803
846
 
804
- report_extra = ["--from-risk", str(temp_root / "risk.json")]
805
- if profile:
806
- report_extra.extend(["--profile", profile])
807
- if progress:
808
- progress(total_components, total_components, "audit-report")
809
- report = _run_command("audit-report", root, temp_root / "audit-report.json", report_extra)
810
- # The composed `--from-risk` path is a temporary file; what the manifest
811
- # publishes is the reproducible form, which is `risk`'s own artifact.
812
- report["invocation"] = [
813
- "ask", "audit-report", "--from-risk", "risk.json",
814
- *(["--profile", profile] if profile else []),
815
- str(root), "--format", "json",
816
- ]
817
- results["audit-report"] = report
818
- artifacts["audit-report"] = _write_artifact(output_dir, "audit-report", _carrier(report))
847
+ if "audit-report" in commands:
848
+ report_extra = ["--from-risk", str(temp_root / "risk.json")]
849
+ if profile:
850
+ report_extra.extend(["--profile", profile])
851
+ if progress:
852
+ progress(total_components, total_components, "audit-report")
853
+ report = _run_command("audit-report", root, temp_root / "audit-report.json", report_extra)
854
+ # The composed `--from-risk` path is a temporary file; what the manifest
855
+ # publishes is the reproducible form, which is `risk`'s own artifact.
856
+ report["invocation"] = [
857
+ "ask", "audit-report", "--from-risk", "risk.json",
858
+ *(["--profile", profile] if profile else []),
859
+ str(root), "--format", "json",
860
+ ]
861
+ results["audit-report"] = report
862
+ artifacts["audit-report"] = _write_artifact(output_dir, "audit-report", _carrier(report))
819
863
 
820
864
  components = _index(results, artifacts)
821
865
  failures = [name for name, item in results.items() if item["exit_code"] not in (0,)]
@@ -842,7 +886,7 @@ def run_assessment(root: Path, *, profile: Optional[str] = None,
842
886
  "exit_code": exit_code,
843
887
  "commands": list(results),
844
888
  "failures": failures,
845
- "non_coverage": pack_non_coverage("assessment"),
889
+ "non_coverage": _assessment_non_coverage(commands),
846
890
  "aggregation_rule": PACK_AGGREGATION["assessment"],
847
891
  "manifest": pack_manifest.manifest(
848
892
  pack="assessment",
@@ -853,16 +897,28 @@ def run_assessment(root: Path, *, profile: Optional[str] = None,
853
897
  inputs={"profile": profile,
854
898
  "deployment": [str(path) for path in (deployment or [])],
855
899
  "compact": compact,
900
+ "selected_components": commands,
856
901
  "output_dir": str(output_dir.resolve()) if output_dir else None},
857
902
  ),
858
903
  "artifacts": artifact_payloads,
859
904
  "intersections": build_intersections(artifact_payloads),
860
905
  "output_dir": str(output_dir.resolve()) if output_dir else None,
906
+ "selection": {
907
+ "commands": commands,
908
+ "omitted_components": [
909
+ name for name in PACKS["assessment"]["commands"] if name not in commands
910
+ ],
911
+ "basis": (
912
+ "All declared assessment components ran."
913
+ if len(commands) == len(PACKS["assessment"]["commands"])
914
+ else "The caller selected this component subset with --only."
915
+ ),
916
+ },
861
917
  **({"no_write_substitution": no_write} if no_write else {}),
862
918
  }
863
919
 
864
920
 
865
- def run_gate(root: Path, *, since: str, profile: Optional[str] = None,
921
+ def run_gate(root: Path, *, since: str, pr: Optional[int] = None, profile: Optional[str] = None,
866
922
  allow_unverified: bool = False, compact: bool = False,
867
923
  output_dir: Optional[Path] = None) -> dict[str, Any]:
868
924
  """Build one CI verdict from the existing gate-capable commands."""
@@ -891,7 +947,8 @@ def run_gate(root: Path, *, since: str, profile: Optional[str] = None,
891
947
  if profile:
892
948
  posture_extra.extend(["--profile", profile])
893
949
  results["posture"] = _run_command("posture", root, temp_root / "posture.json", posture_extra)
894
- pr_impact = _run_command("pr-impact", root, temp_root / "pr-impact.json", ["--since", since])
950
+ pr_impact_args = ["--pr", str(pr)] if pr is not None else ["--since", since]
951
+ pr_impact = _run_command("pr-impact", root, temp_root / "pr-impact.json", pr_impact_args)
895
952
  # A clean comparison is a valid no-op, not a failed safety check. The
896
953
  # standalone command refuses an empty change set; the pack can state
897
954
  # that condition explicitly because it is the workflow orchestrator.
@@ -953,6 +1010,7 @@ def run_gate(root: Path, *, since: str, profile: Optional[str] = None,
953
1010
  "pack": "gate",
954
1011
  "repository": str(root.resolve()),
955
1012
  "since": since,
1013
+ "pr": pr,
956
1014
  "profile": profile,
957
1015
  "verdict": verdict,
958
1016
  "exit_code": exit_code,
@@ -979,7 +1037,7 @@ def run_gate(root: Path, *, since: str, profile: Optional[str] = None,
979
1037
  components=components,
980
1038
  verdict=verdict,
981
1039
  exit_code=exit_code,
982
- inputs={"since": since, "profile": profile, "compact": compact,
1040
+ inputs={"since": since, "pr": pr, "profile": profile, "compact": compact,
983
1041
  "allow_unverified": allow_unverified,
984
1042
  "output_dir": str(output_dir.resolve()) if output_dir else None},
985
1043
  ),
sourcecode/readonly.py CHANGED
@@ -34,6 +34,8 @@ from __future__ import annotations
34
34
  import os
35
35
  import sys
36
36
  from pathlib import Path
37
+
38
+ from sourcecode.path_display import portable_path
37
39
  from typing import Optional
38
40
 
39
41
  #: Reads the mode for a process that was not given a flag.
@@ -197,7 +199,7 @@ def as_dict() -> dict:
197
199
  """The mode as data, for a payload that wants to state what it ran under."""
198
200
  return {
199
201
  "no_write": is_readonly(),
200
- "scope": str(_SCOPE) if _SCOPE else None,
202
+ "scope": portable_path(_SCOPE) if _SCOPE else None,
201
203
  "refused": refusals(),
202
204
  "guarantee": (
203
205
  "Nothing is created or modified inside the analysed repository. Shared caches "
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 5.8.30
3
+ Version: 5.8.31
4
4
  Summary: Persistent structural context and ultra-fast repeated analysis for AI coding agents
5
5
  Project-URL: Homepage, https://github.com/HarounDominique/sourcecode
6
6
  Project-URL: Repository, https://github.com/HarounDominique/sourcecode
@@ -59,7 +59,7 @@ Description-Content-Type: text/markdown
59
59
  > question. All analysis is local and deterministic; see [Privacy](#configuration--privacy)
60
60
  > before inspecting a repository whose telemetry policy you need to control.
61
61
 
62
- ![Version](https://img.shields.io/badge/version-5.8.30-blue)
62
+ ![Version](https://img.shields.io/badge/version-5.8.31-blue)
63
63
  ![Python](https://img.shields.io/badge/python-3.9%2B-green)
64
64
 
65
65
  Copyright (c) 2026 Dominique Haroun. All rights reserved. ASK Engine 5.7.0 and
@@ -177,7 +177,7 @@ set `ASK_MAX_RSS_MB=<megabytes>`; if the process exceeds it, ASK refuses the
177
177
  answer with `MEMORY_TOO_LARGE`, including the observed peak and limit. Leave it
178
178
  unset, or set it to `0`, to disable the ceiling explicitly.
179
179
 
180
- **Current performance status.** Release 5.8.30 retains the shared Canonical IR
180
+ **Current performance status.** Release 5.8.31 retains the shared Canonical IR
181
181
  path used by `validation` and now passes that same CIR into labelled `data-exposure`
182
182
  runs; the no-label path remains parse-free. These are implementation properties,
183
183
  not duration promises. A controlled external warm-path audit has opened performance
@@ -210,7 +210,7 @@ brew tap haroundominique/sourcecode && brew install sourcecode
210
210
  # pip / pipx
211
211
  pipx install sourcecode # or: pip install sourcecode
212
212
 
213
- ask version # ask 5.8.30 — and, on a build that has aged,
213
+ ask version # ask 5.8.31 — and, on a build that has aged,
214
214
  # how many releases have probably shipped since
215
215
  ```
216
216
 
@@ -1,6 +1,6 @@
1
- sourcecode/__init__.py,sha256=ZtJO4wGTOdXFDoPlFpOvl25Gw0oliGFJ-_kFgOT_Qr8,309
1
+ sourcecode/__init__.py,sha256=x6huFekCWuzbMyWgV9DNW6WDTwRfZV3q9UlfspK-7AY,309
2
2
  sourcecode/__main__.py,sha256=qDFVkobwsdZrX0B3stiRqsUNivVpybKO-egzAwCW4xw,165
3
- sourcecode/_build_commit.py,sha256=X3yn3fg6SQXQ5Ac9CFyu16QI9RSVRvLOe79xSYeftVw,8740
3
+ sourcecode/_build_commit.py,sha256=gOxdbVEG8QZSIEAPML8CaTzP3DaBaqHqkVEV25ceY4U,8740
4
4
  sourcecode/adaptive_scanner.py,sha256=yJBKjNpkY6bpueYJ2YnRezen3sYZDecEt7WaaNWdqug,9466
5
5
  sourcecode/analysis_budget.py,sha256=ZuNEboPF8A6GK-_V7WNt92ezgriga7_Rbr-vvSN4UEE,4183
6
6
  sourcecode/answer_bounds.py,sha256=_51_DCuYEUmI_xwUFxDMiprSavkNakkLiIBbPjevQ3M,9793
@@ -19,7 +19,7 @@ sourcecode/breaking_changes.py,sha256=iaTEkegVGnR_DEQP45U66GQKMkq-_qNM60nv7XEPm7
19
19
  sourcecode/build_modules.py,sha256=rsT8reXoeOGztX28SNwem3yGdBhAC5VJx9RL2vRp_d0,15935
20
20
  sourcecode/build_stamp.py,sha256=YWlnT8CEFzMre5pacRQkc244BfZNG5owySIyP9Dq4pw,7677
21
21
  sourcecode/bundled_docs.py,sha256=KymEkB7P8oeg0-PjcD8eRSDhqQbwQxDUbHv1i00LQOc,2663
22
- sourcecode/cache.py,sha256=z_1T0ClTbC3DaG_Fo-6_HKRUdBXHbwNoVvj8gZmQVGo,45591
22
+ sourcecode/cache.py,sha256=cCvSNJvm897M_i_nGHZYW-_T9TvXwCBnT5EYqFXkMSY,45799
23
23
  sourcecode/cache_model.py,sha256=fI5dEvK2-dA246a_-DHyq8zumBPR0rjYvyxx397SNW4,73716
24
24
  sourcecode/cache_observation.py,sha256=5E2BeqiYE5wBCbvDglkc5A9fTNhXkT_OhcDuuCqRu4Q,5622
25
25
  sourcecode/call_surface.py,sha256=fiqYfHooxN1fX9oQoysq1LS3LoZcobhyUNjAGEZKpwk,4148
@@ -31,7 +31,7 @@ sourcecode/change_plan.py,sha256=drAoDsqFplutCLc6Y0xue7sYkTls0SpYh7aOXvttv3I,129
31
31
  sourcecode/ci_output.py,sha256=X4NRokWWMRF9Ex8OQrEO2g04GzJ00GDP5zYIoqI9YCc,4625
32
32
  sourcecode/cir_graphs.py,sha256=RytqSv1WF8kdlfXj2fPQz16LY4akS2kyThbdWL8beCQ,14835
33
33
  sourcecode/classifier.py,sha256=JBzPwSSrDG-tUHAbcKB678HRbjLpD-ohzbzzO62mgpo,20114
34
- sourcecode/cli.py,sha256=PK-DWNQw58k-SYybYv9lMziIulPJeB2rQ86FZiuo8J0,867520
34
+ sourcecode/cli.py,sha256=kA6mou1cf-9nQ90E2K9oGNTFplI2BReBcTPjPUcTDVs,869605
35
35
  sourcecode/client_calls.py,sha256=YOPnfRZzRyqmdHvXSVeiunW8cuiuCuWXacNIQRgKMCw,22640
36
36
  sourcecode/code_notes_analyzer.py,sha256=EJemNCNc9Dn-1RZYu-aNbK0ELzmsyC4s6FdHi3XyNEI,9392
37
37
  sourcecode/compare.py,sha256=Lnfmm9I3k0H1jP1tV6ZJ-R7znjQPLPLCe5TzV1Jb_PM,15323
@@ -64,7 +64,7 @@ sourcecode/endpoint_literals.py,sha256=Qf4gTZzvNSFDGDuOvF0YRL9NvaYKKj24klhR5LIOa
64
64
  sourcecode/endpoint_metrics.py,sha256=sLSLUIgiIyvNdOynaxVgHd9SjRF_DbN3QxevaquykaU,2840
65
65
  sourcecode/entrypoint_classifier.py,sha256=jhTYlyqDJH2AtdEcLVaRU3lYRTJuF8DkxVzl4-W3zWE,5322
66
66
  sourcecode/env_analyzer.py,sha256=tU2CcW-Lkl__60DMd4ibYnXnxfmPbV5Z9GrToSWLdSA,22029
67
- sourcecode/envelope.py,sha256=gAvGZrH2Q1ovfDdqjuvx5gIc31zUNAJLVCHu6pMxAnI,17397
67
+ sourcecode/envelope.py,sha256=rISj4NXJZTX0scP7O01fmxl6xnCr_D_c482LkpPzVc0,17407
68
68
  sourcecode/environment_resolution.py,sha256=e86HT3RNbIIUIRChvz1Pu9Um81UvYu22BkpHNnwbUQI,30650
69
69
  sourcecode/error_schema.py,sha256=uAWEknt3Z-6pNoNaiaSVeiDHdBe-bmt08BDlkS1YaAs,2951
70
70
  sourcecode/evidence_provider.py,sha256=GSSL44JEaouO5AHks2sB3d1YvC9xIKIld1yBYxZpXxo,4277
@@ -81,18 +81,18 @@ sourcecode/functional_routes.py,sha256=KXMrDoBwj_GC80w10FvgA3zddIGE1iW9KjpDtCllS
81
81
  sourcecode/gate_anchors.py,sha256=26v8wUtzOk1K1Un5uXdUxAu20mqSPX3jo82zuM05ByE,2066
82
82
  sourcecode/git_analyzer.py,sha256=irvEwddbd5_tbA_eYUZebf4mH7_nFhpjwaWAV1f7jUY,15755
83
83
  sourcecode/git_checkout.py,sha256=gCnkMwHpU6yLyc10FoGzE8W9-tI8KyYxKTgpbWPjayo,6009
84
- sourcecode/github_diff.py,sha256=EVjSR853IoEuKUn10lDjpqw2a6r0-jM_xsxwEOS-Wzs,1399
84
+ sourcecode/github_diff.py,sha256=H1woYKuCjb6S9sofBPpMlOpn0L4LoVxuVP7ddnhsNaA,3848
85
85
  sourcecode/graph_analyzer.py,sha256=Gw2MzLp0P990TGx6D6Ie-WIPnjWVE6X6dNBQnoM9xPU,65857
86
86
  sourcecode/graph_evidence.py,sha256=rENNsYRZeNstX_ExNCLlbHJAruFQwxo5d00x6wO3xwI,15030
87
87
  sourcecode/hibernate_strat.py,sha256=kLAa5GMwYFZgOI7edl-nDcJTr4SFVYAoxtMy-fj2BsA,77954
88
88
  sourcecode/identity_fallback.py,sha256=uRC_j_80uaI4Ue4tf-OhKX4h472dmufYcjEFGSxY2jk,9190
89
89
  sourcecode/integration_coordinates.py,sha256=rvuApnS7WdRUbeQLg_oKj-Gi0koO2RKdw6HenXNgrDo,12443
90
90
  sourcecode/jdk_exports.py,sha256=fCrlwNAXUT9gge_joq6kMnY3zJxYB2pxqy-0w3o3MJI,874
91
- sourcecode/license.py,sha256=vvgE1vBUWh8ozWI7USYuteh6noxntnjuzDQIPF-l4rA,27795
91
+ sourcecode/license.py,sha256=N5EpGnX3nL2x2goZFyyCMSFKj4gfUse5nigRIuPN0Ek,28049
92
92
  sourcecode/manifest_cache.py,sha256=aPRHUs781d00fVbtlTiSaq0-AS9bAqS7_zJ0snZvlJs,2244
93
- sourcecode/mcp_nudge.py,sha256=lKemOqK_wny2u7Ymcr2Idi5Kx8pXY02jCi-_nJYLGMg,2992
93
+ sourcecode/mcp_nudge.py,sha256=beNjfyb7z09T1rnS4t6Q4qfbLzZQNaP6ddCA4XpmV0s,3256
94
94
  sourcecode/metrics_analyzer.py,sha256=gLoRWKygF18jLgwsqmGXSWopw-f5iO1VbM7Jjdif6ag,22809
95
- sourcecode/migrate_check.py,sha256=Y7q0H1Q4vS0xM8mTpdm1cJyI6wrCuRi8-u3YjcAsaxY,170803
95
+ sourcecode/migrate_check.py,sha256=BJj_nTnZ0fAIh5X_buL9SR2i5YdilQR3a2mkTgJFwJc,171075
96
96
  sourcecode/migration_apply.py,sha256=36E9IUq7RbpGVt6RZ8PlSZKgDoEMHorZrXw6UVWPnpw,8692
97
97
  sourcecode/migration_blast.py,sha256=OPryWkM6-PbvcG3eJFdcWUnlpXBje41nu2BkrZnE2hg,9359
98
98
  sourcecode/non_coverage.py,sha256=x-P6nRWc3cfUgHLUjjFWkxiyENASlksUhVHJYwd-a_8,30024
@@ -104,7 +104,7 @@ sourcecode/output_ceiling.py,sha256=rMLDHbXeC6C_uP8iQSVbbCGiJ_n0gMr2YI9zt5nltFA,
104
104
  sourcecode/output_encoding.py,sha256=OxiZQtr7uWBDUtblNQviNHsTH1Xo9AZEpsegPlQWKFk,2139
105
105
  sourcecode/output_sink.py,sha256=Eya-PnXxqc3RGulJoLhuC9LUF73SZD0aO5O2B0xAMXU,8762
106
106
  sourcecode/pack_manifest.py,sha256=Qm6et6SQsFCLc-HJ-Uhz1XlcOa77ZDHgks4JVDEENss,20820
107
- sourcecode/packs.py,sha256=BudazaJg2Xd1UwVmWYxVuf5XxsLiN05iS0yEQn94Sgk,46151
107
+ sourcecode/packs.py,sha256=y5IGuzF4LYzZl9z5WtkxjWFAmUNphDvmbHUFGkuUieE,48879
108
108
  sourcecode/parallel.py,sha256=QocwdZoUabdxzd_jEz7f6B2XMsYWFaCFaIl0tIEQs3g,10546
109
109
  sourcecode/parse_cache.py,sha256=BaPzh-KygmY4OpJQm2YGh6PWztYsj58vHWTu2eSF4s8,38769
110
110
  sourcecode/partial_contract.py,sha256=FZUBACkClvRAmPeYVjxNWeQmP6Y22KW4fPeeTfmT80A,5951
@@ -123,7 +123,7 @@ sourcecode/progress.py,sha256=naKbWFqf-eTE3vtLsi-eHYILz0p3pxCASAzMmvxUIAI,21643
123
123
  sourcecode/provenance.py,sha256=gLbsLv0gze7k7ChM4i5M3MwKfFPzs8wzM72rUd2C5sM,7342
124
124
  sourcecode/ranking_engine.py,sha256=ZAucq_YX2KkWUuAZf4P0lhtQ_38vEFnUhuGtSZd1S0E,12970
125
125
  sourcecode/readiness_timeline.py,sha256=KjghC1MWH7Tzto97TBR3N0F8FkR87w5z7lZ1QsWvAQE,8506
126
- sourcecode/readonly.py,sha256=9MdpSPC6wHSi9pRD4JrPcDfyJmgWehljiDS5u-ZTnjY,7401
126
+ sourcecode/readonly.py,sha256=8MJfg5E5gjwHN2f2qw0RM7fdzxTFeOsdGwLNKHCh-xc,7462
127
127
  sourcecode/reconciliation.py,sha256=pmqc0JNcAagKGWDcjH2rLDlKlAbfJCVUj86vV--YEXQ,35689
128
128
  sourcecode/redactor.py,sha256=SB4hwIvg8h-hvcqKcDWaZvA-aSyn-at-BIRwa0tUv5E,3227
129
129
  sourcecode/reference_facts.py,sha256=mx7H-Ax5y8sKAQHrnJCXlgjkUzqZtQTByv9Zy2lxKQQ,15500
@@ -257,13 +257,13 @@ sourcecode/telemetry/consent.py,sha256=-Wb8BFGXEexOs8M0Eja7F-T6ZtLNPeRoZnHcHvlP7
257
257
  sourcecode/telemetry/events.py,sha256=l3Z2SQUO4_C2D2ItXOOdVNimAmHedUHnUxqYFTxnsAE,2900
258
258
  sourcecode/telemetry/filters.py,sha256=-lqT2oorECuqEIdeHb--7AZ6BCaUx0bya720a-Z5x6w,7335
259
259
  sourcecode/telemetry/transport.py,sha256=4gGHsq0WeY9VywEZXA3vUxykfiYnw9uuqfjAAec7F8o,1681
260
- sourcecode/_docs/DEFECT-LEDGER.md,sha256=3xTXcOm_zn2Ty597MG3fUOSAjCgDZL3nuh_cuRY5Y4M,1108377
260
+ sourcecode/_docs/DEFECT-LEDGER.md,sha256=K5k1J1JDBBeXnB50o9KxIFnFJRHBillTJNoKoiQmLXY,1108377
261
261
  sourcecode/_docs/LICENSE,sha256=23-fk61oSWGVmkWyka-FIM0rhAPM2hcYHnsaridL8Uo,1859
262
262
  sourcecode/_docs/NOTICE,sha256=Br-AA8Y3iJo1WXa5uP8QBpzqI5nDu3iGLbFyvDt3BOs,321
263
- sourcecode/_docs/USER_GUIDE.md,sha256=91R8fih4OvBvzpZ0UvhbHek7gg0RoIZK8apLUmH9ar0,93284
264
- sourcecode-5.8.30.dist-info/METADATA,sha256=feREJq3ivFy-CBGFs8SDUAX-nlQDVEByROi2VJxqd5c,55428
265
- sourcecode-5.8.30.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
266
- sourcecode-5.8.30.dist-info/entry_points.txt,sha256=-JEAdChrK5We51kZcb7OaDcyil-dHBjBPL-NhuO-QY8,89
267
- sourcecode-5.8.30.dist-info/licenses/LICENSE,sha256=23-fk61oSWGVmkWyka-FIM0rhAPM2hcYHnsaridL8Uo,1859
268
- sourcecode-5.8.30.dist-info/licenses/NOTICE,sha256=Br-AA8Y3iJo1WXa5uP8QBpzqI5nDu3iGLbFyvDt3BOs,321
269
- sourcecode-5.8.30.dist-info/RECORD,,
263
+ sourcecode/_docs/USER_GUIDE.md,sha256=w8YGMcBHQIRLwnFzqodOZhvP5eF8pfYMtw5FyUlRpNk,93284
264
+ sourcecode-5.8.31.dist-info/METADATA,sha256=8XTeIYslvJubUEPmt2L6EObS9m9aw4BVKL6BfBDYN0w,55428
265
+ sourcecode-5.8.31.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
266
+ sourcecode-5.8.31.dist-info/entry_points.txt,sha256=-JEAdChrK5We51kZcb7OaDcyil-dHBjBPL-NhuO-QY8,89
267
+ sourcecode-5.8.31.dist-info/licenses/LICENSE,sha256=23-fk61oSWGVmkWyka-FIM0rhAPM2hcYHnsaridL8Uo,1859
268
+ sourcecode-5.8.31.dist-info/licenses/NOTICE,sha256=Br-AA8Y3iJo1WXa5uP8QBpzqI5nDu3iGLbFyvDt3BOs,321
269
+ sourcecode-5.8.31.dist-info/RECORD,,