This is an automated email from the ASF dual-hosted git repository.
skrawcz pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/burr.git
The following commit(s) were added to refs/heads/main by this push:
new f61d30f5 fix: pass partition_key to child PointerModel in fork/spawn
relationships
f61d30f5 is described below
commit f61d30f5291a586f43a4c880917d2eef6e7fd054
Author: André Ahlert <[email protected]>
AuthorDate: Wed Mar 18 11:09:42 2026 -0300
fix: pass partition_key to child PointerModel in fork/spawn relationships
The _log_child_relationships function was hardcoding partition_key=None
when creating child PointerModels in children.jsonl. This caused the UI
to generate broken links for forked/spawned apps that use partition keys,
since the route includes the partition_key segment.
Closes #518
---
burr/tracking/client.py | 6 ++-
tests/tracking/test_local_tracking_client.py | 67 ++++++++++++++++++++++++++++
2 files changed, 71 insertions(+), 2 deletions(-)
diff --git a/burr/tracking/client.py b/burr/tracking/client.py
index 44919aed..5375cdb4 100644
--- a/burr/tracking/client.py
+++ b/burr/tracking/client.py
@@ -207,6 +207,7 @@ class LocalTrackingClient(
fork_parent_pointer_model: Optional[burr_types.ParentPointer],
spawn_parent_pointer_model: Optional[burr_types.ParentPointer],
app_id: str,
+ partition_key: Optional[str] = None,
):
"""Logs a child relationship. This is special as it does not log to
the main log file. Rather
it logs within the parent directory. Note this only exists to maintain
(denormalized) bidirectional
@@ -227,7 +228,7 @@ class LocalTrackingClient(
child=PointerModel(
app_id=app_id,
sequence_id=None,
- partition_key=None, # TODO -- get partition key
+ partition_key=partition_key,
),
event_time=datetime.datetime.now(),
event_type="fork",
@@ -245,7 +246,7 @@ class LocalTrackingClient(
child=PointerModel(
app_id=app_id,
sequence_id=None,
- partition_key=None, # TODO -- get partition key
+ partition_key=partition_key,
),
event_time=datetime.datetime.now(),
event_type="spawn_start",
@@ -436,6 +437,7 @@ class LocalTrackingClient(
parent_pointer,
spawning_parent_pointer,
app_id,
+ partition_key=partition_key,
)
def _append_write_line(self, model: pydantic.BaseModel):
diff --git a/tests/tracking/test_local_tracking_client.py
b/tests/tracking/test_local_tracking_client.py
index 7a8196c0..db071f96 100644
--- a/tests/tracking/test_local_tracking_client.py
+++ b/tests/tracking/test_local_tracking_client.py
@@ -242,6 +242,73 @@ def test_persister_tracks_parent(tmpdir):
assert metadata_parsed.parent_pointer.partition_key == "user123"
+def test_fork_children_have_correct_partition_key(tmpdir):
+ """Tests that children.jsonl in the parent app directory has the correct
+ partition_key for the forked child app. Regression test for #518."""
+ old_app_id = "parent_app"
+ new_app_id = "forked_app"
+ partition_key = "user123"
+ log_dir = os.path.join(tmpdir, "tracking")
+ project_name = "test_fork_children_partition_key"
+ tracking_client = LocalTrackingClient(project=project_name,
storage_dir=log_dir)
+
+ # Create the parent app first
+ parent_app: Application = (
+ ApplicationBuilder()
+ .with_actions(counter, Result("count").with_name("result"))
+ .with_transitions(
+ ("counter", "counter", expr("counter < 3")),
+ ("counter", "result", default),
+ )
+ .with_state(counter=0, break_at=-1)
+ .with_entrypoint("counter")
+ .with_identifiers(app_id=old_app_id, partition_key=partition_key)
+ .with_tracker(tracking_client)
+ .build()
+ )
+ parent_app.run(halt_after=["result"])
+
+ # Fork from the parent
+ forked_app: Application = (
+ ApplicationBuilder()
+ .with_actions(counter, Result("count").with_name("result"))
+ .with_transitions(
+ ("counter", "counter", expr("counter < 5")),
+ ("counter", "result", default),
+ )
+ .initialize_from(
+ tracking_client,
+ resume_at_next_action=True,
+ default_state={"counter": 0, "break_at": -1},
+ default_entrypoint="counter",
+ fork_from_app_id=old_app_id,
+ fork_from_partition_key=partition_key,
+ fork_from_sequence_id=2,
+ )
+ .with_identifiers(app_id=new_app_id, partition_key=partition_key)
+ .with_tracker(tracking_client)
+ .build()
+ )
+ forked_app.run(halt_after=["result"])
+
+ # Check children.jsonl in the parent app directory
+ children_path = os.path.join(
+ log_dir, project_name, old_app_id,
LocalTrackingClient.CHILDREN_FILENAME
+ )
+ assert os.path.exists(children_path), "children.jsonl should exist for the
parent app"
+
+ with open(children_path) as f:
+ children = [ChildApplicationModel.model_validate(json.loads(line)) for
line in f]
+
+ assert len(children) == 1
+ child = children[0]
+ assert child.child.app_id == new_app_id
+ assert child.child.partition_key == partition_key, (
+ f"Child partition_key should be '{partition_key}', got
'{child.child.partition_key}'"
+ )
+ assert child.event_type == "fork"
+
+
def test_multi_fork_tracking_client(tmpdir):
"""This is more of an end-to-end test. We shoudl probably break it out
into smaller tests but the local tracking client being used as a persister
is