activegraph 1.0.3__tar.gz → 1.0.4__tar.gz
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.
- {activegraph-1.0.3 → activegraph-1.0.4}/PKG-INFO +1 -1
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/__init__.py +1 -1
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/core/graph.py +27 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph.egg-info/PKG-INFO +1 -1
- {activegraph-1.0.3 → activegraph-1.0.4}/pyproject.toml +1 -1
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_graph.py +98 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_requeue_unfired.py +64 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/README.md +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/__main__.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/behaviors/__init__.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/behaviors/base.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/behaviors/decorators.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/cli/__init__.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/cli/main.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/cli/quickstart.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/core/__init__.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/core/clock.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/core/event.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/core/ids.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/core/patch.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/core/view.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/errors.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/frame.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/llm/__init__.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/llm/anthropic.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/llm/cache.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/llm/errors.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/llm/openai.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/llm/parsing.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/llm/prompt.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/llm/provider.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/llm/recorded.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/llm/types.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/observability/__init__.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/observability/logging.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/observability/metrics.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/observability/migration.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/observability/prometheus.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/observability/status.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/packs/__init__.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/packs/diligence/__init__.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/packs/diligence/behaviors.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/packs/diligence/fixtures/__init__.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/packs/diligence/fixtures/companies.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/packs/diligence/object_types.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/packs/diligence/prompts/document_researcher.md +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/packs/diligence/prompts/memo_synthesizer.md +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/packs/diligence/prompts/question_generator.md +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/packs/diligence/prompts/risk_identifier.md +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/packs/diligence/settings.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/packs/diligence/tools.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/packs/loader.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/packs/scaffold.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/policy.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/runtime/__init__.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/runtime/_live.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/runtime/behavior_graph.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/runtime/budget.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/runtime/config_errors.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/runtime/diff.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/runtime/errors.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/runtime/exec_errors.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/runtime/patterns.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/runtime/queue.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/runtime/registration_errors.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/runtime/registry.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/runtime/runtime.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/runtime/scheduler.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/runtime/view_builder.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/store/__init__.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/store/base.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/store/conformance.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/store/errors.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/store/memory.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/store/postgres.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/store/serde.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/store/sqlite.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/store/url.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/tools/__init__.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/tools/base.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/tools/cache.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/tools/context.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/tools/decorators.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/tools/errors.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/tools/graph_query.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/tools/recorded.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/tools/web_fetch.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/trace/__init__.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/trace/causal.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph/trace/printer.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph.egg-info/SOURCES.txt +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph.egg-info/dependency_links.txt +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph.egg-info/entry_points.txt +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph.egg-info/requires.txt +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/activegraph.egg-info/top_level.txt +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/setup.cfg +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_activate_after.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_causal_cross_tool.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_cli.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_clock.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_diff.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_diligence_pack.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_diligence_with_tools.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_doc_links.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_doc_site_reachable.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_errors_format.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_event.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_fork.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_ids.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_llm_anthropic.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_llm_behavior.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_llm_budget.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_llm_causal.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_llm_claim_extraction.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_llm_default_model.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_llm_determinism.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_llm_failure.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_llm_openai.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_llm_prompt.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_llm_provider_fixtures.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_llm_replay.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_llm_tool_loop.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_llm_trace.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_llm_trace_snapshot.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_llm_types.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_migration.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_observability_logging.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_observability_metrics.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_operate_example.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_pack_scaffold.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_packs.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_patch.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_pattern_matcher.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_pattern_parser.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_pattern_subscriptions.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_persistence.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_postgres_store.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_quickstart.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_quickstart_snapshot.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_replay.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_replay_trace_snapshot.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_resume_example.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_runtime.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_runtime_status.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_serde.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_store_conformance.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_store_url.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_tool_replay.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_tool_trace_snapshot.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_tools.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_trace.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_tutorial_snippets.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_v1_0_1_patches.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_v1_0_3_behavior_failed_ux.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_v1_0_3_tool_multiturn.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_version_sync.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_view.py +0 -0
- {activegraph-1.0.3 → activegraph-1.0.4}/tests/test_wheel_completeness.py +0 -0
|
@@ -181,6 +181,33 @@ class Graph:
|
|
|
181
181
|
out.append(r)
|
|
182
182
|
return out
|
|
183
183
|
|
|
184
|
+
def relations(
|
|
185
|
+
self,
|
|
186
|
+
source: Optional[str] = None,
|
|
187
|
+
target: Optional[str] = None,
|
|
188
|
+
type: Optional[str] = None,
|
|
189
|
+
) -> list[Relation]:
|
|
190
|
+
"""Return relations filtered by ``source``, ``target``, and/or ``type``.
|
|
191
|
+
|
|
192
|
+
v1.0.4 #1: the canonical filter API on ``Graph``. Decomposes the
|
|
193
|
+
v0 ``get_relations(object_id=, direction=)`` axis into separate
|
|
194
|
+
``source`` and ``target`` slots so the call reads the way users
|
|
195
|
+
already write it (matches ``docs/concepts/graph.md``). Filter
|
|
196
|
+
kwargs compose by AND; calling with no kwargs returns every
|
|
197
|
+
relation. ``Graph.get_relations(object_id=, type=, direction=)``
|
|
198
|
+
stays as a backward-compatible alias.
|
|
199
|
+
"""
|
|
200
|
+
out: list[Relation] = []
|
|
201
|
+
for r in self._relations.values():
|
|
202
|
+
if source is not None and r.source != source:
|
|
203
|
+
continue
|
|
204
|
+
if target is not None and r.target != target:
|
|
205
|
+
continue
|
|
206
|
+
if type is not None and r.type != type:
|
|
207
|
+
continue
|
|
208
|
+
out.append(r)
|
|
209
|
+
return out
|
|
210
|
+
|
|
184
211
|
def neighborhood(self, object_id: str, depth: int = 1) -> tuple[list[Object], list[Relation]]:
|
|
185
212
|
if object_id not in self._objects:
|
|
186
213
|
return ([], [])
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "activegraph"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.4"
|
|
8
8
|
description = "An event-sourced reactive graph runtime for long-running, auditable, agentic systems."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -129,6 +129,104 @@ def test_query_alias_still_works_with_positional_arg():
|
|
|
129
129
|
assert {o.type for o in g.query("claim")} == {"claim"}
|
|
130
130
|
|
|
131
131
|
|
|
132
|
+
# v1.0.4 #1: graph.relations(source=, target=, type=) as the canonical
|
|
133
|
+
# filter API, decomposing the v0 get_relations(object_id=, direction=)
|
|
134
|
+
# axis into separate source/target slots. The contract claim is the
|
|
135
|
+
# eight filter combinations enumerated in CONTRACT v1.0.4 #1; the tests
|
|
136
|
+
# anchor on each combination directly, not on equivalence to the alias.
|
|
137
|
+
# The alias-still-works check is its own test.
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def _three_node_graph():
|
|
141
|
+
g = _g()
|
|
142
|
+
a = g.add_object("task", {"k": "a"})
|
|
143
|
+
b = g.add_object("task", {"k": "b"})
|
|
144
|
+
c = g.add_object("task", {"k": "c"})
|
|
145
|
+
rel_ab_dep = g.add_relation(a.id, b.id, "depends_on")
|
|
146
|
+
rel_ac_dep = g.add_relation(a.id, c.id, "depends_on")
|
|
147
|
+
rel_bc_blk = g.add_relation(b.id, c.id, "blocks")
|
|
148
|
+
rel_ba_dep = g.add_relation(b.id, a.id, "depends_on")
|
|
149
|
+
return g, a, b, c, rel_ab_dep, rel_ac_dep, rel_bc_blk, rel_ba_dep
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def test_relations_no_kwargs_returns_every_relation():
|
|
153
|
+
# Contract row 1: (None, None, None) -> every relation.
|
|
154
|
+
g, _, _, _, *rels = _three_node_graph()
|
|
155
|
+
out = g.relations()
|
|
156
|
+
assert {r.id for r in out} == {r.id for r in rels}
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def test_relations_source_only_returns_outgoing_from_source():
|
|
160
|
+
# Contract row 2: (A, None, None) -> relations where source == A.
|
|
161
|
+
g, a, b, c, rel_ab, rel_ac, _, _ = _three_node_graph()
|
|
162
|
+
out = g.relations(source=a.id)
|
|
163
|
+
assert {r.id for r in out} == {rel_ab.id, rel_ac.id}
|
|
164
|
+
assert all(r.source == a.id for r in out)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def test_relations_target_only_returns_incoming_to_target():
|
|
168
|
+
# Contract row 3: (None, B, None) -> relations where target == B.
|
|
169
|
+
g, a, b, c, rel_ab, _, _, _ = _three_node_graph()
|
|
170
|
+
out = g.relations(target=b.id)
|
|
171
|
+
assert {r.id for r in out} == {rel_ab.id}
|
|
172
|
+
assert all(r.target == b.id for r in out)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def test_relations_source_and_target_returns_intersection():
|
|
176
|
+
# Contract row 4: (A, B, None) -> relations from A to B.
|
|
177
|
+
g, a, b, c, rel_ab, _, _, rel_ba = _three_node_graph()
|
|
178
|
+
out = g.relations(source=a.id, target=b.id)
|
|
179
|
+
assert {r.id for r in out} == {rel_ab.id}
|
|
180
|
+
# Not the reverse direction.
|
|
181
|
+
assert rel_ba.id not in {r.id for r in out}
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def test_relations_type_only_returns_every_relation_of_type():
|
|
185
|
+
# Contract row 5: (None, None, T) -> every relation of type T.
|
|
186
|
+
g, *_, rel_bc_blk, _ = _three_node_graph()
|
|
187
|
+
out = g.relations(type="blocks")
|
|
188
|
+
assert {r.id for r in out} == {rel_bc_blk.id}
|
|
189
|
+
assert all(r.type == "blocks" for r in out)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def test_relations_source_and_type_returns_outgoing_of_type():
|
|
193
|
+
# Contract row 6: (A, None, T) -> relations from A of type T.
|
|
194
|
+
g, a, _, _, rel_ab, rel_ac, _, _ = _three_node_graph()
|
|
195
|
+
out = g.relations(source=a.id, type="depends_on")
|
|
196
|
+
assert {r.id for r in out} == {rel_ab.id, rel_ac.id}
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def test_relations_target_and_type_returns_incoming_of_type():
|
|
200
|
+
# Contract row 7: (None, B, T) -> relations to B of type T.
|
|
201
|
+
g, a, b, _, rel_ab, _, _, _ = _three_node_graph()
|
|
202
|
+
out = g.relations(target=b.id, type="depends_on")
|
|
203
|
+
assert {r.id for r in out} == {rel_ab.id}
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def test_relations_source_target_and_type_most_specific():
|
|
207
|
+
# Contract row 8: (A, B, T) -> relations from A to B of type T.
|
|
208
|
+
g, a, b, _, rel_ab, _, _, rel_ba = _three_node_graph()
|
|
209
|
+
out = g.relations(source=a.id, target=b.id, type="depends_on")
|
|
210
|
+
assert {r.id for r in out} == {rel_ab.id}
|
|
211
|
+
# Different-direction same-type relation is excluded.
|
|
212
|
+
assert rel_ba.id not in {r.id for r in out}
|
|
213
|
+
# Wrong-type from A->B does not exist; sanity check empty for a wrong type.
|
|
214
|
+
assert g.relations(source=a.id, target=b.id, type="blocks") == []
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def test_get_relations_alias_still_works():
|
|
218
|
+
# Backward-compat: the v0 shape continues to work byte-identically.
|
|
219
|
+
# This is the alias relationship, not the contract claim — kept as
|
|
220
|
+
# its own test per CONTRACT v1.0.4 #1's Standing Rule §2 carve-out.
|
|
221
|
+
g, a, b, c, rel_ab, rel_ac, _, rel_ba = _three_node_graph()
|
|
222
|
+
out = g.get_relations(object_id=a.id, direction="outgoing")
|
|
223
|
+
assert {r.id for r in out} == {rel_ab.id, rel_ac.id}
|
|
224
|
+
incoming = g.get_relations(object_id=a.id, direction="incoming")
|
|
225
|
+
assert {r.id for r in incoming} == {rel_ba.id}
|
|
226
|
+
both = g.get_relations(object_id=a.id, direction="both")
|
|
227
|
+
assert {r.id for r in both} == {rel_ab.id, rel_ac.id, rel_ba.id}
|
|
228
|
+
|
|
229
|
+
|
|
132
230
|
def test_neighborhood_walks_to_depth():
|
|
133
231
|
g = _g()
|
|
134
232
|
a = g.add_object("task", {})
|
|
@@ -128,6 +128,70 @@ class TestRequeueUnfiredDoesNotFalselyRequeue:
|
|
|
128
128
|
except FileNotFoundError:
|
|
129
129
|
pass
|
|
130
130
|
|
|
131
|
+
def test_zero_subscriber_event_ids_are_absent_from_requeue_set_on_load(self):
|
|
132
|
+
"""Boundary-anchored sibling to the queue_depth assertion above.
|
|
133
|
+
|
|
134
|
+
CONTRACT v0.5 #8 names the boundary as `Runtime.load` and the
|
|
135
|
+
subject as the requeue set itself: "events with NO
|
|
136
|
+
`behavior.started` referencing them are re-queued; events that
|
|
137
|
+
any behavior started on are NOT re-queued." A zero-subscriber
|
|
138
|
+
event has no `behavior.started` referencing it but is
|
|
139
|
+
popped-and-discarded by the runtime loop — so the contract
|
|
140
|
+
carve-out is that zero-subscriber events are NOT in the
|
|
141
|
+
requeue set on load.
|
|
142
|
+
|
|
143
|
+
The sibling test above asserts `queue_depth == 0` (the
|
|
144
|
+
implementation's symptom). This test asserts directly on the
|
|
145
|
+
boundary the contract names: it identifies the zero-subscriber
|
|
146
|
+
event IDs from the saved log, reloads, and verifies those IDs
|
|
147
|
+
are absent from `rt._queue` after `_requeue_unfired` ran on
|
|
148
|
+
load. Anchors on what the contract says, not on whether the
|
|
149
|
+
post-load queue depth happens to be zero (CONTRACT v1.0.4 #4,
|
|
150
|
+
Standing Rule §2).
|
|
151
|
+
"""
|
|
152
|
+
_register_subscriber_for_goal_only()
|
|
153
|
+
with tempfile.NamedTemporaryFile(suffix=".db", delete=False) as f:
|
|
154
|
+
path = f.name
|
|
155
|
+
os.remove(path)
|
|
156
|
+
try:
|
|
157
|
+
g = Graph()
|
|
158
|
+
rt = Runtime(g, persist_to=path)
|
|
159
|
+
rt.run_goal("test_goal")
|
|
160
|
+
rt.save_state()
|
|
161
|
+
|
|
162
|
+
zero_subscriber_event_ids = {
|
|
163
|
+
e.id for e in rt.graph.events
|
|
164
|
+
if e.type == "downstream.no_subscribers"
|
|
165
|
+
}
|
|
166
|
+
assert zero_subscriber_event_ids, (
|
|
167
|
+
"Fixture is supposed to produce at least one "
|
|
168
|
+
"downstream.no_subscribers event. Without it, the "
|
|
169
|
+
"contract claim's specific subject (the zero-"
|
|
170
|
+
"subscriber carve-out) isn't being exercised."
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
_register_subscriber_for_goal_only()
|
|
174
|
+
rt2 = Runtime.load(path, run_id=rt.run_id)
|
|
175
|
+
|
|
176
|
+
requeued_event_ids = {e.id for e in rt2._queue._q} # noqa: SLF001
|
|
177
|
+
falsely_requeued = zero_subscriber_event_ids & requeued_event_ids
|
|
178
|
+
assert not falsely_requeued, (
|
|
179
|
+
f"CONTRACT v0.5 #8 carve-out: zero-subscriber events are "
|
|
180
|
+
f"popped-and-discarded with no behavior.started emitted, "
|
|
181
|
+
f"so on Runtime.load they must NOT appear in the requeue "
|
|
182
|
+
f"set. The following zero-subscriber event IDs were "
|
|
183
|
+
f"falsely requeued: {sorted(falsely_requeued)}. This is "
|
|
184
|
+
f"the v0.5 #8 boundary the contract names; failure here "
|
|
185
|
+
f"means the requeue set itself violates the contract "
|
|
186
|
+
f"regardless of what queue_depth summarizes."
|
|
187
|
+
)
|
|
188
|
+
finally:
|
|
189
|
+
for suffix in ("", "-wal", "-shm"):
|
|
190
|
+
try:
|
|
191
|
+
os.remove(path + suffix)
|
|
192
|
+
except FileNotFoundError:
|
|
193
|
+
pass
|
|
194
|
+
|
|
131
195
|
|
|
132
196
|
class TestRequeueUnfiredPreservesCrashRecovery:
|
|
133
197
|
"""The fix narrows the requeue scope to events after the last drain.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{activegraph-1.0.3 → activegraph-1.0.4}/activegraph/packs/diligence/prompts/document_researcher.md
RENAMED
|
File without changes
|
{activegraph-1.0.3 → activegraph-1.0.4}/activegraph/packs/diligence/prompts/memo_synthesizer.md
RENAMED
|
File without changes
|
{activegraph-1.0.3 → activegraph-1.0.4}/activegraph/packs/diligence/prompts/question_generator.md
RENAMED
|
File without changes
|
{activegraph-1.0.3 → activegraph-1.0.4}/activegraph/packs/diligence/prompts/risk_identifier.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|