xrefkit 0.4.7__tar.gz → 0.4.9__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.9/PKG-INFO +121 -0
- xrefkit-0.4.9/README.md +82 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/pyproject.toml +1 -1
- xrefkit-0.4.9/tests/test_brownfield_file_editing_protocol.py +55 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_dashboard.py +153 -0
- xrefkit-0.4.9/tests/test_host_precheck.py +49 -0
- xrefkit-0.4.9/tests/test_human_evaluation.py +93 -0
- xrefkit-0.4.9/tests/test_instruction_workflow.py +462 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_skills_sync.py +6 -6
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/__init__.py +1 -1
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/cli.py +12 -2
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/dashboard.py +425 -7
- xrefkit-0.4.9/xrefkit/host_precheck.py +125 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/mcp/__init__.py +10 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/mcp/audit.py +45 -3
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/mcp/catalog.py +56 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/mcp/client_cache.py +21 -0
- xrefkit-0.4.9/xrefkit/mcp/client_flow.py +325 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/mcp/context_token.py +22 -1
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/mcp/contracts.py +10 -2
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/mcp/schemas.py +2 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/mcp/server.py +44 -1
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/mcp/startup_contract_pack.py +8 -4
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/models/__init__.py +3 -0
- xrefkit-0.4.9/xrefkit/models/human_evaluation.py +93 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/operations_cli.py +212 -3
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/skillrun.py +718 -16
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/skills_sync.py +61 -16
- xrefkit-0.4.9/xrefkit.egg-info/PKG-INFO +121 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit.egg-info/SOURCES.txt +6 -0
- xrefkit-0.4.7/PKG-INFO +0 -356
- xrefkit-0.4.7/README.md +0 -317
- xrefkit-0.4.7/tests/test_instruction_workflow.py +0 -172
- xrefkit-0.4.7/xrefkit.egg-info/PKG-INFO +0 -356
- {xrefkit-0.4.7 → xrefkit-0.4.9}/LICENSE +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/setup.cfg +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_base_sync_ownership.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_boundary_analysis.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_calibration_lint.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_check_skill_knowledge_xids.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_cli.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_collect_analyzer_sarif.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_convert_to_xrefkit_skill.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_cs_scope_probe.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_csharp_commonality.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_csharp_naming_profile.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_ctx.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_cutover_readiness.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_error_policy_audit.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_error_policy_locator.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_fm_multiroot.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_gate.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_goal_desired_state.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_knowledge_relations_validator.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_mcp_setup.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_ownership.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_packmeta.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_project_quality_baseline.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_resource_provider.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_runtime_contracts.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_sarif_to_locator.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_skill_runtime_audit.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_skillmeta.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_structure_catalog.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_xref.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_xrefkit_instance.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_xrefkit_tools.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_xrefkit_v2_discovery.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_xrefkit_v2_models.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/tests/test_xrefkit_v2_pipeline.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/__main__.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/boundary_analysis.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/catalog_cli.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/contracts.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/ctx.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/discovery.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/gate.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/goalstate.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/hashing.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/import_skill.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/instance.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/loaders.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/mcp/bootstrap.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/mcp/cli.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/mcp/context_registry.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/mcp/dist.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/mcp/ownership.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/mcp/repository.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/mcp/setup.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/mcp_tools.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/models/common.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/models/effective_bundle.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/models/local_manifest.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/models/package_manifest.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/models/run_log.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/models/server_config.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/models/skill_definition.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/ownership.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/packmeta.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/registry.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/resolver.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/resource_provider.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/resources/base/contracts.json +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/resources/base/current.json +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/resources/base/generations/7a682a5272907354/contracts.json +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/resources/base/generations/7a682a5272907354/model_body.md +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/resources/base/generations/9929294385ccb7b0/contracts.json +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/resources/base/generations/9929294385ccb7b0/model_body.md +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/resources/base/model_body.md +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/runlog.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/skillmeta.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/structure_catalog.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/tools/__init__.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/tools/__main__.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/v2_cli.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/workspace.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit/xref.py +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit.egg-info/dependency_links.txt +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit.egg-info/entry_points.txt +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit.egg-info/requires.txt +0 -0
- {xrefkit-0.4.7 → xrefkit-0.4.9}/xrefkit.egg-info/top_level.txt +0 -0
xrefkit-0.4.9/PKG-INFO
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: xrefkit
|
|
3
|
+
Version: 0.4.9
|
|
4
|
+
Summary: Portable XID, Skill, Knowledge, workflow, and MCP runtime for XRefKit
|
|
5
|
+
Author: synthaicode
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Ritu
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Requires-Python: >=3.11
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Requires-Dist: PyYAML<7,>=6.0.2
|
|
32
|
+
Requires-Dist: pydantic<3,>=2.0
|
|
33
|
+
Provides-Extra: mcp
|
|
34
|
+
Requires-Dist: mcp>=1.0.0; extra == "mcp"
|
|
35
|
+
Requires-Dist: uvicorn>=0.30; extra == "mcp"
|
|
36
|
+
Provides-Extra: test
|
|
37
|
+
Requires-Dist: pytest>=8.0.0; extra == "test"
|
|
38
|
+
Dynamic: license-file
|
|
39
|
+
|
|
40
|
+
# XRefKit
|
|
41
|
+
|
|
42
|
+
XRefKit is a framework for making AI-assisted work repeatable, reviewable, and
|
|
43
|
+
handoff-ready.
|
|
44
|
+
|
|
45
|
+
It helps teams turn domain procedures and knowledge into work that can be
|
|
46
|
+
performed with explicit evidence, human judgment, and completion checks.
|
|
47
|
+
|
|
48
|
+
## Why XRefKit?
|
|
49
|
+
|
|
50
|
+
Using AI for real work creates recurring operating problems:
|
|
51
|
+
|
|
52
|
+

|
|
53
|
+
|
|
54
|
+
- the AI can act from incomplete context or unsupported guesses
|
|
55
|
+
- procedures, domain facts, and judgment criteria get mixed together in prompts
|
|
56
|
+
- execution, checking, and handoff collapse into one opaque step
|
|
57
|
+
- work becomes hard to continue across agents, humans, or sessions
|
|
58
|
+
- outputs may lack evidence, closure discipline, or auditability
|
|
59
|
+
|
|
60
|
+
XRefKit provides a repository and runtime model for addressing these problems.
|
|
61
|
+
|
|
62
|
+
## What it provides
|
|
63
|
+
|
|
64
|
+
- **Skills** — reusable procedures for a defined kind of work
|
|
65
|
+
- **Knowledge** — source-backed domain facts and local rules
|
|
66
|
+
- **Workflow protocol** — recorded progress, deterministic verification, and
|
|
67
|
+
closure checks
|
|
68
|
+
- **Evidence and handoffs** — outputs, judgments, concerns, and decisions that
|
|
69
|
+
remain reviewable after the work is done
|
|
70
|
+
- **Skill Run Dashboard** — inspect Skill execution status, referenced XIDs,
|
|
71
|
+
evidence, judgments, concerns, and handoffs to improve the auditability of
|
|
72
|
+
results
|
|
73
|
+
- **XIDs** — stable references for connecting procedures, knowledge, and
|
|
74
|
+
supporting documents
|
|
75
|
+
|
|
76
|
+
The package includes the resolver, Skill runtime, workflow controls, client
|
|
77
|
+
tools, and an optional MCP adapter.
|
|
78
|
+
|
|
79
|
+
The [Skill Run Dashboard](docs/guides/086_skill_run_observation_dashboard_usage.md#xid-4A4763A2DE63)
|
|
80
|
+
helps people trace how a Skill run used its referenced XIDs and recorded its
|
|
81
|
+
evidence before accepting or handing off the result.
|
|
82
|
+
|
|
83
|
+
## Quick start
|
|
84
|
+
|
|
85
|
+
XRefKit requires Python 3.11 or later.
|
|
86
|
+
|
|
87
|
+
```powershell
|
|
88
|
+
python -m pip install xrefkit
|
|
89
|
+
xrefkit init
|
|
90
|
+
xrefkit --help
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
For local development:
|
|
94
|
+
|
|
95
|
+
```powershell
|
|
96
|
+
python -m pip install -e .
|
|
97
|
+
xrefkit init
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
For the optional MCP server:
|
|
101
|
+
|
|
102
|
+
```powershell
|
|
103
|
+
python -m pip install "xrefkit[mcp]"
|
|
104
|
+
xrefkit mcp serve --repo . --transport stdio
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Where to go next
|
|
108
|
+
|
|
109
|
+
- [Install XRefKit and register Skill Packages](docs/guides/089_xrefkit_package_first_registration.md#xid-4F8C2A7D1E90)
|
|
110
|
+
- [Understand the workflow protocol](docs/guides/087_workflow_protocol_sequence_for_humans.md#xid-E8B4D2F19A63)
|
|
111
|
+
- [Use an instruction-backed workflow](docs/guides/088_instruction_workflow_protocol.md#xid-9F4C2A7D1B60)
|
|
112
|
+
- [Understand Skills and Knowledge](docs/core/models/052_flow_capability_skill_knowledge_model.md#xid-91C4B7E2D5A8)
|
|
113
|
+
- [Author a Skill with xref](docs/guides/013_skill_authoring_with_xref.md#xid-3DB05A0F5F5B)
|
|
114
|
+
- [Browse the complete documentation index](docs/000_index.md#xid-56DD6EB68343)
|
|
115
|
+
|
|
116
|
+
## Security
|
|
117
|
+
|
|
118
|
+
XRefKit does not require provider API keys to explore or install the package.
|
|
119
|
+
Do not commit secrets, API keys, access tokens, `.env` files, or provider
|
|
120
|
+
credentials. Authenticate external AI tools through their official provider
|
|
121
|
+
mechanisms.
|
xrefkit-0.4.9/README.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# XRefKit
|
|
2
|
+
|
|
3
|
+
XRefKit is a framework for making AI-assisted work repeatable, reviewable, and
|
|
4
|
+
handoff-ready.
|
|
5
|
+
|
|
6
|
+
It helps teams turn domain procedures and knowledge into work that can be
|
|
7
|
+
performed with explicit evidence, human judgment, and completion checks.
|
|
8
|
+
|
|
9
|
+
## Why XRefKit?
|
|
10
|
+
|
|
11
|
+
Using AI for real work creates recurring operating problems:
|
|
12
|
+
|
|
13
|
+

|
|
14
|
+
|
|
15
|
+
- the AI can act from incomplete context or unsupported guesses
|
|
16
|
+
- procedures, domain facts, and judgment criteria get mixed together in prompts
|
|
17
|
+
- execution, checking, and handoff collapse into one opaque step
|
|
18
|
+
- work becomes hard to continue across agents, humans, or sessions
|
|
19
|
+
- outputs may lack evidence, closure discipline, or auditability
|
|
20
|
+
|
|
21
|
+
XRefKit provides a repository and runtime model for addressing these problems.
|
|
22
|
+
|
|
23
|
+
## What it provides
|
|
24
|
+
|
|
25
|
+
- **Skills** — reusable procedures for a defined kind of work
|
|
26
|
+
- **Knowledge** — source-backed domain facts and local rules
|
|
27
|
+
- **Workflow protocol** — recorded progress, deterministic verification, and
|
|
28
|
+
closure checks
|
|
29
|
+
- **Evidence and handoffs** — outputs, judgments, concerns, and decisions that
|
|
30
|
+
remain reviewable after the work is done
|
|
31
|
+
- **Skill Run Dashboard** — inspect Skill execution status, referenced XIDs,
|
|
32
|
+
evidence, judgments, concerns, and handoffs to improve the auditability of
|
|
33
|
+
results
|
|
34
|
+
- **XIDs** — stable references for connecting procedures, knowledge, and
|
|
35
|
+
supporting documents
|
|
36
|
+
|
|
37
|
+
The package includes the resolver, Skill runtime, workflow controls, client
|
|
38
|
+
tools, and an optional MCP adapter.
|
|
39
|
+
|
|
40
|
+
The [Skill Run Dashboard](docs/guides/086_skill_run_observation_dashboard_usage.md#xid-4A4763A2DE63)
|
|
41
|
+
helps people trace how a Skill run used its referenced XIDs and recorded its
|
|
42
|
+
evidence before accepting or handing off the result.
|
|
43
|
+
|
|
44
|
+
## Quick start
|
|
45
|
+
|
|
46
|
+
XRefKit requires Python 3.11 or later.
|
|
47
|
+
|
|
48
|
+
```powershell
|
|
49
|
+
python -m pip install xrefkit
|
|
50
|
+
xrefkit init
|
|
51
|
+
xrefkit --help
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
For local development:
|
|
55
|
+
|
|
56
|
+
```powershell
|
|
57
|
+
python -m pip install -e .
|
|
58
|
+
xrefkit init
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
For the optional MCP server:
|
|
62
|
+
|
|
63
|
+
```powershell
|
|
64
|
+
python -m pip install "xrefkit[mcp]"
|
|
65
|
+
xrefkit mcp serve --repo . --transport stdio
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Where to go next
|
|
69
|
+
|
|
70
|
+
- [Install XRefKit and register Skill Packages](docs/guides/089_xrefkit_package_first_registration.md#xid-4F8C2A7D1E90)
|
|
71
|
+
- [Understand the workflow protocol](docs/guides/087_workflow_protocol_sequence_for_humans.md#xid-E8B4D2F19A63)
|
|
72
|
+
- [Use an instruction-backed workflow](docs/guides/088_instruction_workflow_protocol.md#xid-9F4C2A7D1B60)
|
|
73
|
+
- [Understand Skills and Knowledge](docs/core/models/052_flow_capability_skill_knowledge_model.md#xid-91C4B7E2D5A8)
|
|
74
|
+
- [Author a Skill with xref](docs/guides/013_skill_authoring_with_xref.md#xid-3DB05A0F5F5B)
|
|
75
|
+
- [Browse the complete documentation index](docs/000_index.md#xid-56DD6EB68343)
|
|
76
|
+
|
|
77
|
+
## Security
|
|
78
|
+
|
|
79
|
+
XRefKit does not require provider API keys to explore or install the package.
|
|
80
|
+
Do not commit secrets, API keys, access tokens, `.env` files, or provider
|
|
81
|
+
credentials. Authenticate external AI tools through their official provider
|
|
82
|
+
mechanisms.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
ROOT = Path(__file__).resolve().parents[1]
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_brownfield_file_editing_protocol_is_in_canonical_and_packaged_skill() -> None:
|
|
8
|
+
canonical = (ROOT / "skills" / "brownfield-workflow" / "SKILL.md").read_text(encoding="utf-8")
|
|
9
|
+
packaged = (
|
|
10
|
+
ROOT / "packages" / "xrefkit-skills-brownfield" / "src" / "xrefkit_skills_brownfield"
|
|
11
|
+
/ "skills" / "brownfield_workflow" / "entry.md"
|
|
12
|
+
).read_text(encoding="utf-8")
|
|
13
|
+
|
|
14
|
+
for keyword in (
|
|
15
|
+
"encoding",
|
|
16
|
+
"BOM",
|
|
17
|
+
"newline",
|
|
18
|
+
"Unicode",
|
|
19
|
+
"strict",
|
|
20
|
+
"after_bytes",
|
|
21
|
+
"mojibake",
|
|
22
|
+
"concurrency",
|
|
23
|
+
"revision token",
|
|
24
|
+
"compare-and-swap",
|
|
25
|
+
"abort",
|
|
26
|
+
"atomically",
|
|
27
|
+
"specification",
|
|
28
|
+
"semantic",
|
|
29
|
+
"authoritative",
|
|
30
|
+
"hypothesis",
|
|
31
|
+
"semantic_alignment",
|
|
32
|
+
"Historical conflict investigation",
|
|
33
|
+
"bounded",
|
|
34
|
+
"Git",
|
|
35
|
+
"uncommitted",
|
|
36
|
+
"newest",
|
|
37
|
+
"Uncommitted-file policy",
|
|
38
|
+
"pre_existing_human_or_unknown",
|
|
39
|
+
"ai_owned_current_work",
|
|
40
|
+
"mixed_or_overlapping",
|
|
41
|
+
"untracked",
|
|
42
|
+
"stash",
|
|
43
|
+
"New-file extension conformity",
|
|
44
|
+
"peer",
|
|
45
|
+
"companion files",
|
|
46
|
+
"extension-specific",
|
|
47
|
+
"cluster",
|
|
48
|
+
"majority",
|
|
49
|
+
"same directory",
|
|
50
|
+
"confidence",
|
|
51
|
+
"weak margin",
|
|
52
|
+
"repository-wide fallback",
|
|
53
|
+
):
|
|
54
|
+
assert keyword in canonical
|
|
55
|
+
assert keyword in packaged
|
|
@@ -241,6 +241,149 @@ class DashboardTests(unittest.TestCase):
|
|
|
241
241
|
self.assertEqual(1, payload["summary"]["runs"])
|
|
242
242
|
self.assertEqual("sample_skill", payload["runs"][0]["skill_id"])
|
|
243
243
|
|
|
244
|
+
def test_dashboard_exposes_recovery_trace(self) -> None:
|
|
245
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
246
|
+
root = Path(tmp)
|
|
247
|
+
run_log = self._write_closed_run(root)
|
|
248
|
+
common = [
|
|
249
|
+
"workflow",
|
|
250
|
+
"recovery",
|
|
251
|
+
"--log",
|
|
252
|
+
str(run_log),
|
|
253
|
+
"--recovery-id",
|
|
254
|
+
"REC-001",
|
|
255
|
+
"--resume-location",
|
|
256
|
+
"after reconcile",
|
|
257
|
+
"--reason",
|
|
258
|
+
"child status was not yet projected",
|
|
259
|
+
"--next-action",
|
|
260
|
+
"confirm and rerun reconcile",
|
|
261
|
+
]
|
|
262
|
+
self._run_main([*common, "--status", "proposed"])
|
|
263
|
+
self._run_main([*common, "--status", "confirmed", "--reviewer", "human@example.test"])
|
|
264
|
+
|
|
265
|
+
payload = build_payload(root, root / "work" / "sessions")
|
|
266
|
+
self.assertEqual(2, payload["summary"]["recoveries"])
|
|
267
|
+
self.assertEqual(
|
|
268
|
+
["proposed", "confirmed"],
|
|
269
|
+
[item["status"] for item in payload["recoveries"]],
|
|
270
|
+
)
|
|
271
|
+
html = _html_page(payload)
|
|
272
|
+
self.assertIn('data-panel="recovery"', html)
|
|
273
|
+
self.assertIn('id="recovery"', html)
|
|
274
|
+
self.assertIn("Resume location", html)
|
|
275
|
+
self.assertIn("after reconcile", html)
|
|
276
|
+
self.assertIn("human@example.test", html)
|
|
277
|
+
self.assertIn("Executable action", html)
|
|
278
|
+
self.assertIn("Verification", html)
|
|
279
|
+
self.assertIn("Max attempts", html)
|
|
280
|
+
|
|
281
|
+
def test_dashboard_aggregates_runs_by_prompt_flow(self) -> None:
|
|
282
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
283
|
+
root = Path(tmp)
|
|
284
|
+
first = root / "work" / "sessions" / "root.md"
|
|
285
|
+
second = root / "work" / "sessions" / "child.md"
|
|
286
|
+
for out, run_id, parent, work_item in (
|
|
287
|
+
(first, "11111111-1111-4111-8111-111111111111", None, None),
|
|
288
|
+
(second, "22222222-2222-4222-8222-222222222222", "11111111-1111-4111-8111-111111111111", "WI-002"),
|
|
289
|
+
):
|
|
290
|
+
args = [
|
|
291
|
+
"workflow", "run", "--task", "Flow node", "--out", str(out),
|
|
292
|
+
"--run-id", run_id, "--flow-id", "FLOW-001",
|
|
293
|
+
"--root-run-id", "11111111-1111-4111-8111-111111111111",
|
|
294
|
+
"--use-default-completion-conditions",
|
|
295
|
+
]
|
|
296
|
+
if parent:
|
|
297
|
+
args.extend(["--parent-run-id", parent, "--work-item-id", work_item])
|
|
298
|
+
self._run_main(args)
|
|
299
|
+
|
|
300
|
+
payload = build_payload(root, root / "work" / "sessions")
|
|
301
|
+
assert payload["summary"]["flows"] == 1
|
|
302
|
+
flow = payload["flows"][0]
|
|
303
|
+
assert flow["flow_id"] == "FLOW-001"
|
|
304
|
+
assert flow["root_run_id"] == "11111111-1111-4111-8111-111111111111"
|
|
305
|
+
assert flow["state"] == "blocked"
|
|
306
|
+
assert set(flow["run_ids"]) == {
|
|
307
|
+
"11111111-1111-4111-8111-111111111111",
|
|
308
|
+
"22222222-2222-4222-8222-222222222222",
|
|
309
|
+
}
|
|
310
|
+
child = next(run for run in payload["runs"] if run["run_id"] == "22222222-2222-4222-8222-222222222222")
|
|
311
|
+
assert child["parent_run_id"] == "11111111-1111-4111-8111-111111111111"
|
|
312
|
+
assert child["work_item_id"] == "WI-002"
|
|
313
|
+
|
|
314
|
+
def test_workflow_delegate_starts_child_skill_and_records_parent_flow_trace(self) -> None:
|
|
315
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
316
|
+
root = Path(tmp)
|
|
317
|
+
self._write_valid_skill(root)
|
|
318
|
+
parent = root / "work" / "sessions" / "parent.md"
|
|
319
|
+
child = root / "work" / "sessions" / "child.md"
|
|
320
|
+
self._run_main([
|
|
321
|
+
"workflow", "run", "--task", "Delegate one item", "--out", str(parent),
|
|
322
|
+
"--run-id", "11111111-1111-4111-8111-111111111111",
|
|
323
|
+
"--flow-id", "FLOW-002", "--use-default-completion-conditions",
|
|
324
|
+
])
|
|
325
|
+
self._run_main([
|
|
326
|
+
"workflow", "delegate", "--root", str(root), "--parent-log", str(parent), "--meta", "skills/sample/meta.md",
|
|
327
|
+
"--task", "Execute delegated item", "--out", str(child),
|
|
328
|
+
"--run-id", "22222222-2222-4222-8222-222222222222", "--work-item-id", "WI-002",
|
|
329
|
+
])
|
|
330
|
+
parent_text = parent.read_text(encoding="utf-8")
|
|
331
|
+
child_text = child.read_text(encoding="utf-8")
|
|
332
|
+
assert '"event":"child_run.started"' in parent_text
|
|
333
|
+
assert "- flow_id: `FLOW-002`" in child_text
|
|
334
|
+
assert "- parent_run_id: `11111111-1111-4111-8111-111111111111`" in child_text
|
|
335
|
+
assert "- work_item_id: `WI-002`" in child_text
|
|
336
|
+
|
|
337
|
+
def test_prompt_flow_supports_multiple_delegated_work_items(self) -> None:
|
|
338
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
339
|
+
root = Path(tmp)
|
|
340
|
+
self._write_valid_skill(root)
|
|
341
|
+
parent = root / "work" / "sessions" / "parent.md"
|
|
342
|
+
children = [root / "work" / "sessions" / "child-a.md", root / "work" / "sessions" / "child-b.md"]
|
|
343
|
+
self._run_main([
|
|
344
|
+
"workflow", "run", "--task", "Mixed prompt", "--out", str(parent),
|
|
345
|
+
"--run-id", "11111111-1111-4111-8111-111111111111", "--flow-id", "FLOW-MULTI",
|
|
346
|
+
"--use-default-completion-conditions",
|
|
347
|
+
])
|
|
348
|
+
for index, child in enumerate(children, start=1):
|
|
349
|
+
self._run_main([
|
|
350
|
+
"workflow", "delegate", "--root", str(root), "--parent-log", str(parent),
|
|
351
|
+
"--meta", "skills/sample/meta.md", "--task", f"Execute item {index}",
|
|
352
|
+
"--out", str(child), "--run-id", f"{index + 1:08d}-2222-4222-8222-222222222222",
|
|
353
|
+
"--work-item-id", f"WI-00{index}",
|
|
354
|
+
])
|
|
355
|
+
|
|
356
|
+
payload = build_payload(root, root / "work" / "sessions")
|
|
357
|
+
flow = next(flow for flow in payload["flows"] if flow["flow_id"] == "FLOW-MULTI")
|
|
358
|
+
assert len(flow["run_ids"]) == 3
|
|
359
|
+
parent_run = next(run for run in flow["runs"] if run["run_id"] == "11111111-1111-4111-8111-111111111111")
|
|
360
|
+
assert len([event for event in parent_run["observation_events"] if event.get("event") == "child_run.started"]) == 2
|
|
361
|
+
assert {run["work_item_id"] for run in flow["runs"] if run["parent_run_id"]} == {"WI-001", "WI-002"}
|
|
362
|
+
|
|
363
|
+
def test_quality_review_routes_selected_skill_and_starts_child(self) -> None:
|
|
364
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
365
|
+
root = Path(tmp)
|
|
366
|
+
self._write_valid_skill(root)
|
|
367
|
+
parent = root / "work" / "sessions" / "parent.md"
|
|
368
|
+
child = root / "work" / "sessions" / "quality.md"
|
|
369
|
+
self._run_main([
|
|
370
|
+
"workflow", "run", "--task", "Review flow", "--out", str(parent),
|
|
371
|
+
"--run-id", "11111111-1111-4111-8111-111111111111",
|
|
372
|
+
"--flow-id", "FLOW-QUALITY", "--use-default-completion-conditions",
|
|
373
|
+
])
|
|
374
|
+
self._run_main([
|
|
375
|
+
"workflow", "quality-review", "--root", str(root), "--parent-log", str(parent),
|
|
376
|
+
"--meta", "skills/sample/meta.md", "--selected-skill", "sample_skill",
|
|
377
|
+
"--candidate", "sample_skill", "--reason", "The output requires the selected review capability",
|
|
378
|
+
"--task", "Review the output", "--out", str(child), "--work-item-id", "WI-001",
|
|
379
|
+
])
|
|
380
|
+
parent_text = parent.read_text(encoding="utf-8")
|
|
381
|
+
child_text = child.read_text(encoding="utf-8")
|
|
382
|
+
assert '"selection_mode":"quality_review"' in parent_text
|
|
383
|
+
assert '"event":"child_run.started"' in parent_text
|
|
384
|
+
assert "- flow_id: `FLOW-QUALITY`" in child_text
|
|
385
|
+
assert "- work_item_id: `WI-001`" in child_text
|
|
386
|
+
|
|
244
387
|
def test_dashboard_clears_missing_information_when_observability_is_recorded(self) -> None:
|
|
245
388
|
with tempfile.TemporaryDirectory() as tmp:
|
|
246
389
|
root = Path(tmp)
|
|
@@ -403,6 +546,7 @@ class DashboardTests(unittest.TestCase):
|
|
|
403
546
|
html = _html_page(build_payload(root, root / "work" / "sessions"))
|
|
404
547
|
|
|
405
548
|
self.assertIn('data-panel="overview"', html)
|
|
549
|
+
self.assertIn('data-panel="flows"', html)
|
|
406
550
|
self.assertIn('data-panel="attention"', html)
|
|
407
551
|
self.assertIn('data-panel="closure"', html)
|
|
408
552
|
self.assertIn('data-panel="evidence"', html)
|
|
@@ -411,6 +555,15 @@ class DashboardTests(unittest.TestCase):
|
|
|
411
555
|
self.assertIn('data-panel="analysis"', html)
|
|
412
556
|
self.assertIn('data-panel="missing-information"', html)
|
|
413
557
|
self.assertIn('id="overview"', html)
|
|
558
|
+
self.assertIn('id="flows"', html)
|
|
559
|
+
self.assertIn("Execution tree", html)
|
|
560
|
+
self.assertIn("Flow details", html)
|
|
561
|
+
self.assertIn("Work Item", html)
|
|
562
|
+
self.assertIn("Minimum intake", html)
|
|
563
|
+
self.assertIn("State", html)
|
|
564
|
+
self.assertIn("Execution records", html)
|
|
565
|
+
self.assertIn("Activity", html)
|
|
566
|
+
self.assertIn("Evidence and concerns", html)
|
|
414
567
|
self.assertIn('id="attention"', html)
|
|
415
568
|
self.assertIn('id="closure"', html)
|
|
416
569
|
self.assertIn('id="evidence"', html)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from xrefkit.host_precheck import build_precheck_report
|
|
5
|
+
from xrefkit.__main__ import main
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _spec(**overrides):
|
|
9
|
+
value = {
|
|
10
|
+
"host": "Codex Desktop 1.2",
|
|
11
|
+
"extension": "XRefKit extension 0.4.8",
|
|
12
|
+
"transcript_reference": "human-run/transcript-001",
|
|
13
|
+
"baseline": {"skill": "brownfield_workflow", "result": "managed"},
|
|
14
|
+
"observed": {"skill": "brownfield_workflow", "result": "managed"},
|
|
15
|
+
"evidence": {"bootstrap": True, "discovery": True, "route_selection": True},
|
|
16
|
+
"catalog": "available",
|
|
17
|
+
"intent": "clear",
|
|
18
|
+
}
|
|
19
|
+
value.update(overrides)
|
|
20
|
+
return value
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_precheck_passes_only_with_observable_managed_route_evidence():
|
|
24
|
+
report = build_precheck_report(_spec())
|
|
25
|
+
assert report["schema"] == "xrefkit.host_compatibility_precheck/v1"
|
|
26
|
+
assert report["assessment"]["status"] == "pass"
|
|
27
|
+
assert "private model reasoning" in report["unobservable"]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test_precheck_blocks_generic_preselection_without_claiming_override():
|
|
31
|
+
report = build_precheck_report(_spec(generic_preselection=True))
|
|
32
|
+
assert report["assessment"]["status"] == "blocked"
|
|
33
|
+
assert "explicit XRefKit entrypoint" in report["assessment"]["next_action"]
|
|
34
|
+
assert any("whether XRefKit overrode" in item for item in report["unobservable"])
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_precheck_distinguishes_missing_catalog_and_ambiguous_intent():
|
|
38
|
+
assert build_precheck_report(_spec(catalog="unavailable"))["assessment"]["status"] == "blocked"
|
|
39
|
+
assert build_precheck_report(_spec(intent="ambiguous"))["assessment"]["status"] == "needs_human_confirmation"
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_precheck_cli_writes_repeatable_json_report(tmp_path: Path, capsys):
|
|
43
|
+
source = tmp_path / "input.json"
|
|
44
|
+
output = tmp_path / "report.json"
|
|
45
|
+
source.write_text(json.dumps(_spec()), encoding="utf-8")
|
|
46
|
+
assert main(["host", "precheck", "--input", str(source), "--out", str(output)]) == 0
|
|
47
|
+
report = json.loads(output.read_text(encoding="utf-8"))
|
|
48
|
+
assert report["assessment"]["status"] == "pass"
|
|
49
|
+
assert json.loads(capsys.readouterr().out)["schema"] == report["schema"]
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import contextlib
|
|
2
|
+
import io
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from xrefkit.__main__ import main
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _run(root: Path, *args: str) -> int:
|
|
9
|
+
with contextlib.redirect_stdout(io.StringIO()):
|
|
10
|
+
argv = list(args)
|
|
11
|
+
if argv[:2] == ["workflow", "run"]:
|
|
12
|
+
argv.extend(["--root", str(root)])
|
|
13
|
+
return main(argv)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _closed_run(tmp_path: Path) -> Path:
|
|
17
|
+
log = tmp_path / "work" / "sessions" / "preceding.md"
|
|
18
|
+
assert _run(
|
|
19
|
+
tmp_path,
|
|
20
|
+
"workflow", "run", "--task", "Produce a bounded output", "--out", str(log),
|
|
21
|
+
"--use-default-completion-conditions",
|
|
22
|
+
) == 0
|
|
23
|
+
assert _run(
|
|
24
|
+
tmp_path, "skill", "workitem", "--log", str(log), "--item", "WI-001",
|
|
25
|
+
"--text", "Produce output", "--completion-criterion", "output is recorded",
|
|
26
|
+
"--status", "done", "--role", "instruction:executor",
|
|
27
|
+
) == 0
|
|
28
|
+
for artifact_id, kind, target, role in (
|
|
29
|
+
("OUT-001", "output", "output.md", "instruction:executor"),
|
|
30
|
+
("EVD-001", "evidence", "test command passed", "instruction:checker"),
|
|
31
|
+
):
|
|
32
|
+
assert _run(
|
|
33
|
+
tmp_path, "skill", "artifact", "--log", str(log), "--artifact", artifact_id,
|
|
34
|
+
"--kind", kind, "--target", target, "--item", "WI-001", "--status", "done",
|
|
35
|
+
"--role", role,
|
|
36
|
+
) == 0
|
|
37
|
+
assert _run(tmp_path, "skill", "phase", "--log", str(log), "--phase", "execution", "--status", "done", "--role", "instruction:executor") == 0
|
|
38
|
+
assert _run(tmp_path, "skill", "phase", "--log", str(log), "--phase", "handoff", "--status", "done", "--role", "instruction:handoff_owner") == 0
|
|
39
|
+
assert _run(tmp_path, "skill", "verify", "--log", str(log)) == 0
|
|
40
|
+
assert _run(tmp_path, "skill", "close", "--log", str(log)) == 0
|
|
41
|
+
return log
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def test_human_evaluation_is_optional_and_scoped(tmp_path: Path) -> None:
|
|
45
|
+
log = _closed_run(tmp_path)
|
|
46
|
+
assert _run(
|
|
47
|
+
tmp_path, "skill", "evaluate", "--log", str(log),
|
|
48
|
+
"--decision", "accepted_with_conditions",
|
|
49
|
+
"--classification", "correction",
|
|
50
|
+
"--next-handling", "repair_previous_run",
|
|
51
|
+
"--purpose-fit", "The overall purpose remains valid",
|
|
52
|
+
"--verified", "WI-001 and EVD-001",
|
|
53
|
+
"--uncertainty", "target B source is not snapshotted",
|
|
54
|
+
"--scope-finding", "WI-A|accepted|Target A is acceptable",
|
|
55
|
+
"--scope-finding", "WI-B|correction|Target B needs repair",
|
|
56
|
+
"--scope-link", "WI-B|EVD-B",
|
|
57
|
+
"--context-ref", "criteria:v1",
|
|
58
|
+
"--comparability", "gap",
|
|
59
|
+
"--comparability-gap", "target B source snapshot is unavailable",
|
|
60
|
+
"--evaluated-at", "2026-08-19T01:02:03Z",
|
|
61
|
+
"--proposed-classification", "continuation",
|
|
62
|
+
) == 0
|
|
63
|
+
text = log.read_text(encoding="utf-8")
|
|
64
|
+
assert '"event":"human.evaluation"' in text
|
|
65
|
+
assert '"classification":"correction"' in text
|
|
66
|
+
assert '"preceding_run_id"' in text
|
|
67
|
+
assert '"target":"WI-B"' in text
|
|
68
|
+
assert '"linked_targets":["EVD-B"]' in text
|
|
69
|
+
assert '"comparability":"gap"' in text
|
|
70
|
+
assert '"classification_source":"human_confirmed"' in text
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def test_human_evaluation_does_not_accept_an_open_run(tmp_path: Path) -> None:
|
|
74
|
+
log = tmp_path / "work" / "sessions" / "open.md"
|
|
75
|
+
assert _run(
|
|
76
|
+
tmp_path, "workflow", "run", "--task", "Open work", "--out", str(log),
|
|
77
|
+
"--use-default-completion-conditions",
|
|
78
|
+
) == 0
|
|
79
|
+
assert _run(
|
|
80
|
+
tmp_path, "skill", "evaluate", "--log", str(log), "--decision", "accepted",
|
|
81
|
+
"--classification", "continuation", "--next-handling", "continue_next_step",
|
|
82
|
+
"--purpose-fit", "still fits", "--verified", "none", "--uncertainty", "none",
|
|
83
|
+
) == 1
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def test_comparability_gap_requires_a_reason(tmp_path: Path) -> None:
|
|
87
|
+
log = _closed_run(tmp_path)
|
|
88
|
+
assert _run(
|
|
89
|
+
tmp_path, "skill", "evaluate", "--log", str(log), "--decision", "accepted",
|
|
90
|
+
"--classification", "continuation", "--next-handling", "continue_next_step",
|
|
91
|
+
"--purpose-fit", "still fits", "--verified", "none", "--uncertainty", "none",
|
|
92
|
+
"--comparability", "gap",
|
|
93
|
+
) == 1
|