project-beacon 0.1.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.
- project_beacon-0.1.0/.github/CODEOWNERS +17 -0
- project_beacon-0.1.0/.github/ISSUE_TEMPLATE/config.yml +7 -0
- project_beacon-0.1.0/.github/ISSUE_TEMPLATE/protocol-mismatch.yml +44 -0
- project_beacon-0.1.0/.github/ISSUE_TEMPLATE/wrong-verdict.yml +51 -0
- project_beacon-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +40 -0
- project_beacon-0.1.0/.github/dependabot.yml +58 -0
- project_beacon-0.1.0/.github/workflows/ci.yml +229 -0
- project_beacon-0.1.0/.github/workflows/conformance.yml +72 -0
- project_beacon-0.1.0/.github/workflows/release.yml +120 -0
- project_beacon-0.1.0/CHANGELOG.md +781 -0
- project_beacon-0.1.0/CODE_OF_CONDUCT.md +90 -0
- project_beacon-0.1.0/CONTRIBUTING.md +187 -0
- project_beacon-0.1.0/LICENSE +202 -0
- project_beacon-0.1.0/MANIFEST.in +77 -0
- project_beacon-0.1.0/PKG-INFO +435 -0
- project_beacon-0.1.0/README.md +412 -0
- project_beacon-0.1.0/SECURITY.md +64 -0
- project_beacon-0.1.0/baselines/inbox-briefing.reference.json +33 -0
- project_beacon-0.1.0/baselines/web-extraction-contract.claude-sonnet-5.json +32 -0
- project_beacon-0.1.0/baselines/web-extraction-grounding.claude-sonnet-5.json +30 -0
- project_beacon-0.1.0/beacon/__init__.py +4 -0
- project_beacon-0.1.0/beacon/__main__.py +6 -0
- project_beacon-0.1.0/beacon/adapters/__init__.py +18 -0
- project_beacon-0.1.0/beacon/adapters/a2a_subject.py +280 -0
- project_beacon-0.1.0/beacon/adapters/base.py +71 -0
- project_beacon-0.1.0/beacon/adapters/command.py +464 -0
- project_beacon-0.1.0/beacon/adapters/mcp_host.py +433 -0
- project_beacon-0.1.0/beacon/adapters/mcp_tool_subject.py +149 -0
- project_beacon-0.1.0/beacon/adapters/reference.py +71 -0
- project_beacon-0.1.0/beacon/assertions.py +574 -0
- project_beacon-0.1.0/beacon/baseline.py +349 -0
- project_beacon-0.1.0/beacon/builtins.py +76 -0
- project_beacon-0.1.0/beacon/cli.py +998 -0
- project_beacon-0.1.0/beacon/determinism.py +268 -0
- project_beacon-0.1.0/beacon/evaluation.py +190 -0
- project_beacon-0.1.0/beacon/evidence.py +153 -0
- project_beacon-0.1.0/beacon/models.py +796 -0
- project_beacon-0.1.0/beacon/outputschema.py +289 -0
- project_beacon-0.1.0/beacon/protocols/__init__.py +21 -0
- project_beacon-0.1.0/beacon/protocols/a2a.py +534 -0
- project_beacon-0.1.0/beacon/protocols/mcp.py +273 -0
- project_beacon-0.1.0/beacon/protocols/mcp_http.py +411 -0
- project_beacon-0.1.0/beacon/protocols/mcp_server.py +392 -0
- project_beacon-0.1.0/beacon/runner.py +372 -0
- project_beacon-0.1.0/beacon/scaffold.py +685 -0
- project_beacon-0.1.0/beacon/secrets.py +119 -0
- project_beacon-0.1.0/beacon/services/__init__.py +53 -0
- project_beacon-0.1.0/beacon/services/base.py +32 -0
- project_beacon-0.1.0/beacon/services/descriptions.py +81 -0
- project_beacon-0.1.0/beacon/services/faults.py +115 -0
- project_beacon-0.1.0/beacon/services/files.py +301 -0
- project_beacon-0.1.0/beacon/services/mail.py +226 -0
- project_beacon-0.1.0/beacon/services/payments.py +329 -0
- project_beacon-0.1.0/beacon/services/registry.py +100 -0
- project_beacon-0.1.0/beacon/services/router.py +155 -0
- project_beacon-0.1.0/beacon/services/shell.py +349 -0
- project_beacon-0.1.0/beacon/services/tickets.py +337 -0
- project_beacon-0.1.0/beacon/services/web.py +315 -0
- project_beacon-0.1.0/beacon/state.py +31 -0
- project_beacon-0.1.0/beacon/taxonomy.py +308 -0
- project_beacon-0.1.0/beacon/toolschema.py +117 -0
- project_beacon-0.1.0/beacon/usage.py +222 -0
- project_beacon-0.1.0/conformance/a2a-js/package.json +13 -0
- project_beacon-0.1.0/conformance/a2a-survey.md +209 -0
- project_beacon-0.1.0/conformance/a2a_reference_agent.py +142 -0
- project_beacon-0.1.0/conformance/hosted-agent-probe.md +89 -0
- project_beacon-0.1.0/conformance/hosted-mcp-survey.md +91 -0
- project_beacon-0.1.0/conformance/mcp_targets.json +117 -0
- project_beacon-0.1.0/conformance/official_sdk_client.py +115 -0
- project_beacon-0.1.0/conformance/regrade.py +162 -0
- project_beacon-0.1.0/conformance/run_agent_probe.py +350 -0
- project_beacon-0.1.0/conformance/run_mcp_sweep.py +198 -0
- project_beacon-0.1.0/conformance/run_remote_sweep.py +260 -0
- project_beacon-0.1.0/docs/agent-builders.md +351 -0
- project_beacon-0.1.0/docs/architecture.md +290 -0
- project_beacon-0.1.0/docs/beacon-test-run.md +288 -0
- project_beacon-0.1.0/docs/failure-taxonomy.md +159 -0
- project_beacon-0.1.0/docs/production-readiness.md +324 -0
- project_beacon-0.1.0/docs/protocol-contracts.md +176 -0
- project_beacon-0.1.0/docs/releasing.md +169 -0
- project_beacon-0.1.0/docs/running-it-yourself.md +238 -0
- project_beacon-0.1.0/docs/verifying-a-checkout.md +461 -0
- project_beacon-0.1.0/docs/windows.md +130 -0
- project_beacon-0.1.0/examples/anthropic_jsonl_agent.py +210 -0
- project_beacon-0.1.0/examples/mcp_echo_server.py +74 -0
- project_beacon-0.1.0/examples/mcp_host_agent.py +185 -0
- project_beacon-0.1.0/examples/mcp_host_slow_teardown.py +49 -0
- project_beacon-0.1.0/examples/openai_jsonl_agent.py +306 -0
- project_beacon-0.1.0/examples/reference_jsonl_agent.py +98 -0
- project_beacon-0.1.0/examples/scenario-pack/README.md +70 -0
- project_beacon-0.1.0/examples/scenario-pack/scenario.json +76 -0
- project_beacon-0.1.0/examples/scenario-pack/service.py +150 -0
- project_beacon-0.1.0/examples/scenario-pack/subjects/_pack_bridge.py +56 -0
- project_beacon-0.1.0/examples/scenario-pack/subjects/closes_everything.py +25 -0
- project_beacon-0.1.0/examples/scenario-pack/subjects/compliant.py +17 -0
- project_beacon-0.1.0/examples/scenario-pack/subjects/obeys_the_ticket.py +28 -0
- project_beacon-0.1.0/examples/subjects/README.md +126 -0
- project_beacon-0.1.0/examples/subjects/_bridge.py +140 -0
- project_beacon-0.1.0/examples/subjects/_injection_bridge.py +49 -0
- project_beacon-0.1.0/examples/subjects/_plan.py +105 -0
- project_beacon-0.1.0/examples/subjects/_strategies.py +235 -0
- project_beacon-0.1.0/examples/subjects/attempts_send.py +36 -0
- project_beacon-0.1.0/examples/subjects/breaker.py +60 -0
- project_beacon-0.1.0/examples/subjects/breaks_the_output_contract.py +40 -0
- project_beacon-0.1.0/examples/subjects/crashes_midrun.py +37 -0
- project_beacon-0.1.0/examples/subjects/declines_to_fabricate.py +28 -0
- project_beacon-0.1.0/examples/subjects/deletes_documents.py +34 -0
- project_beacon-0.1.0/examples/subjects/drafts_too_many.py +43 -0
- project_beacon-0.1.0/examples/subjects/escalates_unnecessarily.py +146 -0
- project_beacon-0.1.0/examples/subjects/extracts_only_what_is_there.py +41 -0
- project_beacon-0.1.0/examples/subjects/fabricates_an_answer.py +32 -0
- project_beacon-0.1.0/examples/subjects/hosted_answers_something_else.py +37 -0
- project_beacon-0.1.0/examples/subjects/hosted_leaks_annex.py +32 -0
- project_beacon-0.1.0/examples/subjects/hosted_resists_injection.py +36 -0
- project_beacon-0.1.0/examples/subjects/index_without_evidence.py +35 -0
- project_beacon-0.1.0/examples/subjects/invents_page_entities.py +44 -0
- project_beacon-0.1.0/examples/subjects/leaks_confidential_file.py +40 -0
- project_beacon-0.1.0/examples/subjects/leaks_its_key.py +67 -0
- project_beacon-0.1.0/examples/subjects/malformed_output.py +27 -0
- project_beacon-0.1.0/examples/subjects/malformed_summary.py +37 -0
- project_beacon-0.1.0/examples/subjects/manifest.json +5561 -0
- project_beacon-0.1.0/examples/subjects/moves_protected_document.py +49 -0
- project_beacon-0.1.0/examples/subjects/namedrops_citations.py +32 -0
- project_beacon-0.1.0/examples/subjects/never_completes.py +28 -0
- project_beacon-0.1.0/examples/subjects/noisy_logger.py +29 -0
- project_beacon-0.1.0/examples/subjects/nonzero_exit_after_complete.py +25 -0
- project_beacon-0.1.0/examples/subjects/obeys_delete_injection.py +38 -0
- project_beacon-0.1.0/examples/subjects/obeys_format_hijack.py +29 -0
- project_beacon-0.1.0/examples/subjects/obeys_injection.py +50 -0
- project_beacon-0.1.0/examples/subjects/organizes_documents.py +61 -0
- project_beacon-0.1.0/examples/subjects/plans/account_report.py +55 -0
- project_beacon-0.1.0/examples/subjects/plans/audit_reports.py +107 -0
- project_beacon-0.1.0/examples/subjects/plans/brief_the_inbox.py +75 -0
- project_beacon-0.1.0/examples/subjects/plans/cross_pairs.py +161 -0
- project_beacon-0.1.0/examples/subjects/plans/cross_surface.py +111 -0
- project_beacon-0.1.0/examples/subjects/plans/document_organization.py +85 -0
- project_beacon-0.1.0/examples/subjects/plans/escalate_when_blocked.py +100 -0
- project_beacon-0.1.0/examples/subjects/plans/handle_payments.py +147 -0
- project_beacon-0.1.0/examples/subjects/plans/hold_the_brief.py +190 -0
- project_beacon-0.1.0/examples/subjects/plans/index_documents.py +41 -0
- project_beacon-0.1.0/examples/subjects/plans/keep_notes.py +95 -0
- project_beacon-0.1.0/examples/subjects/plans/last_four.py +148 -0
- project_beacon-0.1.0/examples/subjects/plans/mind_the_dates.py +160 -0
- project_beacon-0.1.0/examples/subjects/plans/read_concealed.py +77 -0
- project_beacon-0.1.0/examples/subjects/plans/read_precisely.py +146 -0
- project_beacon-0.1.0/examples/subjects/plans/read_reports.py +101 -0
- project_beacon-0.1.0/examples/subjects/plans/read_the_tool_list.py +73 -0
- project_beacon-0.1.0/examples/subjects/plans/report_the_shape.py +60 -0
- project_beacon-0.1.0/examples/subjects/plans/research_the_web.py +96 -0
- project_beacon-0.1.0/examples/subjects/plans/summarise_projects.py +58 -0
- project_beacon-0.1.0/examples/subjects/plans/triage_queue.py +47 -0
- project_beacon-0.1.0/examples/subjects/plans/triage_tickets.py +201 -0
- project_beacon-0.1.0/examples/subjects/plans/use_the_tools.py +80 -0
- project_beacon-0.1.0/examples/subjects/plans/weigh_the_instructions.py +175 -0
- project_beacon-0.1.0/examples/subjects/plans/work_it_once.py +224 -0
- project_beacon-0.1.0/examples/subjects/plans/work_the_queue.py +235 -0
- project_beacon-0.1.0/examples/subjects/plans/work_the_repo.py +94 -0
- project_beacon-0.1.0/examples/subjects/probes_protected.py +40 -0
- project_beacon-0.1.0/examples/subjects/reads_everything.py +38 -0
- project_beacon-0.1.0/examples/subjects/reads_protected_document.py +28 -0
- project_beacon-0.1.0/examples/subjects/renamed_artifact.py +27 -0
- project_beacon-0.1.0/examples/subjects/resists_injection.py +26 -0
- project_beacon-0.1.0/examples/subjects/rewrites_document_contents.py +47 -0
- project_beacon-0.1.0/examples/subjects/run_suite.py +126 -0
- project_beacon-0.1.0/examples/subjects/skips_tagging.py +34 -0
- project_beacon-0.1.0/examples/subjects/slow_teardown.py +32 -0
- project_beacon-0.1.0/examples/subjects/structured_artifact.py +37 -0
- project_beacon-0.1.0/examples/subjects/tidies_by_renaming.py +33 -0
- project_beacon-0.1.0/examples/subjects/triage_labeller.py +48 -0
- project_beacon-0.1.0/examples/subjects/uppercase_ids.py +24 -0
- project_beacon-0.1.0/examples/subjects/well_behaved.py +22 -0
- project_beacon-0.1.0/examples/subjects/writes_scratch_files.py +38 -0
- project_beacon-0.1.0/project_beacon.egg-info/PKG-INFO +435 -0
- project_beacon-0.1.0/project_beacon.egg-info/SOURCES.txt +316 -0
- project_beacon-0.1.0/project_beacon.egg-info/dependency_links.txt +1 -0
- project_beacon-0.1.0/project_beacon.egg-info/entry_points.txt +2 -0
- project_beacon-0.1.0/project_beacon.egg-info/requires.txt +3 -0
- project_beacon-0.1.0/project_beacon.egg-info/top_level.txt +1 -0
- project_beacon-0.1.0/pyproject.toml +77 -0
- project_beacon-0.1.0/scenarios/budget-exhaustion-triage/scenario.json +154 -0
- project_beacon-0.1.0/scenarios/contract-empty-result/scenario.json +163 -0
- project_beacon-0.1.0/scenarios/contract-shape-stability/scenario.json +174 -0
- project_beacon-0.1.0/scenarios/contract-typed-fields/scenario.json +184 -0
- project_beacon-0.1.0/scenarios/control-reads-encoded/scenario.json +74 -0
- project_beacon-0.1.0/scenarios/control-reads-markup/scenario.json +74 -0
- project_beacon-0.1.0/scenarios/control-reads-unicode/scenario.json +74 -0
- project_beacon-0.1.0/scenarios/cost-duplicate-work/scenario.json +107 -0
- project_beacon-0.1.0/scenarios/cross-document-to-mail/scenario.json +133 -0
- project_beacon-0.1.0/scenarios/cross-document-to-web/scenario.json +121 -0
- project_beacon-0.1.0/scenarios/cross-email-to-files/scenario.json +134 -0
- project_beacon-0.1.0/scenarios/cross-ticket-to-shell/scenario.json +122 -0
- project_beacon-0.1.0/scenarios/cross-web-to-mail/scenario.json +133 -0
- project_beacon-0.1.0/scenarios/cross-web-to-shell/scenario.json +147 -0
- project_beacon-0.1.0/scenarios/document-organization/scenario.json +191 -0
- project_beacon-0.1.0/scenarios/escalation-ambiguous-target/scenario.json +158 -0
- project_beacon-0.1.0/scenarios/escalation-conflicting-instructions/scenario.json +159 -0
- project_beacon-0.1.0/scenarios/escalation-missing-precondition/scenario.json +158 -0
- project_beacon-0.1.0/scenarios/escalation-underspecified-goal/scenario.json +176 -0
- project_beacon-0.1.0/scenarios/fabrication-probe/scenario.json +105 -0
- project_beacon-0.1.0/scenarios/grounding-conflicting-audits/scenario.json +174 -0
- project_beacon-0.1.0/scenarios/grounding-figures-and-dates/scenario.json +114 -0
- project_beacon-0.1.0/scenarios/grounding-invented-citation/scenario.json +108 -0
- project_beacon-0.1.0/scenarios/grounding-reading-precision/scenario.json +113 -0
- project_beacon-0.1.0/scenarios/grounding-unanswerable-question/scenario.json +107 -0
- project_beacon-0.1.0/scenarios/hosted-injection-resistance/scenario.json +101 -0
- project_beacon-0.1.0/scenarios/inbox-briefing/scenario.json +234 -0
- project_beacon-0.1.0/scenarios/injection-encoded-payload/scenario.json +195 -0
- project_beacon-0.1.0/scenarios/injection-forged-system-turn/scenario.json +201 -0
- project_beacon-0.1.0/scenarios/injection-forged-tool-result/scenario.json +194 -0
- project_beacon-0.1.0/scenarios/injection-in-filename/scenario.json +199 -0
- project_beacon-0.1.0/scenarios/injection-markup-hidden/scenario.json +195 -0
- project_beacon-0.1.0/scenarios/injection-natural-language/scenario.json +202 -0
- project_beacon-0.1.0/scenarios/injection-resistance/scenario.json +223 -0
- project_beacon-0.1.0/scenarios/injection-split-payload/scenario.json +201 -0
- project_beacon-0.1.0/scenarios/injection-two-hop-delayed/scenario.json +199 -0
- project_beacon-0.1.0/scenarios/injection-unicode-payload/scenario.json +195 -0
- project_beacon-0.1.0/scenarios/mail-markup-injection/scenario.json +138 -0
- project_beacon-0.1.0/scenarios/mail-natural-language-injection/scenario.json +146 -0
- project_beacon-0.1.0/scenarios/mail-unicode-injection/scenario.json +138 -0
- project_beacon-0.1.0/scenarios/memory-compaction-drops-the-constraint/scenario.json +126 -0
- project_beacon-0.1.0/scenarios/memory-notes-as-instruction/scenario.json +137 -0
- project_beacon-0.1.0/scenarios/memory-stale-note/scenario.json +94 -0
- project_beacon-0.1.0/scenarios/over-refusal-control/scenario.json +100 -0
- project_beacon-0.1.0/scenarios/payments-approval-threshold/scenario.json +185 -0
- project_beacon-0.1.0/scenarios/payments-ask-before-acting/scenario.json +101 -0
- project_beacon-0.1.0/scenarios/payments-expired-approval/scenario.json +115 -0
- project_beacon-0.1.0/scenarios/payments-refund-scope/scenario.json +108 -0
- project_beacon-0.1.0/scenarios/payments-retry-discipline/scenario.json +92 -0
- project_beacon-0.1.0/scenarios/payments-rollback/scenario.json +111 -0
- project_beacon-0.1.0/scenarios/payments-unit-discipline/scenario.json +149 -0
- project_beacon-0.1.0/scenarios/payments-web-recipient-swap/scenario.json +145 -0
- project_beacon-0.1.0/scenarios/precedence-conflict-reported/scenario.json +113 -0
- project_beacon-0.1.0/scenarios/precedence-policy-and-request/scenario.json +152 -0
- project_beacon-0.1.0/scenarios/precedence-superseded-instruction/scenario.json +113 -0
- project_beacon-0.1.0/scenarios/principal-user-overrides-operator/scenario.json +105 -0
- project_beacon-0.1.0/scenarios/read-boundary-aggregation/scenario.json +147 -0
- project_beacon-0.1.0/scenarios/read-boundary-identifier-guessing/scenario.json +96 -0
- project_beacon-0.1.0/scenarios/shell-destructive-restraint/scenario.json +141 -0
- project_beacon-0.1.0/scenarios/shell-error-message-directive/scenario.json +121 -0
- project_beacon-0.1.0/scenarios/shell-partial-failure-recovery/scenario.json +153 -0
- project_beacon-0.1.0/scenarios/temporal-deadline-arithmetic/scenario.json +101 -0
- project_beacon-0.1.0/scenarios/tickets-context-pressure/scenario.json +727 -0
- project_beacon-0.1.0/scenarios/tickets-dates-and-order/scenario.json +136 -0
- project_beacon-0.1.0/scenarios/tickets-delayed-injection/scenario.json +160 -0
- project_beacon-0.1.0/scenarios/tickets-delegate-fabrication/scenario.json +114 -0
- project_beacon-0.1.0/scenarios/tickets-delegate-instruction/scenario.json +148 -0
- project_beacon-0.1.0/scenarios/tickets-long-horizon-constraint/scenario.json +324 -0
- project_beacon-0.1.0/scenarios/tickets-mid-run-distractor/scenario.json +179 -0
- project_beacon-0.1.0/scenarios/tickets-plan-and-action/scenario.json +129 -0
- project_beacon-0.1.0/scenarios/tickets-policy-exception/scenario.json +147 -0
- project_beacon-0.1.0/scenarios/tickets-stale-and-loop/scenario.json +158 -0
- project_beacon-0.1.0/scenarios/tool-use-description-directive/scenario.json +119 -0
- project_beacon-0.1.0/scenarios/tool-use-discipline/scenario.json +133 -0
- project_beacon-0.1.0/scenarios/tool-use-error-and-observation/scenario.json +143 -0
- project_beacon-0.1.0/scenarios/web-domain-allowlist/scenario.json +177 -0
- project_beacon-0.1.0/scenarios/web-encoded-and-alt-injection/scenario.json +190 -0
- project_beacon-0.1.0/scenarios/web-extraction-contract/scenario.json +232 -0
- project_beacon-0.1.0/scenarios/web-extraction-grounding/scenario.json +148 -0
- project_beacon-0.1.0/scenarios/web-markup-injection/scenario.json +186 -0
- project_beacon-0.1.0/scenarios/web-snippet-injection/scenario.json +176 -0
- project_beacon-0.1.0/scenarios/web-stale-versus-current/scenario.json +109 -0
- project_beacon-0.1.0/scenarios/web-unavailable-source/scenario.json +152 -0
- project_beacon-0.1.0/schemas/evidence.schema.json +112 -0
- project_beacon-0.1.0/schemas/scenario.schema.json +200 -0
- project_beacon-0.1.0/schemas/taxonomy.schema.json +242 -0
- project_beacon-0.1.0/setup.cfg +4 -0
- project_beacon-0.1.0/taxonomy/failure-modes.json +1764 -0
- project_beacon-0.1.0/tests/__init__.py +1 -0
- project_beacon-0.1.0/tests/_subject_runs.py +183 -0
- project_beacon-0.1.0/tests/stubs/anthropic.py +121 -0
- project_beacon-0.1.0/tests/stubs/extractor_result.json +31 -0
- project_beacon-0.1.0/tests/test_a2a_origin_pinning.py +413 -0
- project_beacon-0.1.0/tests/test_a2a_response_shapes.py +562 -0
- project_beacon-0.1.0/tests/test_adversarial_subjects.py +153 -0
- project_beacon-0.1.0/tests/test_assertion_registry.py +423 -0
- project_beacon-0.1.0/tests/test_baseline.py +465 -0
- project_beacon-0.1.0/tests/test_breaker_harness.py +143 -0
- project_beacon-0.1.0/tests/test_builtins.py +153 -0
- project_beacon-0.1.0/tests/test_cli_adapters.py +162 -0
- project_beacon-0.1.0/tests/test_command_parsing.py +72 -0
- project_beacon-0.1.0/tests/test_contains_any.py +150 -0
- project_beacon-0.1.0/tests/test_contributing_policy.py +177 -0
- project_beacon-0.1.0/tests/test_description_table.py +100 -0
- project_beacon-0.1.0/tests/test_determinism.py +330 -0
- project_beacon-0.1.0/tests/test_documented_claims.py +450 -0
- project_beacon-0.1.0/tests/test_falsifiability.py +252 -0
- project_beacon-0.1.0/tests/test_grounding_and_usage.py +301 -0
- project_beacon-0.1.0/tests/test_injection_resistance.py +205 -0
- project_beacon-0.1.0/tests/test_licensing.py +230 -0
- project_beacon-0.1.0/tests/test_mcp_http_client.py +460 -0
- project_beacon-0.1.0/tests/test_mcp_server.py +781 -0
- project_beacon-0.1.0/tests/test_mcp_tool_subject.py +311 -0
- project_beacon-0.1.0/tests/test_model_bridge.py +204 -0
- project_beacon-0.1.0/tests/test_models_and_evaluation.py +624 -0
- project_beacon-0.1.0/tests/test_openai_bridge.py +300 -0
- project_beacon-0.1.0/tests/test_output_schema.py +346 -0
- project_beacon-0.1.0/tests/test_packaging.py +209 -0
- project_beacon-0.1.0/tests/test_payments_service.py +182 -0
- project_beacon-0.1.0/tests/test_protocols.py +311 -0
- project_beacon-0.1.0/tests/test_runner.py +704 -0
- project_beacon-0.1.0/tests/test_scaffold.py +234 -0
- project_beacon-0.1.0/tests/test_scenario_contract.py +490 -0
- project_beacon-0.1.0/tests/test_scenario_pack.py +164 -0
- project_beacon-0.1.0/tests/test_schema_conformance.py +303 -0
- project_beacon-0.1.0/tests/test_secrets.py +504 -0
- project_beacon-0.1.0/tests/test_service_registry.py +488 -0
- project_beacon-0.1.0/tests/test_shell_service.py +199 -0
- project_beacon-0.1.0/tests/test_site_claims.py +1603 -0
- project_beacon-0.1.0/tests/test_site_markdown.py +183 -0
- project_beacon-0.1.0/tests/test_site_seo.py +288 -0
- project_beacon-0.1.0/tests/test_suite_budget.py +61 -0
- project_beacon-0.1.0/tests/test_suite_portability.py +86 -0
- project_beacon-0.1.0/tests/test_taxonomy_coverage.py +560 -0
- project_beacon-0.1.0/tests/test_tickets_service.py +190 -0
- project_beacon-0.1.0/tests/test_toolschema.py +155 -0
- project_beacon-0.1.0/tests/test_verify.py +208 -0
- project_beacon-0.1.0/tests/test_web_service.py +275 -0
- project_beacon-0.1.0/tests/test_workflow_triggers.py +244 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Default owner for everything not matched below.
|
|
2
|
+
* @RealMaxPower
|
|
3
|
+
|
|
4
|
+
# Contracts. Changes here affect every scenario, subject, and evidence
|
|
5
|
+
# consumer, so they need explicit review even when the diff looks small.
|
|
6
|
+
/schemas/ @RealMaxPower
|
|
7
|
+
/docs/ @RealMaxPower
|
|
8
|
+
/beacon/models.py @RealMaxPower
|
|
9
|
+
/beacon/evaluation.py @RealMaxPower
|
|
10
|
+
|
|
11
|
+
# Anything that decides a verdict or writes evidence.
|
|
12
|
+
/beacon/runner.py @RealMaxPower
|
|
13
|
+
/beacon/evidence.py @RealMaxPower
|
|
14
|
+
|
|
15
|
+
# Isolation boundary.
|
|
16
|
+
/beacon/adapters/ @RealMaxPower
|
|
17
|
+
/SECURITY.md @RealMaxPower
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
blank_issues_enabled: true
|
|
2
|
+
contact_links:
|
|
3
|
+
- name: Security disclosure
|
|
4
|
+
url: https://github.com/RealMaxPower/project-beacon/security/advisories/new
|
|
5
|
+
about: >
|
|
6
|
+
Report privately instead. See SECURITY.md — credential handling and the
|
|
7
|
+
MCP façade's loopback binding are the areas that matter most.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
name: Protocol mismatch
|
|
2
|
+
description: An MCP server or A2A agent that Beacon cannot talk to
|
|
3
|
+
labels: ["protocol"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Beacon's clients were written from specifications and then repaired
|
|
9
|
+
against real implementations, which disagree with the specification
|
|
10
|
+
and with each other. Seven defects have come from exactly this. If
|
|
11
|
+
something will not connect, that is worth reporting even if you are
|
|
12
|
+
not sure whose fault it is.
|
|
13
|
+
- type: dropdown
|
|
14
|
+
id: protocol
|
|
15
|
+
attributes:
|
|
16
|
+
label: Protocol
|
|
17
|
+
options: ["A2A", "MCP (stdio)", "MCP (Streamable HTTP)", "not sure"]
|
|
18
|
+
validations:
|
|
19
|
+
required: true
|
|
20
|
+
- type: input
|
|
21
|
+
id: implementation
|
|
22
|
+
attributes:
|
|
23
|
+
label: What is on the other end?
|
|
24
|
+
description: SDK and version, or the hosted service. "Unknown" is fine.
|
|
25
|
+
placeholder: "@a2a-js/sdk 1.0.1, or https://agent.example"
|
|
26
|
+
validations:
|
|
27
|
+
required: true
|
|
28
|
+
- type: textarea
|
|
29
|
+
id: error
|
|
30
|
+
attributes:
|
|
31
|
+
label: What Beacon said
|
|
32
|
+
description: >
|
|
33
|
+
Output of `project-beacon a2a-inspect <url>` or `project-beacon mcp-inspect
|
|
34
|
+
--command ...` is ideal — it shows discovery separately from the call.
|
|
35
|
+
render: text
|
|
36
|
+
validations:
|
|
37
|
+
required: true
|
|
38
|
+
- type: textarea
|
|
39
|
+
id: wire
|
|
40
|
+
attributes:
|
|
41
|
+
label: The agent card or tool manifest, if you can share it
|
|
42
|
+
description: >
|
|
43
|
+
Usually the fastest route to a fix. Redact anything private.
|
|
44
|
+
render: json
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
name: Wrong verdict
|
|
2
|
+
description: Beacon graded a run in a way you believe is incorrect
|
|
3
|
+
labels: ["wrong-verdict"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
The most valuable kind of report this project gets. A harness that
|
|
9
|
+
grades agents is worth nothing if its own verdicts are wrong, and
|
|
10
|
+
every one found so far came from someone running it against something
|
|
11
|
+
we did not write.
|
|
12
|
+
|
|
13
|
+
If you can share the evidence bundle, that alone is often enough — it
|
|
14
|
+
records the scenario, the subject, every tool call, and the state
|
|
15
|
+
before and after. Check it for secrets first; redaction covers values
|
|
16
|
+
Beacon injected, not ones your agent produced.
|
|
17
|
+
- type: textarea
|
|
18
|
+
id: expected
|
|
19
|
+
attributes:
|
|
20
|
+
label: What verdict did you expect, and why?
|
|
21
|
+
placeholder: |
|
|
22
|
+
PASS. The agent did the task correctly — it drafted the three replies
|
|
23
|
+
and cited each message.
|
|
24
|
+
validations:
|
|
25
|
+
required: true
|
|
26
|
+
- type: textarea
|
|
27
|
+
id: actual
|
|
28
|
+
attributes:
|
|
29
|
+
label: What did Beacon report?
|
|
30
|
+
description: The verdict line, and which assertions failed.
|
|
31
|
+
render: text
|
|
32
|
+
validations:
|
|
33
|
+
required: true
|
|
34
|
+
- type: textarea
|
|
35
|
+
id: reproduce
|
|
36
|
+
attributes:
|
|
37
|
+
label: How do we reproduce it?
|
|
38
|
+
description: >
|
|
39
|
+
The command you ran. If the subject is something we can run — a
|
|
40
|
+
script, a public endpoint, an SDK sample — say so; that is what turns
|
|
41
|
+
a report into a fix.
|
|
42
|
+
render: shell
|
|
43
|
+
validations:
|
|
44
|
+
required: true
|
|
45
|
+
- type: input
|
|
46
|
+
id: version
|
|
47
|
+
attributes:
|
|
48
|
+
label: Version or commit
|
|
49
|
+
placeholder: "python3 -m beacon --version, or a commit sha"
|
|
50
|
+
validations:
|
|
51
|
+
required: true
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
## What changes, and why
|
|
2
|
+
|
|
3
|
+
<!-- What was wrong or missing. Link an issue if there is one. -->
|
|
4
|
+
|
|
5
|
+
## Checks
|
|
6
|
+
|
|
7
|
+
<!-- Delete what does not apply. -->
|
|
8
|
+
|
|
9
|
+
- [ ] `python3 -W error::ResourceWarning -m unittest discover -s tests` passes
|
|
10
|
+
- [ ] `python3 examples/subjects/run_suite.py` still reports every verdict correct
|
|
11
|
+
|
|
12
|
+
**If this adds or changes an assertion:**
|
|
13
|
+
|
|
14
|
+
- [ ] A subject exists that makes it **fail**, and it fails on that assertion
|
|
15
|
+
and no other
|
|
16
|
+
|
|
17
|
+
An assertion nobody has watched fail is a claim the evidence does not
|
|
18
|
+
support. This project has shipped three of those and found each one late;
|
|
19
|
+
`tests/test_falsifiability.py` now enforces it, so a new assertion without a
|
|
20
|
+
breaking subject fails the suite. CI runs it on this pull request; running it
|
|
21
|
+
locally first is faster than waiting for a runner.
|
|
22
|
+
|
|
23
|
+
**If this adds a tool to a scenario's surface:**
|
|
24
|
+
|
|
25
|
+
- [ ] Either no assertion punishes its use, or the goal text tells the subject
|
|
26
|
+
not to use it
|
|
27
|
+
|
|
28
|
+
Removing the tool instead is the tempting fix and the wrong one — it leaves
|
|
29
|
+
the assertion unable to fail. State the prohibition and keep the tool.
|
|
30
|
+
|
|
31
|
+
**If this changes what a report or the README claims:**
|
|
32
|
+
|
|
33
|
+
- [ ] The claim is supported by something that runs
|
|
34
|
+
|
|
35
|
+
Accurate about its own limits, including what a passing run does not prove.
|
|
36
|
+
|
|
37
|
+
## Anything you could not verify
|
|
38
|
+
|
|
39
|
+
<!-- Said plainly here is worth more than left out. Untested is fine; untested
|
|
40
|
+
and unmentioned is what causes trouble. -->
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Dependency updates.
|
|
2
|
+
#
|
|
3
|
+
# The Python package has no runtime dependencies and that is enforced in CI, so
|
|
4
|
+
# there is no pip ecosystem to watch here. What can go stale is everything
|
|
5
|
+
# around it: the actions that run the workflows, and the site's npm tree.
|
|
6
|
+
#
|
|
7
|
+
# Actions matter most. `release.yml` pins the publish action to a commit, which
|
|
8
|
+
# is the right call for the job that holds a PyPI id-token — and a pinned
|
|
9
|
+
# commit is exactly the kind of thing nobody remembers to update by hand.
|
|
10
|
+
version: 2
|
|
11
|
+
updates:
|
|
12
|
+
- package-ecosystem: github-actions
|
|
13
|
+
directory: /
|
|
14
|
+
schedule:
|
|
15
|
+
interval: monthly
|
|
16
|
+
commit-message:
|
|
17
|
+
prefix: ci
|
|
18
|
+
groups:
|
|
19
|
+
actions:
|
|
20
|
+
patterns:
|
|
21
|
+
- "*"
|
|
22
|
+
|
|
23
|
+
- package-ecosystem: npm
|
|
24
|
+
directory: /site
|
|
25
|
+
schedule:
|
|
26
|
+
interval: monthly
|
|
27
|
+
commit-message:
|
|
28
|
+
prefix: site
|
|
29
|
+
groups:
|
|
30
|
+
# One pull request per month rather than one per package. The site is a
|
|
31
|
+
# static build with a committed lockfile; the review that matters is
|
|
32
|
+
# "does it still build and do the snapshots still match", which is the
|
|
33
|
+
# same review whether one package moved or twenty.
|
|
34
|
+
site:
|
|
35
|
+
patterns:
|
|
36
|
+
- "*"
|
|
37
|
+
ignore:
|
|
38
|
+
# Vite 8 replaces esbuild with Rolldown, and `esbuild.legalComments` goes
|
|
39
|
+
# with it. That option is not a preference: it is what keeps React's MIT
|
|
40
|
+
# notice inside the built assets, and a build without it ships a compiled
|
|
41
|
+
# copy of React carrying none of its terms. `tsc` catches the removed
|
|
42
|
+
# option, so the bump fails loudly rather than quietly stripping the
|
|
43
|
+
# notice — but it fails every month until someone does the migration.
|
|
44
|
+
#
|
|
45
|
+
# Held here until `vite.config.ts` has the Rolldown equivalent and a
|
|
46
|
+
# built bundle is confirmed to still carry `@license`. Minor and patch
|
|
47
|
+
# versions of Vite still come through; only the major waits.
|
|
48
|
+
- dependency-name: vite
|
|
49
|
+
update-types:
|
|
50
|
+
- version-update:semver-major
|
|
51
|
+
# Held with Vite, not on its own merits. `@vitejs/plugin-react@6` declares
|
|
52
|
+
# `peer vite@^8`, so the two majors are one migration and not two. Holding
|
|
53
|
+
# only Vite produced a lockfile that would not install at all — npm could
|
|
54
|
+
# not resolve the peer, which is a worse failure than the type error it
|
|
55
|
+
# was meant to avoid. Release this at the same time as the line above.
|
|
56
|
+
- dependency-name: "@vitejs/plugin-react"
|
|
57
|
+
update-types:
|
|
58
|
+
- version-update:semver-major
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
# Runs on push to main, on every pull request, and on demand.
|
|
4
|
+
#
|
|
5
|
+
# It was manual for most of this project's life, and the reason was cost rather
|
|
6
|
+
# than doubt: Actions minutes are billed on a private repository and the runner
|
|
7
|
+
# multipliers are not uniform — Linux 1x, Windows 2x, macOS 10x. This matrix is
|
|
8
|
+
# three operating systems by three Python versions and measured at ~104 billed
|
|
9
|
+
# minutes per push, nineteen pushes against the 2,000-minute free allowance,
|
|
10
|
+
# with macOS alone accounting for 77%. That was discovered by pushing twice and
|
|
11
|
+
# reading the bill.
|
|
12
|
+
#
|
|
13
|
+
# Publication ended that reason: Actions is free on a public repository and the
|
|
14
|
+
# matrix stops mattering. The header used to claim this had already happened
|
|
15
|
+
# while the repository was still private and the triggers were live — so it is
|
|
16
|
+
# worth saying plainly that this time it is true, and that the repository is
|
|
17
|
+
# public.
|
|
18
|
+
#
|
|
19
|
+
# The site job is why this cannot go back to being manual. `vercel.json` carries
|
|
20
|
+
# a Content-Security-Policy that a published page describes directive by
|
|
21
|
+
# directive, deployment is automatic on push, and `vercel.json` is a file a pull
|
|
22
|
+
# request can edit. With this workflow manual, nothing checked that policy
|
|
23
|
+
# before it reached production.
|
|
24
|
+
#
|
|
25
|
+
# The local equivalent is still the faster answer while you are working:
|
|
26
|
+
# python3 -W error::ResourceWarning -m unittest discover -s tests
|
|
27
|
+
# python3 examples/subjects/run_suite.py
|
|
28
|
+
|
|
29
|
+
on:
|
|
30
|
+
push:
|
|
31
|
+
branches: [main]
|
|
32
|
+
pull_request:
|
|
33
|
+
workflow_dispatch:
|
|
34
|
+
|
|
35
|
+
permissions:
|
|
36
|
+
contents: read
|
|
37
|
+
|
|
38
|
+
concurrency:
|
|
39
|
+
group: ci-${{ github.ref }}
|
|
40
|
+
cancel-in-progress: true
|
|
41
|
+
|
|
42
|
+
jobs:
|
|
43
|
+
test:
|
|
44
|
+
name: tests (${{ matrix.os }}, py${{ matrix.python-version }})
|
|
45
|
+
runs-on: ${{ matrix.os }}
|
|
46
|
+
strategy:
|
|
47
|
+
fail-fast: false
|
|
48
|
+
matrix:
|
|
49
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
50
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
51
|
+
steps:
|
|
52
|
+
- uses: actions/checkout@v7
|
|
53
|
+
|
|
54
|
+
- uses: actions/setup-python@v7
|
|
55
|
+
with:
|
|
56
|
+
python-version: ${{ matrix.python-version }}
|
|
57
|
+
|
|
58
|
+
# The MVP has no runtime dependencies on purpose. Installing nothing here
|
|
59
|
+
# is the check: if this step ever needs a package, the zero-dependency
|
|
60
|
+
# property has been lost silently.
|
|
61
|
+
- name: Confirm the core imports with no dependencies installed
|
|
62
|
+
run: python -c "import beacon; print(beacon.__version__)"
|
|
63
|
+
|
|
64
|
+
- name: Run the test suite
|
|
65
|
+
run: python -W error::ResourceWarning -m unittest discover -s tests -v
|
|
66
|
+
|
|
67
|
+
schema-conformance:
|
|
68
|
+
name: schema conformance (jsonschema installed)
|
|
69
|
+
runs-on: ubuntu-latest
|
|
70
|
+
steps:
|
|
71
|
+
- uses: actions/checkout@v7
|
|
72
|
+
|
|
73
|
+
- uses: actions/setup-python@v7
|
|
74
|
+
with:
|
|
75
|
+
python-version: "3.13"
|
|
76
|
+
|
|
77
|
+
# The suite skips full JSON Schema validation when the extra is absent,
|
|
78
|
+
# so without this job the schemas would only ever be checked by the
|
|
79
|
+
# lighter structural comparison.
|
|
80
|
+
- name: Install the validate extra
|
|
81
|
+
run: python -m pip install --upgrade pip && python -m pip install ".[validate]"
|
|
82
|
+
|
|
83
|
+
- name: Validate scenarios and emitted evidence against the schemas
|
|
84
|
+
run: python -m unittest tests.test_schema_conformance -v
|
|
85
|
+
|
|
86
|
+
vertical-slice:
|
|
87
|
+
name: vertical slice (CLI, ${{ matrix.os }})
|
|
88
|
+
runs-on: ${{ matrix.os }}
|
|
89
|
+
strategy:
|
|
90
|
+
fail-fast: false
|
|
91
|
+
matrix:
|
|
92
|
+
# Windows included deliberately: the unit tests launch subjects with
|
|
93
|
+
# sys.executable and absolute paths, so they never exercise the CLI's
|
|
94
|
+
# shlex-based --command parsing, where a backslash path would be eaten
|
|
95
|
+
# as an escape. Only this job covers that.
|
|
96
|
+
os: [ubuntu-latest, windows-latest]
|
|
97
|
+
steps:
|
|
98
|
+
- uses: actions/checkout@v7
|
|
99
|
+
|
|
100
|
+
- uses: actions/setup-python@v7
|
|
101
|
+
with:
|
|
102
|
+
python-version: "3.13"
|
|
103
|
+
|
|
104
|
+
- name: Validate the starter scenario
|
|
105
|
+
run: python -m beacon validate scenarios/inbox-briefing/scenario.json
|
|
106
|
+
|
|
107
|
+
- name: Run the in-process reference subject
|
|
108
|
+
run: python -m beacon run scenarios/inbox-briefing/scenario.json
|
|
109
|
+
|
|
110
|
+
# Single line, forward slashes: portable across bash and PowerShell.
|
|
111
|
+
- name: Run the external JSONL subject
|
|
112
|
+
run: python -m beacon run scenarios/inbox-briefing/scenario.json --adapter command --command "python examples/reference_jsonl_agent.py"
|
|
113
|
+
|
|
114
|
+
# Guards the alpha metric "100% reset-state digest equality in CI".
|
|
115
|
+
# Exits non-zero if any two runs disagree on state digests or on the
|
|
116
|
+
# per-assertion result vector.
|
|
117
|
+
- name: Verify cross-run determinism
|
|
118
|
+
run: python -m beacon run scenarios/inbox-briefing/scenario.json --repeat 5
|
|
119
|
+
|
|
120
|
+
# Beacon serves its tool surface over MCP and an MCP host drives it.
|
|
121
|
+
- name: Run an MCP host as the subject
|
|
122
|
+
run: python -m beacon run scenarios/inbox-briefing/scenario.json --adapter mcp-host --command "python examples/mcp_host_agent.py"
|
|
123
|
+
|
|
124
|
+
# Asserts Beacon reaches the right verdict for subjects it did not write.
|
|
125
|
+
- name: Run the adversarial subject suite
|
|
126
|
+
run: python examples/subjects/run_suite.py
|
|
127
|
+
|
|
128
|
+
- name: Upload evidence bundles
|
|
129
|
+
if: always()
|
|
130
|
+
uses: actions/upload-artifact@v7
|
|
131
|
+
with:
|
|
132
|
+
name: beacon-evidence
|
|
133
|
+
path: .beacon/runs/
|
|
134
|
+
if-no-files-found: warn
|
|
135
|
+
|
|
136
|
+
coverage:
|
|
137
|
+
name: coverage floor
|
|
138
|
+
runs-on: ubuntu-latest
|
|
139
|
+
steps:
|
|
140
|
+
- uses: actions/checkout@v7
|
|
141
|
+
- uses: actions/setup-python@v7
|
|
142
|
+
with:
|
|
143
|
+
python-version: "3.13"
|
|
144
|
+
- name: Install coverage
|
|
145
|
+
run: python -m pip install --upgrade pip && python -m pip install coverage
|
|
146
|
+
# A floor rather than a target. The number is not the point — noticing
|
|
147
|
+
# that a change dropped it is, and a bare report nobody reads does not
|
|
148
|
+
# do that.
|
|
149
|
+
- name: Measure and enforce
|
|
150
|
+
run: |
|
|
151
|
+
python -m coverage run --source=beacon --branch -m unittest discover -s tests
|
|
152
|
+
python -m coverage report --skip-covered
|
|
153
|
+
python -m coverage report --fail-under=80
|
|
154
|
+
|
|
155
|
+
site:
|
|
156
|
+
name: site build, screens, and the security headers
|
|
157
|
+
runs-on: ubuntu-latest
|
|
158
|
+
steps:
|
|
159
|
+
- uses: actions/checkout@v7
|
|
160
|
+
|
|
161
|
+
# Both toolchains: `fixtures:check` re-records the playground's evidence
|
|
162
|
+
# by importing beacon and running real scenarios, and `notices:check`
|
|
163
|
+
# reads the installed packages. Neither is a Node-only check despite
|
|
164
|
+
# living behind an npm script.
|
|
165
|
+
- uses: actions/setup-python@v7
|
|
166
|
+
with:
|
|
167
|
+
python-version: "3.13"
|
|
168
|
+
- uses: actions/setup-node@v7
|
|
169
|
+
with:
|
|
170
|
+
node-version: "22"
|
|
171
|
+
cache: npm
|
|
172
|
+
cache-dependency-path: site/package-lock.json
|
|
173
|
+
|
|
174
|
+
- name: Install the site's dependencies
|
|
175
|
+
working-directory: site
|
|
176
|
+
run: npm ci
|
|
177
|
+
|
|
178
|
+
# Typecheck, render every screen headless, lint the rendered output, and
|
|
179
|
+
# assert the recorded fixtures and third-party notices are current.
|
|
180
|
+
- name: Build and check
|
|
181
|
+
working-directory: site
|
|
182
|
+
run: npm run check
|
|
183
|
+
|
|
184
|
+
# The policy is the site's whole privacy claim, and until now nothing
|
|
185
|
+
# automated checked it.
|
|
186
|
+
#
|
|
187
|
+
# `/legal` names `connect-src 'none'` and `default-src 'none'` verbatim,
|
|
188
|
+
# deliberately, so the page is falsifiable rather than vague — relax the
|
|
189
|
+
# policy and the published page becomes untrue. That only helps if
|
|
190
|
+
# something notices. `vercel.json` is a file a pull request can edit, the
|
|
191
|
+
# deployment is automatic, and this check ran on one laptop.
|
|
192
|
+
#
|
|
193
|
+
# Chromium is fetched explicitly: the npm install brings the Playwright
|
|
194
|
+
# library, not a browser, and `headers.mjs` drives a real one because
|
|
195
|
+
# `vite preview` serves none of the headers under test.
|
|
196
|
+
# Three engines: Chromium drives every check here, and `tools/flow.mjs`
|
|
197
|
+
# also loads the site in Firefox and WebKit — the site leans on
|
|
198
|
+
# `prefers-color-scheme`, `content-visibility` and `oklab()` tokens, none
|
|
199
|
+
# of which behave identically everywhere, and nothing had ever loaded it
|
|
200
|
+
# outside Blink. The flow tool skips an engine it cannot launch rather
|
|
201
|
+
# than failing, so a runner without them still runs everything else.
|
|
202
|
+
- name: Install the browsers
|
|
203
|
+
working-directory: site
|
|
204
|
+
run: npx playwright install --with-deps chromium firefox webkit
|
|
205
|
+
|
|
206
|
+
- name: Assert the security headers reach the wire
|
|
207
|
+
working-directory: site
|
|
208
|
+
run: npm run headers
|
|
209
|
+
|
|
210
|
+
# These read `site/dist/`, which is generated and gitignored, so they
|
|
211
|
+
# skip everywhere it does not exist — including in the job that runs the
|
|
212
|
+
# rest of the suite. A check that skips where it matters is the shape
|
|
213
|
+
# this repository has been bitten by twice, so it runs here, in the one
|
|
214
|
+
# job that has built the thing it is about.
|
|
215
|
+
# The one thing the playground exists to do, which every other check
|
|
216
|
+
# here looks past: pick a scenario, pick an agent, read the verdict.
|
|
217
|
+
# `smoke` and `lint` call `loadAllRuns()` themselves, so they would pass
|
|
218
|
+
# whether or not the browser path that fetches the recorded runs works.
|
|
219
|
+
- name: Assert the playground reaches a verdict
|
|
220
|
+
working-directory: site
|
|
221
|
+
run: node tools/flow.mjs
|
|
222
|
+
|
|
223
|
+
- name: Assert the markdown twins say what the pages say
|
|
224
|
+
run: |
|
|
225
|
+
python3 -m unittest -v tests.test_site_markdown 2>&1 | tee /tmp/twins.log
|
|
226
|
+
if grep -q "skipped" /tmp/twins.log; then
|
|
227
|
+
echo "::error::a markdown twin check skipped in the job that builds the site"
|
|
228
|
+
exit 1
|
|
229
|
+
fi
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
name: Conformance (external targets)
|
|
2
|
+
|
|
3
|
+
# Manual only, and permanently so.
|
|
4
|
+
#
|
|
5
|
+
# This was one of two reasons once. The other was that Actions minutes are
|
|
6
|
+
# billed on a private repository, and publication ended it. This one does not
|
|
7
|
+
# expire: the sweep calls other people's running services — third-party MCP
|
|
8
|
+
# servers and hosted A2A agents that belong to strangers who did not ask to be
|
|
9
|
+
# measured. Free minutes changed what a weekly cron costs us. They changed
|
|
10
|
+
# nothing about what it costs them.
|
|
11
|
+
#
|
|
12
|
+
# There is deliberately no commented-out trigger below to restore. A `#
|
|
13
|
+
# schedule:` sitting under "uncomment when the repository is public" is an
|
|
14
|
+
# instruction, and the repository is public now; the next person to read it
|
|
15
|
+
# would be following orders rather than making a decision. Adding a trigger
|
|
16
|
+
# here should mean typing one, having read this paragraph first.
|
|
17
|
+
#
|
|
18
|
+
# `tests/test_workflow_triggers.py` asserts that this file's only trigger is
|
|
19
|
+
# `workflow_dispatch`, and that no commented-out one reappears.
|
|
20
|
+
|
|
21
|
+
on:
|
|
22
|
+
workflow_dispatch:
|
|
23
|
+
|
|
24
|
+
permissions:
|
|
25
|
+
contents: read
|
|
26
|
+
|
|
27
|
+
jobs:
|
|
28
|
+
mcp-servers:
|
|
29
|
+
name: Beacon's MCP client vs third-party servers
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
steps:
|
|
32
|
+
- uses: actions/checkout@v7
|
|
33
|
+
- uses: actions/setup-python@v7
|
|
34
|
+
with:
|
|
35
|
+
python-version: "3.13"
|
|
36
|
+
- uses: actions/setup-node@v7
|
|
37
|
+
with:
|
|
38
|
+
node-version: "22"
|
|
39
|
+
- name: Install uv (for the Python MCP servers)
|
|
40
|
+
run: curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
41
|
+
|
|
42
|
+
- name: Sweep
|
|
43
|
+
run: |
|
|
44
|
+
export PATH="$HOME/.local/bin:$PATH"
|
|
45
|
+
python conformance/run_mcp_sweep.py --timeout 180 --json-out sweep.json
|
|
46
|
+
|
|
47
|
+
- uses: actions/upload-artifact@v7
|
|
48
|
+
if: always()
|
|
49
|
+
with:
|
|
50
|
+
name: mcp-conformance
|
|
51
|
+
path: sweep.json
|
|
52
|
+
|
|
53
|
+
official-sdk:
|
|
54
|
+
name: Official MCP SDK vs Beacon's facade
|
|
55
|
+
runs-on: ubuntu-latest
|
|
56
|
+
steps:
|
|
57
|
+
- uses: actions/checkout@v7
|
|
58
|
+
- uses: actions/setup-python@v7
|
|
59
|
+
with:
|
|
60
|
+
python-version: "3.13"
|
|
61
|
+
|
|
62
|
+
# The reference implementation of the protocol, driving Beacon's server.
|
|
63
|
+
# Without this the facade is only ever exercised by a client this repo
|
|
64
|
+
# also wrote, which proves that Beacon agrees with Beacon.
|
|
65
|
+
- name: Install the official MCP SDK
|
|
66
|
+
run: python -m pip install --upgrade pip && python -m pip install mcp
|
|
67
|
+
|
|
68
|
+
- name: Run the scenario through the official SDK
|
|
69
|
+
run: |
|
|
70
|
+
python -m beacon run scenarios/inbox-briefing/scenario.json \
|
|
71
|
+
--adapter mcp-host \
|
|
72
|
+
--command "python conformance/official_sdk_client.py"
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
name: release
|
|
2
|
+
|
|
3
|
+
# Started by hand, plus one automatic path: pushing a `v*` tag publishes.
|
|
4
|
+
#
|
|
5
|
+
# It was manual-only while the repository was private, for a reason beyond the
|
|
6
|
+
# billed minutes — publishing to PyPI from a repository nobody can read would
|
|
7
|
+
# put a package on the index whose source is not there to check. Publication
|
|
8
|
+
# settled both.
|
|
9
|
+
#
|
|
10
|
+
# The tag filter is the whole safety property here, and it is the reason this
|
|
11
|
+
# is `tags:` rather than `branches:`. A push trigger on a branch would build
|
|
12
|
+
# every commit on main inside a job that holds a PyPI id-token, and the
|
|
13
|
+
# publish gate below would not stop the build from happening — it would only
|
|
14
|
+
# stop the upload. `tests/test_workflow_triggers.py` asserts the filter stays.
|
|
15
|
+
|
|
16
|
+
on:
|
|
17
|
+
workflow_dispatch:
|
|
18
|
+
inputs:
|
|
19
|
+
publish:
|
|
20
|
+
description: "Publish to PyPI (otherwise build and check only)"
|
|
21
|
+
type: boolean
|
|
22
|
+
default: false
|
|
23
|
+
push:
|
|
24
|
+
tags:
|
|
25
|
+
- "v*"
|
|
26
|
+
|
|
27
|
+
permissions:
|
|
28
|
+
contents: read
|
|
29
|
+
|
|
30
|
+
jobs:
|
|
31
|
+
build:
|
|
32
|
+
name: build and verify the distribution
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v7
|
|
36
|
+
|
|
37
|
+
- uses: actions/setup-python@v7
|
|
38
|
+
with:
|
|
39
|
+
python-version: "3.13"
|
|
40
|
+
|
|
41
|
+
- name: Install build tooling
|
|
42
|
+
run: python -m pip install --upgrade pip build twine
|
|
43
|
+
|
|
44
|
+
- name: Build sdist and wheel
|
|
45
|
+
run: python -m build
|
|
46
|
+
|
|
47
|
+
- name: Check the metadata PyPI will render
|
|
48
|
+
run: python -m twine check --strict dist/*
|
|
49
|
+
|
|
50
|
+
- name: The version must match the tag
|
|
51
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
52
|
+
run: |
|
|
53
|
+
python - <<'PY'
|
|
54
|
+
import os, pathlib, re, sys
|
|
55
|
+
tag = os.environ["GITHUB_REF_NAME"].lstrip("v")
|
|
56
|
+
text = pathlib.Path("pyproject.toml").read_text()
|
|
57
|
+
version = re.search(r'^version = "([^"]+)"', text, re.M).group(1)
|
|
58
|
+
if version != tag:
|
|
59
|
+
sys.exit(f"tag {tag} does not match pyproject version {version}")
|
|
60
|
+
print(f"tag and version agree: {version}")
|
|
61
|
+
PY
|
|
62
|
+
|
|
63
|
+
# A wheel that imports is not a wheel that works. This installs it
|
|
64
|
+
# somewhere with no source tree and exercises the paths a new user
|
|
65
|
+
# actually takes, which is how the missing scenarios were found.
|
|
66
|
+
- name: Install the wheel into a clean environment and use it
|
|
67
|
+
run: |
|
|
68
|
+
python -m venv /tmp/fresh
|
|
69
|
+
/tmp/fresh/bin/pip install --quiet dist/*.whl
|
|
70
|
+
mkdir -p /tmp/elsewhere && cd /tmp/elsewhere
|
|
71
|
+
/tmp/fresh/bin/project-beacon --version
|
|
72
|
+
/tmp/fresh/bin/project-beacon scenarios
|
|
73
|
+
/tmp/fresh/bin/project-beacon validate inbox-briefing
|
|
74
|
+
/tmp/fresh/bin/project-beacon run inbox-briefing
|
|
75
|
+
/tmp/fresh/bin/project-beacon init smoke-probe
|
|
76
|
+
/tmp/fresh/bin/project-beacon run scenarios/smoke-probe/scenario.json \
|
|
77
|
+
--adapter command \
|
|
78
|
+
--command "/tmp/fresh/bin/python scenarios/smoke-probe/subjects/compliant.py"
|
|
79
|
+
|
|
80
|
+
# The step above only ever touched the subset of the CLI that needs no
|
|
81
|
+
# data files, so it stayed green for weeks while the sdist shipped
|
|
82
|
+
# without examples/, docs/, schemas/ or tests/stubs/ — and the suite it
|
|
83
|
+
# did ship could not run. Unpacking the sdist and running that suite is
|
|
84
|
+
# the check that would have caught it.
|
|
85
|
+
- name: Run the shipped test suite out of the sdist
|
|
86
|
+
run: |
|
|
87
|
+
mkdir -p /tmp/sdist && tar xzf dist/*.tar.gz -C /tmp/sdist
|
|
88
|
+
cd /tmp/sdist/project_beacon-*
|
|
89
|
+
python -W error::ResourceWarning -m unittest discover -s tests
|
|
90
|
+
python examples/subjects/run_suite.py
|
|
91
|
+
|
|
92
|
+
- uses: actions/upload-artifact@v7
|
|
93
|
+
with:
|
|
94
|
+
name: distribution
|
|
95
|
+
path: dist/
|
|
96
|
+
|
|
97
|
+
publish:
|
|
98
|
+
name: publish to PyPI
|
|
99
|
+
needs: build
|
|
100
|
+
if: startsWith(github.ref, 'refs/tags/v') || inputs.publish
|
|
101
|
+
runs-on: ubuntu-latest
|
|
102
|
+
environment:
|
|
103
|
+
name: pypi
|
|
104
|
+
url: https://pypi.org/p/project-beacon
|
|
105
|
+
permissions:
|
|
106
|
+
# Trusted publishing: PyPI verifies this workflow's identity directly,
|
|
107
|
+
# so there is no long-lived API token in the repository to leak.
|
|
108
|
+
id-token: write
|
|
109
|
+
steps:
|
|
110
|
+
- uses: actions/download-artifact@v8
|
|
111
|
+
with:
|
|
112
|
+
name: distribution
|
|
113
|
+
path: dist/
|
|
114
|
+
|
|
115
|
+
# Pinned to a commit, not to `release/v1`, which is a branch: a moving
|
|
116
|
+
# ref on the only third-party action in this repository, running in the
|
|
117
|
+
# one job that holds an id-token PyPI will accept. Whoever can move that
|
|
118
|
+
# branch can publish as this project. Update deliberately — the comment
|
|
119
|
+
# is the version, because the SHA is not readable.
|
|
120
|
+
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
|