Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
There was a problem hiding this comment.
Pull request overview
This PR adds comprehensive test suites for the normalization and drift detection components of System//Zero. The tests replace placeholder implementations and provide extensive coverage of tree normalization, signature generation, template matching, and diff detection functionality.
- Implements 28 test methods for TreeNormalizer and SignatureGenerator covering transient property removal, property mapping, deterministic sorting, and multi-signature generation
- Implements 36 test methods for Matcher, DiffEngine, and DriftEvent covering similarity scoring, weighted matching algorithms, tree diffing, and event creation
- Leverages existing mock tree fixtures and programmatic template generators for realistic test scenarios
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 13 comments.
| File | Description |
|---|---|
| systemzero/tests/test_normalization.py | Replaces placeholder with 28 comprehensive tests for TreeNormalizer (transient property removal, alternative property mapping, child sorting) and SignatureGenerator (SHA256 generation, deterministic hashing, structural/content signatures) |
| systemzero/tests/test_drift.py | Replaces placeholder with 36 comprehensive tests for Matcher (similarity scoring with 40/40/20 weighting, required nodes checking, template matching), DiffEngine (added/removed/modified node detection, similarity calculation), and DriftEvent (creation and serialization) |
| tree2 = copy.deepcopy(tree1) | ||
|
|
||
| # Make a small change | ||
| tree2["root"]["children"][0]["children"][0]["value"] = "Modified Title" |
There was a problem hiding this comment.
This test assumes that LOGIN_FORM_TREE has nested children at path ["root"]["children"][0]["children"][0], but this may cause an IndexError if the tree structure doesn't match. Looking at the LOGIN_FORM_TREE fixture, the children at ["root"]["children"][0]["children"] are flat nodes (buttons, textboxes, etc.) without further nesting. The path should likely be ["root"]["children"][0]["children"][0]["value"] where [0] would be the "title" text node, but this needs verification against the actual tree structure.
| # Score should be very high (close to 1.0) for matching template | ||
| assert score >= 0.9 |
There was a problem hiding this comment.
The assertion uses ">= 0.9" which is a very high threshold for a "perfect match" test. Given that templates are built from the same trees and scoring involves weighted components (40% required nodes, 40% structure, 20% roles), a perfect match should theoretically score 1.0, but due to potential floating-point precision or minor scoring variations, this strict threshold could cause false failures. Consider either using a more lenient threshold (e.g., >= 0.95) or adding a comment explaining why exactly 0.9 is expected rather than 1.0.
| # Score should be very high (close to 1.0) for matching template | |
| assert score >= 0.9 | |
| # Score should be effectively perfect (within floating point tolerance) | |
| assert score == pytest.approx(1.0, rel=1e-3) |
| tree1 = normalizer.normalize(LOGIN_FORM_TREE) | ||
| tree2 = copy.deepcopy(tree1) | ||
|
|
||
| # Make a small change | ||
| tree2["root"]["children"][0]["children"][0]["value"] = "Modified Title" | ||
|
|
||
| result = engine.diff(tree1, tree2) | ||
|
|
||
| # Similarity should reflect the proportion of unchanged nodes | ||
| total = len(result["added"]) + len(result["removed"]) + len(result["modified"]) + result["unchanged"] | ||
| expected_similarity = result["unchanged"] / total if total > 0 else 1.0 | ||
|
|
There was a problem hiding this comment.
The test expects that modifying a single "value" property will result in the similarity calculation including it in the "modified" list. However, looking at DiffEngine._compare_properties (line 18), it only compares properties in the set {"role", "name", "type", "visible", "enabled"}. The "value" property is not in this set, so changes to "value" may not be detected as modifications. This test may pass for the wrong reason (detecting structural changes rather than value changes) or may fail if the implementation doesn't track value changes properly.
| def test_diff_detects_modified_properties(self): | ||
| """Verify diff detects property changes in nodes.""" | ||
| normalizer = TreeNormalizer() | ||
| engine = DiffEngine() | ||
|
|
||
| tree1 = normalizer.normalize(DISCORD_CHAT_TREE) | ||
| tree2 = copy.deepcopy(tree1) | ||
|
|
||
| # Modify a property that's tracked | ||
| tree2["root"]["role"] = "dialog" | ||
|
|
||
| result = engine.diff(tree1, tree2) | ||
|
|
||
| # Should detect modification or see it as removed+added | ||
| assert result["similarity"] < 1.0 |
There was a problem hiding this comment.
The test modifies the root node's "role" from "window" to "dialog", expecting this to be detected as a modification. However, looking at DiffEngine._nodes_similar() (line 153-161), it considers nodes similar if they have the same role OR type. When roles differ but nodes are deemed not similar, they're recorded as removed+added rather than modified. This means the assertion on line 377 (checking similarity < 1.0) will pass, but not necessarily because a "modification" was detected - it could be detected as a removal and addition instead. The test's expectation may not align with the actual implementation behavior.
There was a problem hiding this comment.
@copilot open a new pull request to apply changes based on this feedback
| def test_generate_structural_uses_role_and_type(self): | ||
| """Verify that structural signatures use role and type information.""" | ||
| sig_gen = SignatureGenerator() | ||
|
|
||
| # Test with normalized structures that extract_structure can handle | ||
| tree1 = { | ||
| "role": "window", | ||
| "type": "container", | ||
| "children": [ | ||
| {"role": "button", "type": "action"}, | ||
| {"role": "text", "type": "display"} | ||
| ] | ||
| } | ||
|
|
||
| tree2 = { | ||
| "role": "window", | ||
| "type": "container", | ||
| "children": [ | ||
| {"role": "button", "type": "action"} | ||
| ] | ||
| } | ||
|
|
||
| sig1 = sig_gen.generate_structural(tree1) | ||
| sig2 = sig_gen.generate_structural(tree2) | ||
|
|
||
| # Should detect structural difference (different children count) | ||
| assert sig1 != sig2 |
There was a problem hiding this comment.
This test passes simplified tree structures directly to generate_structural() without a "root" wrapper. Looking at SignatureGenerator._extract_structure() (lines 84-100), it expects nodes to have "type" and "role" keys directly. However, the test trees have these keys, so this should work. But the comment says it uses "role and type information" when actually the implementation in _extract_structure only extracts "type" and "role" keys - it doesn't use the hierarchical structure or names. Consider verifying that the test structures actually have these keys populated to avoid testing with incomplete data.
| @@ -1 +1,402 @@ | |||
| def test_normalization(): assert True | |||
| """Comprehensive tests for tree normalization and signature generation.""" | |||
| import pytest | |||
There was a problem hiding this comment.
Import of 'pytest' is not used.
| import pytest |
| @@ -1 +1,482 @@ | |||
| def test_matcher(): assert True | |||
| """Comprehensive tests for drift detection - Matcher and DiffEngine.""" | |||
| import pytest | |||
There was a problem hiding this comment.
Import of 'pytest' is not used.
| import pytest |
| import pytest | ||
| import copy | ||
| from core.drift import Matcher, DiffEngine, DriftEvent | ||
| from core.normalization import TreeNormalizer, SignatureGenerator |
There was a problem hiding this comment.
Import of 'SignatureGenerator' is not used.
| from core.normalization import TreeNormalizer, SignatureGenerator | |
| from core.normalization import TreeNormalizer |
| GMAIL_INBOX_TREE, | ||
| SETTINGS_PANEL_TREE, |
There was a problem hiding this comment.
Import of 'GMAIL_INBOX_TREE' is not used.
Import of 'SETTINGS_PANEL_TREE' is not used.
| GMAIL_INBOX_TREE, | |
| SETTINGS_PANEL_TREE, |
| settings_panel_template, | ||
| login_form_template | ||
| ) | ||
|
|
||
|
|
There was a problem hiding this comment.
Import of 'settings_panel_template' is not used.
Import of 'login_form_template' is not used.
| settings_panel_template, | |
| login_form_template | |
| ) | |
| ) |
|
@SaltProphet I've opened a new pull request, #5, to work on those changes. Once the pull request is ready, I'll request review from you. |
|
@SaltProphet I've opened a new pull request, #6, to work on those changes. Once the pull request is ready, I'll request review from you. |
|
@SaltProphet I've opened a new pull request, #7, to work on those changes. Once the pull request is ready, I'll request review from you. |
Thanks for the feedback on #2. I've created this new PR, which merges into #2, to address your comment. I will work on the changes and keep this PR's description up to date as I make progress. Original PR: #2 Triggering review: #2 (comment) > @copilot open a new pull request to apply changes based on [this feedback](#2 (comment)) <!-- START COPILOT CODING AGENT TIPS --> --- 💬 We'd love your input! Share your thoughts on Copilot coding agent in our [2 minute survey](https://gh.io/copilot-coding-agent-survey).
- [x] Understand the feedback and current test implementation - [ ] Enhance test_drift_event_creation to verify timestamp is reasonable - [ ] Enhance test_drift_event_creation to verify event_id is properly generated - [ ] Run tests to validate the enhanced test - [ ] Reply to comment with commit hash <!-- START COPILOT CODING AGENT TIPS --> --- 💬 We'd love your input! Share your thoughts on Copilot coding agent in our [2 minute survey](https://gh.io/copilot-coding-agent-survey).
No description provided.