From 5bfdd65dbc2cfc4cc04a87a3a0575d5b4f494ce4 Mon Sep 17 00:00:00 2001 From: jwinterm Date: Mon, 6 Jul 2026 03:27:48 -0400 Subject: [PATCH] Add interaction policy to fixture manifests --- ampg/manifest.py | 11 +++++++ docs/fixture-manifests.md | 19 ++++++++++++ tests/test_fixture_manifest.py | 55 ++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+) diff --git a/ampg/manifest.py b/ampg/manifest.py index 247ec2b..e11f1b6 100644 --- a/ampg/manifest.py +++ b/ampg/manifest.py @@ -72,6 +72,7 @@ def _fixture_entry(site: SiteConfig, protocol: ProtocolConfig) -> dict[str, Any] "transport": transport, "profile": transport, }, + "interaction": _interaction_policy(protocol), } @@ -81,6 +82,16 @@ def _transport_for(protocol_name: str) -> str: return protocol_name +def _interaction_policy(protocol: ProtocolConfig) -> dict[str, Any]: + return { + "tier": str(protocol.options.get("tier", protocol.options.get("max_tier", "static"))), + "identity": str(protocol.options.get("identity", "none")), + "payments": str(protocol.options.get("payments", "none")), + "realtime": bool(protocol.options.get("realtime", False)), + "public_allowed": bool(protocol.options.get("public_allowed", True)), + } + + def _fixture_url(site: SiteConfig, protocol: ProtocolConfig) -> tuple[str, str]: configured_url = protocol.options.get("fixture_url") or protocol.options.get("browser_url") if configured_url: diff --git a/docs/fixture-manifests.md b/docs/fixture-manifests.md index c50ee82..03ee876 100644 --- a/docs/fixture-manifests.md +++ b/docs/fixture-manifests.md @@ -20,6 +20,8 @@ The manifest contains public route expectations only: - protocol renderer and relative output path. - route URL for AMPB checks. - expected AMPB transport and profile. +- declared interaction tier, identity adapter, payment adapter, realtime flag, and + public exposure flag. It must not contain private host inventory, hidden-service keys, tunnel keys, credentials, or deployment notes. @@ -39,3 +41,20 @@ manifest and does not rebuild protocol outputs. Some transports may not have final public addresses when a fixture is generated. In those cases AMPG uses route-valid placeholders such as `http://wownero.onion/` so AMPB can still verify transport selection without contacting the network. + +## Interaction Policy + +Fixture interaction policy defaults to: + +```json +{ + "tier": "static", + "identity": "none", + "payments": "none", + "realtime": false, + "public_allowed": true +} +``` + +Route-group overrides will be added separately. Until then, protocol-level options can +declare the fixture-level policy that AMPB should check. diff --git a/tests/test_fixture_manifest.py b/tests/test_fixture_manifest.py index e9173bf..de8b32c 100644 --- a/tests/test_fixture_manifest.py +++ b/tests/test_fixture_manifest.py @@ -73,6 +73,61 @@ cid = "bafyexample" self.assertEqual("gemini://example.test/", by_protocol["gemini"]["url"]) self.assertEqual("ipfs://bafyexample", by_protocol["ipfs"]["url"]) self.assertEqual({"transport": "ipfs", "profile": "ipfs"}, by_protocol["ipfs"]["checks"]) + self.assertEqual( + { + "identity": "none", + "payments": "none", + "public_allowed": True, + "realtime": False, + "tier": "static", + }, + by_protocol["ipfs"]["interaction"], + ) + + def test_manifest_includes_configured_interaction_policy(self): + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + source = root / "site" + source.mkdir() + (source / "index.html").write_text("

Store

", encoding="utf-8") + config_path = root / "gateway.toml" + config_path.write_text( + """ +[[site]] +id = "store" +domain = "store.test" + +[site.source] +kind = "static-html" +path = "./site" + +[site.outputs] +root = "./out" +plan_root = "./plan" + +[site.protocols.tor] +enabled = true +renderer = "privacy-html" +tier = "transactional" +identity = "http-session" +payments = "server-invoice" +""", + encoding="utf-8", + ) + + config = load_config(config_path) + manifest = fixture_manifest(config.sites[0]) + + self.assertEqual( + { + "identity": "http-session", + "payments": "server-invoice", + "public_allowed": True, + "realtime": False, + "tier": "transactional", + }, + manifest["fixtures"][0]["interaction"], + ) if __name__ == "__main__":