Skip to content

Commit 583b469

Browse files
colombodColombo D
andauthored
fix(tests): make dtu tool-composition test portable and collection-safe (#30)
tests/dtu/test_tool_delegate_composition.py hardcoded an absolute, root-owned path /root/.amplifier/cache/amplifier-bundle-context-intelligence-ecd41f3e6fa67bd2 and executed its validation logic (including sys.exit(1)) at MODULE/import level. On any machine that isn't that exact DTU container, this raised PermissionError during pytest collection and aborted the ENTIRE tests/ collection. Fix: resolve the bundle root relative to the test file (Path(__file__).resolve().parents[2]) — the agent/mode files under test are shipped in this repo — and move the logic into a proper def test_tool_delegate_composition() function that asserts instead of sys.exit. Kept an if __name__ == "__main__" runner so it still works as a standalone DTU script. No behavioral change to the 14 checks. Co-authored-by: Colombo D <colombod@github.com>
1 parent a9ce2a8 commit 583b469

1 file changed

Lines changed: 165 additions & 158 deletions

File tree

tests/dtu/test_tool_delegate_composition.py

Lines changed: 165 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -30,175 +30,182 @@
3030
cannot load context-intelligence-tool-design / eval-design skills
3131
"""
3232

33-
import sys
3433
import yaml
3534
from pathlib import Path
3635

3736
PASS = "\033[32mPASS\033[0m"
3837
FAIL = "\033[31mFAIL\033[0m"
39-
failures = []
4038

39+
# Resolve the bundle root relative to this test file so the checks work in a
40+
# normal checkout, in CI, and inside a DTU container alike. The previous
41+
# implementation hardcoded an absolute, root-owned cache path
42+
# (/root/.amplifier/cache/...), which broke pytest collection on every other
43+
# machine and froze a specific cache hash. The agent/mode files under test are
44+
# shipped in this repo, so the repo root is the correct, portable source.
45+
BUNDLE_ROOT = Path(__file__).resolve().parents[2]
4146

42-
def check(label, condition, detail=""):
43-
if condition:
44-
print(f" {PASS} {label}")
45-
else:
46-
print(f" {FAIL} {label}" + (f"\n detail: {detail}" if detail else ""))
47-
failures.append(label)
4847

48+
def _load_frontmatter(rel_path):
49+
text = (BUNDLE_ROOT / rel_path).read_text()
50+
parts = text.split("---", 2)
51+
return yaml.safe_load(parts[1]), parts[2]
4952

50-
cache = Path("/root/.amplifier/cache/amplifier-bundle-context-intelligence-ecd41f3e6fa67bd2")
5153

54+
def test_tool_delegate_composition():
55+
failures = []
5256

53-
def load_frontmatter(rel_path):
54-
text = (cache / rel_path).read_text()
55-
parts = text.split("---", 2)
56-
return yaml.safe_load(parts[1]), parts[2]
57+
def check(label, condition, detail=""):
58+
if condition:
59+
print(f" {PASS} {label}")
60+
else:
61+
print(f" {FAIL} {label}" + (f"\n detail: {detail}" if detail else ""))
62+
failures.append(label)
63+
64+
facilitator_fm, _ = _load_frontmatter("agents/context-intelligence-design-facilitator.md")
65+
designer_fm, _ = _load_frontmatter("agents/context-intelligence-tool-designer.md")
66+
mode_fm, _ = _load_frontmatter("modes/context-intelligence.md")
67+
68+
fac_tools = {t["module"]: t for t in facilitator_fm.get("tools", [])}
69+
des_tools = {t["module"]: t for t in designer_fm.get("tools", [])}
70+
mode_safe = mode_fm.get("mode", {}).get("tools", {}).get("safe", [])
71+
72+
print("\n── Group D: Tool composition — Brian's operational note ──────────────────\n")
73+
74+
# D1/D2: Explicit tool-delegate declaration
75+
check(
76+
"D1 Facilitator explicitly declares tool-delegate in tools:",
77+
"tool-delegate" in fac_tools,
78+
f"declared tools: {list(fac_tools.keys())}",
79+
)
80+
check(
81+
"D2 Tool-designer explicitly declares tool-delegate in tools:",
82+
"tool-delegate" in des_tools,
83+
f"declared tools: {list(des_tools.keys())}",
84+
)
85+
86+
# D3: Mode has 'delegate' in safe list
87+
check("D3 Mode tools.safe contains 'delegate' (root-session policy)", "delegate" in mode_safe)
88+
89+
# D4: Mode tool policies are NOT in agent frontmatters
90+
# (Agents must be self-sufficient; they cannot rely on mode policy propagation)
91+
fac_safe = facilitator_fm.get("mode", {}).get("tools", {}).get("safe", [])
92+
des_safe = designer_fm.get("mode", {}).get("tools", {}).get("safe", [])
93+
check(
94+
"D4 Facilitator frontmatter has NO mode.tools.safe block (not relying on mode policy)",
95+
not fac_safe,
96+
f"fac mode.tools.safe={fac_safe}",
97+
)
98+
check(
99+
"D4b Tool-designer frontmatter has NO mode.tools.safe block",
100+
not des_safe,
101+
f"des mode.tools.safe={des_safe}",
102+
)
103+
104+
# D5: Both declare tool-skills (not inherited from parent session)
105+
check(
106+
"D5 Facilitator explicitly declares tool-skills in tools:",
107+
"tool-skills" in fac_tools,
108+
f"declared tools: {list(fac_tools.keys())}",
109+
)
110+
check(
111+
"D5b Tool-designer explicitly declares tool-skills in tools:",
112+
"tool-skills" in des_tools,
113+
f"declared tools: {list(des_tools.keys())}",
114+
)
115+
116+
# D6: tool-delegate source points to amplifier-foundation (correct)
117+
fac_delegate_src = fac_tools.get("tool-delegate", {}).get("source", "")
118+
des_delegate_src = des_tools.get("tool-delegate", {}).get("source", "")
119+
foundation_domain = "amplifier-foundation"
120+
check(
121+
"D6a Facilitator's tool-delegate source is amplifier-foundation",
122+
foundation_domain in fac_delegate_src,
123+
f"source={fac_delegate_src}",
124+
)
125+
check(
126+
"D6b Tool-designer's tool-delegate source is amplifier-foundation",
127+
foundation_domain in des_delegate_src,
128+
f"source={des_delegate_src}",
129+
)
130+
131+
# D7: tool-skills source points to amplifier-bundle-skills (correct)
132+
fac_skills_src = fac_tools.get("tool-skills", {}).get("source", "")
133+
des_skills_src = des_tools.get("tool-skills", {}).get("source", "")
134+
skills_domain = "amplifier-bundle-skills"
135+
check(
136+
"D7a Facilitator's tool-skills source is amplifier-bundle-skills",
137+
skills_domain in fac_skills_src,
138+
f"source={fac_skills_src}",
139+
)
140+
check(
141+
"D7b Tool-designer's tool-skills source is amplifier-bundle-skills",
142+
skills_domain in des_skills_src,
143+
f"source={des_skills_src}",
144+
)
145+
146+
# D8: tool-skills config.skills includes CI bundle skills subtree
147+
fac_skills_cfg = fac_tools.get("tool-skills", {}).get("config", {}).get("skills", [])
148+
des_skills_cfg = des_tools.get("tool-skills", {}).get("config", {}).get("skills", [])
149+
ci_bundle = "amplifier-bundle-context-intelligence"
150+
151+
check(
152+
"D8a Facilitator's tool-skills config points to CI bundle skills",
153+
any(ci_bundle in s for s in fac_skills_cfg),
154+
f"config.skills={fac_skills_cfg}",
155+
)
156+
check(
157+
"D8b Tool-designer's tool-skills config points to CI bundle skills",
158+
any(ci_bundle in s for s in des_skills_cfg),
159+
f"config.skills={des_skills_cfg}",
160+
)
57161

162+
# D9: Phase-transition guard — what would break if tool-delegate were absent
163+
# Simulate: agent with tool-delegate removed from tools: — would it matter?
164+
# The test proves this is a sub-session concern, not inheritable from mode.
165+
class FakeTool:
166+
def __init__(self, name):
167+
self.name = name
58168

59-
facilitator_fm, _ = load_frontmatter("agents/context-intelligence-design-facilitator.md")
60-
designer_fm, _ = load_frontmatter("agents/context-intelligence-tool-designer.md")
61-
mode_fm, _ = load_frontmatter("modes/context-intelligence.md")
62-
63-
fac_tools = {t["module"]: t for t in facilitator_fm.get("tools", [])}
64-
des_tools = {t["module"]: t for t in designer_fm.get("tools", [])}
65-
mode_safe = mode_fm.get("mode", {}).get("tools", {}).get("safe", [])
66-
67-
print("\n── Group D: Tool composition — Brian's operational note ────────────────────\n")
68-
69-
# D1/D2: Explicit tool-delegate declaration
70-
check(
71-
"D1 Facilitator explicitly declares tool-delegate in tools:",
72-
"tool-delegate" in fac_tools,
73-
f"declared tools: {list(fac_tools.keys())}",
74-
)
75-
check(
76-
"D2 Tool-designer explicitly declares tool-delegate in tools:",
77-
"tool-delegate" in des_tools,
78-
f"declared tools: {list(des_tools.keys())}",
79-
)
80-
81-
# D3: Mode has 'delegate' in safe list
82-
check("D3 Mode tools.safe contains 'delegate' (root-session policy)", "delegate" in mode_safe)
83-
84-
# D4: Mode tool policies are NOT in agent frontmatters
85-
# (Agents must be self-sufficient; they cannot rely on mode policy propagation)
86-
fac_safe = facilitator_fm.get("mode", {}).get("tools", {}).get("safe", [])
87-
des_safe = designer_fm.get("mode", {}).get("tools", {}).get("safe", [])
88-
check(
89-
"D4 Facilitator frontmatter has NO mode.tools.safe block (not relying on mode policy)",
90-
not fac_safe,
91-
f"fac mode.tools.safe={fac_safe}",
92-
)
93-
check(
94-
"D4b Tool-designer frontmatter has NO mode.tools.safe block",
95-
not des_safe,
96-
f"des mode.tools.safe={des_safe}",
97-
)
98-
99-
# D5: Both declare tool-skills (not inherited from parent session)
100-
check(
101-
"D5 Facilitator explicitly declares tool-skills in tools:",
102-
"tool-skills" in fac_tools,
103-
f"declared tools: {list(fac_tools.keys())}",
104-
)
105-
check(
106-
"D5b Tool-designer explicitly declares tool-skills in tools:",
107-
"tool-skills" in des_tools,
108-
f"declared tools: {list(des_tools.keys())}",
109-
)
110-
111-
# D6: tool-delegate source points to amplifier-foundation (correct)
112-
fac_delegate_src = fac_tools.get("tool-delegate", {}).get("source", "")
113-
des_delegate_src = des_tools.get("tool-delegate", {}).get("source", "")
114-
foundation_domain = "amplifier-foundation"
115-
check(
116-
"D6a Facilitator's tool-delegate source is amplifier-foundation",
117-
foundation_domain in fac_delegate_src,
118-
f"source={fac_delegate_src}",
119-
)
120-
check(
121-
"D6b Tool-designer's tool-delegate source is amplifier-foundation",
122-
foundation_domain in des_delegate_src,
123-
f"source={des_delegate_src}",
124-
)
125-
126-
# D7: tool-skills source points to amplifier-bundle-skills (correct)
127-
fac_skills_src = fac_tools.get("tool-skills", {}).get("source", "")
128-
des_skills_src = des_tools.get("tool-skills", {}).get("source", "")
129-
skills_domain = "amplifier-bundle-skills"
130-
check(
131-
"D7a Facilitator's tool-skills source is amplifier-bundle-skills",
132-
skills_domain in fac_skills_src,
133-
f"source={fac_skills_src}",
134-
)
135-
check(
136-
"D7b Tool-designer's tool-skills source is amplifier-bundle-skills",
137-
skills_domain in des_skills_src,
138-
f"source={des_skills_src}",
139-
)
140-
141-
# D8: tool-skills config.skills includes CI bundle skills subtree
142-
fac_skills_cfg = fac_tools.get("tool-skills", {}).get("config", {}).get("skills", [])
143-
des_skills_cfg = des_tools.get("tool-skills", {}).get("config", {}).get("skills", [])
144-
ci_bundle = "amplifier-bundle-context-intelligence"
145-
146-
check(
147-
"D8a Facilitator's tool-skills config points to CI bundle skills",
148-
any(ci_bundle in s for s in fac_skills_cfg),
149-
f"config.skills={fac_skills_cfg}",
150-
)
151-
check(
152-
"D8b Tool-designer's tool-skills config points to CI bundle skills",
153-
any(ci_bundle in s for s in des_skills_cfg),
154-
f"config.skills={des_skills_cfg}",
155-
)
156-
157-
158-
# D9: Phase-transition guard — what would break if tool-delegate were absent
159-
# Simulate: agent with tool-delegate removed from tools: — would it matter?
160-
# The test proves this is a sub-session concern, not inheritable from mode.
161-
class FakeTool:
162-
def __init__(self, name):
163-
self.name = name
164-
165-
166-
class FakeCoordinator:
167-
def __init__(self, tools):
168-
self.tools = tools
169-
170-
def get(self, key):
171-
return {t.name: t for t in self.tools}.get(key)
172-
173-
174-
# Sub-session with tool-delegate: delegate call is possible
175-
coord_with_delegate = FakeCoordinator([FakeTool("tool-delegate"), FakeTool("tool-skills")])
176-
coord_without_delegate = FakeCoordinator([FakeTool("tool-skills")])
177-
178-
can_delegate_with = coord_with_delegate.get("tool-delegate") is not None
179-
can_delegate_without = coord_without_delegate.get("tool-delegate") is not None
180-
181-
check("D9 Sub-session WITH tool-delegate: can call delegate()", can_delegate_with)
182-
check(
183-
"D9b Sub-session WITHOUT tool-delegate: CANNOT call delegate() — proves explicit declaration is required",
184-
not can_delegate_without,
185-
"this proves Brian's note: the fix makes B reachable but delegate tool must be declared",
186-
)
187-
188-
# Summary
189-
total = 14
190-
passed = total - len(failures)
191-
print(f"\n══ Group D Results: {passed}/{total} passed ══\n")
192-
if failures:
193-
print("Failed:")
194-
for f in failures:
195-
print(f" ✗ {f}")
196-
sys.exit(1)
197-
else:
198-
print(
199-
"Both agents satisfy Brian's operational note:\n"
200-
" • tool-delegate declared explicitly in each agent's own tools:\n"
201-
" • Neither agent relies on mode tool-policy inheritance\n"
202-
" • Phase 1→2 handoff (facilitator→tool-designer via delegate) is safe\n"
203-
" • Phase 2 per-signal delegation (tool-designer→self) is safe\n"
169+
class FakeCoordinator:
170+
def __init__(self, tools):
171+
self.tools = tools
172+
173+
def get(self, key):
174+
return {t.name: t for t in self.tools}.get(key)
175+
176+
# Sub-session with tool-delegate: delegate call is possible
177+
coord_with_delegate = FakeCoordinator([FakeTool("tool-delegate"), FakeTool("tool-skills")])
178+
coord_without_delegate = FakeCoordinator([FakeTool("tool-skills")])
179+
180+
can_delegate_with = coord_with_delegate.get("tool-delegate") is not None
181+
can_delegate_without = coord_without_delegate.get("tool-delegate") is not None
182+
183+
check("D9 Sub-session WITH tool-delegate: can call delegate()", can_delegate_with)
184+
check(
185+
"D9b Sub-session WITHOUT tool-delegate: CANNOT call delegate() — proves explicit declaration is required",
186+
not can_delegate_without,
187+
"this proves Brian's note: the fix makes B reachable but delegate tool must be declared",
204188
)
189+
190+
# Summary
191+
total = 14
192+
passed = total - len(failures)
193+
print(f"\n══ Group D Results: {passed}/{total} passed ══\n")
194+
if failures:
195+
print("Failed:")
196+
for f in failures:
197+
print(f" ✗ {f}")
198+
else:
199+
print(
200+
"Both agents satisfy Brian's operational note:\n"
201+
" • tool-delegate declared explicitly in each agent's own tools:\n"
202+
" • Neither agent relies on mode tool-policy inheritance\n"
203+
" • Phase 1→2 handoff (facilitator→tool-designer via delegate) is safe\n"
204+
" • Phase 2 per-signal delegation (tool-designer→self) is safe\n"
205+
)
206+
207+
assert not failures, "Group D tool-composition failures: " + ", ".join(failures)
208+
209+
210+
if __name__ == "__main__":
211+
test_tool_delegate_composition()

0 commit comments

Comments
 (0)