diff --git a/README.md b/README.md index 8bf1a4b..fa7ab88 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ The repository root is a skill-only plugin for OpenAI/Codex and Claude. `.codex- Skill Feedback Engine has no MCP component, and none is declared by these manifests. The registration files prepare local discovery only; they do not install, authenticate, publish, or activate anything externally. -`publisher/publisher.json` derives Openly Useful identity and public policy URLs from . Openly Useful LLC remains a planned, formation-pending publisher/operator/licensee, and external publication authorization remains withheld. +`publisher/publisher.json` derives Openly Useful identity and public policy URLs from . Openly Useful is founder-operated while Openly Useful LLC remains formation-pending. External publication is authorized directly by the founder-owner, subject to namespace verification, provider-account authentication, and provider review. This does not represent the planned LLC as formed, active, or the current operator. ## Daily review on macOS diff --git a/publisher/publisher.json b/publisher/publisher.json index 0237fd0..86b5c3b 100644 --- a/publisher/publisher.json +++ b/publisher/publisher.json @@ -16,6 +16,12 @@ "licensee" ] }, + "currentOperator": { + "status": "founder-operated", + "type": "founder-individual", + "displayName": "Founder of Openly Useful", + "operatingAs": "Openly Useful" + }, "policies": { "privacy": "https://openlyuseful.org/legal/privacy", "terms": "https://openlyuseful.org/legal/terms", @@ -39,8 +45,15 @@ ], "mcp": false }, - "externalPublication": { - "allowed": false, - "authorization": "withheld" + "publication": { + "externalPublicationAllowed": true, + "authorization": "granted", + "authorizationBasis": "founder-owner-direct", + "effectiveWhileFormationPending": true, + "blockingRequirements": [ + "namespace-verification", + "provider-account-authentication", + "provider-review" + ] } } diff --git a/scripts/validate_registration.py b/scripts/validate_registration.py index a566a81..3dace75 100644 --- a/scripts/validate_registration.py +++ b/scripts/validate_registration.py @@ -46,8 +46,27 @@ def validate_registration(root: Path = ROOT) -> List[str]: errors.append("planned entity must be Openly Useful LLC with formation-pending status") elif sorted(legal.get("roles", [])) != ["licensee", "operator", "publisher"]: errors.append("planned entity roles are invalid") - if publisher.get("externalPublication") != {"allowed": False, "authorization": "withheld"}: - errors.append("external publication must remain withheld") + expected_operator = { + "status": "founder-operated", + "type": "founder-individual", + "displayName": "Founder of Openly Useful", + "operatingAs": "Openly Useful", + } + if publisher.get("currentOperator") != expected_operator: + errors.append("current operation must remain founder-operated while formation is pending") + expected_publication = { + "externalPublicationAllowed": True, + "authorization": "granted", + "authorizationBasis": "founder-owner-direct", + "effectiveWhileFormationPending": True, + "blockingRequirements": [ + "namespace-verification", + "provider-account-authentication", + "provider-review", + ], + } + if publisher.get("publication") != expected_publication: + errors.append("external publication must use founder-owner-direct authority while formation is pending") component = publisher.get("component") if not isinstance(component, dict): diff --git a/tests/test_registration.py b/tests/test_registration.py index 4441ca7..329c9f5 100644 --- a/tests/test_registration.py +++ b/tests/test_registration.py @@ -67,6 +67,50 @@ def test_validator_rejects_premature_llc_activation(self): errors = validate_registration(fixture) self.assertTrue(any("formation-pending" in error for error in errors)) + def test_validator_rejects_non_founder_current_operator(self): + with tempfile.TemporaryDirectory() as directory: + fixture = Path(directory) + for relative in [ + "publisher/publisher.json", + ".codex-plugin/plugin.json", + ".claude-plugin/plugin.json", + ".claude-plugin/marketplace.json", + ".agents/plugins/marketplace.json", + "skills/skill-feedback-engine/SKILL.md", + ]: + source = ROOT / relative + target = fixture / relative + target.parent.mkdir(parents=True, exist_ok=True) + target.write_bytes(source.read_bytes()) + publisher_path = fixture / "publisher" / "publisher.json" + publisher = json.loads(publisher_path.read_text(encoding="utf-8")) + publisher["currentOperator"]["status"] = "llc-operated" + publisher_path.write_text(json.dumps(publisher), encoding="utf-8") + errors = validate_registration(fixture) + self.assertTrue(any("founder-operated" in error for error in errors)) + + def test_validator_rejects_publication_without_founder_authority(self): + with tempfile.TemporaryDirectory() as directory: + fixture = Path(directory) + for relative in [ + "publisher/publisher.json", + ".codex-plugin/plugin.json", + ".claude-plugin/plugin.json", + ".claude-plugin/marketplace.json", + ".agents/plugins/marketplace.json", + "skills/skill-feedback-engine/SKILL.md", + ]: + source = ROOT / relative + target = fixture / relative + target.parent.mkdir(parents=True, exist_ok=True) + target.write_bytes(source.read_bytes()) + publisher_path = fixture / "publisher" / "publisher.json" + publisher = json.loads(publisher_path.read_text(encoding="utf-8")) + publisher["publication"]["authorizationBasis"] = "planned-entity" + publisher_path.write_text(json.dumps(publisher), encoding="utf-8") + errors = validate_registration(fixture) + self.assertTrue(any("founder-owner-direct" in error for error in errors)) + if __name__ == "__main__": unittest.main()