feat(workforce-optimization): governed nonexpert clarification and evidence (#106)

## 摘要 / Summary

补问、原话解释与真人确认分离;增加版本能力预检、sourceField/evidenceLinks、有限语义用例及正确工件依赖顺序。

Separate answers, interpretation and human confirmation; add capability
discovery, explicit source/evidence bindings, finite semantic checks and
artifact ordering.

发现描述覆盖“仅澄清”入口;有歧义的原话保持缺口,不把“不确定”塞入精确枚举或规范化值。按当前对话语言加载框架与固定事实门尾注。

当前请求中已唯一确定的值会写成类型化、待真人确认的 `node.value`;只有未知或仍有歧义的事实才保持 `needs_input`。

Discovery covers clarify-only requests. Ambiguous raw answers remain
unresolved, rather than becoming exact placeholder values. The framework
and fixed fact-gate footer follow the current conversation language.

Exact values uniquely supplied by the current request become typed,
human-reviewable `node.value` proposals; only genuinely unknown or
ambiguous facts remain `needs_input`.

应用/服务重启或重试 fork 后,入口必须在当前父轮重新加载 Skill,并在委派前用 ToolCatalog 核实阶段工具;子 Agent
不得突破未激活父级的能力上限。

After an app/service restart or retry fork, the entry Agent reloads the
Skill in the current parent turn and verifies stage tools before
delegation; a child never expands an unactivated parent ceiling.

新的 decision-grade `OptimizationSpec` 强制使用 v2,并完整声明 `semantic_contract`
中的 solve intent 及所有 objective/variable/constraint/data reference
的单位/维度;legacy v1 仅只读兼容。

New decision-grade `OptimizationSpec` artifacts use v2 and a complete
semantic contract for solve intent plus every material objective,
variable, constraint and data reference; legacy v1 remains read-only
compatibility.

## 验证 / Validation

- Scoped Skill/i18n/catalog check passes with zero errors. Existing
repository warnings remain.
- Publication safety check passed, including hidden working-tree files,
new paths, branch/commit metadata and collaboration text.
- 双语说明与 source hash 已同步,版本更新为 2.7.0;缺少新平台契约时保持普通澄清,不模拟缺失门禁。
- Bilingual bodies and source hashes are synchronized at version 2.7.0.
Older clients stay in plain-text clarification when capability discovery
fails.

## 状态 / Status

Runtime acceptance is still in progress; draft only. No customer data,
credentials, solver software or deployment settings are included.

真机验收仍在进行,本 PR 暂为草稿。保留外部求解器许可证、部署和费用披露;本变更不包含求解器、客户数据或凭据。

---------

Co-authored-by: yige <yige@yigedeMacBook-Neo.local>
This commit is contained in:
2026-09-01 07:40:21 -04:00
committed by GitHub
parent e77c658958
commit 8265c8f4a9
6 changed files with 112 additions and 23 deletions

View File

@@ -207,6 +207,53 @@ class PublishableTeamCatalogTests(unittest.TestCase):
with tempfile.TemporaryDirectory() as tmp:
with patch.object(VALIDATOR, "REPO_ROOT", Path(tmp)):
self.assertEqual([], VALIDATOR.count_publishable_teams())
class WorkforceClarificationDiscoveryTests(unittest.TestCase):
"""Guard the catalog-only entry text; actual model selection still needs runtime acceptance."""
def test_clarify_only_requests_are_explicit_in_both_discovery_locales(self) -> None:
import json
import yaml
directory = Path(__file__).resolve().parents[2] / "skills" / "workforce-optimization"
raw = (directory / "SKILL.md").read_text(encoding="utf-8")
metadata = yaml.safe_load(raw.split("---", 2)[1])
locales = metadata["metadata"]["i18n"]
catalog = json.loads((directory / "catalog-metadata.v1.json").read_text(encoding="utf-8"))
# Keep the repository's on-demand-body policy; don't enable eager injection of all Skills.
self.assertIs(metadata["disable-model-invocation"], True)
self.assertIn("只澄清", metadata["description"][:180])
self.assertIn("Skill", metadata["description"][:180])
for locale, trigger in (("zh-CN", "暂不求解"), ("en-US", "clarify only")):
description = locales[locale]["description"]
self.assertIn(trigger, description)
self.assertIn("DecisionWorkspace", description)
self.assertIn("AskUserQuestion", description)
self.assertEqual(description, catalog["presentation"]["i18n"][locale]["description"])
self.assertIn("clarification works without a connected solver", metadata["compatibility"])
self.assertIn("separately", metadata["compatibility"])
self.assertIn("Generic AskUserQuestion may handle non-modeling setup", raw)
chinese = (directory / "SKILL.zh-CN.md").read_text(encoding="utf-8")
self.assertIn("普通 AskUserQuestion 只用于非建模设置选择", chinese)
def test_ambiguous_answers_and_current_language_keep_their_boundaries(self) -> None:
directory = Path(__file__).resolve().parents[2] / "skills" / "workforce-optimization"
english = (directory / "SKILL.md").read_text(encoding="utf-8")
chinese = (directory / "SKILL.zh-CN.md").read_text(encoding="utf-8")
self.assertIn("only if raw_text uniquely determines", english)
self.assertIn("keep the original answer and needs_input", english)
self.assertIn("Do not add epistemic placeholders", english)
self.assertIn("proposals must include a typed `node.value`", english)
self.assertIn("for Chinese use [中文澄清框架]", english)
# 以下断言分别覆盖中文规范化、未知与语言入口。
self.assertIn("仅在 raw_text 能唯一确定业务值及必要单位/统计窗口时", chinese)
self.assertIn("仍有歧义时保留原答案和 needs_input", chinese)
self.assertIn("不得把“目前不确定”“不知道”等知识缺口", chinese)
self.assertIn("提议节点必须写入类型化 `node.value`", chinese)
self.assertIn("技能 metadata 默认语言不覆盖用户语言", chinese)
for locale in ("", ".zh-CN"):
framework = (directory / "references" / f"requirement-clarification-framework{locale}.md").read_text(encoding="utf-8")
self.assertIn("needs_input", framework)
self.assertIn("node.value", framework)
if __name__ == "__main__":