scitex 2.16.1__py3-none-any.whl → 2.17.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.
Files changed (48) hide show
  1. scitex/_mcp_resources/_cheatsheet.py +1 -1
  2. scitex/_mcp_resources/_modules.py +1 -1
  3. scitex/_mcp_tools/__init__.py +2 -0
  4. scitex/_mcp_tools/verify.py +256 -0
  5. scitex/cli/main.py +2 -0
  6. scitex/cli/verify.py +476 -0
  7. scitex/dev/plt/__init__.py +1 -1
  8. scitex/dev/plt/mpl/get_dir_ax.py +1 -1
  9. scitex/dev/plt/mpl/get_signatures.py +1 -1
  10. scitex/dev/plt/mpl/get_signatures_details.py +1 -1
  11. scitex/io/_load.py +8 -1
  12. scitex/io/_save.py +12 -0
  13. scitex/session/README.md +2 -2
  14. scitex/session/__init__.py +1 -0
  15. scitex/session/_decorator.py +57 -33
  16. scitex/session/_lifecycle/__init__.py +23 -0
  17. scitex/session/_lifecycle/_close.py +225 -0
  18. scitex/session/_lifecycle/_config.py +112 -0
  19. scitex/session/_lifecycle/_matplotlib.py +83 -0
  20. scitex/session/_lifecycle/_start.py +246 -0
  21. scitex/session/_lifecycle/_utils.py +186 -0
  22. scitex/session/_manager.py +40 -3
  23. scitex/session/template.py +1 -1
  24. scitex/template/_templates/plt.py +1 -1
  25. scitex/template/_templates/session.py +1 -1
  26. scitex/verify/README.md +312 -0
  27. scitex/verify/__init__.py +212 -0
  28. scitex/verify/_chain.py +369 -0
  29. scitex/verify/_db.py +600 -0
  30. scitex/verify/_hash.py +187 -0
  31. scitex/verify/_integration.py +127 -0
  32. scitex/verify/_rerun.py +253 -0
  33. scitex/verify/_tracker.py +330 -0
  34. scitex/verify/_visualize.py +48 -0
  35. scitex/verify/_viz/__init__.py +56 -0
  36. scitex/verify/_viz/_colors.py +84 -0
  37. scitex/verify/_viz/_format.py +302 -0
  38. scitex/verify/_viz/_json.py +192 -0
  39. scitex/verify/_viz/_mermaid.py +440 -0
  40. scitex/verify/_viz/_plotly.py +193 -0
  41. scitex/verify/_viz/_templates.py +246 -0
  42. scitex/verify/_viz/_utils.py +56 -0
  43. {scitex-2.16.1.dist-info → scitex-2.17.0.dist-info}/METADATA +1 -1
  44. {scitex-2.16.1.dist-info → scitex-2.17.0.dist-info}/RECORD +47 -23
  45. scitex/session/_lifecycle.py +0 -827
  46. {scitex-2.16.1.dist-info → scitex-2.17.0.dist-info}/WHEEL +0 -0
  47. {scitex-2.16.1.dist-info → scitex-2.17.0.dist-info}/entry_points.txt +0 -0
  48. {scitex-2.16.1.dist-info → scitex-2.17.0.dist-info}/licenses/LICENSE +0 -0
scitex/cli/verify.py ADDED
@@ -0,0 +1,476 @@
1
+ #!/usr/bin/env python3
2
+ # Timestamp: "2026-02-01 (ywatanabe)"
3
+ # File: /home/ywatanabe/proj/scitex-python/src/scitex/cli/verify.py
4
+ """
5
+ SciTeX CLI - Verify Commands (Hash-based verification).
6
+
7
+ Provides commands for tracking and verifying reproducibility of computations.
8
+ """
9
+
10
+ import sys
11
+ from pathlib import Path
12
+
13
+ import click
14
+
15
+
16
+ @click.group(
17
+ context_settings={"help_option_names": ["-h", "--help"]},
18
+ invoke_without_command=True,
19
+ )
20
+ @click.option("--help-recursive", is_flag=True, help="Show help for all subcommands")
21
+ @click.pass_context
22
+ def verify(ctx, help_recursive):
23
+ """
24
+ Hash-based verification for reproducible science.
25
+
26
+ \b
27
+ Commands:
28
+ list List all tracked runs with verification status
29
+ run Verify a specific session run
30
+ chain Verify dependency chain for a target file
31
+ status Show changed files (like git status)
32
+ stats Show database statistics
33
+
34
+ \b
35
+ Examples:
36
+ scitex verify list # List all runs
37
+ scitex verify run 2025Y-11M-18D-09h12m03s # Verify specific run
38
+ scitex verify chain ./results/figure3.png # Trace back to source
39
+ scitex verify status # Show changes
40
+ """
41
+ if help_recursive:
42
+ _print_help_recursive(ctx)
43
+ ctx.exit(0)
44
+ elif ctx.invoked_subcommand is None:
45
+ click.echo(ctx.get_help())
46
+
47
+
48
+ def _print_help_recursive(ctx):
49
+ """Print help for all commands recursively."""
50
+ fake_parent = click.Context(click.Group(), info_name="scitex")
51
+ parent_ctx = click.Context(verify, info_name="verify", parent=fake_parent)
52
+ click.secho("━━━ scitex verify ━━━", fg="cyan", bold=True)
53
+ click.echo(verify.get_help(parent_ctx))
54
+ for name in sorted(verify.list_commands(ctx) or []):
55
+ cmd = verify.get_command(ctx, name)
56
+ if cmd is None:
57
+ continue
58
+ click.echo()
59
+ click.secho(f"━━━ scitex verify {name} ━━━", fg="cyan", bold=True)
60
+ with click.Context(cmd, info_name=name, parent=parent_ctx) as sub_ctx:
61
+ click.echo(cmd.get_help(sub_ctx))
62
+
63
+
64
+ @verify.command("list")
65
+ @click.option(
66
+ "--limit", "-n", type=int, default=50, help="Maximum number of runs to show"
67
+ )
68
+ @click.option(
69
+ "--filter-status",
70
+ "-s",
71
+ type=click.Choice(["all", "success", "failed", "running"]),
72
+ default="all",
73
+ help="Filter by run status",
74
+ )
75
+ @click.option("--no-verify", is_flag=True, help="Skip verification (faster)")
76
+ @click.option("--json", "as_json", is_flag=True, help="Output as JSON")
77
+ def list_runs(limit, filter_status, no_verify, as_json):
78
+ """
79
+ List all tracked runs with verification status.
80
+
81
+ \b
82
+ Examples:
83
+ scitex verify list # List all runs
84
+ scitex verify list -n 10 # Limit to 10 runs
85
+ scitex verify list -s success # Only successful runs
86
+ scitex verify list --no-verify # Skip verification (faster)
87
+ """
88
+ try:
89
+ from scitex.verify import format_list, get_db
90
+
91
+ db = get_db()
92
+ status_filter = None if filter_status == "all" else filter_status
93
+ runs = db.list_runs(status=status_filter, limit=limit)
94
+
95
+ if as_json:
96
+ import json
97
+
98
+ output = []
99
+ for run in runs:
100
+ output.append(
101
+ {
102
+ "session_id": run["session_id"],
103
+ "script_path": run.get("script_path"),
104
+ "status": run.get("status"),
105
+ "started_at": run.get("started_at"),
106
+ "finished_at": run.get("finished_at"),
107
+ }
108
+ )
109
+ click.echo(json.dumps(output, indent=2))
110
+ else:
111
+ if not runs:
112
+ click.echo("No tracked runs found.")
113
+ click.echo(
114
+ "\nTo start tracking, use @stx.session decorator with stx.io."
115
+ )
116
+ return
117
+
118
+ output = format_list(runs, verify=not no_verify)
119
+ click.echo(output)
120
+ click.echo(f"\nShowing {len(runs)} runs (use --limit to change)")
121
+
122
+ except Exception as e:
123
+ click.secho(f"Error: {e}", fg="red", err=True)
124
+ sys.exit(1)
125
+
126
+
127
+ @verify.command("run")
128
+ @click.argument("targets", nargs=-1, required=True)
129
+ @click.option("--rerun", is_flag=True, help="Re-execute script and compare (thorough)")
130
+ @click.option("-v", "--verbose", is_flag=True, help="Show detailed file information")
131
+ @click.option("--json", "as_json", is_flag=True, help="Output as JSON")
132
+ def verify_run_cmd(targets, rerun, verbose, as_json):
133
+ """
134
+ Verify session run(s).
135
+
136
+ TARGETS can be (one or multiple):
137
+ - A session ID: 2025Y-11M-18D-09h12m03s_HmH5
138
+ - A script path: ./script.py (latest run of this script)
139
+ - An artifact path: ./results/figure3.png (session that produced it)
140
+
141
+ \b
142
+ Examples:
143
+ scitex verify run 2025Y-11M-18D-09h12m03s_HmH5
144
+ scitex verify run ./results/figure3.png
145
+ scitex verify run ./script.py --rerun
146
+ scitex verify run file1.csv file2.csv --rerun
147
+ """
148
+ try:
149
+ from scitex.verify import format_run_verification, verify_by_rerun, verify_run
150
+
151
+ results = []
152
+ for target in targets:
153
+ if rerun:
154
+ verification = verify_by_rerun(target)
155
+ else:
156
+ verification = verify_run(target)
157
+ results.append(verification)
158
+
159
+ if as_json:
160
+ import json
161
+
162
+ output = [
163
+ {
164
+ "session_id": v.session_id,
165
+ "script_path": v.script_path,
166
+ "status": v.status.value,
167
+ "level": v.level.value,
168
+ "is_verified": v.is_verified,
169
+ }
170
+ for v in results
171
+ ]
172
+ click.echo(json.dumps(output, indent=2))
173
+ else:
174
+ all_verified = True
175
+ for v in results:
176
+ badge = "✓✓" if v.level.value == "rerun" else "✓"
177
+ if v.is_verified:
178
+ click.secho(f"{badge} {v.session_id}", fg="green")
179
+ else:
180
+ click.secho(f"✗ {v.session_id}", fg="red")
181
+ all_verified = False
182
+ if verbose:
183
+ click.echo(format_run_verification(v, verbose=True))
184
+
185
+ if not all_verified:
186
+ sys.exit(1)
187
+
188
+ except Exception as e:
189
+ click.secho(f"Error: {e}", fg="red", err=True)
190
+ sys.exit(1)
191
+
192
+
193
+ @verify.command("chain")
194
+ @click.argument("target_file", type=click.Path(exists=True))
195
+ @click.option("-v", "--verbose", is_flag=True, help="Show detailed information")
196
+ @click.option("--mermaid", is_flag=True, help="Output as Mermaid diagram")
197
+ @click.option("--json", "as_json", is_flag=True, help="Output as JSON")
198
+ def verify_chain_cmd(target_file, verbose, mermaid, as_json):
199
+ """
200
+ Verify the dependency chain for a target file.
201
+
202
+ Traces back through all sessions that contributed to producing
203
+ the target file and verifies each one.
204
+
205
+ \b
206
+ Examples:
207
+ scitex verify chain ./results/figure3.png
208
+ scitex verify chain ./results/figure3.png -v
209
+ scitex verify chain ./results/figure3.png --mermaid
210
+ """
211
+ try:
212
+ from scitex.verify import (
213
+ format_chain_verification,
214
+ generate_mermaid_dag,
215
+ verify_chain,
216
+ )
217
+
218
+ chain = verify_chain(target_file)
219
+
220
+ if mermaid:
221
+ output = generate_mermaid_dag(target_file=str(Path(target_file).resolve()))
222
+ click.echo(output)
223
+ elif as_json:
224
+ import json
225
+
226
+ output = {
227
+ "target_file": chain.target_file,
228
+ "status": chain.status.value,
229
+ "is_verified": chain.is_verified,
230
+ "runs": [
231
+ {
232
+ "session_id": r.session_id,
233
+ "script_path": r.script_path,
234
+ "status": r.status.value,
235
+ "is_verified": r.is_verified,
236
+ }
237
+ for r in chain.runs
238
+ ],
239
+ }
240
+ click.echo(json.dumps(output, indent=2))
241
+ else:
242
+ output = format_chain_verification(chain, verbose=verbose)
243
+ click.echo(output)
244
+
245
+ if chain.is_verified:
246
+ click.echo()
247
+ click.secho("✓ Chain fully verified!", fg="green")
248
+ else:
249
+ click.echo()
250
+ click.secho("✗ Chain verification failed", fg="red")
251
+ if chain.failed_runs:
252
+ click.echo(f" {len(chain.failed_runs)} run(s) have issues")
253
+ sys.exit(1)
254
+
255
+ except Exception as e:
256
+ click.secho(f"Error: {e}", fg="red", err=True)
257
+ sys.exit(1)
258
+
259
+
260
+ @verify.command("render")
261
+ @click.argument("output_path", type=click.Path())
262
+ @click.option("--session", "-s", help="Session ID to visualize")
263
+ @click.option("--file", "-f", "target_file", help="Target file to trace chain")
264
+ @click.option("--title", "-t", default="Verification DAG", help="Title for output")
265
+ @click.option("--plotly", "-p", is_flag=True, help="Use Plotly (interactive)")
266
+ def render_cmd(output_path, session, target_file, title, plotly):
267
+ """
268
+ Render verification DAG to file (HTML, PNG, SVG, or Mermaid).
269
+
270
+ The output format is determined by the file extension:
271
+ - .html: Interactive HTML (Mermaid.js or Plotly with --plotly)
272
+ - .png: PNG image
273
+ - .svg: SVG image
274
+ - .mmd: Raw Mermaid code
275
+
276
+ \b
277
+ Examples:
278
+ scitex verify render dag.html --file ./results/fig.png
279
+ scitex verify render dag.html --file ./results/fig.png --plotly
280
+ scitex verify render dag.png --session 2025Y-11M-18D-09h12m03s
281
+ """
282
+ try:
283
+ if not session and not target_file:
284
+ click.secho("Error: Specify --session or --file", fg="red", err=True)
285
+ sys.exit(1)
286
+
287
+ if plotly:
288
+ from scitex.verify import render_plotly_dag
289
+
290
+ result_path = render_plotly_dag(
291
+ output_path=output_path,
292
+ session_id=session,
293
+ target_file=target_file,
294
+ title=title,
295
+ )
296
+ else:
297
+ from scitex.verify import render_dag
298
+
299
+ result_path = render_dag(
300
+ output_path=output_path,
301
+ session_id=session,
302
+ target_file=target_file,
303
+ title=title,
304
+ )
305
+ click.secho(f"Rendered to: {result_path}", fg="green")
306
+
307
+ except Exception as e:
308
+ click.secho(f"Error: {e}", fg="red", err=True)
309
+ sys.exit(1)
310
+
311
+
312
+ @verify.command("status")
313
+ @click.option("--json", "as_json", is_flag=True, help="Output as JSON")
314
+ def status_cmd(as_json):
315
+ """
316
+ Show verification status (like git status).
317
+
318
+ Displays a summary of all tracked runs and highlights any
319
+ that have changed files (hash mismatches) or missing files.
320
+
321
+ \b
322
+ Examples:
323
+ scitex verify status
324
+ scitex verify status --json
325
+ """
326
+ try:
327
+ from scitex.verify import format_status, get_status
328
+
329
+ status = get_status()
330
+
331
+ if as_json:
332
+ import json
333
+
334
+ click.echo(json.dumps(status, indent=2))
335
+ else:
336
+ output = format_status(status)
337
+ click.echo(output)
338
+
339
+ except Exception as e:
340
+ click.secho(f"Error: {e}", fg="red", err=True)
341
+ sys.exit(1)
342
+
343
+
344
+ @verify.command("stats")
345
+ @click.option("--json", "as_json", is_flag=True, help="Output as JSON")
346
+ def stats_cmd(as_json):
347
+ """
348
+ Show database statistics.
349
+
350
+ \b
351
+ Examples:
352
+ scitex verify stats
353
+ scitex verify stats --json
354
+ """
355
+ try:
356
+ from scitex.verify import get_db
357
+
358
+ db = get_db()
359
+ db_stats = db.stats()
360
+
361
+ if as_json:
362
+ import json
363
+
364
+ click.echo(json.dumps(db_stats, indent=2))
365
+ else:
366
+ click.secho("Verification Database Statistics", fg="cyan", bold=True)
367
+ click.echo("=" * 40)
368
+ click.echo(f"Database path: {db_stats['db_path']}")
369
+ click.echo(f"Total runs: {db_stats['total_runs']}")
370
+ click.echo(f" Successful: {db_stats['success_runs']}")
371
+ click.echo(f" Failed: {db_stats['failed_runs']}")
372
+ click.echo(f"Total file records: {db_stats['total_file_records']}")
373
+ click.echo(f"Unique files tracked: {db_stats['unique_files']}")
374
+
375
+ except Exception as e:
376
+ click.secho(f"Error: {e}", fg="red", err=True)
377
+ sys.exit(1)
378
+
379
+
380
+ @verify.command("clear")
381
+ @click.option("--force", "-f", is_flag=True, help="Skip confirmation")
382
+ def clear_cmd(force):
383
+ """
384
+ Clear the verification database.
385
+
386
+ \b
387
+ Examples:
388
+ scitex verify clear
389
+ scitex verify clear -f
390
+ """
391
+ try:
392
+ from scitex.verify import get_db
393
+
394
+ db = get_db()
395
+ db_stats = db.stats()
396
+
397
+ if not force:
398
+ click.echo(f"This will delete {db_stats['total_runs']} runs and ")
399
+ click.echo(f"{db_stats['total_file_records']} file records.")
400
+ if not click.confirm("Are you sure?"):
401
+ click.echo("Cancelled.")
402
+ return
403
+
404
+ # Delete the database file
405
+ db_path = Path(db_stats["db_path"])
406
+ if db_path.exists():
407
+ db_path.unlink()
408
+ click.secho("Database cleared.", fg="green")
409
+ else:
410
+ click.echo("Database already empty.")
411
+
412
+ except Exception as e:
413
+ click.secho(f"Error: {e}", fg="red", err=True)
414
+ sys.exit(1)
415
+
416
+
417
+ @verify.group(invoke_without_command=True)
418
+ @click.pass_context
419
+ def mcp(ctx):
420
+ """
421
+ MCP (Model Context Protocol) server operations.
422
+
423
+ \b
424
+ Commands:
425
+ list-tools - List available MCP tools
426
+
427
+ \b
428
+ Examples:
429
+ scitex verify mcp list-tools
430
+ """
431
+ if ctx.invoked_subcommand is None:
432
+ click.echo(ctx.get_help())
433
+
434
+
435
+ @mcp.command("list-tools")
436
+ def list_tools():
437
+ """
438
+ List available MCP tools for verification.
439
+
440
+ \b
441
+ Example:
442
+ scitex verify mcp list-tools
443
+ """
444
+ click.secho("Verify MCP Tools", fg="cyan", bold=True)
445
+ click.echo()
446
+ tools = [
447
+ ("verify_list", "List all tracked runs with verification status"),
448
+ ("verify_run", "Verify a specific session run"),
449
+ ("verify_chain", "Verify dependency chain for a target file"),
450
+ ("verify_status", "Show verification status (like git status)"),
451
+ ("verify_stats", "Show database statistics"),
452
+ ]
453
+ for name, desc in tools:
454
+ click.echo(f" {name}: {desc}")
455
+
456
+
457
+ @verify.command("list-python-apis")
458
+ @click.option("-v", "--verbose", count=True, help="Verbosity: -v +doc, -vv full doc")
459
+ @click.option("-d", "--max-depth", type=int, default=5, help="Max recursion depth")
460
+ @click.option("--json", "as_json", is_flag=True, help="Output as JSON")
461
+ @click.pass_context
462
+ def list_python_apis(ctx, verbose, max_depth, as_json):
463
+ """List Python APIs (alias for: scitex introspect api scitex.verify)."""
464
+ from scitex.cli.introspect import api
465
+
466
+ ctx.invoke(
467
+ api,
468
+ dotted_path="scitex.verify",
469
+ verbose=verbose,
470
+ max_depth=max_depth,
471
+ as_json=as_json,
472
+ )
473
+
474
+
475
+ if __name__ == "__main__":
476
+ verify()
@@ -16,7 +16,7 @@ Usage:
16
16
  from scitex.dev.plt import PLOTTERS_STX, PLOTTERS_SNS, PLOTTERS_MPL
17
17
 
18
18
  @stx.session
19
- def main(plt=stx.INJECTED, rng=stx.INJECTED):
19
+ def main(plt=stx.INJECTED, rngg=stx.INJECTED):
20
20
  rng = rng("demo")
21
21
 
22
22
  # stx_* API (ArrayLike)
@@ -21,7 +21,7 @@ def main(
21
21
  CONFIG=stx.INJECTED,
22
22
  plt=stx.INJECTED,
23
23
  COLORS=stx.INJECTED,
24
- rng=stx.INJECTED,
24
+ rngg=stx.INJECTED,
25
25
  logger=stx.INJECTED,
26
26
  ):
27
27
  """Help message for `$ python __file__ --help`"""
@@ -146,7 +146,7 @@ def main(
146
146
  CONFIG=stx.INJECTED,
147
147
  plt=stx.INJECTED,
148
148
  COLORS=stx.INJECTED,
149
- rng=stx.INJECTED,
149
+ rngg=stx.INJECTED,
150
150
  logger=stx.INJECTED,
151
151
  ):
152
152
  """Inspect and display matplotlib plotting function signatures."""
@@ -492,7 +492,7 @@ def main(
492
492
  CONFIG=stx.INJECTED,
493
493
  plt=stx.INJECTED,
494
494
  COLORS=stx.INJECTED,
495
- rng=stx.INJECTED,
495
+ rngg=stx.INJECTED,
496
496
  logger=stx.INJECTED,
497
497
  ):
498
498
  """Extract signatures with flattened *args/**kwargs."""
scitex/io/_load.py CHANGED
@@ -286,7 +286,6 @@ def load(
286
286
  >>> # Load file without extension (e.g., UUID PDF)
287
287
  >>> pdf = load('f2694ccb-1b6f-4994-add8-5111fd4d52f1', ext='pdf')
288
288
  """
289
-
290
289
  # Don't use clean_path as it breaks relative paths like ./file.txt
291
290
  # lpath = clean_path(lpath)
292
291
 
@@ -445,6 +444,14 @@ def load(
445
444
  if verbose:
446
445
  print(f"[Cache STORED] Cached data for: {lpath}")
447
446
 
447
+ # Track input for verification (if session is active)
448
+ try:
449
+ from scitex.verify import on_io_load
450
+
451
+ on_io_load(lpath)
452
+ except Exception:
453
+ pass # Silent fail - don't interrupt load operations
454
+
448
455
  return result
449
456
  except (ValueError, FileNotFoundError) as e:
450
457
  raise ValueError(f"Error loading file {lpath}: {str(e)}")
scitex/io/_save.py CHANGED
@@ -71,6 +71,7 @@ def save(
71
71
  crop_margin_mm: float = 1.0,
72
72
  metadata_extra: dict = None,
73
73
  json_schema: str = "editable",
74
+ track: bool = True,
74
75
  **kwargs,
75
76
  ) -> None:
76
77
  """
@@ -102,6 +103,8 @@ def save(
102
103
  Additional metadata to merge with auto-collected metadata.
103
104
  json_schema : str, optional
104
105
  Schema type for JSON metadata output. Default is "editable".
106
+ track : bool, optional
107
+ If True, track this file in verification system. Default is True.
105
108
  **kwargs
106
109
  Additional keyword arguments for the underlying save function.
107
110
  """
@@ -149,6 +152,15 @@ def save(
149
152
  # Symbolic links
150
153
  _symlink(spath, spath_cwd, symlink_from_cwd, verbose)
151
154
  _symlink_to(spath_final, symlink_to, verbose)
155
+
156
+ # Track output for verification (if session is active)
157
+ try:
158
+ from scitex.verify import on_io_save
159
+
160
+ on_io_save(spath_final, track=track)
161
+ except Exception:
162
+ pass # Silent fail - don't interrupt save operations
163
+
152
164
  return Path(spath)
153
165
 
154
166
  except AssertionError:
scitex/session/README.md CHANGED
@@ -22,7 +22,7 @@ def main(
22
22
  CONFIG=scitex.INJECTED,
23
23
  plt=scitex.INJECTED,
24
24
  COLORS=scitex.INJECTED,
25
- rng=scitex.INJECTED,
25
+ rngg=scitex.INJECTED,
26
26
  ):
27
27
  """Args injected by @scitex.session decorator"""
28
28
  print(f"Session ID: {CONFIG['ID']}")
@@ -46,7 +46,7 @@ def main(
46
46
  CONFIG=scitex.INJECTED,
47
47
  plt=scitex.INJECTED,
48
48
  COLORS=scitex.INJECTED,
49
- rng=scitex.INJECTED,
49
+ rngg=scitex.INJECTED,
50
50
  ):
51
51
  """Args injected by @scitex.session decorator"""
52
52
  print(f"Session ID: {CONFIG['ID']}")
@@ -52,6 +52,7 @@ INJECTED = _InjectedSentinel()
52
52
 
53
53
 
54
54
  # Import session management functionality
55
+ # Use refactored _lifecycle subpackage (verification hooks included)
55
56
  from ._decorator import run, session
56
57
  from ._lifecycle import close, running2finished, start
57
58
  from ._manager import SessionManager