dsh-completion-guard 0.6.0 → 0.6.1
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.
- package/CHANGELOG.md +14 -0
- package/CHANGELOG.zh-CN.md +14 -0
- package/README.md +19 -9
- package/README.zh-CN.md +12 -8
- package/dist/domain/index.d.ts +2 -2
- package/dist/domain/index.js +2 -2
- package/dist/{domain-COehX7MB.js → domain-DKr8sLZZ.js} +453 -44
- package/dist/{index-BJPVGdg9.d.ts → index-C_N6DaSF.d.ts} +68 -6
- package/dist/index.d.ts +2 -2
- package/dist/index.js +244 -37
- package/docs/LOCAL_ACCEPTANCE.md +97 -0
- package/docs/NEXT_VERSION_REPAIR_NOTES.md +19 -3
- package/docs/WINDOWS_0_6_0_REPAIR_PLAN.md +92 -0
- package/package.json +2 -2
|
@@ -79,9 +79,11 @@ const PUNCT = String.raw`[\s。,、;:!?.,;:!?\-*"'“”‘’()(
|
|
|
79
79
|
/**
|
|
80
80
|
* Session-layer phrases that acknowledge or advance the conversation without
|
|
81
81
|
* stating a task. Longer forms come first so the alternation consumes them
|
|
82
|
-
* before their prefixes.
|
|
82
|
+
* before their prefixes. A bare whole-message acknowledgment ("当然。",
|
|
83
|
+
* "Of course.") is session talk: it is never captured as an obligation, so it
|
|
84
|
+
* can never block certification either.
|
|
83
85
|
*/
|
|
84
|
-
const PROGRESSION_SOURCE = String.raw`(
|
|
86
|
+
const PROGRESSION_SOURCE = String.raw`(?:继续执行|继续吧|请继续|继续|接着做|接着|下一步|没问题|知道了|明白了|了解|好的?|是的?|对的?|收到|可以|行|嗯+|当然|那当然|continue|go on|go ahead|keep going|proceed|okay|ok|yes|sure|right|next|of course)`;
|
|
85
87
|
const PROGRESSION_WHOLE = new RegExp(`^${PUNCT}*${PROGRESSION_SOURCE}${PUNCT}*$`, "i");
|
|
86
88
|
const PROGRESSION_LEAD = new RegExp(`^${PROGRESSION_SOURCE}${PUNCT}+`, "i");
|
|
87
89
|
const PROGRESSION_ANYWHERE = new RegExp(PROGRESSION_SOURCE, "gi");
|
|
@@ -944,9 +946,16 @@ const ACTION_VERB = new RegExp(ACTION_VERB_PATTERN, "i");
|
|
|
944
946
|
/** Operation verbs beyond the guard action surface (local work and diagnosis). */
|
|
945
947
|
const WORK_VERB = /创建|生成|新建|写入|修改|编辑|运行|执行|编写|撰写|部署|安装|升级|提交|下载|上传|拉取|同步|重启|测试|检查|验证|确认|修复|更新|清理|整理|记录|构建|编译|重构|迁移|删除|回滚|发布|推送|合并|继续|恢复|还原|回滚|实现|\b(?:build|create|write|modify|change|edit|run|fix|update|install|push|publish|test|verify|check|commit|deploy|migrate|remove|delete|restart|revert|refactor|inspect|fetch|pull|implement)\b/i;
|
|
946
948
|
/** Explanatory framings: an action named afterwards is an object, not an order. */
|
|
947
|
-
const EXPLAIN_VERB = /解释|说明|讲解|介绍|阐述|分析|讨论|描述|科普|什么意思|是什么意思|有什么(?:作用|影响|区别)|\bexplain\b|\bdescribe\b|\bclarify\b|\bwhat\s+does\b|\bwhat\s+is\b|\bhow\s+does\b|\bmeaning\s+of\b/i;
|
|
949
|
+
const EXPLAIN_VERB = /解释|说明|讲解|介绍|阐述|分析|讨论|描述|科普|什么意思|是什么意思|有什么(?:作用|影响|区别)|\bexplain\b|\bdescribe\b|\bclarify\b|\btell\b|\bhow\s+to\b|\bwhat\s+does\b|\bwhat\s+is\b|\bhow\s+does\b|\bmeaning\s+of\b/i;
|
|
948
950
|
/** Interrogative framings that make a scope a question rather than an order. */
|
|
949
|
-
|
|
951
|
+
/**
|
|
952
|
+
* Interrogative framings that make a scope a question rather than an order.
|
|
953
|
+
* The bare English wh-words are matched only at the START of a scope ("What
|
|
954
|
+
* changed in the build"), where they are genuine interrogatives; a mid-clause
|
|
955
|
+
* match would misread the relative clause of a real order ("Create a file
|
|
956
|
+
* where logs are stored") as a question — the 0.6.1 review regression.
|
|
957
|
+
*/
|
|
958
|
+
const QUESTION_SCOPE = /[??]|是否|是不是|为什么|为何|怎么|如何|什么|哪些|哪一种|能否|可否|要不要|该不该|由谁|是谁|^\s*(?:what|how|when|where|who|which|whether|why)\b|\b(?:whether|which|why|should|could|would)\b/i;
|
|
950
959
|
const NEGATORS = [
|
|
951
960
|
["不要", "zh"],
|
|
952
961
|
["不用", "zh"],
|
|
@@ -1097,7 +1106,17 @@ const NARRATIVE_PAST = /(?:已经|已|刚刚|刚才|此前|之前)(?:经)?(?:推
|
|
|
1097
1106
|
*/
|
|
1098
1107
|
const NARRATIVE_ASPECT = /(?:完了|好了|过了)|(?:已经|已|刚刚|刚才|此前|之前)[\p{Script=Han}]{0,4}(?:了|过)|\b(?:was|were|has been|have been)\b/iu;
|
|
1099
1108
|
const NARRATIVE_DIRECTIVE = /请|需要你|帮我|麻烦|务必|\b(?:please|must)\b/i;
|
|
1100
|
-
|
|
1109
|
+
/**
|
|
1110
|
+
* POSITIVE statement evidence (0.6.1 review): a clause with no resolvable
|
|
1111
|
+
* action reads as a statement only when one of these structural markers is
|
|
1112
|
+
* present — a passive (被/受到/遭到), a negator or progress marker
|
|
1113
|
+
* ("不要"/"没有"/"尚未"/"还没"/"从未"), or an English declarative shape
|
|
1114
|
+
* (finite aux/copula, or an article/possessive-led subject, which an
|
|
1115
|
+
* imperative can never start with). Everything else defaults to `unresolved`:
|
|
1116
|
+
* an unknown request ("Please sanitize these inputs", "处理这个问题") must
|
|
1117
|
+
* never degrade to information, where the turn's answer would auto-close it —
|
|
1118
|
+
* and no vocabulary can be complete, so the default never consults one.
|
|
1119
|
+
*/
|
|
1101
1120
|
/**
|
|
1102
1121
|
* A completed confirmation receipt: the root reports that the event it was
|
|
1103
1122
|
* waiting for already happened. It reserves nothing, so it must not mint a
|
|
@@ -1360,8 +1379,11 @@ function scopeOf(raw, options = {}) {
|
|
|
1360
1379
|
...conditionText ? { condition: conditionText } : {}
|
|
1361
1380
|
}
|
|
1362
1381
|
});
|
|
1363
|
-
|
|
1364
|
-
|
|
1382
|
+
if (head$1 && (clauseStart < 0 || firstActionVerb(maskCodeSpans(head$1)) >= 0)) pending.push({
|
|
1383
|
+
text: head$1,
|
|
1384
|
+
offset
|
|
1385
|
+
});
|
|
1386
|
+
} else if (head$1) pending.push({
|
|
1365
1387
|
text: head$1,
|
|
1366
1388
|
offset
|
|
1367
1389
|
});
|
|
@@ -1664,23 +1686,37 @@ function stripNegatorsPrefix(value) {
|
|
|
1664
1686
|
function stripConnectors(text) {
|
|
1665
1687
|
return text.replace(new RegExp(`^${CONNECTOR_PATTERN}\\s*`, "i"), "").trim();
|
|
1666
1688
|
}
|
|
1667
|
-
/**
|
|
1689
|
+
/**
|
|
1690
|
+
* Whether a past/aspect marker is the clause's ENTIRE predicate: the span
|
|
1691
|
+
* extends to the end of the clause (only particles and punctuation may
|
|
1692
|
+
* follow), so no modifier ("…的"), attributive chain, or coordinated demand
|
|
1693
|
+
* can hide behind the report (0.6.1 review round 8: distance thresholds and
|
|
1694
|
+
* coordinator lists cannot enumerate modifiers).
|
|
1695
|
+
*/
|
|
1696
|
+
function mainClauseTailReport(masked) {
|
|
1697
|
+
for (const pattern of [NARRATIVE_PAST, NARRATIVE_ASPECT]) {
|
|
1698
|
+
const match = pattern.exec(masked);
|
|
1699
|
+
if (!match) continue;
|
|
1700
|
+
if (/^[^,。;!?\s]*的/u.test(masked.slice(match.index + match[0].length))) continue;
|
|
1701
|
+
if (/^(?:了|过)?[。,;!?、\s.!?]*$/u.test(masked.slice(match.index + match[0].length))) return true;
|
|
1702
|
+
}
|
|
1703
|
+
return false;
|
|
1704
|
+
}
|
|
1668
1705
|
function classifyPositive(text) {
|
|
1669
1706
|
const masked = maskCodeSpans(text);
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
if (explain) {
|
|
1673
|
-
const verb = firstActionVerb(masked);
|
|
1674
|
-
if (verb < 0 || verb >= explain.index) return "informational";
|
|
1675
|
-
}
|
|
1707
|
+
const visibleVerb = firstActionVerb(masked);
|
|
1708
|
+
if (visibleVerb < 0 && firstActionVerb(text) >= 0) return "informational";
|
|
1676
1709
|
if (QUESTION_SCOPE.test(masked)) return "informational";
|
|
1677
|
-
if (
|
|
1678
|
-
if ((NARRATIVE_PAST.test(masked) || NARRATIVE_ASPECT.test(masked)) && !NARRATIVE_DIRECTIVE.test(masked)) return "narrative";
|
|
1710
|
+
if (mainClauseTailReport(masked) && !NARRATIVE_DIRECTIVE.test(masked)) return "narrative";
|
|
1679
1711
|
if (CONFIRMATION_RECEIPT.test(masked.trim())) return "narrative";
|
|
1712
|
+
if (visibleVerb < 0) return "unresolved";
|
|
1713
|
+
const explain = EXPLAIN_VERB.exec(masked);
|
|
1714
|
+
if (explain && (visibleVerb < 0 || visibleVerb >= explain.index)) return "unresolved";
|
|
1715
|
+
if (/了[。,;!?、\s.!?]*$/u.test(masked)) return "unresolved";
|
|
1680
1716
|
return "directive";
|
|
1681
1717
|
}
|
|
1682
1718
|
function executeeOf(text, directive) {
|
|
1683
|
-
if (directive
|
|
1719
|
+
if (directive !== "directive") return "unresolved";
|
|
1684
1720
|
const masked = maskCodeSpans(text);
|
|
1685
1721
|
if (USER_ACTOR_PATTERNS.some((pattern) => pattern.test(masked))) return "user";
|
|
1686
1722
|
if (AGENT_ACTOR_PATTERNS.some((pattern) => pattern.test(masked))) return "agent";
|
|
@@ -1693,6 +1729,7 @@ function isOutputRequest(text) {
|
|
|
1693
1729
|
}
|
|
1694
1730
|
function dispositionOf(scope, executee) {
|
|
1695
1731
|
if (scope.directive === "prohibition") return "prohibition";
|
|
1732
|
+
if (scope.directive === "unresolved") return "unresolved";
|
|
1696
1733
|
if (scope.directive === "informational" || scope.directive === "narrative") return "informational";
|
|
1697
1734
|
if (scope.directive === "conditional") return "conditional_wait";
|
|
1698
1735
|
if (scope.condition) return "conditional_wait";
|
|
@@ -1763,7 +1800,7 @@ function interpretClause(text, options = {}) {
|
|
|
1763
1800
|
directive: "informational"
|
|
1764
1801
|
});
|
|
1765
1802
|
if (scopes.length === 1) return interpret(scopes[0]);
|
|
1766
|
-
const directive = scopes.some((scope) => scope.directive === "directive") ? "directive" : scopes.some((scope) => scope.directive === "prohibition") ? "prohibition" : "informational";
|
|
1803
|
+
const directive = scopes.some((scope) => scope.directive === "directive") ? "directive" : scopes.some((scope) => scope.directive === "prohibition") ? "prohibition" : scopes.some((scope) => scope.directive === "unresolved") ? "unresolved" : "informational";
|
|
1767
1804
|
return interpret({
|
|
1768
1805
|
text: normalized,
|
|
1769
1806
|
body: scopes.map((scope) => scope.body).join(";"),
|
|
@@ -2384,6 +2421,10 @@ const REASON_CLASS_TABLE = {
|
|
|
2384
2421
|
legacy_authority_unclassified: "source_insufficient",
|
|
2385
2422
|
inquiry_non_certifiable: "source_insufficient",
|
|
2386
2423
|
inquiry_awaiting_delivery: "source_insufficient",
|
|
2424
|
+
asset_interpretation_required: "source_insufficient",
|
|
2425
|
+
information_non_certifiable: "source_insufficient",
|
|
2426
|
+
information_awaiting_delivery: "source_insufficient",
|
|
2427
|
+
interpretation_unresolved: "source_insufficient",
|
|
2387
2428
|
answer_delivered: "source_insufficient",
|
|
2388
2429
|
certified: "source_insufficient",
|
|
2389
2430
|
semantic_action_mismatch: "source_insufficient",
|
|
@@ -2427,7 +2468,10 @@ const REASON_CLASS_TABLE = {
|
|
|
2427
2468
|
proof_external_fact_incomplete: "producer_capability_unavailable",
|
|
2428
2469
|
proof_source_bounded_delegation: "producer_capability_unavailable",
|
|
2429
2470
|
historical_evidence_gap: "historical_gap",
|
|
2471
|
+
effect_already_applied: "historical_gap",
|
|
2472
|
+
action_already_applied: "historical_gap",
|
|
2430
2473
|
effect_only_insufficient_state_readback: "historical_gap",
|
|
2474
|
+
execution_unattributable: "historical_gap",
|
|
2431
2475
|
rebind_evidence_predates_source: "historical_gap",
|
|
2432
2476
|
resolution_expected_transition_missing: "historical_gap",
|
|
2433
2477
|
resolution_expected_transition_digest_missing: "historical_gap",
|
|
@@ -2470,6 +2514,7 @@ const REASON_CLASS_TABLE = {
|
|
|
2470
2514
|
certificate_manifest_rejected: "integrity_failure",
|
|
2471
2515
|
session_ref_unavailable: "integrity_failure",
|
|
2472
2516
|
projection_durability_unavailable: "integrity_failure",
|
|
2517
|
+
interpretation_receipt_mismatch: "integrity_failure",
|
|
2473
2518
|
guard_unavailable: "integrity_failure",
|
|
2474
2519
|
binding_role_mismatch: "integrity_failure",
|
|
2475
2520
|
binding_role_order_invalid: "integrity_failure",
|
|
@@ -2556,17 +2601,51 @@ const TARGET_FIELD_REASONS = {
|
|
|
2556
2601
|
requested_target_service_id_missing: "service_id",
|
|
2557
2602
|
requested_target_registry_missing_or_invalid: "registry"
|
|
2558
2603
|
};
|
|
2604
|
+
/**
|
|
2605
|
+
* The evidence roles the item's OWN obligation contract requires (0.6.1,
|
|
2606
|
+
* W060-04). A stateful change needs the full resolution/effect/state chain; a
|
|
2607
|
+
* read-only verification (inspect, test, verify, generic readback) needs ONE
|
|
2608
|
+
* matching fact in the `effect` role — exactly the manifest `simpleRecord`
|
|
2609
|
+
* accepts. Asking every obligation for all three roles made prepare and
|
|
2610
|
+
* diagnosis demand a change chain a read-only verification can never produce.
|
|
2611
|
+
*/
|
|
2612
|
+
function requiredEvidenceRoles(item) {
|
|
2613
|
+
return isStatefulAction(item.semanticAction ?? "generic_run") ? [
|
|
2614
|
+
"resolution",
|
|
2615
|
+
"effect",
|
|
2616
|
+
"state"
|
|
2617
|
+
] : ["effect"];
|
|
2618
|
+
}
|
|
2559
2619
|
function evidenceFacets(p, item) {
|
|
2560
2620
|
const present = /* @__PURE__ */ new Set();
|
|
2561
2621
|
for (const evidence of p.evidence.values()) {
|
|
2562
2622
|
if (!relevantEvidence(p, item, evidence)) continue;
|
|
2563
2623
|
if (evidence.evidenceRole) present.add(evidence.evidenceRole);
|
|
2564
2624
|
}
|
|
2565
|
-
return
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2625
|
+
return requiredEvidenceRoles(item).filter((facet) => !present.has(facet));
|
|
2626
|
+
}
|
|
2627
|
+
/**
|
|
2628
|
+
* An ordinary shell command whose TEXT ANCHORED at command position to this
|
|
2629
|
+
* obligation's action completed successfully, but which failed closed
|
|
2630
|
+
* parsing, so per-command execution cannot be established (0.6.1, W060-05).
|
|
2631
|
+
* Only the pre-existing head-anchored action signal counts: the guard does
|
|
2632
|
+
* NOT scan compound text for actions, because quoted data and short-circuit
|
|
2633
|
+
* control flow would fabricate observations. A failed command is not a
|
|
2634
|
+
* signal either.
|
|
2635
|
+
*/
|
|
2636
|
+
function unattributedExecutionOf(p, item) {
|
|
2637
|
+
const action = item.semanticAction;
|
|
2638
|
+
if (!action || action === "generic_run") return void 0;
|
|
2639
|
+
for (const evidence of p.evidence.values()) {
|
|
2640
|
+
if (evidence.outcome !== "success") continue;
|
|
2641
|
+
if (evidence.parseStatus === void 0 || evidence.parseStatus === "supported") continue;
|
|
2642
|
+
if (![
|
|
2643
|
+
"bash",
|
|
2644
|
+
"pwsh",
|
|
2645
|
+
"shell"
|
|
2646
|
+
].includes(evidence.toolName)) continue;
|
|
2647
|
+
if (evidence.semanticAction !== void 0 && evidence.semanticAction !== "generic_run" && actionCompatible(action, evidence.semanticAction)) return evidence;
|
|
2648
|
+
}
|
|
2570
2649
|
}
|
|
2571
2650
|
/**
|
|
2572
2651
|
* The pure repair judge. It decides between: fixable from existing evidence,
|
|
@@ -2650,6 +2729,21 @@ function judgeItemDiagnosis(p, item) {
|
|
|
2650
2729
|
};
|
|
2651
2730
|
if (kind === "inquiry") {
|
|
2652
2731
|
const closable = p.boundaryProtocol === 5;
|
|
2732
|
+
if (item.asset !== void 0 && !p.interpretationFacts.some((fact) => fact.itemId === item.id)) return {
|
|
2733
|
+
...base,
|
|
2734
|
+
certification: "unsupported",
|
|
2735
|
+
reason_code: "asset_interpretation_required",
|
|
2736
|
+
repairability: "unsupported",
|
|
2737
|
+
missing_fields: [],
|
|
2738
|
+
missing_facets: [],
|
|
2739
|
+
next_action: {
|
|
2740
|
+
kind: "report_only",
|
|
2741
|
+
tool: "context_guard_interpret",
|
|
2742
|
+
required_input: `the item ID of the interpreted attachment (${item.id})`,
|
|
2743
|
+
resume_condition: "Read the attachment, record it with context_guard_interpret for this item, and deliver the actual answer; the host-confirmed final response of a completed turn then closes this item. The record proves the asset was read, never that the interpretation is correct."
|
|
2744
|
+
},
|
|
2745
|
+
attempt_fingerprint: fingerprint(p, item, "asset_interpretation_required")
|
|
2746
|
+
};
|
|
2653
2747
|
return {
|
|
2654
2748
|
...base,
|
|
2655
2749
|
certification: "unsupported",
|
|
@@ -2664,6 +2758,35 @@ function judgeItemDiagnosis(p, item) {
|
|
|
2664
2758
|
attempt_fingerprint: fingerprint(p, item, closable ? "inquiry_awaiting_delivery" : "inquiry_non_certifiable")
|
|
2665
2759
|
};
|
|
2666
2760
|
}
|
|
2761
|
+
if (item.authorityDisposition === "informational") {
|
|
2762
|
+
const closable = p.boundaryProtocol === 5;
|
|
2763
|
+
return {
|
|
2764
|
+
...base,
|
|
2765
|
+
certification: "unsupported",
|
|
2766
|
+
reason_code: closable ? "information_awaiting_delivery" : "information_non_certifiable",
|
|
2767
|
+
repairability: "unsupported",
|
|
2768
|
+
missing_fields: [],
|
|
2769
|
+
missing_facets: [],
|
|
2770
|
+
next_action: {
|
|
2771
|
+
kind: "report_only",
|
|
2772
|
+
resume_condition: closable ? "The trusted final response of this turn closes the recorded statement; it certifies the answer was delivered, never its accuracy." : "The recorded statement stays open as uncertified information; no confirmation, rebind, or execution changes this."
|
|
2773
|
+
},
|
|
2774
|
+
attempt_fingerprint: fingerprint(p, item, closable ? "information_awaiting_delivery" : "information_non_certifiable")
|
|
2775
|
+
};
|
|
2776
|
+
}
|
|
2777
|
+
if (item.authorityDisposition === "unresolved") return {
|
|
2778
|
+
...base,
|
|
2779
|
+
certification: "unsupported",
|
|
2780
|
+
reason_code: "interpretation_unresolved",
|
|
2781
|
+
repairability: "none",
|
|
2782
|
+
missing_fields: [],
|
|
2783
|
+
missing_facets: [],
|
|
2784
|
+
next_action: {
|
|
2785
|
+
kind: "report_only",
|
|
2786
|
+
resume_condition: "The clause could not be read as a concrete instruction; it stays recorded, non-executable, and never closes by delivery. A new explicit root instruction naming a supported action supersedes it."
|
|
2787
|
+
},
|
|
2788
|
+
attempt_fingerprint: fingerprint(p, item, "interpretation_unresolved")
|
|
2789
|
+
};
|
|
2667
2790
|
if (action !== "generic_run" && !item.legacyFlags?.length && item.targetCaptureStatus === "clarification_required") {
|
|
2668
2791
|
const missingFields = item.targetCaptureReasonCode ? [TARGET_FIELD_REASONS[item.targetCaptureReasonCode] ?? item.targetCaptureReasonCode] : [];
|
|
2669
2792
|
return {
|
|
@@ -2718,7 +2841,20 @@ function judgeItemDiagnosis(p, item) {
|
|
|
2718
2841
|
},
|
|
2719
2842
|
attempt_fingerprint: fingerprint(p, item, "adapter_unavailable")
|
|
2720
2843
|
};
|
|
2721
|
-
|
|
2844
|
+
const statefulChain = isStatefulAction(action);
|
|
2845
|
+
if (requiredEvidenceRoles(item).some((role) => !missing_facets.includes(role)) ? void 0 : unattributedExecutionOf(p, item)) return {
|
|
2846
|
+
...base,
|
|
2847
|
+
certification: "unsupported",
|
|
2848
|
+
reason_code: "execution_unattributable",
|
|
2849
|
+
repairability: "historical_gap",
|
|
2850
|
+
missing_fields: [],
|
|
2851
|
+
next_action: {
|
|
2852
|
+
kind: "report_only",
|
|
2853
|
+
resume_condition: "An ordinary shell command beginning with this action succeeded earlier in the session, but the command could not be securely parsed, so whether it performed the action cannot be established. Check the actual current state with a read-only command first. The obligation stays uncertified; perform the action through the guarded producer path only if the state shows it has not happened and the instruction still calls for it; never repeat an action to mint evidence, and do not assert it never ran."
|
|
2854
|
+
},
|
|
2855
|
+
attempt_fingerprint: fingerprint(p, item, "execution_unattributable")
|
|
2856
|
+
};
|
|
2857
|
+
if (statefulChain && missing_facets.includes("resolution") && !missing_facets.includes("effect")) return {
|
|
2722
2858
|
...base,
|
|
2723
2859
|
certification: "unsupported",
|
|
2724
2860
|
reason_code: "historical_evidence_gap",
|
|
@@ -2739,7 +2875,7 @@ function judgeItemDiagnosis(p, item) {
|
|
|
2739
2875
|
next_action: {
|
|
2740
2876
|
kind: "collect_evidence",
|
|
2741
2877
|
tool: "context_guard_prepare",
|
|
2742
|
-
resume_condition: "Collect the matching durable evidence in resolution/effect/state order, then checkpoint."
|
|
2878
|
+
resume_condition: statefulChain ? "Collect the matching durable evidence in resolution/effect/state order, then checkpoint." : "Collect the single matching durable verification fact, then checkpoint."
|
|
2743
2879
|
},
|
|
2744
2880
|
attempt_fingerprint: fingerprint(p, item, "missing_evidence")
|
|
2745
2881
|
};
|
|
@@ -3358,6 +3494,7 @@ function createProjection() {
|
|
|
3358
3494
|
releaseStateDamaged: false,
|
|
3359
3495
|
policy: "standard",
|
|
3360
3496
|
trustedSelections: [],
|
|
3497
|
+
interpretationFacts: [],
|
|
3361
3498
|
approvals: [],
|
|
3362
3499
|
sessionRefDigest: "11".repeat(32),
|
|
3363
3500
|
hostLockDigest: "22".repeat(32),
|
|
@@ -4954,7 +5091,7 @@ function renderRecoveryPacket(projection, options = {}) {
|
|
|
4954
5091
|
if (add(`[${clip(item.id, 20)}] root_condition_pending; wait for trusted root: ${item.resumeEvent ?? item.condition ?? item.normalizedText}; do not execute before release`, compact ? 160 : 310)) count++;
|
|
4955
5092
|
return;
|
|
4956
5093
|
}
|
|
4957
|
-
const remedy = diagnosis.repairability === "agent_repairable" ? "Collect matching evidence; checkpoint" : diagnosis.repairability === "historical_gap" ? "Read back observed state; do not re-execute" : diagnosis.next_action.kind === "clarify_target" ? "Supply the exact target; then collect evidence and checkpoint" : diagnosis.certification === "unsupported" ? "Deliver honestly; stays uncertified unless a fresh instruction names a supported action" : "Restore audited host/adapter capability";
|
|
5094
|
+
const remedy = diagnosis.repairability === "agent_repairable" ? "Collect matching evidence; checkpoint" : diagnosis.repairability === "historical_gap" ? "Read back observed state; do not re-execute" : diagnosis.repairability === "none" ? "Recorded as unresolved; only a fresh explicit instruction resolves it" : diagnosis.next_action.tool === "context_guard_interpret" ? "Read the attachment; record context_guard_interpret; then answer" : diagnosis.next_action.kind === "clarify_target" ? "Supply the exact target; then collect evidence and checkpoint" : diagnosis.certification === "unsupported" ? "Deliver honestly; stays uncertified unless a fresh instruction names a supported action" : "Restore audited host/adapter capability";
|
|
4958
5095
|
if (add(`[${clip(item.id, 20)}] ${diagnosis.reason_code}; ${compact ? remedy : diagnosis.next_action.resume_condition ?? remedy}; ${clip(item.normalizedText, 70)}`, compact ? 110 : 310)) count++;
|
|
4959
5096
|
};
|
|
4960
5097
|
if (constraints[0]) constraint(constraints[0]);
|
|
@@ -9832,16 +9969,37 @@ function deriveTrustedDeliveries(events) {
|
|
|
9832
9969
|
* slot is information (an inquiry or an explanation request). Execution,
|
|
9833
9970
|
* constraints, and unknowns are never closed by delivery, and neither are
|
|
9834
9971
|
* questions from earlier messages.
|
|
9835
|
-
|
|
9836
|
-
|
|
9972
|
+
*
|
|
9973
|
+
* An ATTACHMENT obligation (one with an `asset` identity) closes through its
|
|
9974
|
+
* CURRENT interpretation instead of its original message (0.6.1 W060-01
|
|
9975
|
+
* review): a re-interpreted old asset would otherwise never close, because
|
|
9976
|
+
* its root message can no longer belong to a live turn. The binding is the
|
|
9977
|
+
* interpretation fact itself — the delivery must be the answer of the turn
|
|
9978
|
+
* that recorded the interpretation, and the fact must exist at the delivery
|
|
9979
|
+
* watermark. The final answer — even a real one — still never interprets
|
|
9980
|
+
* images on the model's behalf.
|
|
9981
|
+
*/
|
|
9982
|
+
function informationItemIdsForDelivery(items, delivery, turnRootInputSeqs, eligibleUnitIds, interpretationFacts) {
|
|
9837
9983
|
const closed = [];
|
|
9838
9984
|
for (const [itemId, item] of items) {
|
|
9839
9985
|
if (item.status !== "pending") continue;
|
|
9840
9986
|
if (item.kind === "prohibition") continue;
|
|
9841
|
-
|
|
9842
|
-
|
|
9843
|
-
|
|
9844
|
-
|
|
9987
|
+
const isAssetObligation = item.asset !== void 0 && item.asset !== null;
|
|
9988
|
+
if (item.unitId !== void 0 && eligibleUnitIds !== void 0 && !eligibleUnitIds.has(item.unitId)) continue;
|
|
9989
|
+
const informationSlot = item.taskKind === "inquiry" || item.authorityDisposition === "informational" && item.kind === "requirement";
|
|
9990
|
+
item.asset !== void 0 && item.asset;
|
|
9991
|
+
if (isAssetObligation) {
|
|
9992
|
+
if (!(interpretationFacts ?? []).some((fact) => fact.itemId === itemId && fact.turn === delivery.turn && fact.resultSeq <= delivery.turnEndSeq)) continue;
|
|
9993
|
+
closed.push(itemId);
|
|
9994
|
+
continue;
|
|
9995
|
+
}
|
|
9996
|
+
if (informationSlot) {
|
|
9997
|
+
const interpretedThisTurn = (interpretationFacts ?? []).some((fact) => fact.itemId === itemId && fact.turn === delivery.turn && fact.resultSeq <= delivery.turnEndSeq);
|
|
9998
|
+
const sourceSeq = /^m(\d+)(?::|$)/.exec(item.sourceMessageId);
|
|
9999
|
+
if (!interpretedThisTurn && (!sourceSeq || !turnRootInputSeqs.has(Number(sourceSeq[1])))) continue;
|
|
10000
|
+
closed.push(itemId);
|
|
10001
|
+
continue;
|
|
10002
|
+
}
|
|
9845
10003
|
}
|
|
9846
10004
|
return closed;
|
|
9847
10005
|
}
|
|
@@ -10551,6 +10709,180 @@ function pushReleaseDiagnostic(projection, seq, reasonCode, damaging = false) {
|
|
|
10551
10709
|
});
|
|
10552
10710
|
if (projection.releaseDiagnostics.length > 16) projection.releaseDiagnostics.shift();
|
|
10553
10711
|
}
|
|
10712
|
+
function assetReceiptMatches(receipt, asset) {
|
|
10713
|
+
const record = asRecord(receipt);
|
|
10714
|
+
return record !== void 0 && record.message_seq === asset.messageSeq && record.part_index === asset.partIndex && record.media_sha256 === asset.mediaSha256;
|
|
10715
|
+
}
|
|
10716
|
+
/**
|
|
10717
|
+
* Atomically supersede one unresolved clause by its recorded interpretation
|
|
10718
|
+
* partition (0.6.1 review round 10). Every declared sub-span becomes its own
|
|
10719
|
+
* obligation bound to the exact sub-span: information sub-spans become
|
|
10720
|
+
* delivery-closable informational obligations; declared-unknown and
|
|
10721
|
+
* undeclared sub-spans become pending unresolved obligations that keep the
|
|
10722
|
+
* clause's execution and unknown demands open. Returns the ids of the
|
|
10723
|
+
* created information sub-items.
|
|
10724
|
+
*/
|
|
10725
|
+
function supersedeClauseByPartition(projection, item, receipt) {
|
|
10726
|
+
const extent = itemExtentOf(item);
|
|
10727
|
+
const information = readPartitionSpans(receipt.information_spans);
|
|
10728
|
+
const unknown = readPartitionSpans(receipt.unknown_spans);
|
|
10729
|
+
if (!information || !unknown) return [];
|
|
10730
|
+
for (const span of [...information, ...unknown]) if (span.start < extent.start || span.end > extent.end) return [];
|
|
10731
|
+
const ordered = [...information, ...unknown].sort((left, right) => left.start - right.start || left.end - right.end);
|
|
10732
|
+
for (let index = 1; index < ordered.length; index += 1) if (ordered[index].start < ordered[index - 1].end) return [];
|
|
10733
|
+
const complement = [];
|
|
10734
|
+
let cursor = extent.start;
|
|
10735
|
+
for (const span of ordered) {
|
|
10736
|
+
if (span.start > cursor) complement.push({
|
|
10737
|
+
start: cursor,
|
|
10738
|
+
end: span.start
|
|
10739
|
+
});
|
|
10740
|
+
cursor = Math.max(cursor, span.end);
|
|
10741
|
+
}
|
|
10742
|
+
if (cursor < extent.end) complement.push({
|
|
10743
|
+
start: cursor,
|
|
10744
|
+
end: extent.end
|
|
10745
|
+
});
|
|
10746
|
+
const partIndex = (item.spans ?? [])[0]?.partIndex ?? 0;
|
|
10747
|
+
const rawTextSha256 = item.rawTextSha256;
|
|
10748
|
+
const revisionBase = projection.contractRevision;
|
|
10749
|
+
const informationIds = [];
|
|
10750
|
+
const makeSubItem = (span, informational, offset$1) => {
|
|
10751
|
+
const revision = revisionBase + 1 + offset$1;
|
|
10752
|
+
const kind = "requirement";
|
|
10753
|
+
const id = `${informational ? "R" : "R"}${nextNumericId(projection.items, "R")}`;
|
|
10754
|
+
const sub = {
|
|
10755
|
+
id,
|
|
10756
|
+
revision,
|
|
10757
|
+
kind,
|
|
10758
|
+
sourceMessageId: item.sourceMessageId,
|
|
10759
|
+
normalizedText: item.normalizedText,
|
|
10760
|
+
textSha256: item.textSha256,
|
|
10761
|
+
status: "pending",
|
|
10762
|
+
verification: {
|
|
10763
|
+
enforced: false,
|
|
10764
|
+
surface: "scope",
|
|
10765
|
+
subject: item.verification.subject ?? "scope"
|
|
10766
|
+
},
|
|
10767
|
+
semanticAction: "generic_run",
|
|
10768
|
+
requestedTarget: { scope: item.verification.subject ?? "scope" },
|
|
10769
|
+
targetCaptureStatus: "resolved",
|
|
10770
|
+
authority: item.authority,
|
|
10771
|
+
taskKind: informational ? "inquiry" : "action",
|
|
10772
|
+
directive: informational ? "informational" : void 0,
|
|
10773
|
+
executee: "unresolved",
|
|
10774
|
+
authorityDisposition: informational ? "informational" : "unresolved",
|
|
10775
|
+
interpretationFingerprint: `partition:${item.id}:${span.start}:${span.end}`,
|
|
10776
|
+
rawTextSha256,
|
|
10777
|
+
spans: [{
|
|
10778
|
+
partIndex,
|
|
10779
|
+
start: span.start,
|
|
10780
|
+
end: span.end,
|
|
10781
|
+
class: "instruction"
|
|
10782
|
+
}],
|
|
10783
|
+
unitId: item.unitId,
|
|
10784
|
+
clarifiesItemId: item.id,
|
|
10785
|
+
interpretedFromUnresolved: item.id
|
|
10786
|
+
};
|
|
10787
|
+
projection.items.set(id, sub);
|
|
10788
|
+
projection.contractRevision = Math.max(projection.contractRevision, revision);
|
|
10789
|
+
return sub;
|
|
10790
|
+
};
|
|
10791
|
+
let offset = 0;
|
|
10792
|
+
for (const span of information) {
|
|
10793
|
+
informationIds.push(makeSubItem(span, true, offset).id);
|
|
10794
|
+
offset += 1;
|
|
10795
|
+
}
|
|
10796
|
+
for (const span of [...unknown, ...complement]) {
|
|
10797
|
+
makeSubItem(span, false, offset);
|
|
10798
|
+
offset += 1;
|
|
10799
|
+
}
|
|
10800
|
+
if (informationIds.length > 0) {
|
|
10801
|
+
item.status = "superseded";
|
|
10802
|
+
item.supersededBy = informationIds[0];
|
|
10803
|
+
}
|
|
10804
|
+
return informationIds;
|
|
10805
|
+
}
|
|
10806
|
+
/** The next numeric id for a prefix, shared with nextId's numbering. */
|
|
10807
|
+
function nextNumericId(items, prefix) {
|
|
10808
|
+
let max = 0;
|
|
10809
|
+
for (const item of items.values()) {
|
|
10810
|
+
if (!item.id.startsWith(prefix)) continue;
|
|
10811
|
+
const num = Number(item.id.slice(prefix.length));
|
|
10812
|
+
if (Number.isInteger(num) && num > max) max = num;
|
|
10813
|
+
}
|
|
10814
|
+
return max + 1;
|
|
10815
|
+
}
|
|
10816
|
+
function readPartitionSpans(raw) {
|
|
10817
|
+
if (!Array.isArray(raw)) return void 0;
|
|
10818
|
+
const spans = [];
|
|
10819
|
+
for (const entry of raw) {
|
|
10820
|
+
const record = asRecord(entry);
|
|
10821
|
+
const start = record?.start;
|
|
10822
|
+
const end = record?.end;
|
|
10823
|
+
if (typeof start !== "number" || !Number.isSafeInteger(start) || typeof end !== "number" || !Number.isSafeInteger(end) || start >= end) return void 0;
|
|
10824
|
+
spans.push({
|
|
10825
|
+
start,
|
|
10826
|
+
end
|
|
10827
|
+
});
|
|
10828
|
+
}
|
|
10829
|
+
return spans;
|
|
10830
|
+
}
|
|
10831
|
+
function itemExtentOf(item) {
|
|
10832
|
+
const spans = item.spans ?? [];
|
|
10833
|
+
if (spans.length === 0) return {
|
|
10834
|
+
start: 0,
|
|
10835
|
+
end: 0
|
|
10836
|
+
};
|
|
10837
|
+
return {
|
|
10838
|
+
start: Math.min(...spans.map((span) => span.start)),
|
|
10839
|
+
end: Math.max(...spans.map((span) => span.end))
|
|
10840
|
+
};
|
|
10841
|
+
}
|
|
10842
|
+
/**
|
|
10843
|
+
* Replay validation of a clause-kind interpretation: the CALL's partition
|
|
10844
|
+
* (from the persisted tool/call arguments) must be present and structurally
|
|
10845
|
+
* valid against the obligation's extent, the receipt's echoed spans must
|
|
10846
|
+
* match the contract's spans, and the receipt's partition must EQUAL the
|
|
10847
|
+
* call's partition. A receipt that redraws the partition — replacing a
|
|
10848
|
+
* submitted unknown span with an information claim — is tampering.
|
|
10849
|
+
*/
|
|
10850
|
+
function clauseCallReceiptMatches(callInformation, callUnknown, recorded, item) {
|
|
10851
|
+
const spans = item.spans ?? [];
|
|
10852
|
+
const echoed = recorded.spans;
|
|
10853
|
+
if (!Array.isArray(echoed) || echoed.length !== spans.length) return false;
|
|
10854
|
+
if (!spans.every((span, index) => {
|
|
10855
|
+
const echo = asRecord(echoed[index]);
|
|
10856
|
+
return echo !== void 0 && echo.part_index === span.partIndex && echo.start === span.start && echo.end === span.end;
|
|
10857
|
+
})) return false;
|
|
10858
|
+
if (callInformation === void 0 || callUnknown === void 0 || callInformation.length === 0) return false;
|
|
10859
|
+
const extent = itemExtentOf(item);
|
|
10860
|
+
const allCall = [...callInformation, ...callUnknown];
|
|
10861
|
+
for (const span of allCall) if (span.start < extent.start || span.end > extent.end) return false;
|
|
10862
|
+
const orderedCall = [...allCall].sort((left, right) => left.start - right.start || left.end - right.end);
|
|
10863
|
+
for (let index = 1; index < orderedCall.length; index += 1) if (orderedCall[index].start < orderedCall[index - 1].end) return false;
|
|
10864
|
+
const receiptInformation = readPartitionSpans(recorded.information_spans);
|
|
10865
|
+
const receiptUnknown = readPartitionSpans(recorded.unknown_spans);
|
|
10866
|
+
if (receiptInformation === void 0 || receiptUnknown === void 0) return false;
|
|
10867
|
+
return samePartition(receiptInformation, receiptUnknown, callInformation, callUnknown);
|
|
10868
|
+
}
|
|
10869
|
+
function samePartition(leftInformation, leftUnknown, rightInformation, rightUnknown) {
|
|
10870
|
+
const normalize = (information, unknown) => {
|
|
10871
|
+
const ordered = [...information.map((span) => ({
|
|
10872
|
+
...span,
|
|
10873
|
+
information: true
|
|
10874
|
+
})), ...unknown.map((span) => ({
|
|
10875
|
+
...span,
|
|
10876
|
+
information: false
|
|
10877
|
+
}))].sort((left, right) => left.start - right.start || left.end - right.end);
|
|
10878
|
+
return JSON.stringify(ordered.map((span) => [
|
|
10879
|
+
span.start,
|
|
10880
|
+
span.end,
|
|
10881
|
+
span.information
|
|
10882
|
+
]));
|
|
10883
|
+
};
|
|
10884
|
+
return normalize(leftInformation, leftUnknown) === normalize(rightInformation, rightUnknown);
|
|
10885
|
+
}
|
|
10554
10886
|
/**
|
|
10555
10887
|
* Whether a recorded certificate is exactly the certificate this log re-derives.
|
|
10556
10888
|
*
|
|
@@ -10805,6 +11137,7 @@ function insertItems(projection, text, sourceMessageId, scope, authority = "root
|
|
|
10805
11137
|
for (const [id, item] of projection.items) {
|
|
10806
11138
|
if (before.has(id)) continue;
|
|
10807
11139
|
if (item.kind !== "requirement" || item.waitAuthorization || item.authorityDisposition === "conditional_wait") continue;
|
|
11140
|
+
if (item.authorityDisposition !== void 0 && item.authorityDisposition !== "executable_now") continue;
|
|
10808
11141
|
for (const [otherId, other] of projection.items) {
|
|
10809
11142
|
if (otherId === id || other.status !== "pending") continue;
|
|
10810
11143
|
if (!other.waitAuthorization || other.kind !== "requirement") continue;
|
|
@@ -10825,7 +11158,7 @@ function insertItems(projection, text, sourceMessageId, scope, authority = "root
|
|
|
10825
11158
|
if (otherId === id || !before.has(otherId)) continue;
|
|
10826
11159
|
if (other.status !== "pending" || other.kind === "prohibition") continue;
|
|
10827
11160
|
if (other.waitAuthorization || other.legacyFlags?.length) continue;
|
|
10828
|
-
if (other.semanticAction
|
|
11161
|
+
if (!(other.semanticAction === "generic_run" && (other.authorityDisposition === "executable_now" || other.authorityDisposition === "unresolved"))) continue;
|
|
10829
11162
|
if (other.normalizedText.length < 4) continue;
|
|
10830
11163
|
if (!clarificationText.includes(other.normalizedText)) continue;
|
|
10831
11164
|
if (other.verification.subject !== item.verification.subject) continue;
|
|
@@ -10863,6 +11196,7 @@ function insert(projection, segment, sourceMessageId, subject, surface, unitId,
|
|
|
10863
11196
|
if (duplicate) supersedeItem(projection.items, duplicate.id, item);
|
|
10864
11197
|
else projection.items.set(id, item);
|
|
10865
11198
|
projection.contractRevision = item.revision;
|
|
11199
|
+
return item;
|
|
10866
11200
|
}
|
|
10867
11201
|
/**
|
|
10868
11202
|
* Pure, deterministic re-derivation of the guard projection from the DSH
|
|
@@ -10894,6 +11228,7 @@ function deriveProjection(sourceEvents, config, scope, durableConfirmed, hostLoc
|
|
|
10894
11228
|
let realRootInputSeen = false;
|
|
10895
11229
|
const trustedDeliveries = (v5BoundarySeq !== void 0 ? deriveTrustedDeliveries(sourceEvents) : []).filter((delivery) => delivery.turnEndSeq > v5BoundarySeq);
|
|
10896
11230
|
let deliveryCursor = 0;
|
|
11231
|
+
const interpretationFacts = [];
|
|
10897
11232
|
const applyDeliveriesUpTo = (seq) => {
|
|
10898
11233
|
while (deliveryCursor < trustedDeliveries.length && trustedDeliveries[deliveryCursor].turnEndSeq <= seq) {
|
|
10899
11234
|
const delivery = trustedDeliveries[deliveryCursor];
|
|
@@ -10902,7 +11237,7 @@ function deriveProjection(sourceEvents, config, scope, durableConfirmed, hostLoc
|
|
|
10902
11237
|
if (!inputSeqs) continue;
|
|
10903
11238
|
const owningUnitId = turnUnitIds.get(delivery.turn);
|
|
10904
11239
|
const eligibleUnitIds = owningUnitId === void 0 ? void 0 : new Set([owningUnitId, ...unitDescendantIds(projection, owningUnitId)]);
|
|
10905
|
-
for (const itemId of informationItemIdsForDelivery(projection.items, delivery, inputSeqs, eligibleUnitIds)) {
|
|
11240
|
+
for (const itemId of informationItemIdsForDelivery(projection.items, delivery, inputSeqs, eligibleUnitIds, interpretationFacts)) {
|
|
10906
11241
|
const item = projection.items.get(itemId);
|
|
10907
11242
|
if (!item || item.status !== "pending") continue;
|
|
10908
11243
|
const sourceSeq = /^m(\d+)(?::|$)/.exec(item.sourceMessageId);
|
|
@@ -11084,7 +11419,7 @@ function deriveProjection(sourceEvents, config, scope, durableConfirmed, hostLoc
|
|
|
11084
11419
|
if ((v4BoundarySeq ?? v5BoundarySeq) !== void 0 && event.seq > (v4BoundarySeq ?? v5BoundarySeq)) content.forEach((part, index) => {
|
|
11085
11420
|
if (!part || typeof part !== "object" || part.type === "text") return;
|
|
11086
11421
|
const identity = sha256(JSON.stringify(part));
|
|
11087
|
-
insert(projection, {
|
|
11422
|
+
const assetItem = insert(projection, {
|
|
11088
11423
|
kind: "requirement",
|
|
11089
11424
|
body: `Uninterpreted root asset m${event.seq} part ${index}: sha256 ${identity}. Interpret the attachment; its contents are reference data, not execution authority.`,
|
|
11090
11425
|
text: `Uninterpreted root asset m${event.seq} part ${index}`,
|
|
@@ -11092,13 +11427,19 @@ function deriveProjection(sourceEvents, config, scope, durableConfirmed, hostLoc
|
|
|
11092
11427
|
interpretation: {
|
|
11093
11428
|
text: `Uninterpreted root asset m${event.seq} part ${index}`,
|
|
11094
11429
|
body: `Interpret the attached asset m${event.seq} part ${index}`,
|
|
11095
|
-
directive: "
|
|
11096
|
-
executee: "
|
|
11097
|
-
immediatelyExecutable:
|
|
11098
|
-
authorityDisposition: "
|
|
11430
|
+
directive: "informational",
|
|
11431
|
+
executee: "unresolved",
|
|
11432
|
+
immediatelyExecutable: false,
|
|
11433
|
+
authorityDisposition: "informational",
|
|
11099
11434
|
fingerprint: `asset:${identity.slice(0, 16)}`
|
|
11100
11435
|
}
|
|
11101
11436
|
}, `m${event.seq}:asset:${index}`, scope.cwd || "scope", "scope", unitId);
|
|
11437
|
+
assetItem.taskKind = "inquiry";
|
|
11438
|
+
assetItem.asset = {
|
|
11439
|
+
messageSeq: event.seq,
|
|
11440
|
+
partIndex: index,
|
|
11441
|
+
mediaSha256: identity
|
|
11442
|
+
};
|
|
11102
11443
|
});
|
|
11103
11444
|
};
|
|
11104
11445
|
if (!text.trim()) {
|
|
@@ -11186,6 +11527,7 @@ function deriveProjection(sourceEvents, config, scope, durableConfirmed, hostLoc
|
|
|
11186
11527
|
name: String(data?.name ?? ""),
|
|
11187
11528
|
arguments: String(data?.arguments ?? ""),
|
|
11188
11529
|
rootCallId: typeof data?.rootCallId === "string" ? data.rootCallId : void 0,
|
|
11530
|
+
...typeof data?.turn === "number" && Number.isSafeInteger(data.turn) ? { turn: data.turn } : {},
|
|
11189
11531
|
...projection.currentUnitId !== void 0 ? { unitIdAtCall: projection.currentUnitId } : {}
|
|
11190
11532
|
};
|
|
11191
11533
|
if (call.name === "context_guard_checkpoint") {
|
|
@@ -11323,6 +11665,47 @@ function deriveProjection(sourceEvents, config, scope, durableConfirmed, hostLoc
|
|
|
11323
11665
|
} else certifyCheckpoint(projection, call.bindings ?? [], id, true);
|
|
11324
11666
|
break;
|
|
11325
11667
|
}
|
|
11668
|
+
if (call.name === "context_guard_interpret") {
|
|
11669
|
+
if (!call.rootCallId && !data?.error) {
|
|
11670
|
+
const callArgs = parseArguments(call.arguments);
|
|
11671
|
+
const requested = typeof callArgs.item_id === "string" ? callArgs.item_id.trim() : "";
|
|
11672
|
+
const recorded = parseArguments(textContent);
|
|
11673
|
+
if (recorded.status === "recorded") {
|
|
11674
|
+
const item = requested ? projection.items.get(requested) : void 0;
|
|
11675
|
+
const resultTurn = typeof data?.turn === "number" && Number.isSafeInteger(data.turn) ? data.turn : void 0;
|
|
11676
|
+
const callInformation = readPartitionSpans(callArgs.information_spans);
|
|
11677
|
+
const callUnknown = readPartitionSpans(callArgs.unknown_spans);
|
|
11678
|
+
if (!(requested !== "" && item !== void 0 && item.status === "pending" && recorded.item_id === requested && recorded.item_revision === item.revision && (item.asset !== void 0 ? recorded.kind === "asset" && !Object.hasOwn(recorded, "information_spans") && !Object.hasOwn(recorded, "unknown_spans") && assetReceiptMatches(recorded.asset, item.asset) : recorded.kind === "clause" && clauseCallReceiptMatches(callInformation, callUnknown, recorded, item)))) {
|
|
11679
|
+
projection.integrity = "corrupt";
|
|
11680
|
+
projection.integrityViolations.push("interpretation_receipt_mismatch");
|
|
11681
|
+
break;
|
|
11682
|
+
}
|
|
11683
|
+
if (call.turn === void 0 || resultTurn === void 0) break;
|
|
11684
|
+
if (call.turn !== resultTurn) {
|
|
11685
|
+
projection.integrity = "corrupt";
|
|
11686
|
+
projection.integrityViolations.push("interpretation_receipt_mismatch");
|
|
11687
|
+
break;
|
|
11688
|
+
}
|
|
11689
|
+
if (item.asset !== void 0) {
|
|
11690
|
+
const existing = interpretationFacts.findIndex((fact) => fact.itemId === requested);
|
|
11691
|
+
if (existing >= 0) interpretationFacts.splice(existing, 1);
|
|
11692
|
+
interpretationFacts.push({
|
|
11693
|
+
itemId: requested,
|
|
11694
|
+
resultSeq: event.seq,
|
|
11695
|
+
turn: call.turn
|
|
11696
|
+
});
|
|
11697
|
+
} else {
|
|
11698
|
+
const informationSubItemIds = supersedeClauseByPartition(projection, item, asRecord(recorded));
|
|
11699
|
+
for (const subItemId of informationSubItemIds) if (interpretationFacts.findIndex((fact) => fact.itemId === subItemId) < 0) interpretationFacts.push({
|
|
11700
|
+
itemId: subItemId,
|
|
11701
|
+
resultSeq: event.seq,
|
|
11702
|
+
turn: call.turn
|
|
11703
|
+
});
|
|
11704
|
+
}
|
|
11705
|
+
}
|
|
11706
|
+
}
|
|
11707
|
+
break;
|
|
11708
|
+
}
|
|
11326
11709
|
if (call.name === "context_guard_boundary") {
|
|
11327
11710
|
const recorded = parseArguments(textContent);
|
|
11328
11711
|
const candidate = call.boundaryRequest ? qualifyBoundary(projection, call.boundaryRequest) : void 0;
|
|
@@ -11376,6 +11759,8 @@ function deriveProjection(sourceEvents, config, scope, durableConfirmed, hostLoc
|
|
|
11376
11759
|
}
|
|
11377
11760
|
projection.enabled = enabled;
|
|
11378
11761
|
projection.epoch = epoch;
|
|
11762
|
+
if (interpretationFacts.length > 64) interpretationFacts.splice(0, interpretationFacts.length - 64);
|
|
11763
|
+
projection.interpretationFacts = interpretationFacts;
|
|
11379
11764
|
projection.trustedSelections = deriveTrustedSelections(sourceEvents, { questionToolNames: DEFAULT_QUESTION_TOOL_NAMES });
|
|
11380
11765
|
if (projection.trustedSelections.length > 16) projection.trustedSelections = projection.trustedSelections.slice(-16);
|
|
11381
11766
|
const approvalAsked = /* @__PURE__ */ new Map();
|
|
@@ -11490,15 +11875,23 @@ function previewFirstStepInjection(input, claimedRealInput) {
|
|
|
11490
11875
|
if (input.boundaryV5Present) return void 0;
|
|
11491
11876
|
return {
|
|
11492
11877
|
boundary: PROTOCOL_V5_NOTICE,
|
|
11493
|
-
guidance:
|
|
11878
|
+
guidance: firstStepGuidance(input.policy ?? "standard")
|
|
11494
11879
|
};
|
|
11495
11880
|
}
|
|
11496
11881
|
/**
|
|
11497
11882
|
* Compact first-step guidance: protection has started, what it protects, and
|
|
11498
|
-
* the
|
|
11499
|
-
*
|
|
11883
|
+
* when the guarded producer path is needed. 0.6.1 (W060-05): the stateful
|
|
11884
|
+
* workflow is stated CONDITIONALLY — only an obligation whose own clause
|
|
11885
|
+
* demands a certified stateful action runs through prepare/producer/checkpoint.
|
|
11886
|
+
* The 0.6.0 text demanded that order for every stateful action unconditionally,
|
|
11887
|
+
* which ordinary business work correctly read as a Guard approval gate.
|
|
11888
|
+
* Ordinary answers, investigations, and ordinary tool work are never gated, and
|
|
11889
|
+
* missing Guard evidence is never a reason to repeat a completed action.
|
|
11500
11890
|
*/
|
|
11501
|
-
|
|
11891
|
+
function firstStepGuidance(policy = "standard") {
|
|
11892
|
+
return "Context Guard is now protecting this session: requirements from your messages stay open until they are certified with matching durable evidence. Ordinary answers, investigations, and ordinary tool work need no Guard approval. When a requirement itself calls for a certified stateful action (install, apply, create, modify, restart, commit, push, publish, pull, fetch), call context_guard_prepare before it to see the supported command shape and the required resolution/effect/state order, run the action through the guarded path, and close items with context_guard_checkpoint; never repeat an already-completed action to mint missing evidence." + (policy === "strict" ? " Under strict policy, a verification the user explicitly requested (a visual readback or a complete-scope check) must be discharged by a real readback fact." : "") + " Ordinary answers and investigations need no certification.";
|
|
11893
|
+
}
|
|
11894
|
+
const FIRST_STEP_GUIDANCE = firstStepGuidance("standard");
|
|
11502
11895
|
/**
|
|
11503
11896
|
* Lifecycle phase derived from durable facts. `enabled` is the log-derived
|
|
11504
11897
|
* enablement (`always`, or the explicit `on`/`off` command sequence), and
|
|
@@ -11793,6 +12186,22 @@ async function executeRevalidatedGitEffect(resolved, manifest, target, currentSt
|
|
|
11793
12186
|
status: "rejected",
|
|
11794
12187
|
...checked.reasonCode ? { reasonCode: checked.reasonCode } : {}
|
|
11795
12188
|
};
|
|
12189
|
+
const text = (key) => {
|
|
12190
|
+
const value = currentStateTuple[key];
|
|
12191
|
+
return typeof value === "string" ? value : value === void 0 ? void 0 : Buffer.from(value).toString("utf8");
|
|
12192
|
+
};
|
|
12193
|
+
if (manifest.action === "push" && text("source_oid") !== void 0 && text("source_oid") === text("destination_oid")) return {
|
|
12194
|
+
status: "rejected",
|
|
12195
|
+
reasonCode: "effect_already_applied"
|
|
12196
|
+
};
|
|
12197
|
+
if (manifest.action === "pull" && text("pre_head_oid") !== void 0 && text("pre_head_oid") === text("upstream_oid")) return {
|
|
12198
|
+
status: "rejected",
|
|
12199
|
+
reasonCode: "effect_already_applied"
|
|
12200
|
+
};
|
|
12201
|
+
if (manifest.action === "fetch" && text("tracking_oid") !== void 0 && text("tracking_oid") === text("upstream_oid")) return {
|
|
12202
|
+
status: "rejected",
|
|
12203
|
+
reasonCode: "effect_already_applied"
|
|
12204
|
+
};
|
|
11796
12205
|
await runner("git", manifest.argv.slice(1), target.repository);
|
|
11797
12206
|
return { status: "executed" };
|
|
11798
12207
|
}
|
|
@@ -12407,4 +12816,4 @@ function verifyComposedHostLockDump(text, expected, roots) {
|
|
|
12407
12816
|
}
|
|
12408
12817
|
|
|
12409
12818
|
//#endregion
|
|
12410
|
-
export {
|
|
12819
|
+
export { extractToolSubject as $, isFrozenV042RebindResponse as $n, sha256 as $r, proofDigest as $t, lifecyclePhase as A, decisionBoundaryKey as An, STATEFUL_ACTIONS as Ar, compareHostVersions as At, RELEASE_RESERVATION_PREFIX as B, effectuateBoundary as Bn, semanticActionFromCommand as Br, certifyCheckpoint as Bt, gitCommandMatchesTarget as C, isVerifyingCapability as Cn, npmEscapedPackageName as Cr, evaluateToolSurfaceCapability as Ct, FIRST_STEP_GUIDANCE as D, classifyCompletionClaim as Dn, CERTIFICATE_VERSION as Dr, MIN_SUPPORTED_HOST_VERSION as Dt, verifiedLinearCommitReadback as E, NO_PROGRESS_TURNS_BEFORE_STOP as En, BOUNDED_ARTIFACT_TYPES as Er, LATEST_SUPPORTED_HOST_VERSION as Et, PROTOCOL_V4_NOTICE as F, observeAssistantOutcome as Fn, boundedArtifactChoiceMatches as Fr, RC015_HOST_PACKAGES as Ft, readbackSettlesContract as G, confirmRebind as Gn, validateManifest as Gr, PROOF_PROTOCOL_VERSION as Gt, contractById as H, qualifyBoundary as Hn, validateActionManifest as Hr, PROOF_KINDS as Ht, PROTOCOL_V5_NOTICE as I, progressFingerprint as In, isStatefulAction as Ir, RC1_HOST_PACKAGES as It, releasePreEffectDecision as J, proposeRebindV042 as Jn, canonicalizePath as Jr, bindProofV2ToProjection as Jt, releaseContractFor as K, proposeRebind as Kn, classifyTaskIntent as Kr, PROOF_PROTOCOL_VERSION_V2 as Kt, deriveProjection as L, goalCompletionDenial as Ln, requestedIdentityKey as Lr, ALPHA3_HOST_PACKAGES as Lt, CAPTURE_V042_NOTICE as M, isWholeTaskCompletionClaim as Mn, STOP_PROTOCOL_VERSION_V2 as Mr, parseHostVersion as Mt, DEFAULT_DELEGATION_TOOL_NAMES as N, latestAssistantText as Nn, SUPPORTED_EVIDENCE_ADAPTERS as Nr, satisfiesSupportedHostRange as Nt, claimedBatchHasRealRootInput as O, decideTurnBoundary as On, CERTIFICATE_VERSION_V2 as Or, SUPPORTED_HOST_RANGE as Ot, PROTOCOL_V3_NOTICE as P, latestRootInstruction as Pn, actionCompatible as Pr, RC015_RC2_HOST_PACKAGES as Pt, extractTextContent as Q, CONFIRM_LINE_PATTERN as Qn, sanitizeUrl as Qr, proofCapabilityReport as Qt, RELEASE_OPERATIONS as R, hasCurrentCertificate as Rn, requestedTargetAuthorizesMutation as Rr, authorityCaptureCounts as Rt, executeRevalidatedGitEffect as S, evidenceMatchesItem as Sn, canonicalRegistryBase as Sr, evaluateHostLock as St, revalidateGitPrestate as T, NO_PROGRESS_RECORD_PREFIX as Tn, ACTION_MANIFEST_VERSION as Tr, selectHostCohort as Tt, inFlightReservation as U, currentContractDigest as Un, validateActionTarget as Ur, PROOF_KINDS_V2 as Ut, RELEASE_SETTLEMENT_PREFIX as V, isCurrentAcceptedBoundary as Vn, semanticActionFromText as Vr, PROOF_CAPABILITY_MATRIX as Vt, normalizeReleaseContract as W, createProjection as Wn, COMMAND_SURFACE_MANIFEST as Wr, PROOF_MANIFEST_DOMAIN_V2 as Wt, supersedeItem as X, rebindResponse as Xn, normalizeClause as Xr, createProofManifest as Xt, reservationFor as Y, rebindAttemptKey as Yn, digestStrings as Yr, canonicalProjection as Yt, evidenceFromPersistedToolResult as Z, replayRebindResult as Zn, sanitizeClauseText as Zr, createProofManifestV2 as Zt, GIT_COMMAND_MANIFEST_IDS as _, openItems as _n, kindOfScope as _r, LEGACY_HOST_COHORTS as _t, injectActiveProfileHostLock as a, requiredSubjectsOf as an, captureClause as ar, parseShellCommand as at, commitTreeSnapshotDigest as b, bindingSatisfies as bn, semanticActionOfScope as br, evaluateExternalWaitCapability as bt, packageRowsFromPnpmLock as c, sessionQueryV2 as cn, extractArtifactPaths as cr, ACTIVE_HOST_LAUNCHER_VERSION as ct, resolveInstalledHostLock as d, certifiableOpenItems as dn, isInformationalMessage as dr, BASE_HOST_PACKAGES as dt, proofDigestV2 as en, parseConfirmationMessage as er, isDeterministicCheck as et, verifyComposedHostLockDump as f, certificateClosure as fn, segmentClauses as fr, DEFAULT_HOST_LOCK as ft, snapshotSessionEvents as g, closingHint as gn, isOpenObligation as gr, HOST_COHORTS as gt, SessionApiError as h, MIN_RECOVERY_CHAR_BUDGET as hn, isExecutableItem as hr, HOST_CAPABILITY_PACKAGE_GROUPS as ht, hostLockRowsFromComposedDump as i, proofV2Rejection as in, relevantEvidence as ir, parsePwshCommand as it, previewFirstStepInjection as j, isRootPauseRequest as jn, STOP_PROTOCOL_VERSION as jr, evaluateMinimumHostVersion as jt, firstStepGuidance as k, decideTurnStopping as kn, SEMANTIC_ACTIONS as kr, SUPPORTED_HOST_VERSIONS as kt, readActiveHostGraph as l, validateProofManifest as ln, extractMethod as lr, ALPHA2_DSHMARKET_139_HOST_PACKAGES as lt, SESSION_EVENT_ENVELOPE_INVALID as m, DEFAULT_RECOVERY_CHAR_BUDGET as mn, interpretMessage as mr, GOAL_HOST_PACKAGES as mt, combineHostPolicy as n, proofHostSurfacesOf as nn, evidenceAvailabilityReason as nr, canonicalArgvFromCommand as nt, inspectTargetHostGraph as o, scopeCoverageDigest as on, captureItem as or, ACTIVE_HOST_COHORT_ID as ot, SESSION_API_UNSUPPORTED as p, unitDescendantIds as pn, interpretClause as pr, EXPECTED_HOST_PACKAGES as pt, releaseCoverage as q, proposeRebindOutcome as qn, classifyUserInteraction as qr, bindProofToProjection as qt, hostLockContextFromComposedDump as r, proofOperationMatches as rn, itemDiagnosis as rr, isRunExecutable as rt, packageRowsFromActiveGraph as s, sessionQuery as sn, classifyClause as sr, ACTIVE_HOST_COHORT_IDS as st, HostProfileError as t, proofEvidenceConstraints as tn, deriveItemDiagnosis as tr, withDurability as tt, resolveActiveProfileHostLock as u, validateProofManifestV2 as un, extractOperation as ur, ALPHA2_HOST_PACKAGES as ut, GIT_COMMAND_TEMPLATES as v, recoveryDigest as vn, maskCodeSpans as vr, bindExecutableIdentity as vt, parseGitCommandManifest as w, CONTROL_RECORD_PREFIX as wn, ACTION_MANIFEST as wr, hostVersionFromPackages as wt, createGitPrestateEnvelope as x, evidenceCoverage as xn, statefulActionsOfScope as xr, evaluateHostCapability as xt, commitIndexSnapshotDigest as y, renderRecoveryPacket as yn, namedActions as yr, bindLiveGoalCapability as yt, RELEASE_OPERATION_SURFACES as z, availableBoundaryQualifications as zn, requestedTargetMatchesResolved as zr, segmentAuthorityBlocks as zt };
|