Skip to content

Commit bfaa1f7

Browse files
authored
Merge pull request #314 from ai-agent-assembly/v0.0.1/AAASM-4721/enforce_exact_pin
[AAASM-4721] ✨ (examples): Enforce exact-pin operator on the core SDK
2 parents 43d098a + 72c71a7 commit bfaa1f7

2 files changed

Lines changed: 75 additions & 4 deletions

File tree

scripts/generate_example_metadata.py

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -193,10 +193,14 @@ def rewrite_python_manifest(path: Path, sdk: PythonSdk) -> bool:
193193
text = path.read_text(encoding="utf-8")
194194

195195
def _sub(match: re.Match[str]) -> str:
196+
# Normalize the operator to exact ``==``. The core SDK pin must never be a
197+
# floor/open range (AAASM-4704 and the repo's "never a bare >=" rule),
198+
# so a bump self-heals a drifted operator; the --check audit enforces the
199+
# same invariant. The regex still captures ``op`` so a non-``==`` pin is
200+
# matched and rewritten.
196201
indent = match.group("indent")
197-
op = match.group("op")
198202
tail = match.group("tail")
199-
return f'{indent}"{sdk.package}{op}{sdk.version}"{tail}'
203+
return f'{indent}"{sdk.package}=={sdk.version}"{tail}'
200204

201205
new_text = _PY_PIN_RE.sub(_sub, text)
202206
return _write_if_changed(path, new_text)
@@ -755,7 +759,7 @@ def process_prereq_rows(repo_root: Path, versions: SdkVersions) -> list[Path]:
755759
# exactly ``@agent-assembly/sdk``; the go id is exactly
756760
# ``github.com/ai-agent-assembly/go-sdk`` followed by whitespace.
757761
_PY_PIN_AUDIT_RE = re.compile(
758-
r"(?<![\w/@.-])agent-assembly(?:==|>=|~=|<=|!=|<|>)(?P<ver>[^\"'\s,]+)"
762+
r"(?<![\w/@.-])agent-assembly(?P<op>==|>=|~=|<=|!=|<|>)(?P<ver>[^\"'\s,]+)"
759763
)
760764
_NODE_PIN_AUDIT_RE = re.compile(r'"@agent-assembly/sdk"\s*:\s*"(?P<ver>[^"]+)"')
761765
_GO_PIN_AUDIT_RE = re.compile(
@@ -816,6 +820,30 @@ def _audit_pins(repo_root: Path, versions: SdkVersions) -> list[str]:
816820
return problems
817821

818822

823+
# The core SDK pin must be exact (``==``): a floor (``>=``) or open range lets a
824+
# resolver pull a future major and silently break an example (AAASM-4704, and the
825+
# repo's own "never a bare >=" rule). The version-drift audit above only checks
826+
# the version token, so this pass enforces the operator separately. Python
827+
# manifests are the only core-SDK pins that carry an operator — node pins are a
828+
# bare ``"<version>"`` string and go pins are a bare ``go.mod`` version.
829+
def _audit_py_operator(repo_root: Path, versions: SdkVersions) -> list[str]:
830+
"""Report every python core-SDK pin whose operator is not exact (``==``)."""
831+
832+
problems: list[str] = []
833+
for path in _globbed(repo_root, _PY_PIN_GLOBS):
834+
for lineno, line in _audit_lines(path):
835+
if EXEMPT_MARKER in line:
836+
continue
837+
match = _PY_PIN_AUDIT_RE.search(line)
838+
if match and match.group("op") != "==":
839+
rel = path.relative_to(repo_root)
840+
problems.append(
841+
f"{rel}:{lineno}: uses {match.group('op')!r} operator on the "
842+
f"core SDK pin, expected '=='"
843+
)
844+
return problems
845+
846+
819847
def _audit_prose(repo_root: Path, versions: SdkVersions) -> list[str]:
820848
"""Report every README/doc prose line whose SDK version drifts from the SoT.
821849
@@ -854,7 +882,9 @@ def audit(repo_root: Path, versions: SdkVersions) -> list[str]:
854882
"""Return every drifted SDK-version literal as a sorted ``file:line`` list."""
855883

856884
return sorted(
857-
_audit_pins(repo_root, versions) + _audit_prose(repo_root, versions)
885+
_audit_pins(repo_root, versions)
886+
+ _audit_py_operator(repo_root, versions)
887+
+ _audit_prose(repo_root, versions)
858888
)
859889

860890

scripts/test_generate_example_metadata.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,5 +219,46 @@ def test_ignores_runtime_subpackage_and_org_path(self) -> None:
219219
self.assertEqual(gen.audit(self.root, self.versions), [])
220220

221221

222+
class PythonPinOperatorTests(_RepoTestCase):
223+
def test_audit_flags_non_exact_operator(self) -> None:
224+
# Correct version, floor operator: the version-drift audit is clean, but
225+
# the operator policy is violated (AAASM-4704).
226+
_in_sync_tree(self.root)
227+
_write(
228+
self.root,
229+
"python/ex/pyproject.toml",
230+
'dependencies = [\n "agent-assembly>=0.0.1rc5",\n]\n',
231+
)
232+
problems = gen.audit(self.root, self.versions)
233+
self.assertEqual(len(problems), 1)
234+
self.assertIn("python/ex/pyproject.toml:2", problems[0])
235+
self.assertIn("operator", problems[0])
236+
237+
def test_audit_passes_on_exact_operator(self) -> None:
238+
_in_sync_tree(self.root) # every python pin is ``==``
239+
self.assertEqual(gen.audit(self.root, self.versions), [])
240+
241+
def test_operator_exemption_is_honored(self) -> None:
242+
_in_sync_tree(self.root)
243+
_write(
244+
self.root,
245+
"python/ex/pyproject.toml",
246+
'dependencies = [\n "agent-assembly>=0.0.1rc5",'
247+
" # sdk-version-exempt\n]\n",
248+
)
249+
self.assertEqual(gen.audit(self.root, self.versions), [])
250+
251+
def test_rewriter_normalizes_operator_to_exact(self) -> None:
252+
path = _write(
253+
self.root,
254+
"python/ex/pyproject.toml",
255+
'dependencies = [\n "agent-assembly>=0.0.1rc3",\n]\n',
256+
)
257+
changed = gen.rewrite_python_manifest(path, self.versions.python)
258+
self.assertTrue(changed)
259+
self.assertIn('"agent-assembly==0.0.1rc5"', path.read_text())
260+
self.assertNotIn(">=", path.read_text())
261+
262+
222263
if __name__ == "__main__":
223264
unittest.main()

0 commit comments

Comments
 (0)