julee 0.1.3__py3-none-any.whl → 0.1.5__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 (82) hide show
  1. julee/__init__.py +1 -1
  2. julee/api/tests/routers/test_assembly_specifications.py +2 -0
  3. julee/api/tests/routers/test_documents.py +8 -6
  4. julee/api/tests/routers/test_knowledge_service_configs.py +2 -0
  5. julee/api/tests/routers/test_knowledge_service_queries.py +2 -0
  6. julee/api/tests/routers/test_system.py +2 -0
  7. julee/api/tests/routers/test_workflows.py +2 -0
  8. julee/api/tests/test_app.py +2 -0
  9. julee/api/tests/test_dependencies.py +2 -0
  10. julee/api/tests/test_requests.py +2 -0
  11. julee/contrib/polling/__init__.py +22 -19
  12. julee/contrib/polling/apps/__init__.py +17 -0
  13. julee/contrib/polling/apps/worker/__init__.py +17 -0
  14. julee/contrib/polling/apps/worker/pipelines.py +288 -0
  15. julee/contrib/polling/domain/__init__.py +7 -9
  16. julee/contrib/polling/domain/models/__init__.py +6 -7
  17. julee/contrib/polling/domain/models/polling_config.py +18 -1
  18. julee/contrib/polling/domain/services/__init__.py +6 -5
  19. julee/contrib/polling/domain/services/poller.py +1 -1
  20. julee/contrib/polling/infrastructure/__init__.py +9 -8
  21. julee/contrib/polling/infrastructure/services/__init__.py +6 -5
  22. julee/contrib/polling/infrastructure/services/polling/__init__.py +6 -5
  23. julee/contrib/polling/infrastructure/services/polling/http/__init__.py +6 -5
  24. julee/contrib/polling/infrastructure/services/polling/http/http_poller_service.py +5 -2
  25. julee/contrib/polling/infrastructure/temporal/__init__.py +12 -12
  26. julee/contrib/polling/infrastructure/temporal/activities.py +1 -1
  27. julee/contrib/polling/infrastructure/temporal/manager.py +291 -0
  28. julee/contrib/polling/infrastructure/temporal/proxies.py +1 -1
  29. julee/contrib/polling/tests/unit/apps/worker/test_pipelines.py +580 -0
  30. julee/contrib/polling/tests/unit/infrastructure/services/polling/http/test_http_poller_service.py +40 -2
  31. julee/contrib/polling/tests/unit/infrastructure/temporal/__init__.py +7 -0
  32. julee/contrib/polling/tests/unit/infrastructure/temporal/test_manager.py +475 -0
  33. julee/docs/sphinx_hcd/__init__.py +4 -10
  34. julee/docs/sphinx_hcd/accelerators.py +277 -180
  35. julee/docs/sphinx_hcd/apps.py +78 -59
  36. julee/docs/sphinx_hcd/config.py +16 -16
  37. julee/docs/sphinx_hcd/epics.py +47 -42
  38. julee/docs/sphinx_hcd/integrations.py +53 -49
  39. julee/docs/sphinx_hcd/journeys.py +124 -110
  40. julee/docs/sphinx_hcd/personas.py +75 -53
  41. julee/docs/sphinx_hcd/stories.py +99 -71
  42. julee/docs/sphinx_hcd/utils.py +23 -18
  43. julee/domain/models/assembly/tests/test_assembly.py +2 -0
  44. julee/domain/models/assembly_specification/tests/test_assembly_specification.py +2 -0
  45. julee/domain/models/assembly_specification/tests/test_knowledge_service_query.py +2 -0
  46. julee/domain/models/custom_fields/tests/test_custom_fields.py +2 -0
  47. julee/domain/models/document/document.py +12 -21
  48. julee/domain/models/document/tests/test_document.py +16 -34
  49. julee/domain/models/policy/tests/test_document_policy_validation.py +2 -0
  50. julee/domain/models/policy/tests/test_policy.py +2 -0
  51. julee/domain/use_cases/extract_assemble_data.py +1 -1
  52. julee/domain/use_cases/initialize_system_data.py +75 -21
  53. julee/domain/use_cases/tests/test_extract_assemble_data.py +2 -0
  54. julee/domain/use_cases/tests/test_initialize_system_data.py +2 -0
  55. julee/domain/use_cases/tests/test_validate_document.py +2 -0
  56. julee/fixtures/documents.yaml +4 -43
  57. julee/fixtures/knowledge_service_queries.yaml +9 -0
  58. julee/maintenance/release.py +90 -30
  59. julee/repositories/memory/document.py +19 -13
  60. julee/repositories/memory/tests/test_document.py +20 -18
  61. julee/repositories/memory/tests/test_document_policy_validation.py +2 -0
  62. julee/repositories/memory/tests/test_policy.py +2 -0
  63. julee/repositories/minio/document.py +25 -22
  64. julee/repositories/minio/tests/test_assembly.py +2 -0
  65. julee/repositories/minio/tests/test_assembly_specification.py +2 -0
  66. julee/repositories/minio/tests/test_client_protocol.py +3 -0
  67. julee/repositories/minio/tests/test_document.py +18 -16
  68. julee/repositories/minio/tests/test_document_policy_validation.py +2 -0
  69. julee/repositories/minio/tests/test_knowledge_service_config.py +2 -0
  70. julee/repositories/minio/tests/test_knowledge_service_query.py +2 -0
  71. julee/repositories/minio/tests/test_policy.py +2 -0
  72. julee/services/knowledge_service/anthropic/tests/test_knowledge_service.py +2 -0
  73. julee/services/knowledge_service/memory/test_knowledge_service.py +2 -0
  74. julee/services/knowledge_service/test_factory.py +2 -0
  75. julee/util/tests/test_decorators.py +2 -0
  76. julee-0.1.5.dist-info/METADATA +103 -0
  77. {julee-0.1.3.dist-info → julee-0.1.5.dist-info}/RECORD +80 -74
  78. julee/fixtures/assembly_specifications.yaml +0 -70
  79. julee-0.1.3.dist-info/METADATA +0 -198
  80. {julee-0.1.3.dist-info → julee-0.1.5.dist-info}/WHEEL +0 -0
  81. {julee-0.1.3.dist-info → julee-0.1.5.dist-info}/licenses/LICENSE +0 -0
  82. {julee-0.1.3.dist-info → julee-0.1.5.dist-info}/top_level.txt +0 -0
@@ -14,28 +14,33 @@ Provides directives:
14
14
  - journeys-for-persona: List journeys for a specific persona
15
15
  """
16
16
 
17
- import re
18
17
  from docutils import nodes
19
18
  from docutils.parsers.rst import directives
20
- from sphinx.util.docutils import SphinxDirective
21
19
  from sphinx.util import logging
20
+ from sphinx.util.docutils import SphinxDirective
22
21
 
23
22
  from .config import get_config
24
- from .utils import normalize_name, slugify, path_to_root, parse_list_option, parse_csv_option
23
+ from .utils import (
24
+ normalize_name,
25
+ parse_csv_option,
26
+ parse_list_option,
27
+ path_to_root,
28
+ slugify,
29
+ )
25
30
 
26
31
  logger = logging.getLogger(__name__)
27
32
 
28
33
 
29
34
  def get_journey_registry(env):
30
35
  """Get or create the journey registry on the environment."""
31
- if not hasattr(env, 'journey_registry'):
36
+ if not hasattr(env, "journey_registry"):
32
37
  env.journey_registry = {}
33
38
  return env.journey_registry
34
39
 
35
40
 
36
41
  def get_current_journey(env):
37
42
  """Get or create the current journey tracker on the environment."""
38
- if not hasattr(env, 'journey_current'):
43
+ if not hasattr(env, "journey_current"):
39
44
  env.journey_current = {}
40
45
  return env.journey_current
41
46
 
@@ -89,12 +94,12 @@ class DefineJourneyDirective(SphinxDirective):
89
94
  required_arguments = 1 # journey slug
90
95
  has_content = True
91
96
  option_spec = {
92
- 'persona': directives.unchanged_required,
93
- 'intent': directives.unchanged,
94
- 'outcome': directives.unchanged,
95
- 'depends-on': directives.unchanged,
96
- 'preconditions': directives.unchanged,
97
- 'postconditions': directives.unchanged,
97
+ "persona": directives.unchanged_required,
98
+ "intent": directives.unchanged,
99
+ "outcome": directives.unchanged,
100
+ "depends-on": directives.unchanged,
101
+ "preconditions": directives.unchanged,
102
+ "postconditions": directives.unchanged,
98
103
  }
99
104
 
100
105
  def run(self):
@@ -105,32 +110,32 @@ class DefineJourneyDirective(SphinxDirective):
105
110
  docname = self.env.docname
106
111
 
107
112
  # Parse options
108
- persona = self.options.get('persona', '').strip()
109
- intent = self.options.get('intent', '').strip()
110
- outcome = self.options.get('outcome', '').strip()
111
- depends_on = parse_csv_option(self.options.get('depends-on', ''))
112
- preconditions = parse_list_option(self.options.get('preconditions', ''))
113
- postconditions = parse_list_option(self.options.get('postconditions', ''))
113
+ persona = self.options.get("persona", "").strip()
114
+ intent = self.options.get("intent", "").strip()
115
+ outcome = self.options.get("outcome", "").strip()
116
+ depends_on = parse_csv_option(self.options.get("depends-on", ""))
117
+ preconditions = parse_list_option(self.options.get("preconditions", ""))
118
+ postconditions = parse_list_option(self.options.get("postconditions", ""))
114
119
 
115
120
  # Goal is the directive content (what they do)
116
- goal = '\n'.join(self.content).strip()
121
+ goal = "\n".join(self.content).strip()
117
122
 
118
123
  # Register the journey in environment
119
124
  journey_registry = get_journey_registry(self.env)
120
125
  current_journey = get_current_journey(self.env)
121
126
 
122
127
  journey_data = {
123
- 'slug': journey_slug,
124
- 'persona': persona,
125
- 'persona_normalized': normalize_name(persona),
126
- 'intent': intent,
127
- 'outcome': outcome,
128
- 'goal': goal,
129
- 'depends_on': depends_on,
130
- 'preconditions': preconditions,
131
- 'postconditions': postconditions,
132
- 'steps': [], # Will be populated by step-story/step-epic/step-phase
133
- 'docname': docname,
128
+ "slug": journey_slug,
129
+ "persona": persona,
130
+ "persona_normalized": normalize_name(persona),
131
+ "intent": intent,
132
+ "outcome": outcome,
133
+ "goal": goal,
134
+ "depends_on": depends_on,
135
+ "preconditions": preconditions,
136
+ "postconditions": postconditions,
137
+ "steps": [], # Will be populated by step-story/step-epic/step-phase
138
+ "docname": docname,
134
139
  }
135
140
  journey_registry[journey_slug] = journey_data
136
141
  current_journey[docname] = journey_slug
@@ -151,7 +156,9 @@ class DefineJourneyDirective(SphinxDirective):
151
156
  intro_para += nodes.Text("The ")
152
157
 
153
158
  persona_slug = slugify(persona)
154
- persona_path = f"{prefix}{config.get_doc_path('personas')}/{persona_slug}.html"
159
+ persona_path = (
160
+ f"{prefix}{config.get_doc_path('personas')}/{persona_slug}.html"
161
+ )
155
162
  persona_valid = normalize_name(persona) in _known_personas
156
163
 
157
164
  if persona_valid:
@@ -181,7 +188,9 @@ class DefineJourneyDirective(SphinxDirective):
181
188
  intro_para += nodes.Text("The goal of the ")
182
189
 
183
190
  persona_slug = slugify(persona)
184
- persona_path = f"{prefix}{config.get_doc_path('personas')}/{persona_slug}.html"
191
+ persona_path = (
192
+ f"{prefix}{config.get_doc_path('personas')}/{persona_slug}.html"
193
+ )
185
194
  persona_valid = normalize_name(persona) in _known_personas
186
195
 
187
196
  if persona_valid:
@@ -203,8 +212,8 @@ class DefineJourneyDirective(SphinxDirective):
203
212
 
204
213
  # Add a placeholder for steps (will be filled in doctree-resolved)
205
214
  steps_placeholder = nodes.container()
206
- steps_placeholder['classes'].append('journey-steps-placeholder')
207
- steps_placeholder['journey_slug'] = journey_slug
215
+ steps_placeholder["classes"].append("journey-steps-placeholder")
216
+ steps_placeholder["journey_slug"] = journey_slug
208
217
  result_nodes.append(steps_placeholder)
209
218
 
210
219
  return result_nodes
@@ -231,10 +240,12 @@ class StepStoryDirective(SphinxDirective):
231
240
 
232
241
  journey_slug = current_journey.get(docname)
233
242
  if journey_slug and journey_slug in journey_registry:
234
- journey_registry[journey_slug]['steps'].append({
235
- 'type': 'story',
236
- 'ref': story_title,
237
- })
243
+ journey_registry[journey_slug]["steps"].append(
244
+ {
245
+ "type": "story",
246
+ "ref": story_title,
247
+ }
248
+ )
238
249
 
239
250
  # Return empty - rendering happens in doctree-resolved
240
251
  return []
@@ -260,10 +271,12 @@ class StepEpicDirective(SphinxDirective):
260
271
 
261
272
  journey_slug = current_journey.get(docname)
262
273
  if journey_slug and journey_slug in journey_registry:
263
- journey_registry[journey_slug]['steps'].append({
264
- 'type': 'epic',
265
- 'ref': epic_slug,
266
- })
274
+ journey_registry[journey_slug]["steps"].append(
275
+ {
276
+ "type": "epic",
277
+ "ref": epic_slug,
278
+ }
279
+ )
267
280
 
268
281
  # Return empty - rendering happens in doctree-resolved
269
282
  return []
@@ -286,7 +299,7 @@ class StepPhaseDirective(SphinxDirective):
286
299
  def run(self):
287
300
  phase_title = self.arguments[0]
288
301
  docname = self.env.docname
289
- description = '\n'.join(self.content).strip()
302
+ description = "\n".join(self.content).strip()
290
303
 
291
304
  # Add to current journey's steps
292
305
  journey_registry = get_journey_registry(self.env)
@@ -294,11 +307,13 @@ class StepPhaseDirective(SphinxDirective):
294
307
 
295
308
  journey_slug = current_journey.get(docname)
296
309
  if journey_slug and journey_slug in journey_registry:
297
- journey_registry[journey_slug]['steps'].append({
298
- 'type': 'phase',
299
- 'ref': phase_title,
300
- 'description': description,
301
- })
310
+ journey_registry[journey_slug]["steps"].append(
311
+ {
312
+ "type": "phase",
313
+ "ref": phase_title,
314
+ "description": description,
315
+ }
316
+ )
302
317
 
303
318
  # Return empty - rendering happens in doctree-resolved
304
319
  return []
@@ -320,8 +335,6 @@ class JourneyIndexDirective(SphinxDirective):
320
335
  para += nodes.emphasis(text="No journeys defined")
321
336
  return [para]
322
337
 
323
- docname = self.env.docname
324
-
325
338
  result_nodes = []
326
339
  bullet_list = nodes.bullet_list()
327
340
 
@@ -338,13 +351,13 @@ class JourneyIndexDirective(SphinxDirective):
338
351
  para += journey_ref
339
352
 
340
353
  # Persona in parentheses
341
- if journey['persona']:
354
+ if journey["persona"]:
342
355
  para += nodes.Text(f" ({journey['persona']})")
343
356
 
344
357
  item += para
345
358
 
346
359
  # Intent as sub-paragraph (preferred), fall back to goal
347
- display_text = journey.get('intent') or journey.get('goal', '')
360
+ display_text = journey.get("intent") or journey.get("goal", "")
348
361
  if display_text:
349
362
  desc_para = nodes.paragraph()
350
363
  # Truncate if too long
@@ -361,6 +374,7 @@ class JourneyIndexDirective(SphinxDirective):
361
374
 
362
375
  class JourneyDependencyGraphPlaceholder(nodes.General, nodes.Element):
363
376
  """Placeholder node for journey dependency graph, replaced at doctree-resolved."""
377
+
364
378
  pass
365
379
 
366
380
 
@@ -401,13 +415,13 @@ def build_dependency_graph_node(env):
401
415
  # Add all journeys as components
402
416
  for slug in sorted(journey_registry.keys()):
403
417
  title = slug.replace("-", " ").title()
404
- lines.append(f'[{title}] as {slug.replace("-", "_")}')
418
+ lines.append(f"[{title}] as {slug.replace('-', '_')}")
405
419
 
406
420
  lines.append("")
407
421
 
408
422
  # Add dependency arrows (A depends on B => A --> B)
409
423
  for slug, journey in sorted(journey_registry.items()):
410
- for dep in journey['depends_on']:
424
+ for dep in journey["depends_on"]:
411
425
  if dep in journey_registry:
412
426
  from_id = slug.replace("-", "_")
413
427
  to_id = dep.replace("-", "_")
@@ -420,9 +434,9 @@ def build_dependency_graph_node(env):
420
434
 
421
435
  # Use the sphinxcontrib.plantuml extension's node type
422
436
  puml_node = plantuml(puml_content)
423
- puml_node['uml'] = puml_content
424
- puml_node['incdir'] = ''
425
- puml_node['filename'] = 'journey-dependency-graph'
437
+ puml_node["uml"] = puml_content
438
+ puml_node["incdir"] = ""
439
+ puml_node["filename"] = "journey-dependency-graph"
426
440
 
427
441
  return puml_node
428
442
 
@@ -460,25 +474,32 @@ class JourneysForPersonaDirective(SphinxDirective):
460
474
  journey_registry = get_journey_registry(self.env)
461
475
 
462
476
  # Find journeys for this persona
463
- journeys = [j for j in journey_registry.values()
464
- if j['persona_normalized'] == persona_normalized]
477
+ journeys = [
478
+ j
479
+ for j in journey_registry.values()
480
+ if j["persona_normalized"] == persona_normalized
481
+ ]
465
482
 
466
483
  if not journeys:
467
484
  para = nodes.paragraph()
468
- para += nodes.emphasis(text=f"No journeys found for persona '{persona_arg}'")
485
+ para += nodes.emphasis(
486
+ text=f"No journeys found for persona '{persona_arg}'"
487
+ )
469
488
  return [para]
470
489
 
471
490
  prefix = path_to_root(docname)
472
491
 
473
492
  bullet_list = nodes.bullet_list()
474
493
 
475
- for journey in sorted(journeys, key=lambda j: j['slug']):
494
+ for journey in sorted(journeys, key=lambda j: j["slug"]):
476
495
  item = nodes.list_item()
477
496
  para = nodes.paragraph()
478
497
 
479
- journey_path = f"{prefix}{config.get_doc_path('journeys')}/{journey['slug']}.html"
498
+ journey_path = (
499
+ f"{prefix}{config.get_doc_path('journeys')}/{journey['slug']}.html"
500
+ )
480
501
  journey_ref = nodes.reference("", "", refuri=journey_path)
481
- journey_ref += nodes.Text(journey['slug'].replace("-", " ").title())
502
+ journey_ref += nodes.Text(journey["slug"].replace("-", " ").title())
482
503
  para += journey_ref
483
504
 
484
505
  item += para
@@ -496,8 +517,9 @@ def clear_journey_state(app, env, docname):
496
517
  del current_journey[docname]
497
518
 
498
519
  # Remove journeys defined in this document
499
- to_remove = [slug for slug, j in journey_registry.items()
500
- if j['docname'] == docname]
520
+ to_remove = [
521
+ slug for slug, j in journey_registry.items() if j["docname"] == docname
522
+ ]
501
523
  for slug in to_remove:
502
524
  del journey_registry[slug]
503
525
 
@@ -510,26 +532,26 @@ def validate_journeys(app, env):
510
532
  _story_registry = stories.get_story_registry()
511
533
  _known_personas = stories.get_known_personas()
512
534
 
513
- story_titles = {normalize_name(s['feature']) for s in _story_registry}
535
+ story_titles = {normalize_name(s["feature"]) for s in _story_registry}
514
536
 
515
537
  for slug, journey in journey_registry.items():
516
538
  # Validate persona
517
- if journey['persona'] and journey['persona_normalized'] not in _known_personas:
539
+ if journey["persona"] and journey["persona_normalized"] not in _known_personas:
518
540
  logger.warning(
519
541
  f"Journey '{slug}' references unknown persona: '{journey['persona']}'"
520
542
  )
521
543
 
522
544
  # Validate depends-on journeys
523
- for dep in journey['depends_on']:
545
+ for dep in journey["depends_on"]:
524
546
  if dep not in journey_registry:
525
547
  logger.warning(
526
548
  f"Journey '{slug}' references unknown dependency: '{dep}'"
527
549
  )
528
550
 
529
551
  # Validate story steps
530
- for step in journey['steps']:
531
- if step['type'] == 'story':
532
- if normalize_name(step['ref']) not in story_titles:
552
+ for step in journey["steps"]:
553
+ if step["type"] == "story":
554
+ if normalize_name(step["ref"]) not in story_titles:
533
555
  logger.warning(
534
556
  f"Journey '{slug}' references unknown story: '{step['ref']}'"
535
557
  )
@@ -594,7 +616,7 @@ def build_epic_node(epic_slug: str, docname: str):
594
616
 
595
617
  def render_journey_steps(journey: dict, docname: str):
596
618
  """Render journey steps as a numbered list with phases grouping stories."""
597
- steps = journey['steps']
619
+ steps = journey["steps"]
598
620
  if not steps:
599
621
  return None
600
622
 
@@ -603,50 +625,46 @@ def render_journey_steps(journey: dict, docname: str):
603
625
  current_phase = None
604
626
 
605
627
  for step in steps:
606
- if step['type'] == 'phase':
628
+ if step["type"] == "phase":
607
629
  # Start a new phase
608
630
  current_phase = {
609
- 'title': step['ref'],
610
- 'description': step.get('description', ''),
611
- 'items': []
631
+ "title": step["ref"],
632
+ "description": step.get("description", ""),
633
+ "items": [],
612
634
  }
613
635
  phases.append(current_phase)
614
- elif step['type'] in ('story', 'epic'):
636
+ elif step["type"] in ("story", "epic"):
615
637
  if current_phase is None:
616
638
  # Stories before any phase - create implicit phase
617
- current_phase = {
618
- 'title': None,
619
- 'description': '',
620
- 'items': []
621
- }
639
+ current_phase = {"title": None, "description": "", "items": []}
622
640
  phases.append(current_phase)
623
- current_phase['items'].append(step)
641
+ current_phase["items"].append(step)
624
642
 
625
643
  # Build enumerated list
626
644
  enum_list = nodes.enumerated_list()
627
- enum_list['enumtype'] = 'arabic'
645
+ enum_list["enumtype"] = "arabic"
628
646
 
629
647
  for phase in phases:
630
648
  list_item = nodes.list_item()
631
649
 
632
650
  # Phase header paragraph: "Title — Description" or just items if no title
633
- if phase['title']:
651
+ if phase["title"]:
634
652
  header_para = nodes.paragraph()
635
- header_para += nodes.strong(text=phase['title'])
636
- if phase['description']:
653
+ header_para += nodes.strong(text=phase["title"])
654
+ if phase["description"]:
637
655
  header_para += nodes.Text(" — ")
638
- header_para += nodes.Text(phase['description'])
656
+ header_para += nodes.Text(phase["description"])
639
657
  list_item += header_para
640
658
 
641
659
  # Nested bullet list for stories/epics
642
- if phase['items']:
660
+ if phase["items"]:
643
661
  bullet_list = nodes.bullet_list()
644
- for item in phase['items']:
662
+ for item in phase["items"]:
645
663
  bullet_item = nodes.list_item()
646
- if item['type'] == 'story':
647
- bullet_item += build_story_node(item['ref'], docname)
648
- elif item['type'] == 'epic':
649
- bullet_item += build_epic_node(item['ref'], docname)
664
+ if item["type"] == "story":
665
+ bullet_item += build_story_node(item["ref"], docname)
666
+ elif item["type"] == "epic":
667
+ bullet_item += build_epic_node(item["ref"], docname)
650
668
  bullet_list += bullet_item
651
669
  list_item += bullet_list
652
670
 
@@ -655,14 +673,15 @@ def render_journey_steps(journey: dict, docname: str):
655
673
  return enum_list
656
674
 
657
675
 
658
- def make_labelled_list(term: str, items: list, env, docname: str = None, item_type: str = 'text'):
676
+ def make_labelled_list(
677
+ term: str, items: list, env, docname: str = None, item_type: str = "text"
678
+ ):
659
679
  """Create a labelled bullet list with term as heading.
660
680
 
661
681
  Uses 'simple' class on bullet list for compact vertical spacing.
662
682
 
663
683
  item_type can be 'text' (plain text) or 'journey' (journey links).
664
684
  """
665
- config = get_config()
666
685
  journey_registry = get_journey_registry(env)
667
686
  container = nodes.container()
668
687
 
@@ -679,7 +698,7 @@ def make_labelled_list(term: str, items: list, env, docname: str = None, item_ty
679
698
  # Use inline container for content to avoid paragraph gaps
680
699
  inline = nodes.inline()
681
700
 
682
- if item_type == 'journey':
701
+ if item_type == "journey":
683
702
  related_slug = item
684
703
  related_path = f"{related_slug}.html"
685
704
  if related_slug in journey_registry:
@@ -719,7 +738,7 @@ def process_journey_steps(app, doctree):
719
738
 
720
739
  # Find and replace the steps placeholder
721
740
  for node in doctree.traverse(nodes.container):
722
- if 'journey-steps-placeholder' in node.get('classes', []):
741
+ if "journey-steps-placeholder" in node.get("classes", []):
723
742
  steps_node = render_journey_steps(journey, docname)
724
743
  if steps_node:
725
744
  node.replace_self(steps_node)
@@ -728,31 +747,26 @@ def process_journey_steps(app, doctree):
728
747
  break
729
748
 
730
749
  # Add preconditions if present (after steps)
731
- if journey['preconditions']:
732
- doctree += make_labelled_list(
733
- "Preconditions", journey['preconditions'], env
734
- )
750
+ if journey["preconditions"]:
751
+ doctree += make_labelled_list("Preconditions", journey["preconditions"], env)
735
752
 
736
753
  # Add postconditions if present
737
- if journey['postconditions']:
738
- doctree += make_labelled_list(
739
- "Postconditions", journey['postconditions'], env
740
- )
754
+ if journey["postconditions"]:
755
+ doctree += make_labelled_list("Postconditions", journey["postconditions"], env)
741
756
 
742
757
  # Add depends-on journeys if present
743
- if journey['depends_on']:
758
+ if journey["depends_on"]:
744
759
  doctree += make_labelled_list(
745
- "Depends On", journey['depends_on'], env, docname, item_type='journey'
760
+ "Depends On", journey["depends_on"], env, docname, item_type="journey"
746
761
  )
747
762
 
748
763
  # Add depended-on-by journeys (inferred from other journeys' depends_on)
749
764
  depended_on_by = [
750
- j['slug'] for j in journey_registry.values()
751
- if journey_slug in j['depends_on']
765
+ j["slug"] for j in journey_registry.values() if journey_slug in j["depends_on"]
752
766
  ]
753
767
  if depended_on_by:
754
768
  doctree += make_labelled_list(
755
- "Depended On By", sorted(depended_on_by), env, docname, item_type='journey'
769
+ "Depended On By", sorted(depended_on_by), env, docname, item_type="journey"
756
770
  )
757
771
 
758
772