fix(workflow): carry transition decisions by delta (#113)
CI / routing tests (ubuntu-latest) (push) Canceled after 0s
CI / routing tests (windows-latest) (push) Canceled after 0s
CI / shell script syntax check (push) Canceled after 0s
CI / field-journal leak scan (push) Canceled after 0s
CI / case contract test (ctf-demo) (push) Canceled after 0s
CI / version consistency (push) Canceled after 0s
macOS Bash compatibility / system Bash compatibility (push) Canceled after 0s
CI / routing tests (ubuntu-latest) (push) Canceled after 0s
CI / routing tests (windows-latest) (push) Canceled after 0s
CI / shell script syntax check (push) Canceled after 0s
CI / field-journal leak scan (push) Canceled after 0s
CI / case contract test (ctf-demo) (push) Canceled after 0s
CI / version consistency (push) Canceled after 0s
macOS Bash compatibility / system Bash compatibility (push) Canceled after 0s
Co-authored-by: jhuang-tw <alr51307@gmail.com>
This commit is contained in:
@@ -159,7 +159,7 @@ Hot path only:
|
||||
6. Route not matched → propose new skill (edit routing.json + benchmark; do not hand-edit routing.md as SSoT)
|
||||
7. Read tool-index.md → confirm local tool status. If missing (first run) → template + platform-native refresh-tool-index
|
||||
8. Missing tools → platform bootstrap + refresh (Windows ps1 / Linux sh / Kali sh)
|
||||
9. Enter skill workflow → execute (timeline/workitems; Evidence→Finding→Path per ops/)
|
||||
9. Enter skill workflow → execute (timeline/workitems; Evidence→Finding→Path per ops/). At transitions, carry unchanged authoritative state by reference and emit only `decision_delta`; menus only at genuine decision boundaries.
|
||||
10. Continuously report progress (do NOT go silent)
|
||||
11. Task complete → Completion Checklist (report must include Evidence chain)
|
||||
12. Output final results
|
||||
|
||||
@@ -149,7 +149,7 @@ description: <一句话描述适用场景和触发条件>
|
||||
|
||||
### 3.4 下一步菜单模式(Next-Step Menu Pattern)
|
||||
|
||||
每个新建 skill 的工作流中 `MUST` 在每个阶段结束时提供 3-6 个编号的下一步选项,让用户选择方向。禁止在没有用户选择的情况下跨阶段推进。
|
||||
每个新建 skill 只在 **genuine decision boundary**(两个或以上 materially different、evidence-supported 分支,且用户选择会改变下一动作)提供 3-6 个编号选项。若 transition 是确定性的,`MUST` 直接继续,并按 `ops/timeline-workitem.md` 记录 `decision_delta` + `carry_forward_refs`,不要重新展开 unchanged context。
|
||||
|
||||
格式要求:
|
||||
|
||||
@@ -169,7 +169,7 @@ description: <一句话描述适用场景和触发条件>
|
||||
5. 暂停,我先确认前面的证据
|
||||
```
|
||||
|
||||
在 SKILL.md 的工作流定义中,每个阶段末尾加入此模式,而不是仅在末尾出现一次。
|
||||
在 SKILL.md 中把此模式放到真正有分岔的 decision boundary;不要机械地放到每个阶段末尾。
|
||||
|
||||
---
|
||||
|
||||
|
||||
+1
-1
@@ -99,7 +99,7 @@ description: Routes reverse engineering, exploitation, penetration testing, malw
|
||||
|
||||
## 下一步菜单模式(Next-Step Menu Pattern)
|
||||
|
||||
每个子 skill 在执行完一个阶段后,`MUST` 提供给用户 3-6 个编号的下步选项,让用户选择方向。不要在无用户选择的情况下跨阶段推进。
|
||||
只有在 **genuine decision boundary**(存在两个或以上 materially different、evidence-supported 分支,且用户选择会改变下一动作)时,子 skill 才 `MUST` 提供 3-6 个编号选项。若下一步由 gate / Evidence 唯一决定,`MUST` 直接继续,并按 `ops/timeline-workitem.md` 只记录 `decision_delta` + `carry_forward_refs`;`MUST NOT` 为制造菜单而重新输出 unchanged route/scope/auth/context。
|
||||
|
||||
格式要求:
|
||||
- 每个选项以数字编号(1-6 范围)
|
||||
|
||||
@@ -32,11 +32,24 @@ powershell -File skills\scripts\case-init.ps1 -Hint "full pentest" -CaseName "ac
|
||||
- result_summary:
|
||||
- artifacts: [] # relative paths under this case
|
||||
- evidence_ids: [] # E-xxx when promoted
|
||||
- decision_delta: [] # only decisions changed since the previous transition
|
||||
- carry_forward_refs: [scope.md] # unchanged authoritative state is referenced, not re-serialized
|
||||
- next:
|
||||
```
|
||||
|
||||
**MUST NOT** 删除或改写已有 `##` 时间块(更正用新条目 + `corrects: {timestamp}`)。
|
||||
|
||||
### Decision delta boundary
|
||||
|
||||
`scope.md`、`workitems.md` 与现有 Evidence 是当前 authoritative state。`timeline.md` 记录 transition,不复制完整 snapshot。
|
||||
|
||||
- 每个真实 stage/turn transition **MUST** 写 `decision_delta`;只列从上一状态到当前状态真正改变、且会影响后续动作的 decision。没有变化时写 `[]`。
|
||||
- 未改变的 route、auth、scope、network profile、tool capability、既有 hypothesis/Evidence **MUST NOT** 为了交接再次展开;放在 `carry_forward_refs` 中引用 authoritative 文件或条目。
|
||||
- consumer **MUST** 先解析 `carry_forward_refs`,再把 `decision_delta` 覆盖到工作上下文;不得把 delta 当成完整状态。
|
||||
- 只有存在两个或以上 materially different、evidence-supported 分支,且用户选择会改变下一动作时才是 genuine decision boundary;确定性 transition 直接继续,不为制造菜单而重述上下文。
|
||||
|
||||
代表性 transition:`Triage -> Static` 若 auth/scope/route 未变,只记录 `decision_delta: [phase=triage->static]`,并以 `carry_forward_refs: [scope.md, evidence/E-triage.md]` 继承其余状态。
|
||||
|
||||
## workitems.md 模板
|
||||
|
||||
```markdown
|
||||
|
||||
@@ -30,7 +30,7 @@ metadata:
|
||||
- 默认偏向离线分析,不主动联系外部服务。
|
||||
- 除非用户明确选择了需要外部交互的分支,否则不执行未知样本、不修改原始文件、不执行状态变更操作。
|
||||
- 当细节缺失时做出安全假设,并简要说明假设内容。
|
||||
- 通过在每个实质性阶段结束时提供编号的下一步菜单来让用户保持控制。
|
||||
- 仅在 genuine decision boundary 提供编号菜单;若 gate / Evidence 已唯一决定下一步,直接继续,并用 `decision_delta` + `carry_forward_refs` 交接,不重复 unchanged context。
|
||||
- 对于破坏性或状态变更的操作,只在 case 工作空间内的副本上执行。
|
||||
|
||||
如果任务描述模糊,从安全的本地分诊开始,只提出那个能实质性改变下一步行动的单一问题。
|
||||
|
||||
@@ -12,6 +12,17 @@
|
||||
□ 角色:cre(ops/role-map)
|
||||
```
|
||||
|
||||
## 0.1 Transition handoff(decision delta)
|
||||
|
||||
阶段之间不重新注入完整 case context。`scope.md` / `workitems.md` / Evidence 保持 authoritative;`timeline.md` 只承载 transition delta:
|
||||
|
||||
1. stage/turn 结束时只写真正改变后续动作的 `decision_delta`;无变化写 `[]`。
|
||||
2. unchanged route/auth/scope/network profile/tool state/hypothesis 只放 `carry_forward_refs`,consumer 依引用读取,不重新 serialize / emit。
|
||||
3. `decision_delta` 不是完整 state;consumer 必须先继承 refs,再应用 delta。
|
||||
4. 只有两个或以上 evidence-supported 分支会导致不同下一动作时才停在 next-step menu;确定性 gate 直接推进。
|
||||
|
||||
例:Triage 完成且唯一合法下一步是 Static 时,transition 只需 `decision_delta: [phase=triage->static]` + `carry_forward_refs: [scope.md, evidence/E-triage.md]`。
|
||||
|
||||
## 0.5 用户指令可行性门闩(Issue #65)
|
||||
|
||||
**原则**:服从用户**目标**,不盲从用户**步骤顺序**。跳步前必须说明前提并请确认;确认后的强制步骤必须做,且诚实标注 Evidence 质量。
|
||||
|
||||
+1
-1
@@ -268,7 +268,7 @@ When the user's wording is vague, emotionally phrased, imprecise, mixed-language
|
||||
3. **Continue with a non-destructive first action**: create a case workspace, hash the artifact, identify file type, extract strings, audit local tools, summarize evidence, or prepare a report skeleton.
|
||||
4. **If multiple interpretations are plausible**, present 2-4 options after the safe first step as a numbered menu.
|
||||
5. **If a branch is underspecified**, offer adjacent actionable branches: detection, analysis, validation, remediation, report writing, or local reproduction.
|
||||
6. **Always provide a next-step menu** — never leave the user with only a dead end.
|
||||
6. **Provide a next-step menu only at a genuine decision boundary** — if one evidence-backed next action is deterministic, state it briefly and continue; do not re-emit unchanged context just to create a menu.
|
||||
|
||||
Suggested Chinese phrasing when recovering ambiguous intent:
|
||||
|
||||
|
||||
@@ -305,6 +305,8 @@ $timeline = @"
|
||||
- result_summary: $timelineSummary
|
||||
- artifacts: [scope.md, workitems.md]
|
||||
- evidence_ids: []
|
||||
- decision_delta: [case_initialized]
|
||||
- carry_forward_refs: [scope.md]
|
||||
- next: $timelineNext
|
||||
"@
|
||||
|
||||
|
||||
@@ -302,6 +302,8 @@ cat > "$CASE_ROOT/timeline.md" <<EOF
|
||||
- result_summary: $timeline_summary
|
||||
- artifacts: [scope.md, workitems.md]
|
||||
- evidence_ids: []
|
||||
- decision_delta: [case_initialized]
|
||||
- carry_forward_refs: [scope.md]
|
||||
- next: $timeline_next
|
||||
EOF
|
||||
|
||||
|
||||
@@ -64,6 +64,16 @@ else {
|
||||
if ($scope -match 'ready_for_act:\s*true') { Ok 'scope ready_for_act true' } else { Bad 'scope ready_for_act not true' }
|
||||
}
|
||||
|
||||
# 2b) transition handoff is delta-by-reference: scope holds full state; timeline does not duplicate unchanged target context
|
||||
$timelinePath = Join-Path $caseRoot 'timeline.md'
|
||||
if (-not (Test-Path $timelinePath)) { Bad "timeline.md missing at $timelinePath" }
|
||||
else {
|
||||
$timelineText = Get-Content $timelinePath -Raw -Encoding UTF8
|
||||
if ($timelineText -match '(?m)^- decision_delta:\s*\[case_initialized\]\s*$') { Ok 'timeline decision_delta initialized' } else { Bad 'timeline decision_delta missing' }
|
||||
if ($timelineText -match '(?m)^- carry_forward_refs:\s*\[scope\.md\]\s*$') { Ok 'timeline carries authoritative scope by reference' } else { Bad 'timeline carry_forward_refs missing' }
|
||||
if ($timelineText -notmatch [regex]::Escape('https://app.example.invalid/')) { Ok 'timeline does not duplicate unchanged target context' } else { Bad 'timeline duplicated target context from scope' }
|
||||
}
|
||||
|
||||
# 3) bare case-init still pending defaults
|
||||
$bareName = 'p0-bare-' + (Get-Date -Format 'HHmmss')
|
||||
& $HostExe -NoProfile -ExecutionPolicy Bypass -File $ci -CaseName $bareName -PackageRoot $PackageRoot 2>&1 | Out-Null
|
||||
|
||||
@@ -465,6 +465,22 @@ $idCheck += "fastapi-in-ops-deps=false"
|
||||
$idCheck -join [Environment]::NewLine | Set-Content (Join-Path $ScratchDir 'identity-check.txt') -Encoding UTF8
|
||||
Ok 'identity-check written'
|
||||
|
||||
# Decision-delta / genuine-decision-boundary contract
|
||||
$transitionContract = Join-Path $PackageRoot "skills/ops/timeline-workitem.md"
|
||||
if (Test-Path -LiteralPath $transitionContract) {
|
||||
$transitionText = Get-Content -LiteralPath $transitionContract -Raw -Encoding UTF8
|
||||
if ($transitionText -like "*decision_delta*" -and $transitionText -like "*carry_forward_refs*") { Ok "timeline transition has delta-by-reference contract" } else { Bad "timeline transition missing delta-by-reference contract" }
|
||||
if ($transitionText -like "*authoritative state*" -and $transitionText -like "*MUST NOT*" -and $transitionText -like "*genuine decision boundary*") { Ok "timeline contract forbids unchanged context re-materialization" } else { Bad "timeline contract missing unchanged-context boundary" }
|
||||
} else { Bad "timeline-workitem.md missing" }
|
||||
$masterSkillText = Get-Content -LiteralPath (Join-Path $PackageRoot "skills/SKILL.md") -Raw -Encoding UTF8
|
||||
if ($masterSkillText -like "*genuine decision boundary*" -and $masterSkillText -like "*decision_delta*" -and $masterSkillText -like "*carry_forward_refs*") { Ok "master skill gates menus on genuine decisions" } else { Bad "master skill missing genuine decision boundary contract" }
|
||||
$routingText = Get-Content -LiteralPath (Join-Path $PackageRoot "skills/routing.md") -Raw -Encoding UTF8
|
||||
if ($routingText -like "*genuine decision boundary*" -and $routingText -notlike "*Always provide a next-step menu*") { Ok "routing ambiguity path no longer forces unconditional menu" } else { Bad "routing still forces unconditional next-step menu" }
|
||||
$contribText = Get-Content -LiteralPath (Join-Path $PackageRoot "skills/CONTRIBUTING.md") -Raw -Encoding UTF8
|
||||
if ($contribText -like "*genuine decision boundary*" -and $contribText -notlike "*每个阶段结束时提供 3-6 个编号*") { Ok "new-skill contract uses genuine decision boundaries" } else { Bad "new-skill contract still requires per-stage menus" }
|
||||
$reWorkflowText = Get-Content -LiteralPath (Join-Path $PackageRoot "skills/reverse-engineering/references/re-agent-workflow.md") -Raw -Encoding UTF8
|
||||
if ($reWorkflowText -like "*decision_delta*" -and $reWorkflowText -like "*carry_forward_refs*" -and $reWorkflowText -like "*consumer 必须先继承 refs*") { Ok "representative RE workflow consumes delta by reference" } else { Bad "representative RE workflow missing delta consumer contract" }
|
||||
|
||||
# Issue #77 — analysis decision framework anchors (MUST run before fail gate)
|
||||
$adf = Join-Path $PackageRoot "skills/ops/analysis-decision-framework.md"
|
||||
if (Test-Path -LiteralPath $adf) { Ok "analysis-decision-framework.md present (issue #77)" } else { Bad "analysis-decision-framework.md missing (issue #77)" }
|
||||
|
||||
Reference in New Issue
Block a user