xrefkit 0.4.16__tar.gz → 0.5.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.
- {xrefkit-0.4.16/xrefkit.egg-info → xrefkit-0.5.0}/PKG-INFO +27 -12
- {xrefkit-0.4.16 → xrefkit-0.5.0}/README.md +26 -11
- {xrefkit-0.4.16 → xrefkit-0.5.0}/pyproject.toml +1 -1
- xrefkit-0.5.0/tests/test_artifact_selected_family.py +46 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_boundary_analysis.py +42 -1
- xrefkit-0.5.0/tests/test_brownfield_csharp_structure_definitions.py +44 -0
- xrefkit-0.5.0/tests/test_business_intake_conversation_definitions.py +46 -0
- xrefkit-0.5.0/tests/test_business_intake_definition.py +55 -0
- xrefkit-0.5.0/tests/test_catalog_preparation_definition.py +47 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_cli.py +9 -1
- xrefkit-0.5.0/tests/test_code_constraint_definition.py +47 -0
- xrefkit-0.5.0/tests/test_constraint_derivation_family_definition.py +68 -0
- xrefkit-0.5.0/tests/test_constraint_derivation_selected_family.py +44 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_contribution_returns.py +1 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_dashboard.py +68 -0
- xrefkit-0.5.0/tests/test_database_batch_definition_migration.py +90 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_decision_trace.py +28 -0
- xrefkit-0.5.0/tests/test_design_business_intake_selected_family.py +36 -0
- xrefkit-0.5.0/tests/test_design_planning_definition_migration.py +72 -0
- xrefkit-0.5.0/tests/test_dotnet_definition_candidate.py +103 -0
- xrefkit-0.5.0/tests/test_editorial_family_definition.py +58 -0
- xrefkit-0.5.0/tests/test_editorial_intake_definition.py +28 -0
- xrefkit-0.5.0/tests/test_editorial_selected_family.py +42 -0
- xrefkit-0.5.0/tests/test_execution_binding.py +198 -0
- xrefkit-0.5.0/tests/test_existing_skill_definition_batch.py +27 -0
- xrefkit-0.5.0/tests/test_final_skilldefinition_batch.py +54 -0
- xrefkit-0.5.0/tests/test_flow_selected_family.py +44 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_gateway.py +45 -0
- xrefkit-0.5.0/tests/test_gateway_mcp.py +236 -0
- xrefkit-0.5.0/tests/test_gateway_skill_adapter.py +342 -0
- xrefkit-0.5.0/tests/test_gateway_work_items.py +542 -0
- xrefkit-0.5.0/tests/test_implementation_flow_definition.py +75 -0
- xrefkit-0.5.0/tests/test_implementation_review_selected_family.py +36 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_instruction_workflow.py +5 -0
- xrefkit-0.5.0/tests/test_language_review_definition.py +58 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_mcp_package_routing.py +79 -0
- xrefkit-0.5.0/tests/test_mcp_subagent_startup.py +452 -0
- xrefkit-0.5.0/tests/test_mcp_subagent_startup_integration.py +170 -0
- xrefkit-0.5.0/tests/test_os_family_definition.py +65 -0
- xrefkit-0.5.0/tests/test_os_knowledge_family_definition.py +54 -0
- xrefkit-0.5.0/tests/test_os_selected_family.py +45 -0
- xrefkit-0.5.0/tests/test_qa_report_definition.py +51 -0
- xrefkit-0.5.0/tests/test_security_definition_migration.py +37 -0
- xrefkit-0.5.0/tests/test_skill_definition.py +157 -0
- xrefkit-0.5.0/tests/test_skill_definition_governance.py +121 -0
- xrefkit-0.5.0/tests/test_skill_definition_mcp.py +262 -0
- xrefkit-0.5.0/tests/test_skill_definition_runtime.py +193 -0
- xrefkit-0.5.0/tests/test_subagent_startup.py +154 -0
- xrefkit-0.5.0/tests/test_subagent_startup_boundaries.py +153 -0
- xrefkit-0.5.0/tests/test_workflow_family_definition.py +60 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_xrefkit_v2_pipeline.py +15 -6
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/__init__.py +1 -1
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/boundary_analysis.py +111 -60
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/dashboard.py +57 -0
- xrefkit-0.5.0/xrefkit/execution_binding.py +205 -0
- xrefkit-0.5.0/xrefkit/execution_binding_cli.py +20 -0
- xrefkit-0.5.0/xrefkit/gateway.py +1733 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/mcp/catalog.py +382 -31
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/mcp/cli.py +14 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/mcp/contracts.py +8 -0
- xrefkit-0.5.0/xrefkit/mcp/gateway.py +169 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/mcp/schemas.py +10 -6
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/mcp/server.py +183 -23
- xrefkit-0.5.0/xrefkit/mcp/startup_contract_pack.py +120 -0
- xrefkit-0.5.0/xrefkit/mcp/subagent_startup.py +316 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/operations_cli.py +55 -1
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/resources/base/startup_sources/011_startup_xref_routing.md +5 -3
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/resources/base/startup_sources/017_base_and_xref_layering.md +3 -1
- xrefkit-0.5.0/xrefkit/skill_definition.py +260 -0
- xrefkit-0.5.0/xrefkit/skill_definition_catalog.py +91 -0
- xrefkit-0.5.0/xrefkit/skill_definition_governance.py +133 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/skillrun.py +105 -16
- xrefkit-0.5.0/xrefkit/subagent_startup.py +166 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0/xrefkit.egg-info}/PKG-INFO +27 -12
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit.egg-info/SOURCES.txt +45 -1
- xrefkit-0.4.16/tests/test_base_sync_ownership.py +0 -123
- xrefkit-0.4.16/tests/test_gateway_mcp.py +0 -116
- xrefkit-0.4.16/xrefkit/gateway.py +0 -450
- xrefkit-0.4.16/xrefkit/mcp/gateway.py +0 -98
- xrefkit-0.4.16/xrefkit/mcp/startup_contract_pack.py +0 -170
- {xrefkit-0.4.16 → xrefkit-0.5.0}/LICENSE +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/setup.cfg +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_brownfield_file_editing_protocol.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_calibration_lint.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_check_skill_knowledge_xids.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_collect_analyzer_sarif.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_convert_to_xrefkit_skill.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_cs_scope_probe.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_csharp_commonality.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_csharp_naming_profile.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_ctx.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_cutover_readiness.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_error_policy_audit.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_error_policy_locator.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_fm_multiroot.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_gate.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_goal_desired_state.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_host_precheck.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_human_evaluation.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_inbound_uploads.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_knowledge_relations_validator.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_mcp_setup.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_ownership.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_packmeta.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_project_quality_baseline.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_resource_provider.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_runtime_contracts.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_sarif_to_locator.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_skill_edits.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_skill_maturity_return.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_skill_runtime_audit.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_skillmeta.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_skills_sync.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_structure_catalog.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_wbs.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_xref.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_xrefkit_instance.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_xrefkit_tools.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_xrefkit_v2_discovery.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/tests/test_xrefkit_v2_models.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/__main__.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/catalog_cli.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/cli.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/contracts.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/ctx.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/decision_trace.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/discovery.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/gate.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/goalstate.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/hashing.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/host_precheck.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/import_skill.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/instance.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/loaders.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/mcp/__init__.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/mcp/audit.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/mcp/bootstrap.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/mcp/client_cache.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/mcp/client_flow.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/mcp/context_registry.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/mcp/context_token.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/mcp/contribution_adoption.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/mcp/contribution_returns.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/mcp/dist.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/mcp/inbound_uploads.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/mcp/knowledge_edits.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/mcp/ownership.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/mcp/repository.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/mcp/setup.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/mcp/skill_edits.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/mcp/skill_maturity.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/mcp_tools.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/models/__init__.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/models/common.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/models/effective_bundle.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/models/human_evaluation.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/models/local_manifest.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/models/package_manifest.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/models/run_log.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/models/server_config.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/models/skill_definition.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/ownership.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/packmeta.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/registry.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/resolver.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/resource_provider.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/resources/base/contracts.json +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/resources/base/current.json +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/resources/base/generations/7a682a5272907354/contracts.json +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/resources/base/generations/7a682a5272907354/model_body.md +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/resources/base/generations/9929294385ccb7b0/contracts.json +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/resources/base/generations/9929294385ccb7b0/model_body.md +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/resources/base/model_body.md +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/resources/base/startup_sources/000_agent_entry.md +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/resources/base/startup_sources/015_shared_memory_operations.md +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/resources/base/startup_sources/016_uncertainty_protocol.md +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/resources/base/startup_sources/053_context_direction_security_guard.md +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/runlog.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/skillmeta.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/skills_sync.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/structure_catalog.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/tools/__init__.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/tools/__main__.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/v2_cli.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/wbs.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/workspace.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit/xref.py +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit.egg-info/dependency_links.txt +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit.egg-info/entry_points.txt +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit.egg-info/requires.txt +0 -0
- {xrefkit-0.4.16 → xrefkit-0.5.0}/xrefkit.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: xrefkit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Portable XID, Skill, Knowledge, workflow, and MCP runtime for XRefKit
|
|
5
5
|
Author: synthaicode
|
|
6
6
|
License: MIT License
|
|
@@ -42,8 +42,8 @@ Dynamic: license-file
|
|
|
42
42
|
XRefKit is a framework for making AI-assisted work repeatable, reviewable, and
|
|
43
43
|
handoff-ready.
|
|
44
44
|
|
|
45
|
-
It helps teams
|
|
46
|
-
|
|
45
|
+
It helps teams structure domain procedures and knowledge so that work can
|
|
46
|
+
record evidence, preserve human judgment, and apply explicit completion checks.
|
|
47
47
|
|
|
48
48
|
## Why XRefKit?
|
|
49
49
|
|
|
@@ -61,24 +61,34 @@ XRefKit provides a repository and runtime model for addressing these problems.
|
|
|
61
61
|
|
|
62
62
|
## What it provides
|
|
63
63
|
|
|
64
|
-
- **Skills** — reusable procedures
|
|
65
|
-
- **Knowledge** — source-backed domain facts and local rules
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
- **Skills** — reusable procedures expressed as SkillDefinitions
|
|
65
|
+
- **Knowledge** — source-backed domain facts and local rules resolved by XID
|
|
66
|
+
when a Skill run needs them
|
|
67
|
+
- **Workflow protocol** — recorded progress, deterministic workflow-record
|
|
68
|
+
verification, and closure checks
|
|
68
69
|
- **Evidence and handoffs** — outputs, judgments, concerns, and decisions that
|
|
69
70
|
remain reviewable after the work is done
|
|
70
|
-
- **Skill Run Dashboard** — inspect Skill execution
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
- **Skill Run Dashboard** — inspect recorded Skill execution state, definition
|
|
72
|
+
identity, runtime binding, referenced XIDs, evidence, judgments, concerns,
|
|
73
|
+
and handoffs
|
|
73
74
|
- **XIDs** — stable references for connecting procedures, knowledge, and
|
|
74
75
|
supporting documents
|
|
75
76
|
|
|
76
77
|
The package includes the resolver, Skill runtime, workflow controls, client
|
|
77
78
|
tools, and an optional MCP adapter.
|
|
78
79
|
|
|
80
|
+
Current Skill authoring targets the one-document `skill_definition_v1` format.
|
|
81
|
+
Existing `legacy_split_v1` Skills and unversioned historical run logs remain
|
|
82
|
+
readable during migration. The [Workflow Runtime Binding](docs/core/contracts/111_workflow_runtime_binding.md#xid-8D50A972BA9F)
|
|
83
|
+
defines how instruction-derived `capability`, `tuning`, `responsibility`, and
|
|
84
|
+
`execution_mode` are captured; these are not fixed SkillDefinition properties.
|
|
85
|
+
Knowledge used by a Skill remains separate and is resolved from the XID catalog
|
|
86
|
+
when needed.
|
|
87
|
+
|
|
79
88
|
The [Skill Run Dashboard](docs/guides/086_skill_run_observation_dashboard_usage.md#xid-4A4763A2DE63)
|
|
80
|
-
helps people
|
|
81
|
-
evidence before
|
|
89
|
+
helps people inspect recorded XID retrieval and use together with the run's
|
|
90
|
+
evidence before a human accepts or hands off the result. The Dashboard reports
|
|
91
|
+
recorded state and missing observations; it does not accept output quality.
|
|
82
92
|
|
|
83
93
|
## Quick start
|
|
84
94
|
|
|
@@ -104,12 +114,17 @@ python -m pip install "xrefkit[mcp]"
|
|
|
104
114
|
xrefkit mcp serve --repo . --transport stdio
|
|
105
115
|
```
|
|
106
116
|
|
|
117
|
+
This command starts the optional catalog and runtime MCP adapter. This checkout
|
|
118
|
+
does not implement management upload, staging, sealing, review, or adoption of
|
|
119
|
+
uploaded SkillDefinition bytes into the active catalog.
|
|
120
|
+
|
|
107
121
|
## Where to go next
|
|
108
122
|
|
|
109
123
|
- [Install XRefKit and register Skill Packages](docs/guides/089_xrefkit_package_first_registration.md#xid-4F8C2A7D1E90)
|
|
110
124
|
- [Understand the workflow protocol](docs/guides/087_workflow_protocol_sequence_for_humans.md#xid-E8B4D2F19A63)
|
|
111
125
|
- [Use an instruction-backed workflow](docs/guides/088_instruction_workflow_protocol.md#xid-9F4C2A7D1B60)
|
|
112
126
|
- [Understand Skills and Knowledge](docs/core/models/052_flow_capability_skill_knowledge_model.md#xid-91C4B7E2D5A8)
|
|
127
|
+
- [Read the SkillDefinition v1 contract](docs/core/contracts/096_skill_definition_contract.md#xid-E6A19D4B72C3)
|
|
113
128
|
- [Author a Skill with xref](docs/guides/013_skill_authoring_with_xref.md#xid-3DB05A0F5F5B)
|
|
114
129
|
- [Browse the complete documentation index](docs/000_index.md#xid-56DD6EB68343)
|
|
115
130
|
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
XRefKit is a framework for making AI-assisted work repeatable, reviewable, and
|
|
4
4
|
handoff-ready.
|
|
5
5
|
|
|
6
|
-
It helps teams
|
|
7
|
-
|
|
6
|
+
It helps teams structure domain procedures and knowledge so that work can
|
|
7
|
+
record evidence, preserve human judgment, and apply explicit completion checks.
|
|
8
8
|
|
|
9
9
|
## Why XRefKit?
|
|
10
10
|
|
|
@@ -22,24 +22,34 @@ XRefKit provides a repository and runtime model for addressing these problems.
|
|
|
22
22
|
|
|
23
23
|
## What it provides
|
|
24
24
|
|
|
25
|
-
- **Skills** — reusable procedures
|
|
26
|
-
- **Knowledge** — source-backed domain facts and local rules
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
- **Skills** — reusable procedures expressed as SkillDefinitions
|
|
26
|
+
- **Knowledge** — source-backed domain facts and local rules resolved by XID
|
|
27
|
+
when a Skill run needs them
|
|
28
|
+
- **Workflow protocol** — recorded progress, deterministic workflow-record
|
|
29
|
+
verification, and closure checks
|
|
29
30
|
- **Evidence and handoffs** — outputs, judgments, concerns, and decisions that
|
|
30
31
|
remain reviewable after the work is done
|
|
31
|
-
- **Skill Run Dashboard** — inspect Skill execution
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
- **Skill Run Dashboard** — inspect recorded Skill execution state, definition
|
|
33
|
+
identity, runtime binding, referenced XIDs, evidence, judgments, concerns,
|
|
34
|
+
and handoffs
|
|
34
35
|
- **XIDs** — stable references for connecting procedures, knowledge, and
|
|
35
36
|
supporting documents
|
|
36
37
|
|
|
37
38
|
The package includes the resolver, Skill runtime, workflow controls, client
|
|
38
39
|
tools, and an optional MCP adapter.
|
|
39
40
|
|
|
41
|
+
Current Skill authoring targets the one-document `skill_definition_v1` format.
|
|
42
|
+
Existing `legacy_split_v1` Skills and unversioned historical run logs remain
|
|
43
|
+
readable during migration. The [Workflow Runtime Binding](docs/core/contracts/111_workflow_runtime_binding.md#xid-8D50A972BA9F)
|
|
44
|
+
defines how instruction-derived `capability`, `tuning`, `responsibility`, and
|
|
45
|
+
`execution_mode` are captured; these are not fixed SkillDefinition properties.
|
|
46
|
+
Knowledge used by a Skill remains separate and is resolved from the XID catalog
|
|
47
|
+
when needed.
|
|
48
|
+
|
|
40
49
|
The [Skill Run Dashboard](docs/guides/086_skill_run_observation_dashboard_usage.md#xid-4A4763A2DE63)
|
|
41
|
-
helps people
|
|
42
|
-
evidence before
|
|
50
|
+
helps people inspect recorded XID retrieval and use together with the run's
|
|
51
|
+
evidence before a human accepts or hands off the result. The Dashboard reports
|
|
52
|
+
recorded state and missing observations; it does not accept output quality.
|
|
43
53
|
|
|
44
54
|
## Quick start
|
|
45
55
|
|
|
@@ -65,12 +75,17 @@ python -m pip install "xrefkit[mcp]"
|
|
|
65
75
|
xrefkit mcp serve --repo . --transport stdio
|
|
66
76
|
```
|
|
67
77
|
|
|
78
|
+
This command starts the optional catalog and runtime MCP adapter. This checkout
|
|
79
|
+
does not implement management upload, staging, sealing, review, or adoption of
|
|
80
|
+
uploaded SkillDefinition bytes into the active catalog.
|
|
81
|
+
|
|
68
82
|
## Where to go next
|
|
69
83
|
|
|
70
84
|
- [Install XRefKit and register Skill Packages](docs/guides/089_xrefkit_package_first_registration.md#xid-4F8C2A7D1E90)
|
|
71
85
|
- [Understand the workflow protocol](docs/guides/087_workflow_protocol_sequence_for_humans.md#xid-E8B4D2F19A63)
|
|
72
86
|
- [Use an instruction-backed workflow](docs/guides/088_instruction_workflow_protocol.md#xid-9F4C2A7D1B60)
|
|
73
87
|
- [Understand Skills and Knowledge](docs/core/models/052_flow_capability_skill_knowledge_model.md#xid-91C4B7E2D5A8)
|
|
88
|
+
- [Read the SkillDefinition v1 contract](docs/core/contracts/096_skill_definition_contract.md#xid-E6A19D4B72C3)
|
|
74
89
|
- [Author a Skill with xref](docs/guides/013_skill_authoring_with_xref.md#xid-3DB05A0F5F5B)
|
|
75
90
|
- [Browse the complete documentation index](docs/000_index.md#xid-56DD6EB68343)
|
|
76
91
|
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from xrefkit.mcp.catalog import XRefCatalog
|
|
6
|
+
from xrefkit.skill_definition import load_skill_definition
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
CASES = [
|
|
10
|
+
("xlsx_spec_traceability", "xlsx_spec_traceability", "A7C3E9D2F610", "2D1B6A9E7C40", "5A7C2D4E9130"),
|
|
11
|
+
("marketing-explainer-video", "marketing_explainer_video", "B8F1A6C4D720", "5E147B19D33D", "A6B923E41178"),
|
|
12
|
+
("marketing_slide_png", "marketing_slide_png", "C2E7B9F5A130", "91B67D4AC2F3", "5E2C4A90D711"),
|
|
13
|
+
("import_skill", "import_skill", "D5A8C1E6B740", "7C2A492D2B72", "1DF4555E1B02"),
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@pytest.mark.parametrize("directory,skill_id,xid,body_xid,meta_xid", CASES)
|
|
18
|
+
def test_artifact_v1_parse_concrete_metadata_and_legacy(directory, skill_id, xid, body_xid, meta_xid):
|
|
19
|
+
repo = Path(__file__).resolve().parents[1]
|
|
20
|
+
relative = Path(f"skills/{directory}/SKILL.v1.md")
|
|
21
|
+
definition = load_skill_definition(repo / relative)
|
|
22
|
+
metadata = definition["metadata"]
|
|
23
|
+
assert metadata["skill_id"] == skill_id
|
|
24
|
+
assert metadata["xid"] == xid
|
|
25
|
+
assert set(metadata["aliases"]) == {body_xid, meta_xid}
|
|
26
|
+
assert metadata["inputs"] and metadata["outputs"]
|
|
27
|
+
assert metadata["control_refs"] == []
|
|
28
|
+
assert "CAP-" not in definition["method"]
|
|
29
|
+
assert "## Reporting Contract" not in definition["method"]
|
|
30
|
+
assert "skill_doc: `./SKILL.md`" in (repo / relative.parent / "meta.md").read_text()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_artifact_v1_explicit_batch_selection_and_knowledge_resolution():
|
|
34
|
+
repo = Path(__file__).resolve().parents[1]
|
|
35
|
+
paths = [Path(f"skills/{directory}/SKILL.v1.md") for directory, *_ in CASES]
|
|
36
|
+
catalog = XRefCatalog.build(repo, skill_definition_paths=paths)
|
|
37
|
+
ids = {case[1] for case in CASES}
|
|
38
|
+
entries = {entry.skill_id: entry for entry in catalog.skills if entry.skill_id in ids}
|
|
39
|
+
assert set(entries) == ids
|
|
40
|
+
assert all(entry.definition_format == "skill_definition_v1" for entry in entries.values())
|
|
41
|
+
for directory, skill_id, *_ in CASES:
|
|
42
|
+
definition = load_skill_definition(repo / f"skills/{directory}/SKILL.v1.md")
|
|
43
|
+
need_ids = [need["id"] for need in definition["metadata"]["knowledge_needs"]]
|
|
44
|
+
result = catalog.resolve_skill_knowledge(skill_id, need_ids)
|
|
45
|
+
assert result["unresolved_activation"] == []
|
|
46
|
+
assert result["unsatisfied_required"] == []
|
|
@@ -17,8 +17,9 @@ class BoundaryAnalysisTests(unittest.TestCase):
|
|
|
17
17
|
xids: list[str],
|
|
18
18
|
*,
|
|
19
19
|
feedback: list[dict[str, str]] | None = None,
|
|
20
|
+
**context: str,
|
|
20
21
|
) -> dict[str, object]:
|
|
21
|
-
|
|
22
|
+
run: dict[str, object] = {
|
|
22
23
|
"path": path,
|
|
23
24
|
"name": Path(path).name,
|
|
24
25
|
"skill_id": skill_id,
|
|
@@ -41,6 +42,8 @@ class BoundaryAnalysisTests(unittest.TestCase):
|
|
|
41
42
|
"observation_events": feedback or [],
|
|
42
43
|
"mcp_events": [],
|
|
43
44
|
}
|
|
45
|
+
run.update(context)
|
|
46
|
+
return run
|
|
44
47
|
|
|
45
48
|
def _payload(self) -> dict[str, object]:
|
|
46
49
|
xid_a = "XID-A-001"
|
|
@@ -92,6 +95,44 @@ class BoundaryAnalysisTests(unittest.TestCase):
|
|
|
92
95
|
self.assertEqual(4, xid_row["run_count"])
|
|
93
96
|
self.assertEqual(4, xid_row["used_count"])
|
|
94
97
|
|
|
98
|
+
def test_analysis_does_not_combine_distinct_definition_bindings(self) -> None:
|
|
99
|
+
feedback = [{"event": "human.feedback", "status": "corrected", "target": "OUT-001"}]
|
|
100
|
+
runs = [
|
|
101
|
+
self._run(
|
|
102
|
+
"alpha", f"a-{index}.md", ["XID-A"], feedback=feedback if index == 1 else [],
|
|
103
|
+
definition_format="skill_definition_v1", definition_xid="DEF-A", definition_sha256="sha-a",
|
|
104
|
+
capability="analysis", tuning="bounded", responsibility="report", execution_mode="subagent_required",
|
|
105
|
+
)
|
|
106
|
+
for index in (1, 2)
|
|
107
|
+
] + [
|
|
108
|
+
self._run(
|
|
109
|
+
"alpha", f"b-{index}.md", ["XID-B"], feedback=feedback if index == 1 else [],
|
|
110
|
+
definition_format="skill_definition_v1", definition_xid="DEF-A", definition_sha256="sha-b",
|
|
111
|
+
capability="analysis", tuning="deep", responsibility="report", execution_mode="subagent_required",
|
|
112
|
+
)
|
|
113
|
+
for index in (1, 2)
|
|
114
|
+
]
|
|
115
|
+
|
|
116
|
+
report = analyze_dashboard_payload({"runs": runs}, min_samples=2)
|
|
117
|
+
categories = {item["category"] for item in report["proposals"]}
|
|
118
|
+
|
|
119
|
+
self.assertNotIn("split", categories)
|
|
120
|
+
self.assertNotIn("skill_correction", categories)
|
|
121
|
+
|
|
122
|
+
def test_merge_requires_samples_under_the_same_runtime_binding(self) -> None:
|
|
123
|
+
runs = [
|
|
124
|
+
self._run(
|
|
125
|
+
skill, f"{skill}-{index}.md", ["XID-A"],
|
|
126
|
+
capability="analysis", tuning=tuning, responsibility="report", execution_mode="subagent_required",
|
|
127
|
+
)
|
|
128
|
+
for skill, tuning in (("alpha", "bounded"), ("beta", "deep"))
|
|
129
|
+
for index in (1, 2)
|
|
130
|
+
]
|
|
131
|
+
|
|
132
|
+
report = analyze_dashboard_payload({"runs": runs}, min_samples=2)
|
|
133
|
+
|
|
134
|
+
self.assertNotIn("merge", {item["category"] for item in report["proposals"]})
|
|
135
|
+
|
|
95
136
|
def test_markdown_explains_proposal_only_boundary(self) -> None:
|
|
96
137
|
markdown = render_markdown(analyze_dashboard_payload(self._payload(), source_hash="source-001"))
|
|
97
138
|
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from xrefkit.mcp.catalog import XRefCatalog
|
|
4
|
+
from xrefkit.skill_definition import load_skill_definition
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
CASES = {
|
|
8
|
+
"brownfield-workflow": ("brownfield_workflow", "E1A7C4D9B260", "A17C4E8B2D91", "9B3D7A1C4E20"),
|
|
9
|
+
"csharp_error_policy_extraction": ("csharp_error_policy_extraction", "F2B8D5A1C370", "FE342FB520D0", "B150A2A54169"),
|
|
10
|
+
"source_structure_overview": ("source_structure_overview", "A6E3C9F2B470", "423C8B8F8AD0", "907B100F9F9D"),
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_tracked_trio_parse_aliases_metadata_and_legacy_readability():
|
|
15
|
+
repo = Path(__file__).resolve().parents[1]
|
|
16
|
+
for directory, (skill_id, xid, body_xid, meta_xid) in CASES.items():
|
|
17
|
+
path = repo / "skills" / directory / "SKILL.v1.md"
|
|
18
|
+
definition = load_skill_definition(path)
|
|
19
|
+
metadata = definition["metadata"]
|
|
20
|
+
assert metadata["skill_id"] == skill_id
|
|
21
|
+
assert metadata["xid"] == xid
|
|
22
|
+
assert set(metadata["aliases"]) == {body_xid, meta_xid}
|
|
23
|
+
assert metadata["control_refs"] == []
|
|
24
|
+
for forbidden in ("capability", "tuning", "responsibility", "execution_mode", "model", "maturity"):
|
|
25
|
+
assert forbidden not in metadata
|
|
26
|
+
for common in ("## Reporting Contract", "## Logging", "## Context Direction Guard"):
|
|
27
|
+
assert common not in definition["method"]
|
|
28
|
+
assert f"<!-- xid: {body_xid} -->" in (repo / "skills" / directory / "SKILL.md").read_text(encoding="utf-8")
|
|
29
|
+
assert f"<!-- xid: {meta_xid} -->" in (repo / "skills" / directory / "meta.md").read_text(encoding="utf-8")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_tracked_trio_combined_catalog_and_knowledge_resolution():
|
|
33
|
+
repo = Path(__file__).resolve().parents[1]
|
|
34
|
+
paths = [repo / "skills" / directory / "SKILL.v1.md" for directory in CASES]
|
|
35
|
+
catalog = XRefCatalog.build(repo, skill_definition_paths=paths)
|
|
36
|
+
entries = {entry.skill_id: entry for entry in catalog.skills if entry.skill_id in {case[0] for case in CASES.values()}}
|
|
37
|
+
assert set(entries) == {case[0] for case in CASES.values()}
|
|
38
|
+
assert all(entry.definition_format == "skill_definition_v1" for entry in entries.values())
|
|
39
|
+
for directory, (skill_id, *_rest) in CASES.items():
|
|
40
|
+
definition = load_skill_definition(repo / "skills" / directory / "SKILL.v1.md")
|
|
41
|
+
need_ids = [need["id"] for need in definition["metadata"]["knowledge_needs"]]
|
|
42
|
+
result = catalog.resolve_skill_knowledge(skill_id, need_ids)
|
|
43
|
+
assert result["unresolved_activation"] == []
|
|
44
|
+
assert result["unsatisfied_required"] == []
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from xrefkit.mcp.catalog import XRefCatalog
|
|
4
|
+
from xrefkit.skill_definition import load_skill_definition
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
CASES = [
|
|
8
|
+
("conversation_topic_branch_mapping", "9D6A4F2B1C80", "2E755FFA0A86", "59777C84933D", []),
|
|
9
|
+
("decision_topology_analysis", "B7E3C1A9D640", "502BB91D25FA", "2C927E868B25", ["7B3E5D1A6102", "7B3E5D1A6103"]),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def test_business_intake_v1_definitions_parse_aliases_and_preserve_legacy():
|
|
14
|
+
repo = Path(__file__).resolve().parents[1]
|
|
15
|
+
for skill_id, xid, body_xid, meta_xid, _ in CASES:
|
|
16
|
+
relative = Path("skills/packs/business-intake") / skill_id / "SKILL.v1.md"
|
|
17
|
+
definition = load_skill_definition(repo / relative)
|
|
18
|
+
metadata = definition["metadata"]
|
|
19
|
+
assert metadata["xid"] == xid
|
|
20
|
+
assert set(metadata["aliases"]) == {body_xid, meta_xid}
|
|
21
|
+
assert metadata["control_refs"] == []
|
|
22
|
+
for forbidden in ("capability", "tuning", "responsibility", "execution_mode", "model", "maturity"):
|
|
23
|
+
assert forbidden not in metadata
|
|
24
|
+
assert "## Context Direction Guard" not in definition["method"]
|
|
25
|
+
assert "## Reporting Contract" not in definition["method"]
|
|
26
|
+
assert f"<!-- xid: {body_xid} -->" in (repo / relative.parent / "SKILL.md").read_text(encoding="utf-8")
|
|
27
|
+
assert f"skill_doc: `./SKILL.md`" in (repo / relative.parent / "meta.md").read_text(encoding="utf-8")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test_business_intake_v1_explicit_catalog_selection_and_knowledge_resolution():
|
|
31
|
+
repo = Path(__file__).resolve().parents[1]
|
|
32
|
+
paths = [Path("skills/packs/business-intake") / skill_id / "SKILL.v1.md" for skill_id, *_ in CASES]
|
|
33
|
+
catalog = XRefCatalog.build(repo, skill_definition_paths=paths)
|
|
34
|
+
entries = [entry for entry in catalog.skills if entry.skill_id in {case[0] for case in CASES}]
|
|
35
|
+
assert len(entries) == 2
|
|
36
|
+
assert all(entry.definition_format == "skill_definition_v1" for entry in entries)
|
|
37
|
+
assert {entry.definition_xid for entry in entries} == {case[1] for case in CASES}
|
|
38
|
+
for skill_id, _, _, _, seed_xids in CASES:
|
|
39
|
+
definition = load_skill_definition(repo / (Path("skills/packs/business-intake") / skill_id / "SKILL.v1.md"))
|
|
40
|
+
need_ids = [need["id"] for need in definition["metadata"]["knowledge_needs"]]
|
|
41
|
+
if need_ids:
|
|
42
|
+
resolved = catalog.resolve_skill_knowledge(skill_id, need_ids)
|
|
43
|
+
assert resolved["unresolved_activation"] == []
|
|
44
|
+
assert resolved["unsatisfied_required"] == []
|
|
45
|
+
assert {candidate["xid"] for need in resolved["needs"] for candidate in need["candidates"]} >= set(seed_xids)
|
|
46
|
+
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from xrefkit.mcp.catalog import XRefCatalog
|
|
4
|
+
from xrefkit.skill_definition import load_skill_definition
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
CASES = (
|
|
8
|
+
("business_learning_interview", "B6C4E9A2D781", "4D8E1A7C5B92", "2B6D4F18A3C1", "7B3E5D1A6103"),
|
|
9
|
+
("business_intake_scoping", "B6C4E9A2D782", "6F2A9C41E8B3", "4E9B2C18D740", "7B3E5D1A6102"),
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def test_business_intake_v1_definitions_parse_select_resolve_and_preserve_legacy():
|
|
14
|
+
repo = Path(__file__).resolve().parents[1]
|
|
15
|
+
paths = []
|
|
16
|
+
for skill_id, xid, body_xid, meta_xid, rule_xid in CASES:
|
|
17
|
+
directory = repo / "skills/packs/business-intake" / skill_id
|
|
18
|
+
definition_path = directory / "SKILL.v1.md"
|
|
19
|
+
paths.append(definition_path.relative_to(repo))
|
|
20
|
+
definition = load_skill_definition(definition_path)
|
|
21
|
+
metadata = definition["metadata"]
|
|
22
|
+
assert metadata["schema_version"] == 1
|
|
23
|
+
assert metadata["skill_id"] == skill_id
|
|
24
|
+
assert metadata["xid"] == xid
|
|
25
|
+
assert set(metadata["aliases"]) == {body_xid, meta_xid}
|
|
26
|
+
assert metadata["xid"] not in metadata["aliases"]
|
|
27
|
+
assert len(metadata["aliases"]) == len(set(metadata["aliases"]))
|
|
28
|
+
assert not {
|
|
29
|
+
"capability", "tuning", "responsibility", "execution_mode",
|
|
30
|
+
"model", "model_tier", "maturity",
|
|
31
|
+
} & set(metadata)
|
|
32
|
+
assert metadata["control_refs"] == []
|
|
33
|
+
assert metadata["knowledge_needs"][0]["seed_xids"] == [rule_xid]
|
|
34
|
+
assert "docs/packs/business-intake/" in definition["method"]
|
|
35
|
+
|
|
36
|
+
catalog = XRefCatalog.build(repo, skill_definition_paths=[definition_path.relative_to(repo)])
|
|
37
|
+
entries = [entry for entry in catalog.skills if entry.skill_id == skill_id]
|
|
38
|
+
assert len(entries) == 1
|
|
39
|
+
assert entries[0].definition_format == "skill_definition_v1"
|
|
40
|
+
assert entries[0].definition_xid == xid
|
|
41
|
+
resolved = catalog.resolve_skill_knowledge(skill_id, ["business_" + ("learning_interview" if skill_id == "business_learning_interview" else "intake_scoping") + "_rules"])
|
|
42
|
+
assert resolved["unresolved_activation"] == []
|
|
43
|
+
assert resolved["unsatisfied_required"] == []
|
|
44
|
+
assert resolved["needs"][0]["satisfied"] is True
|
|
45
|
+
|
|
46
|
+
legacy = (directory / "SKILL.md").read_text(encoding="utf-8")
|
|
47
|
+
meta = (directory / "meta.md").read_text(encoding="utf-8")
|
|
48
|
+
assert f"<!-- xid: {body_xid} -->" in legacy
|
|
49
|
+
assert f"<!-- xid: {meta_xid} -->" in meta
|
|
50
|
+
assert "skill_doc: `./SKILL.md`" in meta
|
|
51
|
+
|
|
52
|
+
catalog = XRefCatalog.build(repo, skill_definition_paths=paths)
|
|
53
|
+
assert {entry.skill_id for entry in catalog.skills if entry.definition_format == "skill_definition_v1"} == {
|
|
54
|
+
"business_learning_interview", "business_intake_scoping"
|
|
55
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from xrefkit.mcp.catalog import XRefCatalog
|
|
6
|
+
from xrefkit.skill_definition import load_skill_definition
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
CASES = [
|
|
10
|
+
("domain_knowledge_catalog_preparation", "skills/os/domain_knowledge_catalog_preparation", "A7C9E2D4F610", "EE95165681E8", "A409BACC6918"),
|
|
11
|
+
("skill_flow_authoring", "skills/os/skill_flow_authoring", "B8D1A4C7E260", "C1B7A42D8E53", "D37E2B5C8A41"),
|
|
12
|
+
("test_tool_catalog_preparation", "skills/test_tool_catalog_preparation", "C9E2B5D8F370", "DE815228B04C", "F2A36B52C0EB"),
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@pytest.mark.parametrize("skill_id,folder,xid,body_xid,meta_xid", CASES)
|
|
17
|
+
def test_v1_definitions_parse_with_aliases_and_concrete_metadata(skill_id, folder, xid, body_xid, meta_xid):
|
|
18
|
+
repo = Path(__file__).resolve().parents[1]
|
|
19
|
+
definition_path = repo / folder / "SKILL.v1.md"
|
|
20
|
+
definition = load_skill_definition(definition_path)
|
|
21
|
+
metadata = definition["metadata"]
|
|
22
|
+
assert metadata["skill_id"] == skill_id
|
|
23
|
+
assert metadata["xid"] == xid
|
|
24
|
+
assert set(metadata["aliases"]) == {body_xid, meta_xid}
|
|
25
|
+
assert metadata["inputs"] and metadata["outputs"]
|
|
26
|
+
assert metadata["control_refs"] == []
|
|
27
|
+
assert not any(key in metadata for key in ("capability", "tuning", "responsibility", "execution_mode", "model", "model_tier", "maturity"))
|
|
28
|
+
assert "CAP-" not in definition["method"]
|
|
29
|
+
assert "## Reporting Contract" not in definition["method"]
|
|
30
|
+
assert "## Required Knowledge (XID)" not in definition["method"]
|
|
31
|
+
assert (repo / folder / "SKILL.md").read_text(encoding="utf-8").startswith("<!-- xid: ")
|
|
32
|
+
assert (repo / folder / "meta.md").read_text(encoding="utf-8").startswith("<!-- xid: ")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_explicit_catalog_and_knowledge_resolution_cover_the_trio():
|
|
36
|
+
repo = Path(__file__).resolve().parents[1]
|
|
37
|
+
paths = [repo / folder / "SKILL.v1.md" for _, folder, *_ in CASES]
|
|
38
|
+
catalog = XRefCatalog.build(repo, skill_definition_paths=paths)
|
|
39
|
+
entries = {entry.skill_id: entry for entry in catalog.skills if entry.skill_id in {case[0] for case in CASES}}
|
|
40
|
+
assert set(entries) == {case[0] for case in CASES}
|
|
41
|
+
assert all(entry.definition_format == "skill_definition_v1" for entry in entries.values())
|
|
42
|
+
for skill_id, folder, *_ in CASES:
|
|
43
|
+
definition = load_skill_definition(repo / folder / "SKILL.v1.md")
|
|
44
|
+
need_ids = [need["id"] for need in definition["metadata"]["knowledge_needs"]]
|
|
45
|
+
result = catalog.resolve_skill_knowledge(skill_id, need_ids)
|
|
46
|
+
assert result["unresolved_activation"] == []
|
|
47
|
+
assert result["unsatisfied_required"] == []
|
|
@@ -307,7 +307,15 @@ class CliTests(unittest.TestCase):
|
|
|
307
307
|
text = out.read_text(encoding="utf-8")
|
|
308
308
|
self.assertIn("## Skill Load Gate", text)
|
|
309
309
|
self.assertIn("## Runtime Role Assignment", text)
|
|
310
|
-
self.assertIn("##
|
|
310
|
+
self.assertIn("## Workflow Runtime Binding", text)
|
|
311
|
+
runtime_role_assignment = text.split("## Runtime Role Assignment", 1)[1].split("## Role Responsibilities", 1)[0]
|
|
312
|
+
self.assertNotIn("- capability: ", runtime_role_assignment)
|
|
313
|
+
self.assertNotIn("- tuning: ", runtime_role_assignment)
|
|
314
|
+
self.assertNotIn("- responsibility: ", runtime_role_assignment)
|
|
315
|
+
self.assertIn("- owner: `workflow_protocol`", text)
|
|
316
|
+
self.assertIn("- contract_xid: `8D50A972BA9F`", text)
|
|
317
|
+
self.assertIn("- source: `legacy_meta_compatibility`", text)
|
|
318
|
+
self.assertIn("- instruction_basis: `run.task`", text)
|
|
311
319
|
self.assertIn("- capability_layering: `required`", text)
|
|
312
320
|
self.assertIn("- workflow_protocol: `required`", text)
|
|
313
321
|
self.assertIn("- tuning: `sample specialization`", text)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from xrefkit.mcp.catalog import XRefCatalog
|
|
4
|
+
from xrefkit.skill_definition import load_skill_definition
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_code_constraint_v1_parses_with_unique_legacy_aliases_and_catalog_selection():
|
|
8
|
+
repo = Path(__file__).resolve().parents[1]
|
|
9
|
+
relative = Path("skills/packs/constraint-derivation/code_constraint_derivation/SKILL.v1.md")
|
|
10
|
+
definition = load_skill_definition(repo / relative)
|
|
11
|
+
metadata = definition["metadata"]
|
|
12
|
+
|
|
13
|
+
assert metadata["schema_version"] == 1
|
|
14
|
+
assert metadata["xid"] == "7C4E9A1B2D60"
|
|
15
|
+
assert set(metadata["aliases"]) == {"D4701BFC6EA4", "D4701BFC6EA5"}
|
|
16
|
+
assert metadata["xid"] not in metadata["aliases"]
|
|
17
|
+
assert len(metadata["aliases"]) == len(set(metadata["aliases"]))
|
|
18
|
+
assert not {"capability", "tuning", "responsibility", "execution_mode", "model_tier", "maturity"} & set(metadata)
|
|
19
|
+
|
|
20
|
+
catalog = XRefCatalog.build(repo, skill_definition_paths=[relative])
|
|
21
|
+
entries = [entry for entry in catalog.skills if entry.skill_id == "code_constraint_derivation"]
|
|
22
|
+
assert len(entries) == 1
|
|
23
|
+
assert entries[0].definition_format == "skill_definition_v1"
|
|
24
|
+
assert entries[0].definition_xid == metadata["xid"]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_code_constraint_v1_resolves_selected_knowledge_and_legacy_files_are_unchanged():
|
|
28
|
+
repo = Path(__file__).resolve().parents[1]
|
|
29
|
+
relative = Path("skills/packs/constraint-derivation/code_constraint_derivation/SKILL.v1.md")
|
|
30
|
+
definition = load_skill_definition(repo / relative)
|
|
31
|
+
need_ids = [need["id"] for need in definition["metadata"]["knowledge_needs"]]
|
|
32
|
+
|
|
33
|
+
catalog = XRefCatalog.build(repo, skill_definition_paths=[relative])
|
|
34
|
+
result = catalog.resolve_skill_knowledge("code_constraint_derivation", need_ids)
|
|
35
|
+
assert result["unresolved_activation"] == []
|
|
36
|
+
assert result["unsatisfied_required"] == []
|
|
37
|
+
assert [need["id"] for need in result["needs"]] == need_ids
|
|
38
|
+
assert all(need["activation_state"] == "active" for need in result["needs"])
|
|
39
|
+
assert all(need["satisfied"] is True for need in result["needs"])
|
|
40
|
+
|
|
41
|
+
meta = (repo / "skills/packs/constraint-derivation/code_constraint_derivation/meta.md").read_text(encoding="utf-8")
|
|
42
|
+
legacy = (repo / "skills/packs/constraint-derivation/code_constraint_derivation/SKILL.md").read_text(encoding="utf-8")
|
|
43
|
+
assert "skill_doc: `./SKILL.md`" in meta
|
|
44
|
+
assert "<!-- xid: D4701BFC6EA4 -->" in meta
|
|
45
|
+
assert "<!-- xid: D4701BFC6EA5 -->" in legacy
|
|
46
|
+
assert "## Reporting Contract" not in definition["method"]
|
|
47
|
+
assert "111D282CA0EA" in definition["metadata"]["control_refs"]
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from xrefkit.mcp.catalog import XRefCatalog
|
|
6
|
+
from xrefkit.skill_definition import load_skill_definition
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
CASES = [
|
|
10
|
+
("integration_constraint_derivation", "9A1C4E7D2B60", "E547F90B1235", "E547F90B1234", ["81A6C4E2B190", "6F0D7C1A2E44"]),
|
|
11
|
+
("integration_scenario_derivation", "5F8B2D6A1C90", "F6923D1E80C9", "F6923D1E80C8", ["81A6C4E2B190", "C3F60AEB5D93"]),
|
|
12
|
+
("logic_constraint_derivation", "3D7A9E2B4C60", "D436E8FA0124", "D436E8FA0123", ["81A6C4E2B190", "4E5B8923C912"]),
|
|
13
|
+
("ui_constraint_derivation", "6B1F8D3A5E20", "C325D7E9F123", "C325D7E9F122", ["81A6C4E2B190", "31C5A06B7E22"]),
|
|
14
|
+
("constraint_derivation_index", "A4C9E2B7D160", "A103B5C7D901", "A103B5C7D900", ["81A6C4E2B190"]),
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@pytest.mark.parametrize("skill_id,xid,body_xid,meta_xid,seed_xids", CASES)
|
|
19
|
+
def test_constraint_derivation_v1_migration(skill_id, xid, body_xid, meta_xid, seed_xids):
|
|
20
|
+
repo = Path(__file__).resolve().parents[1]
|
|
21
|
+
relative = Path("skills/packs/constraint-derivation") / skill_id / "SKILL.v1.md"
|
|
22
|
+
definition = load_skill_definition(repo / relative)
|
|
23
|
+
metadata = definition["metadata"]
|
|
24
|
+
assert metadata["xid"] == xid
|
|
25
|
+
assert set(metadata["aliases"]) == {body_xid, meta_xid}
|
|
26
|
+
assert metadata["control_refs"] == ["111D282CA0EA"]
|
|
27
|
+
assert "## Reporting Contract" not in definition["method"]
|
|
28
|
+
assert "## Required Knowledge (XID)" not in definition["method"]
|
|
29
|
+
assert "Context direction guard" not in definition["method"]
|
|
30
|
+
|
|
31
|
+
legacy = (repo / relative.parent / "SKILL.md").read_bytes()
|
|
32
|
+
assert f"<!-- xid: {body_xid} -->".encode() in legacy
|
|
33
|
+
assert f"skill_doc: `./SKILL.md`".encode() in (repo / relative.parent / "meta.md").read_bytes()
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_constraint_derivation_v1_explicit_selection_and_knowledge_resolution():
|
|
37
|
+
repo = Path(__file__).resolve().parents[1]
|
|
38
|
+
paths = [Path("skills/packs/constraint-derivation") / skill / "SKILL.v1.md" for skill, *_ in CASES]
|
|
39
|
+
catalog = XRefCatalog.build(repo, skill_definition_paths=paths)
|
|
40
|
+
entries = [entry for entry in catalog.skills if entry.skill_id in {case[0] for case in CASES}]
|
|
41
|
+
assert len(entries) == len(CASES)
|
|
42
|
+
assert all(entry.definition_format == "skill_definition_v1" for entry in entries)
|
|
43
|
+
assert {entry.definition_xid for entry in entries} == {case[1] for case in CASES}
|
|
44
|
+
|
|
45
|
+
for skill_id, _, _, _, seed_xids in CASES:
|
|
46
|
+
relative = Path("skills/packs/constraint-derivation") / skill_id / "SKILL.v1.md"
|
|
47
|
+
definition = load_skill_definition(repo / relative)
|
|
48
|
+
result = catalog.resolve_skill_knowledge(skill_id, [need["id"] for need in definition["metadata"]["knowledge_needs"]])
|
|
49
|
+
assert result["unresolved_activation"] == []
|
|
50
|
+
assert result["unsatisfied_required"] == []
|
|
51
|
+
for expected, need in zip(seed_xids, result["needs"], strict=True):
|
|
52
|
+
assert expected in [candidate["xid"] for candidate in need["candidates"]]
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def test_complete_constraint_derivation_family_selects_without_identity_collisions():
|
|
56
|
+
repo = Path(__file__).resolve().parents[1]
|
|
57
|
+
family_root = Path("skills/packs/constraint-derivation")
|
|
58
|
+
paths = sorted(family_root.glob("*/SKILL.v1.md"))
|
|
59
|
+
relative_paths = [path.relative_to(repo) if path.is_absolute() else path for path in paths]
|
|
60
|
+
|
|
61
|
+
assert len(relative_paths) == 11
|
|
62
|
+
catalog = XRefCatalog.build(repo, skill_definition_paths=relative_paths)
|
|
63
|
+
family_ids = {path.parent.name for path in relative_paths}
|
|
64
|
+
entries = [entry for entry in catalog.skills if entry.skill_id in family_ids]
|
|
65
|
+
|
|
66
|
+
assert {entry.skill_id for entry in entries} == family_ids
|
|
67
|
+
assert len({entry.definition_xid for entry in entries}) == 11
|
|
68
|
+
assert all(entry.definition_format == "skill_definition_v1" for entry in entries)
|