foundry-testing-actor 0.2.0__tar.gz → 0.3.0__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.
Files changed (45) hide show
  1. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/PKG-INFO +2 -2
  2. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/README.md +1 -1
  3. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/pyproject.toml +1 -1
  4. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/src/foundry_testing_actor/config.py +22 -3
  5. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/src/foundry_testing_actor/schemas/agentic-context.schema.yaml +3 -2
  6. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/tests/test_config.py +45 -0
  7. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/uv.lock +1 -1
  8. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/.github/workflows/ci.yml +0 -0
  9. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/.github/workflows/release.yml +0 -0
  10. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/.gitignore +0 -0
  11. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/CLAUDE.md +0 -0
  12. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/adr/ADR-FTA-0001-the-machinery-leaves-the-capability.md +0 -0
  13. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/adr/ADR-FTA-0002-this-actors-half-of-the-three-amigos-round.md +0 -0
  14. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/adr/ADR-FTA-0003-every-expectation-says-how-its-data-comes-to-exist.md +0 -0
  15. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/adr/README.md +0 -0
  16. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/adr/template.md +0 -0
  17. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/docker/Dockerfile +0 -0
  18. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/examples/ACME.PARTS.CAP.SUP.007.WID-testing/Dockerfile +0 -0
  19. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/examples/ACME.PARTS.CAP.SUP.007.WID-testing/actor-agentic-context.yaml +0 -0
  20. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/examples/README.md +0 -0
  21. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/scripts/probe_grounding.py +0 -0
  22. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/src/foundry_testing_actor/__init__.py +0 -0
  23. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/src/foundry_testing_actor/cards/actor-data.yaml +0 -0
  24. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/src/foundry_testing_actor/cards/actor-message.yaml +0 -0
  25. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/src/foundry_testing_actor/cards/actor-synchronous-messaging.yaml +0 -0
  26. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/src/foundry_testing_actor/cards/actor.yaml +0 -0
  27. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/src/foundry_testing_actor/cli.py +0 -0
  28. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/src/foundry_testing_actor/conformance.py +0 -0
  29. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/src/foundry_testing_actor/correlation.py +0 -0
  30. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/src/foundry_testing_actor/engine.py +0 -0
  31. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/src/foundry_testing_actor/grounding.py +0 -0
  32. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/src/foundry_testing_actor/handler.py +0 -0
  33. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/src/foundry_testing_actor/instance.py +0 -0
  34. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/src/foundry_testing_actor/runner/Dockerfile +0 -0
  35. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/src/foundry_testing_actor/serve.py +0 -0
  36. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/tests/conftest.py +0 -0
  37. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/tests/fixtures/broken/actor-agentic-context.yaml +0 -0
  38. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/tests/test_cards.py +0 -0
  39. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/tests/test_cli.py +0 -0
  40. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/tests/test_conformance.py +0 -0
  41. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/tests/test_engine.py +0 -0
  42. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/tests/test_grounding.py +0 -0
  43. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/tests/test_handler.py +0 -0
  44. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/tests/test_instance.py +0 -0
  45. {foundry_testing_actor-0.2.0 → foundry_testing_actor-0.3.0}/tests/test_portability.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: foundry-testing-actor
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Runs a headless Claude Code black-box test-authoring session against one capability's own testing repo — a papeete-actor for one use, with the capability supplied by a sidecar.
5
5
  Project-URL: Homepage, https://github.com/papeete-hub/foundry-testing-actor
6
6
  Author-email: Papeete Consulting <yoann.remy@outlook.com>
@@ -202,7 +202,7 @@ It never opens a pull request, and never runs what it wrote beyond `pytest --col
202
202
 
203
203
  | rendering | from |
204
204
  |---|---|
205
- | `ACME.PARTS.CAP.SUP.007.WID-testing` | actor name, git `user.name` (repo half of `source_repo`) |
205
+ | `ACME.PARTS.CAP.SUP.007.WID-testing` | actor name, git `user.name` (`{capability}-testing`) |
206
206
  | `acme-lab/ACME.PARTS.CAP.SUP.007.WID-implementation` | `implementation_repo`, when not declared |
207
207
  | `acme.parts/sup.007.wid` | the id, split at its `CAP` segment |
208
208
  | `acme.parts.cap.sup.007.wid-backend-tests` | the name `papeete-version` versions the test image under |
@@ -179,7 +179,7 @@ It never opens a pull request, and never runs what it wrote beyond `pytest --col
179
179
 
180
180
  | rendering | from |
181
181
  |---|---|
182
- | `ACME.PARTS.CAP.SUP.007.WID-testing` | actor name, git `user.name` (repo half of `source_repo`) |
182
+ | `ACME.PARTS.CAP.SUP.007.WID-testing` | actor name, git `user.name` (`{capability}-testing`) |
183
183
  | `acme-lab/ACME.PARTS.CAP.SUP.007.WID-implementation` | `implementation_repo`, when not declared |
184
184
  | `acme.parts/sup.007.wid` | the id, split at its `CAP` segment |
185
185
  | `acme.parts.cap.sup.007.wid-backend-tests` | the name `papeete-version` versions the test image under |
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "foundry-testing-actor"
3
- version = "0.2.0"
3
+ version = "0.3.0"
4
4
  description = "Runs a headless Claude Code black-box test-authoring session against one capability's own testing repo — a papeete-actor for one use, with the capability supplied by a sidecar."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -14,7 +14,7 @@ They are now derivations of two fields. Nothing in this package spells a capabil
14
14
  source_repo <owner>/ACME.PARTS.CAP.SUP.007.WID-testing ← and the only repo
15
15
 
16
16
  implementation_repo <owner>/<capability>-implementation (declared only when it differs)
17
- actor_name <repo half of source_repo>
17
+ actor_name {capability}-testing
18
18
  actor_slug same, lowercased, dots to hyphens
19
19
  git_author_name actor_name
20
20
  git_author_email {actor_slug}@users.noreply.github.com
@@ -26,6 +26,15 @@ They are now derivations of two fields. Nothing in this package spells a capabil
26
26
  image_name(c) {capability lowercased}-{c} ← what implementation versions
27
27
  image_ref(r,c,v) {r}/{capability_path}/{c}:{v} ← what implementation published
28
28
 
29
+ IDENTITY IS `capability` + ROLE, NOT THE REPO HALF. `actor_name` used to be whatever came after
30
+ the `/` in `source_repo`, which reads as a derivation but is really an assumption: that one
31
+ repository holds exactly one actor. Every sidecar in existence satisfies
32
+ `source_repo == "<owner>/" + capability + "-" + ROLE`, so deriving the name from the two facts it
33
+ was always shorthand for produces the identical string — and it keeps producing the right one when
34
+ a capability's three actors come to share a repository, where the repo half would name all three
35
+ the same thing. `source_repo` is unchanged and still required: it is where this actor clones from
36
+ and pushes to, which is a different question from who it is.
37
+
29
38
  THE IMAGE REFS ARE A THREE-WAY CONTRACT. `image_ref` must stay byte-identical to what the
30
39
  implementation actor publishes, because this actor recomputes it rather than being told it — and
31
40
  `test_image_ref` is what the orchestrating actor parses back apart to run. A component's tests are
@@ -66,6 +75,10 @@ _CAPABILITY_SEGMENT = "cap"
66
75
  # convention never writes the field at all, and one that does not says so in one line.
67
76
  _IMPLEMENTATION_SUFFIX = "-implementation"
68
77
 
78
+ # The role this package plays for the capability it serves. Half of this actor's identity — see
79
+ # `CapabilityConfig.actor_name` — and the half that is a property of the package, not of the use.
80
+ ROLE = "testing"
81
+
69
82
  # What an unsubstituted placeholder looks like: a bare lowercase word in braces, and nothing else.
70
83
  # Narrow on purpose — see `CapabilityConfig.expand`.
71
84
  _PLACEHOLDER = re.compile(r"\{([a-z_]+)\}")
@@ -233,6 +246,7 @@ class CapabilityConfig:
233
246
  )
234
247
  # Force the derivations that can fail, here rather than at the first request that needs
235
248
  # one. A capability id with no `cap` segment is a typo, and it should not survive startup.
249
+ _split_repo(config.source_repo, "source_repo")
236
250
  _ = config.capability_path, config.actor_name, config.implementation_repo
237
251
  return config
238
252
 
@@ -240,8 +254,13 @@ class CapabilityConfig:
240
254
 
241
255
  @property
242
256
  def actor_name(self) -> str:
243
- """The repo half of `source_repo` — this actor's own name, and its git author name."""
244
- return _split_repo(self.source_repo, "source_repo")[1]
257
+ """`{capability}-{ROLE}` — this actor's own name, and its git author name.
258
+
259
+ Not the repo half of `source_repo`, which is the same string for every sidecar that
260
+ exists but stops being this actor's name alone the moment a capability's actors share a
261
+ repository. See this module's own docstring.
262
+ """
263
+ return f"{self.capability}-{ROLE}"
245
264
 
246
265
  @property
247
266
  def actor_slug(self) -> str:
@@ -71,8 +71,9 @@ fields:
71
71
  type: string
72
72
  doc: >-
73
73
  `<owner>/<repo>` of the TESTING repository this actor clones, writes black-box tests into,
74
- and pushes a `test/<task_id>` branch to. The actor's own name and its git commit identity
75
- are derived from the repo half.
74
+ and pushes a `test/<task_id>` branch to. Where it works, not who it is: the actor's own
75
+ name and its git commit identity are `<capability>-testing`, derived from `capability`
76
+ and this package's own role.
76
77
 
77
78
  implementation_repo:
78
79
  type: string
@@ -258,3 +258,48 @@ def test_components_may_not_be_empty(sidecar_dict, write_sidecar):
258
258
  sidecar_dict["components"] = []
259
259
  with pytest.raises(ConfigError, match="empty"):
260
260
  CapabilityConfig.load(write_sidecar(sidecar_dict))
261
+
262
+
263
+ # ── identity: capability + role, not the repo half ──────────────────────────────────────────
264
+
265
+ def test_the_actor_name_is_exactly_what_the_repo_half_used_to_be(config):
266
+ """The no-op half of the change, pinned.
267
+
268
+ `actor_name` was `_split_repo(source_repo)[1]`. It is `{capability}-{ROLE}` now. Every
269
+ sidecar that exists satisfies `source_repo == "<owner>/" + capability + "-" + ROLE`, so the
270
+ two derivations agree on all of them — which is what makes this releasable on its own, ahead
271
+ of any repository moving.
272
+ """
273
+ assert config.source_repo == f"acme-lab/{config.capability}-testing"
274
+ assert config.actor_name == config.source_repo.partition("/")[2]
275
+ assert config.actor_name == "ACME.PARTS.CAP.SUP.007.WID-testing"
276
+
277
+
278
+ def test_the_actor_name_no_longer_follows_the_repository(sidecar_dict, write_sidecar):
279
+ """The point of the change: three actors in one repository still have three names.
280
+
281
+ A consolidated capability repository is named for the capability alone, with no role suffix,
282
+ because all three of its actors live in it. Under the old derivation this actor would have
283
+ been called `ACME.PARTS.CAP.SUP.007.WID` — and so would both of its siblings.
284
+ """
285
+ sidecar_dict["source_repo"] = "acme-lab/ACME.PARTS.CAP.SUP.007.WID"
286
+ sidecar_dict["implementation_repo"] = "acme-lab/ACME.PARTS.CAP.SUP.007.WID"
287
+ config = CapabilityConfig.load(write_sidecar(sidecar_dict))
288
+ assert config.actor_name == "ACME.PARTS.CAP.SUP.007.WID-testing"
289
+ assert config.git_author_name == config.actor_name
290
+ assert config.actor_slug == "acme-parts-cap-sup-007-wid-testing"
291
+ assert config.clone_prefix("TASK-042") == "acme-parts-cap-sup-007-wid-testing-TASK-042-"
292
+
293
+
294
+ def test_a_malformed_source_repo_is_refused_even_when_the_implementation_repo_is_declared(
295
+ sidecar_dict, write_sidecar):
296
+ """`actor_name` used to validate this shape on its way past.
297
+
298
+ The only other reader of `source_repo` at load time is `implementation_repo`, and it reaches
299
+ the field ONLY when it is not declared — so a sidecar that declares one would have carried a
300
+ malformed `source_repo` all the way to its first clone.
301
+ """
302
+ sidecar_dict["source_repo"] = "just-a-name"
303
+ sidecar_dict["implementation_repo"] = "acme-lab/ACME.PARTS.CAP.SUP.007.WID-implementation"
304
+ with pytest.raises(ConfigError, match="source_repo"):
305
+ CapabilityConfig.load(write_sidecar(sidecar_dict))
@@ -18,7 +18,7 @@ wheels = [
18
18
 
19
19
  [[package]]
20
20
  name = "foundry-testing-actor"
21
- version = "0.2.0"
21
+ version = "0.3.0"
22
22
  source = { editable = "." }
23
23
  dependencies = [
24
24
  { name = "papeete-actor-synchronous-messaging" },