sourcecode 5.1.0__py3-none-any.whl → 5.3.0__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.
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.1.0"
7
+ __version__ = "5.3.0"
@@ -235,6 +235,63 @@ def diff_metrics(base: ArchMetrics, head: ArchMetrics) -> dict:
235
235
  }
236
236
 
237
237
 
238
+ #: The one sentence both identical-state payloads are derived from (C3-107).
239
+ #: It is an argument, not an assumption, and it rests on a property this product
240
+ #: publishes and asserts every release: the analysis is a pure function of the
241
+ #: tree state, byte-identical across eleven field rounds and two major jumps.
242
+ IDENTICAL_STATE_BASIS = (
243
+ "The two states are one tree, and the analysis is a deterministic function of "
244
+ "the tree state, so every delta is zero without reading the tree. What is "
245
+ "*not* claimed is anything about the tree itself: the per-side totals were "
246
+ "not measured and are `null`, never 0 — pass two different states, or run "
247
+ "`ask <repo>` on one of them, to measure the repository rather than the diff."
248
+ )
249
+
250
+
251
+ def identical_state_delta() -> dict:
252
+ """The `architectural-delta-v1` payload for two states that are one state.
253
+
254
+ C3-107 closed the second build; the eleventh round measured what was left —
255
+ `delta` 24,6 s and `contract-diff` 59,9 s to conclude that a tree does not
256
+ differ from itself, from a purged cache. Building one side to diff it against
257
+ itself is a measurement of the *repository*, and this command's answer is the
258
+ *difference*: with one tree state the difference is empty by construction.
259
+
260
+ So the deltas are published as the zeroes they provably are, and every figure
261
+ that would require an analysis is `null` with the reason attached — the rule
262
+ this product applies everywhere else (an axis that was not measured is
263
+ `unknown`, never `0`).
264
+ """
265
+ empty_counts = {"base": None, "head": None, "delta": 0}
266
+ return {
267
+ "schema": ARCH_DELTA_SCHEMA,
268
+ "base_cir_hash": None,
269
+ "head_cir_hash": None,
270
+ "totals": {
271
+ "files": dict(empty_counts),
272
+ "symbols": dict(empty_counts),
273
+ "endpoints": dict(empty_counts),
274
+ "dependency_edges": dict(empty_counts),
275
+ "import_cycles": dict(empty_counts),
276
+ },
277
+ "endpoint_surface": {
278
+ "added_count": 0, "removed_count": 0, "added": [], "removed": [],
279
+ },
280
+ "fan_in_shifts": {"changed_count": 0, "shifts": []},
281
+ "import_cycle_shifts": {
282
+ "added_count": 0, "removed_count": 0, "added": [], "removed": [],
283
+ },
284
+ "blast_radius_shifts": {
285
+ "scope": "fan_in_shift_symbols", "changed_count": 0, "shifts": [],
286
+ },
287
+ "analysis": {"performed": False, "basis": IDENTICAL_STATE_BASIS},
288
+ "provenance": (
289
+ "architectural_delta (D1), identical states: no repository was read. "
290
+ + IDENTICAL_STATE_BASIS
291
+ ),
292
+ }
293
+
294
+
238
295
  def _transitive_reach(fqn: str, reverse_graph: dict, node_cap: int) -> int:
239
296
  """Size of the transitive reverse-dependency set of `fqn` (its blast radius).
240
297
 
sourcecode/cache_model.py CHANGED
@@ -141,10 +141,11 @@ REFERENCE_JAVA_FILES = 2000
141
141
  REFERENCE_MEASURED_VERSION = "3.2.2"
142
142
 
143
143
  #: The other end of the measured range, and the reason this module publishes a
144
- #: *class* rather than a projected duration (C4-19). Field evaluation #22, on
145
- #: Windows 11 / PowerShell 5.1 / pipx / Python 3.10: `spring-audit` on a
146
- #: 3 342-file repository ran **8,4 s** — the same command takes 8.8 s on the
147
- #: 2 000-file reference, for a repository 1,7× the size.
144
+ #: *class* rather than a projected duration (C4-19). Field evaluation #26, on
145
+ #: Windows 11 / PowerShell 5.1 / pipx / Python 3.10, every cache purged first:
146
+ #: `spring-audit` on a 3 342-file repository ran **31,0 s** — the same command
147
+ #: takes 8.8 s on the 2 000-file reference, for a repository 1,7× the size, and it
148
+ #: ran 8,4 s on the same subject two releases earlier.
148
149
  #:
149
150
  #: **The refusal to project stands, and this evaluation strengthened it** (C3-97).
150
151
  #: For eight releases the pair of anchors said *cost does not track file count*;
@@ -159,9 +160,11 @@ REFERENCE_MEASURED_VERSION = "3.2.2"
159
160
  #: each was measured on**, and how to run it.
160
161
  #:
161
162
  #: History of the anchor, kept because it is the measurement C3-76 exists for:
162
- #: 408 s (#13) → 2 351 s (#16, C3-72) → 8,4 s (#22, C3-97). The middle figure was
163
- #: quoted as an operational anchor for four releases after the build that produced
164
- #: it, and told operators to detach commands that finish in seconds.
163
+ #: 408 s (#13) → 2 351 s (#16, C3-72) → 8,4 s (#22, C3-97) → 31,0 s (#26, C3-110).
164
+ #: The middle figure was quoted as an operational anchor for four releases after
165
+ #: the build that produced it, and told operators to detach commands that finish in
166
+ #: seconds; the last one moved 3,7× in two releases with byte-identical payloads,
167
+ #: which is the movement the release gate exists to catch and did not.
165
168
  #:
166
169
  #: ⚠ `FIELD_ANCHOR`, `FIELD_ANCHOR_SECONDS` and `FIELD_ANCHOR_MEASURED_VERSION`
167
170
  #: are **derived from the `spring-audit` row**, below `COMMANDS`. They used to be
@@ -242,12 +245,12 @@ COMMANDS: tuple[CommandCache, ...] = (
242
245
  "71,7 s again for `--agent` on the state it had just analysed (C3-103).",
243
246
  "--compact 13.3 s cold → 0.3 s warm (cold re-measured on 3.7.0: was 19.3 s, C3-6); "
244
247
  "--agent --full --env-map --depth 20 34.7 s → 33.9 s (no gain)", analysis_class="repo-wide", cold_seconds=13.3, warm_seconds=0.3,
245
- field_seconds=72.3, field_cache_state="cold", field_measured_version="5.0.0"),
248
+ field_seconds=166.7, field_cache_state="cold", field_measured_version="5.1.0"),
246
249
  CommandCache("posture", ("cir", "parse"), "shared", False,
247
250
  "Resolves the conditional bean graph on every run, over the shared CIR a warm "
248
251
  "builds — the parse it used to repeat for itself. `--diff` compares two profile "
249
252
  "sets over that one IR, so the second side costs the resolution only.",
250
- "10.1 s → 1.6 s", analysis_class="repo-wide", cold_seconds=10.1, warm_seconds=1.6, field_seconds=8.0, field_measured_version="4.18.0"),
253
+ "10.1 s → 1.6 s", analysis_class="repo-wide", cold_seconds=10.1, warm_seconds=1.6, field_seconds=8.3, field_cache_state="mixed", field_measured_version="5.1.0"),
251
254
  CommandCache("risk", ("cir", "parse"), "shared", False,
252
255
  "Composes what the audit, impact-chain and the posture already answer, so it "
253
256
  "pays each of their costs once over the shared CIR a warm builds — one parse "
@@ -255,7 +258,7 @@ COMMANDS: tuple[CommandCache, ...] = (
255
258
  "within the run.",
256
259
  "not measured on the battery yet — the composition is bounded by the "
257
260
  "`spring-audit` + `impact-chain` costs listed here, not by new analysis",
258
- analysis_class="deep", field_seconds=73.3, field_measured_version="4.18.0"),
261
+ analysis_class="deep", field_seconds=77.2, field_cache_state="mixed", field_measured_version="5.1.0"),
259
262
  CommandCache("enrich", ("cir", "parse"), "shared", False,
260
263
  "Runs the same composition as `risk` over the repository, then joins a SARIF "
261
264
  "log to it. Reading the log is negligible; everything a warm helps with is the "
@@ -280,30 +283,31 @@ COMMANDS: tuple[CommandCache, ...] = (
280
283
  "builds. Cost scales with the number of declared types, not with the "
281
284
  "size of the label.",
282
285
  "not measured on the battery yet — one `impact-chain` traversal per "
283
- "declared seed type over a CIR the warm already paid for", analysis_class="repo-wide"),
286
+ "declared seed type over a CIR the warm already paid for", analysis_class="repo-wide",
287
+ field_seconds=28.9, field_cache_state="mixed", field_measured_version="5.1.0"),
284
288
  CommandCache("endpoints", ("ris", "parse"), "shared", False,
285
289
  "Recomputes the endpoint surface on every run, over a parse a warm has already "
286
290
  "paid for. Until 3.7.0 the extractor parsed every file itself instead of reading "
287
291
  "the shared parse cache, and a warm measurably bought it nothing (C3-6).",
288
- "3.3 s → 1.4 s (re-measured on 3.7.0; was 2.8 s → 2.9 s)", analysis_class="repo-wide", cold_seconds=3.3, warm_seconds=1.4, field_seconds=3.8, field_measured_version="4.18.0"),
292
+ "3.3 s → 1.4 s (re-measured on 3.7.0; was 2.8 s → 2.9 s)", analysis_class="repo-wide", cold_seconds=3.3, warm_seconds=1.4, field_seconds=5.6, field_cache_state="mixed", field_measured_version="5.1.0"),
289
293
  CommandCache("spring-audit", ("ris", "parse"), "shared", False,
290
294
  "Recomputes every run, but over a parse a warm has already paid for.",
291
- "8.8 s → 3.7 s", analysis_class="repo-wide", cold_seconds=8.8, warm_seconds=3.7, field_seconds=8.4, field_measured_version="4.18.0"),
295
+ "8.8 s → 3.7 s", analysis_class="repo-wide", cold_seconds=8.8, warm_seconds=3.7, field_seconds=31.0, field_cache_state="mixed", field_measured_version="5.1.0"),
292
296
  CommandCache("migrate-check", ("cir",), "none", False,
293
297
  "Computes its own inventory and shares nothing a warm builds. Only `--blast-radius` "
294
298
  "reuses the shared CIR.",
295
- "4.8 s → 4.8 s", analysis_class="repo-wide", cold_seconds=4.8, warm_seconds=4.8, field_seconds=10.2, field_measured_version="4.18.0"),
299
+ "4.8 s → 4.8 s", analysis_class="repo-wide", cold_seconds=4.8, warm_seconds=4.8, field_seconds=11.3, field_cache_state="mixed", field_measured_version="5.1.0"),
296
300
  CommandCache("impact-chain", ("cir", "parse"), "shared", False,
297
301
  "The CIR is the expensive half — this is where a warm pays most.",
298
302
  "9.9 s → 1.7 s", analysis_class="core", cold_seconds=9.9, warm_seconds=1.7,
299
- field_seconds=5.5, field_measured_version="4.18.0"),
303
+ field_seconds=16.1, field_cache_state="mixed", field_measured_version="5.1.0"),
300
304
  CommandCache("impact", ("parse",), "shared", False, "", "4.9 s → 2.8 s", analysis_class="core", cold_seconds=4.9, warm_seconds=2.8,
301
305
  field_seconds=7.7, field_measured_version="4.18.0"),
302
306
  CommandCache("pr-impact", ("parse",), "shared", False,
303
307
  "Diff-dependent: the answer itself is never stored. What it costs follows the "
304
308
  "diff, not the repository: 12,5 s on an ordinary one and 11,8 s on a diff of "
305
309
  "security configuration, measured at field scale.", analysis_class="core",
306
- field_seconds=12.5, field_measured_version="4.18.0"),
310
+ field_seconds=25.7, field_cache_state="mixed", field_measured_version="5.1.0"),
307
311
  CommandCache("verify", (), "none", False, "Runs the contracts against a fresh reading.", analysis_class="core"),
308
312
  CommandCache("verify-edit", ("parse",), "shared", True,
309
313
  "Built for the edit loop: the parse cache is what keeps an unchanged file out of the "
@@ -311,15 +315,17 @@ COMMANDS: tuple[CommandCache, ...] = (
311
315
  "yet: eval #23 measured 76,6 s on a tree with no edits, because the HEAD side is "
312
316
  "still built in a throwaway worktree instead of reusing the shared CIR (C3-102).",
313
317
  "14.6 s → 9.6 s → 5.6 s on repeat", analysis_class="repo-wide", cold_seconds=14.6, warm_seconds=9.6,
314
- field_seconds=76.6, field_cache_state="mixed", field_measured_version="5.0.0"),
318
+ field_seconds=119.5, field_cache_state="mixed", field_measured_version="5.1.0"),
315
319
  CommandCache("review-pr", ("cir",), "none", False,
316
320
  "Diff-dependent, and it reuses the CIR only if one exists. On a small diff, loading "
317
321
  "the warmed CIR costs more than the work it saves.",
318
322
  "1.1 s → 2.3 s (slower)", analysis_class="core", cold_seconds=1.1, warm_seconds=2.3),
319
323
  CommandCache("plan", ("parse",), "shared", False, "", "9.3 s → 3.8 s", analysis_class="core", cold_seconds=9.3, warm_seconds=3.8),
320
324
  CommandCache("compare", ("parse",), "shared", False, "", analysis_class="core"),
321
- CommandCache("delta", (), "none", False, "Analyses two states — two checkouts, or two refs materialised into temporary trees; neither is the tree the cache describes.", analysis_class="repo-wide"),
322
- CommandCache("contract-diff", (), "none", False, "Analyses two states (checkouts or refs); neither is the tree the cache describes.", analysis_class="repo-wide"),
325
+ CommandCache("delta", (), "none", False, "Analyses two states — two checkouts, or two refs materialised into temporary trees; neither is the tree the cache describes.", analysis_class="repo-wide",
326
+ field_seconds=24.6, field_cache_state="mixed", field_measured_version="5.1.0"),
327
+ CommandCache("contract-diff", (), "none", False, "Analyses two states (checkouts or refs); neither is the tree the cache describes.", analysis_class="repo-wide",
328
+ field_seconds=59.9, field_cache_state="mixed", field_measured_version="5.1.0"),
323
329
  CommandCache("fix-bug", ("task",), "none", True,
324
330
  "Shorthand for `prepare-context fix-bug`; caches its own answer, which a warm never runs.", analysis_class="core"),
325
331
  CommandCache("rename-class", (), "none", False, "", analysis_class="core"),
@@ -341,26 +347,28 @@ COMMANDS: tuple[CommandCache, ...] = (
341
347
  "no answer hit", analysis_class="repo-wide", cold_seconds=6.5, warm_seconds=0.3),
342
348
  CommandCache("explain", ("cir",), "shared", False, "Serves from the shared CIR a warm builds.",
343
349
  "9.8 s → 1.6 s", analysis_class="core", cold_seconds=9.8, warm_seconds=1.6,
344
- field_seconds=4.4, field_measured_version="4.18.0"),
350
+ field_seconds=6.3, field_cache_state="mixed", field_measured_version="5.1.0"),
345
351
  CommandCache("export", ("parse",), "shared", False, "", "8.8 s → 3.7 s", analysis_class="repo-wide", cold_seconds=8.8, warm_seconds=3.7),
346
352
  CommandCache("repo-ir", ("parse",), "shared", False,
347
353
  "Carried as *did not finish* from 4.10.4 until eval #23 ran it at field size in "
348
354
  "9,8 s — a run that did not finish once is not a command that cannot finish "
349
355
  "(C3-100, and the same correction `modernize` needed).",
350
356
  "5.1 s → 2.9 s", analysis_class="repo-wide", cold_seconds=5.1, warm_seconds=2.9,
351
- field_seconds=9.8, field_cache_state="mixed", field_measured_version="5.0.0"),
357
+ field_seconds=19.2, field_cache_state="mixed", field_measured_version="5.1.0"),
352
358
  CommandCache("validation", ("parse",), "shared", False, "", "11.6 s → 6.4 s", analysis_class="repo-wide", cold_seconds=11.6, warm_seconds=6.4,
353
- field_seconds=17.4, field_measured_version="4.18.0"),
359
+ field_seconds=39.5, field_cache_state="mixed", field_measured_version="5.1.0"),
354
360
  CommandCache("modernize", ("parse",), "shared", False,
355
361
  "Blocked in the session that recorded C3-53 and measured since: a run that did "
356
362
  "not finish once is not a command that cannot finish.",
357
363
  "5.2 s → 3.0 s", analysis_class="repo-wide", cold_seconds=5.2, warm_seconds=3.0,
358
- field_seconds=9.1, field_measured_version="4.18.0"),
364
+ field_seconds=17.1, field_cache_state="mixed", field_measured_version="5.1.0"),
359
365
  CommandCache("chunk-file", (), "none", False, "Reads one file; nothing to cache.", analysis_class="core"),
360
366
  CommandCache("cold-start", ("ris",), "answer", True,
361
367
  "Reads the RIS a warm rebuilds — that is all it does. Without one it answers "
362
368
  "`no_ris` instead of a snapshot.",
363
- "0.2 s either way", analysis_class="core", cold_seconds=0.2, warm_seconds=0.2),
369
+ "0.2 s either way", analysis_class="core", cold_seconds=0.2, warm_seconds=0.2,
370
+ field_seconds=0.4, field_cache_state="mixed", field_measured_version="5.1.0"),
371
+ CommandCache("timeline", (), "none", False, "Each sample is a fresh materialisation of a different commit, so nothing is shared between samples: two commits are two trees, and a cache keyed on a tree state can only ever serve one of them. The per-sample cost is measured and published in the payload.", analysis_class="ir"),
364
372
  CommandCache("trend", (), "none", False, "Reads stored baseline artifacts from disk; analyses no source, so no cache layer applies. Same command as `baseline trend`.", analysis_class="none"),
365
373
  CommandCache("baseline", ("parse",), "shared", False,
366
374
  "`capture`/`diff`/`trend` over architectural metrics. The field figure is `capture`, "
@@ -405,13 +413,15 @@ def _row(command: str) -> "CommandCache":
405
413
 
406
414
  #: The headline anchor, read off the table rather than written twice (C3-100).
407
415
  #: `spring-audit` is the command the whole series measured — 408 s (#13), 2 351 s
408
- #: (#16), 8,4 s (#22) — so it is the row the front page quotes, and quoting it
409
- #: means reading it, not copying it.
416
+ #: (#16), 8,4 s (#22), 31,0 s (#26) — so it is the row the front page quotes, and
417
+ #: quoting it means reading it, not copying it. The figure moving *up* between two
418
+ #: rounds with byte-identical payloads is the reason C3-110 exists: nothing in this
419
+ #: repository measured the direction, and the anchor is the only place it shows.
410
420
  _FIELD_ANCHOR_ROW = _row("spring-audit")
411
421
  FIELD_ANCHOR_SECONDS = _FIELD_ANCHOR_ROW.field_seconds
412
422
  FIELD_ANCHOR_MEASURED_VERSION = _FIELD_ANCHOR_ROW.field_measured_version
413
423
  FIELD_ANCHOR = (
414
- f"field evaluation #22: spring-audit on {_thousands(FIELD_ANCHOR_JAVA_FILES)} "
424
+ f"field evaluation #26: spring-audit on {_thousands(FIELD_ANCHOR_JAVA_FILES)} "
415
425
  f"Java files took {FIELD_ANCHOR_SECONDS:g} s (Windows, pipx, "
416
426
  f"{_FIELD_ANCHOR_ROW.field_cache_state} cache) against "
417
427
  f"{_FIELD_ANCHOR_ROW.cold_seconds:g} s on the "
@@ -532,6 +542,37 @@ def field_anchor_note(row: "Optional[CommandCache]") -> "Optional[str]":
532
542
  return f"on {measured_on}"
533
543
 
534
544
 
545
+ def field_anchor_currency_clause(row: "Optional[CommandCache]") -> "Optional[str]":
546
+ """The same fact as :func:`field_anchor_note`, said where it is *acted on* (C3-110).
547
+
548
+ C3-109 made every field figure carry its build, and the eleventh round confirms
549
+ the label is read and believed — and then reports the gap it does not close:
550
+ `spring-audit` publishes *"8,4 s … (4.18.0)"* while the same command measures
551
+ 31,0 s on the build the reader is running. `(on 4.18.0)` is the right label for
552
+ a **row in a table**, where the reader is comparing figures; it is not enough
553
+ on a line that tells somebody how to run something, because there the figure is
554
+ being used as advice about the build in hand.
555
+
556
+ So the same fact gets a longer form for the surfaces that advise: the build,
557
+ and the admission that nothing has re-measured it here. That admission is the
558
+ registry this product applies everywhere else (`counts_are_floor`,
559
+ `unchanged_for`, `confidence_basis`) and the one place it had not applied to
560
+ itself.
561
+
562
+ ``None`` when the figure was taken on the running build — there is nothing to
563
+ admit — or when there is no figure at all.
564
+ """
565
+ if row is None or (row.field_seconds is None and not row.field_blocked):
566
+ return None
567
+ from sourcecode import __version__
568
+
569
+ measured_on = row.field_measured_version
570
+ if measured_on == __version__:
571
+ return None
572
+ where = f"measured on {measured_on}" if measured_on else "build not recorded"
573
+ return f"{where}; this build has not been re-measured at that scale"
574
+
575
+
535
576
  def cost_sentence() -> str:
536
577
  """The one paragraph the front page says about cost, derived here (CL-21).
537
578
 
@@ -544,15 +585,38 @@ def cost_sentence() -> str:
544
585
  with. It is generated from the anchors instead, so refreshing them refreshes
545
586
  the prose.
546
587
  """
588
+ from sourcecode import __version__
589
+
547
590
  audit = next((r for r in COMMANDS if r.command == "spring-audit"), None)
548
591
  seconds = FIELD_ANCHOR_SECONDS if audit is None or audit.field_seconds is None else audit.field_seconds
592
+ # C3-110: the figure is history the moment it is published, and this sentence
593
+ # is the surface a reader budgets against. The field measured 31,0 s where this
594
+ # line said 8,4 s, and the line was not wrong — it named 4.18.0 — it just left
595
+ # the reader to notice that 4.18.0 is not the build they are running. Said
596
+ # outright, and paired with the one figure this project *can* refresh: the gate
597
+ # measurement of the build in hand, when there is one.
598
+ stale = (
599
+ ""
600
+ if FIELD_ANCHOR_MEASURED_VERSION == __version__
601
+ else f", and {__version__} has not been re-measured at that scale"
602
+ )
603
+ gate = ""
604
+ _gate_cell = gate_anchor("spring-audit")
605
+ _gate_state = gate_currency()
606
+ if _gate_cell and _gate_state.get("current"):
607
+ gate = (
608
+ f" On this build the release gate measured the same command at "
609
+ f"{_gate_cell['seconds']:g} s on a "
610
+ f"{_thousands(int(_gate_cell['java_files']))}-file repository "
611
+ f"({_gate_cell['cache_state']} cache, {_gate_cell['host_class']})."
612
+ )
549
613
  return (
550
614
  f"Cost tracks the command class and the build, not the file count: "
551
615
  f"per-symbol queries are the fast path, inventory commands scale with "
552
616
  f"files, and a repository-wide audit measured {seconds:g} s on a "
553
617
  f"{_thousands(FIELD_ANCHOR_JAVA_FILES)}-file repository "
554
- f"({FIELD_ANCHOR_MEASURED_VERSION}). `ask cache model` prints the figure "
555
- f"and the build behind it for every command; "
618
+ f"({FIELD_ANCHOR_MEASURED_VERSION}{stale}).{gate} `ask cache model` prints "
619
+ f"the figure and the build behind it for every command; "
556
620
  f"ASK_MAX_ANALYSIS_SECONDS/ASK_PROGRESS bound and narrate a run where CI "
557
621
  f"wants an explicit budget."
558
622
  )