dsh-completion-guard 0.6.1 → 0.6.2
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 +30 -1
- package/CHANGELOG.zh-CN.md +15 -1
- package/README.md +35 -2
- package/README.zh-CN.md +14 -2
- package/dist/domain/index.d.ts +2 -2
- package/dist/domain/index.js +2 -2
- package/dist/{domain-DKr8sLZZ.js → domain-BtR3J5aL.js} +481 -71
- package/dist/{index-C_N6DaSF.d.ts → index-CZSt3D0G.d.ts} +210 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +51 -8
- package/docs/ARCHITECTURE.md +2 -0
- package/docs/CROSS_END_RESULT_CONTRACT.md +60 -0
- package/docs/DEVELOPMENT_PLAN_0_6_2.md +86 -0
- package/docs/LOCAL_ACCEPTANCE.md +58 -3
- package/docs/RELEASE_PLAN_0_6_2.md +41 -0
- package/docs/SEMANTIC_COMPATIBILITY.md +15 -0
- package/package.json +2 -2
- package/docs/NEXT_VERSION_REPAIR_NOTES.md +0 -97
- package/docs/WINDOWS_0_6_0_REPAIR_PLAN.md +0 -92
|
@@ -2586,6 +2586,109 @@ function reasonClassOf(reasonCode) {
|
|
|
2586
2586
|
return REASON_CLASS_TABLE[reasonCode] ?? "source_insufficient";
|
|
2587
2587
|
}
|
|
2588
2588
|
|
|
2589
|
+
//#endregion
|
|
2590
|
+
//#region src/domain/capability-semantics.ts
|
|
2591
|
+
/**
|
|
2592
|
+
* Whether the item's obligation has a certification path in this cohort at
|
|
2593
|
+
* all. A generic_run item names no concrete action: the manifest still has a
|
|
2594
|
+
* generic entry (the guard may run and observe ordinary commands) but no
|
|
2595
|
+
* user-level completion contract can be certified from it, so the item is
|
|
2596
|
+
* uncertifiable while ordinary execution remains entirely permitted.
|
|
2597
|
+
*/
|
|
2598
|
+
function actionHasCertificationPath(action, legacyMigration) {
|
|
2599
|
+
if (legacyMigration) return false;
|
|
2600
|
+
if (action === "generic_run") return false;
|
|
2601
|
+
if (!isStatefulAction(action)) return true;
|
|
2602
|
+
return ACTION_MANIFEST.actions[action].evidenceProducer === "supported";
|
|
2603
|
+
}
|
|
2604
|
+
/** The capability classification of an item's own obligation contract. */
|
|
2605
|
+
function capabilityFactOf(item) {
|
|
2606
|
+
const action = item.semanticAction ?? "generic_run";
|
|
2607
|
+
const legacyMigration = (item.legacyFlags?.length ?? 0) > 0;
|
|
2608
|
+
const certifiable = actionHasCertificationPath(action, legacyMigration);
|
|
2609
|
+
if (item.kind === "prohibition") return {
|
|
2610
|
+
actionSupported: false,
|
|
2611
|
+
certifiable: false,
|
|
2612
|
+
gap: "constraint",
|
|
2613
|
+
remedy: "none",
|
|
2614
|
+
blockingReasonCodes: []
|
|
2615
|
+
};
|
|
2616
|
+
if (!certifiable) return {
|
|
2617
|
+
actionSupported: action !== "generic_run",
|
|
2618
|
+
certifiable: false,
|
|
2619
|
+
gap: legacyMigration ? "legacy_migration_required" : "missing_adapter",
|
|
2620
|
+
remedy: legacyMigration ? "fresh_root_instruction" : "report_uncertified_capability_gap",
|
|
2621
|
+
blockingReasonCodes: []
|
|
2622
|
+
};
|
|
2623
|
+
return {
|
|
2624
|
+
actionSupported: true,
|
|
2625
|
+
certifiable: true,
|
|
2626
|
+
gap: "none",
|
|
2627
|
+
remedy: "collect_evidence",
|
|
2628
|
+
blockingReasonCodes: []
|
|
2629
|
+
};
|
|
2630
|
+
}
|
|
2631
|
+
/**
|
|
2632
|
+
* `partial_failure` may be reported only from a credible structured
|
|
2633
|
+
* per-operation result, and only for the exact declared subset. `unknown`
|
|
2634
|
+
* stays unknown: the guard never reconstructs a per-operation verdict from
|
|
2635
|
+
* stderr text, and never widens a declared subset into a claim about the rest.
|
|
2636
|
+
*/
|
|
2637
|
+
function partialFailureOf(facts) {
|
|
2638
|
+
const declared = facts.declaredOperationResults;
|
|
2639
|
+
if (!declared?.length) return void 0;
|
|
2640
|
+
if (facts.operationAttribution !== "declared_per_operation") return void 0;
|
|
2641
|
+
const failed = declared.filter((entry) => entry.outcome === "failure");
|
|
2642
|
+
if (!failed.length) return void 0;
|
|
2643
|
+
if (declared.some((entry) => entry.outcome === "unknown")) return void 0;
|
|
2644
|
+
return { failed };
|
|
2645
|
+
}
|
|
2646
|
+
/** The one-line consequence of a gap kind, shared so no lane re-invents it. */
|
|
2647
|
+
function capabilityConsequence(gap) {
|
|
2648
|
+
switch (gap) {
|
|
2649
|
+
case "missing_adapter": return "No certification adapter exists for the exact action this obligation names. Complete the work honestly, keep the observable result, and report it as uncertified; do not claim a certificate, and do not demand that the user restate the request as some other supported action.";
|
|
2650
|
+
case "interpretation_unknown": return "The clause was not read as a concrete instruction. It stays recorded, non-executable, and never closes by delivery; a fresh explicit root instruction naming a concrete action supersedes it.";
|
|
2651
|
+
case "legacy_migration_required": return "A pre-0.5 obligation carries no concrete action. Only its own migration path replaces it: a fresh root instruction naming the action and target, followed by the rebind proposal that maps this item onto that recorded instruction.";
|
|
2652
|
+
case "target_missing": return "The action is supported, but an identity only the root can choose was never named. Supply exactly that field; the recorded obligation keeps its own meaning.";
|
|
2653
|
+
case "input_ambiguous": return "Several targets match. The root must select one before any stateful step; the guard never guesses.";
|
|
2654
|
+
case "historical_preevidence_missing": return "The observed effect has no recorded pre-evidence. Record the current state as a read-only fact; never repeat the action to mint the missing prestate.";
|
|
2655
|
+
case "operation_unattributable": return "The console could not attribute the effect to this obligation. Check the actual current state with a read-only command first, keep the obligation uncertified, never repeat the action to mint evidence, and do not assert that it never ran.";
|
|
2656
|
+
case "condition_pending": return "A declared condition or wait has not been released. Keep the obligation pending; do not execute it or collect effect evidence before release.";
|
|
2657
|
+
case "delivery_pending": return "Deliver the actual answer; the host-confirmed final response of a completed turn closes this obligation, and it certifies delivery only.";
|
|
2658
|
+
case "host_unavailable": return "The audited host cohort is unavailable. Restore it; keep pending work visible at a qualified safe boundary.";
|
|
2659
|
+
case "constraint": return "Keep this constraint enforced; it is not a completion evidence obligation.";
|
|
2660
|
+
case "closed": return "No further binding is needed.";
|
|
2661
|
+
case "none": return "Collect the matching durable evidence in its required order, then checkpoint.";
|
|
2662
|
+
}
|
|
2663
|
+
}
|
|
2664
|
+
/**
|
|
2665
|
+
* D062-03: the applicable condition every removal-like outcome must carry.
|
|
2666
|
+
* "Clean" or "no longer listed" never proves "no dependants", so a completed
|
|
2667
|
+
* subset stays reported as the subset it is. These are the execution-side
|
|
2668
|
+
* facts the guard can name but cannot observe; it states them instead of
|
|
2669
|
+
* inventing a generic remover or promising an automatic block.
|
|
2670
|
+
*/
|
|
2671
|
+
const DEPENDENCY_FREE_ONLY_CONDITION = [
|
|
2672
|
+
"git_unique_content",
|
|
2673
|
+
"dirty_or_untracked_or_ignored_entries",
|
|
2674
|
+
"task_process_cwd",
|
|
2675
|
+
"open_handles_and_running_processes",
|
|
2676
|
+
"runtime_links_and_external_consumers",
|
|
2677
|
+
"recovery_basis"
|
|
2678
|
+
];
|
|
2679
|
+
/** Whether one candidate object may enter the automatic removal set. */
|
|
2680
|
+
function admissibleForRemoval(status) {
|
|
2681
|
+
return status === "dependency_free";
|
|
2682
|
+
}
|
|
2683
|
+
/** Only an object proven dependency-free AND fully removed may read as done. */
|
|
2684
|
+
function removalIsComplete(report, status) {
|
|
2685
|
+
return status === "dependency_free" && report.metadataRemoved === "yes" && report.contentRemoved === "yes" && report.directoryRemoved === "yes";
|
|
2686
|
+
}
|
|
2687
|
+
/** A partially removed object or an unknown dependant is never "no impact". */
|
|
2688
|
+
function removalIsPartiallyKnown(report, status) {
|
|
2689
|
+
return status !== "dependency_free" || report.contentRemoved === "partial" || report.directoryRemoved !== "yes" || report.metadataRemoved !== "yes";
|
|
2690
|
+
}
|
|
2691
|
+
|
|
2589
2692
|
//#endregion
|
|
2590
2693
|
//#region src/domain/diagnostics.ts
|
|
2591
2694
|
/** Bounded, honest task-kind classification for a captured item. */
|
|
@@ -2626,8 +2729,12 @@ function evidenceFacets(p, item) {
|
|
|
2626
2729
|
}
|
|
2627
2730
|
/**
|
|
2628
2731
|
* An ordinary shell command whose TEXT ANCHORED at command position to this
|
|
2629
|
-
* obligation's action completed successfully, but
|
|
2630
|
-
*
|
|
2732
|
+
* obligation's action completed successfully, but whose effect on the
|
|
2733
|
+
* obligation could not be attributed (0.6.1 W060-05; layered by 0.6.2
|
|
2734
|
+
* D062-02). The signal is the same either way — the operation-attribution
|
|
2735
|
+
* fact when the fact carries one, and the frozen parse status otherwise:
|
|
2736
|
+
* a command whose effect cannot be attributed cannot certify an obligation.
|
|
2737
|
+
*
|
|
2631
2738
|
* Only the pre-existing head-anchored action signal counts: the guard does
|
|
2632
2739
|
* NOT scan compound text for actions, because quoted data and short-circuit
|
|
2633
2740
|
* control flow would fabricate observations. A failed command is not a
|
|
@@ -2638,7 +2745,7 @@ function unattributedExecutionOf(p, item) {
|
|
|
2638
2745
|
if (!action || action === "generic_run") return void 0;
|
|
2639
2746
|
for (const evidence of p.evidence.values()) {
|
|
2640
2747
|
if (evidence.outcome !== "success") continue;
|
|
2641
|
-
if (evidence.
|
|
2748
|
+
if (!(evidence.processFacts ? evidence.processFacts.operationAttribution === "unknown" : evidence.parseStatus !== void 0 && evidence.parseStatus !== "supported")) continue;
|
|
2642
2749
|
if (![
|
|
2643
2750
|
"bash",
|
|
2644
2751
|
"pwsh",
|
|
@@ -2648,6 +2755,17 @@ function unattributedExecutionOf(p, item) {
|
|
|
2648
2755
|
}
|
|
2649
2756
|
}
|
|
2650
2757
|
/**
|
|
2758
|
+
* The honest wording for an unattributable shell effect (0.6.2 D062-02). The
|
|
2759
|
+
* two causes are DIFFERENT facts and must not share one sentence: a command
|
|
2760
|
+
* that failed closed parsing was not securely parsed, while a compound runner
|
|
2761
|
+
* whose operation layer is unknown simply has no independent per-operation
|
|
2762
|
+
* result. Both refuse to claim execution either way, and both forbid
|
|
2763
|
+
* re-running the action to mint evidence.
|
|
2764
|
+
*/
|
|
2765
|
+
function unattributedExecutionCondition(evidence) {
|
|
2766
|
+
return `${evidence.parseStatus === void 0 || evidence.parseStatus === "supported" ? "An ordinary shell command beginning with this action ran earlier in the session as an opaque multi-operation script, and the host declared no independent per-operation result, so whether it performed this action cannot be established" : "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.`;
|
|
2767
|
+
}
|
|
2768
|
+
/**
|
|
2651
2769
|
* The pure repair judge. It decides between: fixable from existing evidence,
|
|
2652
2770
|
* missing pre-evidence, missing a user target choice, not supported by any
|
|
2653
2771
|
* adapter, an executed-without-evidence historical gap, or nothing to do —
|
|
@@ -2676,33 +2794,60 @@ function judgeItemDiagnosis(p, item) {
|
|
|
2676
2794
|
task_kind: kind,
|
|
2677
2795
|
missing_facets
|
|
2678
2796
|
};
|
|
2679
|
-
|
|
2680
|
-
|
|
2797
|
+
/**
|
|
2798
|
+
* 0.6.2 D062-01: every verdict carries the shared capability fact for its own
|
|
2799
|
+
* gap. The per-lane override only names the gap KIND; the consequence text
|
|
2800
|
+
* and the reachable-remedy rules stay in one place, so a new branch cannot
|
|
2801
|
+
* drift into demanding user input for a capability this build lacks.
|
|
2802
|
+
*/
|
|
2803
|
+
const verdict = (override) => {
|
|
2804
|
+
const capability = {
|
|
2805
|
+
actionSupported: capabilityFactOf(item).actionSupported,
|
|
2806
|
+
certifiable: override.certifiable ?? false,
|
|
2807
|
+
gap: override.gap,
|
|
2808
|
+
remedy: override.remedy,
|
|
2809
|
+
blockingReasonCodes: override.reason_code === "missing_evidence" || override.reason_code === "certified" || override.reason_code === "answer_delivered" ? [] : [override.reason_code]
|
|
2810
|
+
};
|
|
2811
|
+
const { certifiable: _certifiable, remedy: _remedy, gap: _gap, missing_facets: overrideFacets,...rest } = override;
|
|
2812
|
+
return {
|
|
2813
|
+
...base,
|
|
2814
|
+
...rest,
|
|
2815
|
+
...overrideFacets !== void 0 ? { missing_facets: overrideFacets } : {},
|
|
2816
|
+
capability
|
|
2817
|
+
};
|
|
2818
|
+
};
|
|
2819
|
+
if (item.kind === "prohibition") return verdict({
|
|
2820
|
+
gap: "constraint",
|
|
2821
|
+
remedy: "none",
|
|
2681
2822
|
certification: "unsupported",
|
|
2682
2823
|
reason_code: "prohibition_active",
|
|
2683
2824
|
repairability: "none",
|
|
2684
2825
|
missing_fields: [],
|
|
2685
2826
|
next_action: {
|
|
2686
2827
|
kind: "none",
|
|
2687
|
-
resume_condition: "
|
|
2828
|
+
resume_condition: capabilityConsequence("constraint")
|
|
2688
2829
|
},
|
|
2689
2830
|
attempt_fingerprint: fingerprint(p, item, "prohibition_active")
|
|
2690
|
-
};
|
|
2831
|
+
});
|
|
2691
2832
|
const action = item.semanticAction ?? "generic_run";
|
|
2692
|
-
if (item.status === "passed") return {
|
|
2693
|
-
|
|
2833
|
+
if (item.status === "passed") return verdict({
|
|
2834
|
+
gap: "closed",
|
|
2835
|
+
remedy: "none",
|
|
2836
|
+
certifiable: true,
|
|
2694
2837
|
certification: "supported",
|
|
2695
2838
|
reason_code: "certified",
|
|
2696
2839
|
repairability: "none",
|
|
2697
2840
|
missing_fields: [],
|
|
2698
2841
|
next_action: {
|
|
2699
2842
|
kind: "none",
|
|
2700
|
-
resume_condition: "
|
|
2843
|
+
resume_condition: capabilityConsequence("closed")
|
|
2701
2844
|
},
|
|
2702
2845
|
attempt_fingerprint: fingerprint(p, item, "certified")
|
|
2703
|
-
};
|
|
2704
|
-
if (item.status === "answered") return {
|
|
2705
|
-
|
|
2846
|
+
});
|
|
2847
|
+
if (item.status === "answered") return verdict({
|
|
2848
|
+
gap: "closed",
|
|
2849
|
+
remedy: "none",
|
|
2850
|
+
certifiable: true,
|
|
2706
2851
|
certification: "supported",
|
|
2707
2852
|
reason_code: "answer_delivered",
|
|
2708
2853
|
repairability: "none",
|
|
@@ -2713,9 +2858,10 @@ function judgeItemDiagnosis(p, item) {
|
|
|
2713
2858
|
resume_condition: "The host-confirmed final answer was delivered; no further binding needed."
|
|
2714
2859
|
},
|
|
2715
2860
|
attempt_fingerprint: fingerprint(p, item, "answer_delivered")
|
|
2716
|
-
};
|
|
2717
|
-
if (item.status === "pending" && item.waitAuthorization?.kind === "root_explicit_wait") return {
|
|
2718
|
-
|
|
2861
|
+
});
|
|
2862
|
+
if (item.status === "pending" && item.waitAuthorization?.kind === "root_explicit_wait") return verdict({
|
|
2863
|
+
gap: "condition_pending",
|
|
2864
|
+
remedy: "await_root_input",
|
|
2719
2865
|
certification: "unavailable",
|
|
2720
2866
|
reason_code: "root_condition_pending",
|
|
2721
2867
|
repairability: "user_input_required",
|
|
@@ -2723,14 +2869,15 @@ function judgeItemDiagnosis(p, item) {
|
|
|
2723
2869
|
missing_facets: [],
|
|
2724
2870
|
next_action: {
|
|
2725
2871
|
kind: "none",
|
|
2726
|
-
resume_condition: `Wait for the matching trusted root input: ${item.resumeEvent ?? item.condition ?? item.normalizedText}.
|
|
2872
|
+
resume_condition: `Wait for the matching trusted root input: ${item.resumeEvent ?? item.condition ?? item.normalizedText}. ${capabilityConsequence("condition_pending")}`
|
|
2727
2873
|
},
|
|
2728
2874
|
attempt_fingerprint: fingerprint(p, item, "root_condition_pending")
|
|
2729
|
-
};
|
|
2875
|
+
});
|
|
2730
2876
|
if (kind === "inquiry") {
|
|
2731
2877
|
const closable = p.boundaryProtocol === 5;
|
|
2732
|
-
if (item.asset !== void 0 && !p.interpretationFacts.some((fact) => fact.itemId === item.id)) return {
|
|
2733
|
-
|
|
2878
|
+
if (item.asset !== void 0 && !p.interpretationFacts.some((fact) => fact.itemId === item.id)) return verdict({
|
|
2879
|
+
gap: "delivery_pending",
|
|
2880
|
+
remedy: "record_interpretation",
|
|
2734
2881
|
certification: "unsupported",
|
|
2735
2882
|
reason_code: "asset_interpretation_required",
|
|
2736
2883
|
repairability: "unsupported",
|
|
@@ -2743,9 +2890,10 @@ function judgeItemDiagnosis(p, item) {
|
|
|
2743
2890
|
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
2891
|
},
|
|
2745
2892
|
attempt_fingerprint: fingerprint(p, item, "asset_interpretation_required")
|
|
2746
|
-
};
|
|
2747
|
-
return {
|
|
2748
|
-
|
|
2893
|
+
});
|
|
2894
|
+
return verdict({
|
|
2895
|
+
gap: closable ? "delivery_pending" : "interpretation_unknown",
|
|
2896
|
+
remedy: closable ? "deliver_answer" : "report_uncertified",
|
|
2749
2897
|
certification: "unsupported",
|
|
2750
2898
|
reason_code: closable ? "inquiry_awaiting_delivery" : "inquiry_non_certifiable",
|
|
2751
2899
|
repairability: "unsupported",
|
|
@@ -2756,12 +2904,13 @@ function judgeItemDiagnosis(p, item) {
|
|
|
2756
2904
|
resume_condition: closable ? "Deliver the actual answer; the host-confirmed final response of a completed turn closes this item." : "Complete the investigation and report the actual answer; the item stays recorded as uncertified. No confirmation or rebind changes this."
|
|
2757
2905
|
},
|
|
2758
2906
|
attempt_fingerprint: fingerprint(p, item, closable ? "inquiry_awaiting_delivery" : "inquiry_non_certifiable")
|
|
2759
|
-
};
|
|
2907
|
+
});
|
|
2760
2908
|
}
|
|
2761
2909
|
if (item.authorityDisposition === "informational") {
|
|
2762
2910
|
const closable = p.boundaryProtocol === 5;
|
|
2763
|
-
return {
|
|
2764
|
-
|
|
2911
|
+
return verdict({
|
|
2912
|
+
gap: closable ? "delivery_pending" : "interpretation_unknown",
|
|
2913
|
+
remedy: closable ? "deliver_answer" : "report_uncertified",
|
|
2765
2914
|
certification: "unsupported",
|
|
2766
2915
|
reason_code: closable ? "information_awaiting_delivery" : "information_non_certifiable",
|
|
2767
2916
|
repairability: "unsupported",
|
|
@@ -2772,10 +2921,11 @@ function judgeItemDiagnosis(p, item) {
|
|
|
2772
2921
|
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
2922
|
},
|
|
2774
2923
|
attempt_fingerprint: fingerprint(p, item, closable ? "information_awaiting_delivery" : "information_non_certifiable")
|
|
2775
|
-
};
|
|
2924
|
+
});
|
|
2776
2925
|
}
|
|
2777
|
-
if (item.authorityDisposition === "unresolved") return {
|
|
2778
|
-
|
|
2926
|
+
if (item.authorityDisposition === "unresolved") return verdict({
|
|
2927
|
+
gap: "interpretation_unknown",
|
|
2928
|
+
remedy: "fresh_root_instruction",
|
|
2779
2929
|
certification: "unsupported",
|
|
2780
2930
|
reason_code: "interpretation_unresolved",
|
|
2781
2931
|
repairability: "none",
|
|
@@ -2783,14 +2933,16 @@ function judgeItemDiagnosis(p, item) {
|
|
|
2783
2933
|
missing_facets: [],
|
|
2784
2934
|
next_action: {
|
|
2785
2935
|
kind: "report_only",
|
|
2786
|
-
resume_condition: "
|
|
2936
|
+
resume_condition: capabilityConsequence("interpretation_unknown")
|
|
2787
2937
|
},
|
|
2788
2938
|
attempt_fingerprint: fingerprint(p, item, "interpretation_unresolved")
|
|
2789
|
-
};
|
|
2939
|
+
});
|
|
2790
2940
|
if (action !== "generic_run" && !item.legacyFlags?.length && item.targetCaptureStatus === "clarification_required") {
|
|
2791
2941
|
const missingFields = item.targetCaptureReasonCode ? [TARGET_FIELD_REASONS[item.targetCaptureReasonCode] ?? item.targetCaptureReasonCode] : [];
|
|
2792
|
-
return {
|
|
2793
|
-
|
|
2942
|
+
return verdict({
|
|
2943
|
+
gap: "target_missing",
|
|
2944
|
+
remedy: "supply_target",
|
|
2945
|
+
certifiable: true,
|
|
2794
2946
|
certification: "needs_target",
|
|
2795
2947
|
reason_code: "target_clarification_required",
|
|
2796
2948
|
repairability: "user_input_required",
|
|
@@ -2802,23 +2954,27 @@ function judgeItemDiagnosis(p, item) {
|
|
|
2802
2954
|
resume_condition: "A root-user instruction supplying the exact target re-enables certification."
|
|
2803
2955
|
},
|
|
2804
2956
|
attempt_fingerprint: fingerprint(p, item, "target_clarification_required")
|
|
2805
|
-
};
|
|
2957
|
+
});
|
|
2806
2958
|
}
|
|
2807
|
-
if (action === "generic_run" || item.legacyFlags?.length)
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2959
|
+
if (action === "generic_run" || item.legacyFlags?.length) {
|
|
2960
|
+
const legacyMigration = (item.legacyFlags?.length ?? 0) > 0;
|
|
2961
|
+
return verdict({
|
|
2962
|
+
gap: legacyMigration ? "legacy_migration_required" : "missing_adapter",
|
|
2963
|
+
remedy: legacyMigration ? "fresh_root_instruction" : "report_uncertified_capability_gap",
|
|
2964
|
+
certification: "unsupported",
|
|
2965
|
+
reason_code: "generic_run_non_certifiable",
|
|
2966
|
+
repairability: legacyMigration ? "historical_gap" : "unsupported",
|
|
2967
|
+
missing_fields: [],
|
|
2968
|
+
next_action: {
|
|
2969
|
+
kind: "report_only",
|
|
2970
|
+
resume_condition: capabilityConsequence(legacyMigration ? "legacy_migration_required" : "missing_adapter")
|
|
2971
|
+
},
|
|
2972
|
+
attempt_fingerprint: fingerprint(p, item, "generic_run_non_certifiable")
|
|
2973
|
+
});
|
|
2974
|
+
}
|
|
2975
|
+
if (p.hostStatus !== "supported") return verdict({
|
|
2976
|
+
gap: "host_unavailable",
|
|
2977
|
+
remedy: "restore_host",
|
|
2822
2978
|
certification: "unavailable",
|
|
2823
2979
|
reason_code: "host_unavailable",
|
|
2824
2980
|
repairability: "unsupported",
|
|
@@ -2828,9 +2984,10 @@ function judgeItemDiagnosis(p, item) {
|
|
|
2828
2984
|
resume_condition: "Restore the audited host cohort; keep pending work visible at a qualified safe boundary."
|
|
2829
2985
|
},
|
|
2830
2986
|
attempt_fingerprint: fingerprint(p, item, "host_unavailable")
|
|
2831
|
-
};
|
|
2832
|
-
if (ACTION_MANIFEST.actions[action].evidenceProducer !== "supported") return {
|
|
2833
|
-
|
|
2987
|
+
});
|
|
2988
|
+
if (ACTION_MANIFEST.actions[action].evidenceProducer !== "supported") return verdict({
|
|
2989
|
+
gap: "missing_adapter",
|
|
2990
|
+
remedy: "restore_host",
|
|
2834
2991
|
certification: "unavailable",
|
|
2835
2992
|
reason_code: "adapter_unavailable",
|
|
2836
2993
|
repairability: "unsupported",
|
|
@@ -2840,22 +2997,25 @@ function judgeItemDiagnosis(p, item) {
|
|
|
2840
2997
|
resume_condition: "The audited adapter for this action is unavailable in the installed cohort."
|
|
2841
2998
|
},
|
|
2842
2999
|
attempt_fingerprint: fingerprint(p, item, "adapter_unavailable")
|
|
2843
|
-
};
|
|
3000
|
+
});
|
|
2844
3001
|
const statefulChain = isStatefulAction(action);
|
|
2845
|
-
|
|
2846
|
-
|
|
3002
|
+
const unattributed = requiredEvidenceRoles(item).some((role) => !missing_facets.includes(role)) ? void 0 : unattributedExecutionOf(p, item);
|
|
3003
|
+
if (unattributed) return verdict({
|
|
3004
|
+
gap: "operation_unattributable",
|
|
3005
|
+
remedy: "readback_only",
|
|
2847
3006
|
certification: "unsupported",
|
|
2848
3007
|
reason_code: "execution_unattributable",
|
|
2849
3008
|
repairability: "historical_gap",
|
|
2850
3009
|
missing_fields: [],
|
|
2851
3010
|
next_action: {
|
|
2852
3011
|
kind: "report_only",
|
|
2853
|
-
resume_condition:
|
|
3012
|
+
resume_condition: unattributedExecutionCondition(unattributed)
|
|
2854
3013
|
},
|
|
2855
3014
|
attempt_fingerprint: fingerprint(p, item, "execution_unattributable")
|
|
2856
|
-
};
|
|
2857
|
-
if (statefulChain && missing_facets.includes("resolution") && !missing_facets.includes("effect")) return {
|
|
2858
|
-
|
|
3015
|
+
});
|
|
3016
|
+
if (statefulChain && missing_facets.includes("resolution") && !missing_facets.includes("effect")) return verdict({
|
|
3017
|
+
gap: "historical_preevidence_missing",
|
|
3018
|
+
remedy: "readback_only",
|
|
2859
3019
|
certification: "unsupported",
|
|
2860
3020
|
reason_code: "historical_evidence_gap",
|
|
2861
3021
|
repairability: "historical_gap",
|
|
@@ -2865,9 +3025,11 @@ function judgeItemDiagnosis(p, item) {
|
|
|
2865
3025
|
resume_condition: "Record the observed state as read-only fact; do not repeat the action to mint missing prestate evidence."
|
|
2866
3026
|
},
|
|
2867
3027
|
attempt_fingerprint: fingerprint(p, item, "historical_evidence_gap")
|
|
2868
|
-
};
|
|
2869
|
-
return {
|
|
2870
|
-
|
|
3028
|
+
});
|
|
3029
|
+
return verdict({
|
|
3030
|
+
gap: "none",
|
|
3031
|
+
remedy: "collect_evidence",
|
|
3032
|
+
certifiable: true,
|
|
2871
3033
|
certification: "needs_evidence",
|
|
2872
3034
|
reason_code: "missing_evidence",
|
|
2873
3035
|
repairability: "agent_repairable",
|
|
@@ -2878,7 +3040,7 @@ function judgeItemDiagnosis(p, item) {
|
|
|
2878
3040
|
resume_condition: statefulChain ? "Collect the matching durable evidence in resolution/effect/state order, then checkpoint." : "Collect the single matching durable verification fact, then checkpoint."
|
|
2879
3041
|
},
|
|
2880
3042
|
attempt_fingerprint: fingerprint(p, item, "missing_evidence")
|
|
2881
|
-
};
|
|
3043
|
+
});
|
|
2882
3044
|
}
|
|
2883
3045
|
function fingerprint(p, item, reason) {
|
|
2884
3046
|
return sha256(JSON.stringify([
|
|
@@ -2927,6 +3089,27 @@ function relevantEvidence(p, item, evidence) {
|
|
|
2927
3089
|
const value = (entry) => JSON.stringify(entry && typeof entry === "object" && "v" in entry ? entry.v : entry);
|
|
2928
3090
|
return !!item.requestedTarget && Object.entries(item.requestedTarget).every(([key, entry]) => evidence.resolvedTarget && value(entry) === value(evidence.resolvedTarget[key]));
|
|
2929
3091
|
}
|
|
3092
|
+
/**
|
|
3093
|
+
* The bounded, one-phrase form of a reachable remedy (0.6.2 D062-01). The
|
|
3094
|
+
* capability consequence above is the full explanation; a bounded page lists
|
|
3095
|
+
* many items, so it uses this phrase and leaves the prose to the detail and
|
|
3096
|
+
* preparation surfaces. Both come from the SAME capability fact.
|
|
3097
|
+
*/
|
|
3098
|
+
function capabilityRemedyPhrase(remedy) {
|
|
3099
|
+
switch (remedy) {
|
|
3100
|
+
case "none": return "No further action needed";
|
|
3101
|
+
case "collect_evidence": return "Collect matching evidence; then checkpoint";
|
|
3102
|
+
case "supply_target": return "Supply the exact target; then collect evidence";
|
|
3103
|
+
case "await_root_input": return "Wait for the trusted root input; keep pending";
|
|
3104
|
+
case "deliver_answer": return "Deliver the actual answer";
|
|
3105
|
+
case "record_interpretation": return "Read the attachment; record context_guard_interpret";
|
|
3106
|
+
case "report_uncertified": return "Report honestly; stays uncertified";
|
|
3107
|
+
case "report_uncertified_capability_gap": return "Report as uncertified";
|
|
3108
|
+
case "restore_host": return "Restore the audited host/adapter capability";
|
|
3109
|
+
case "readback_only": return "Read back the current state; do not re-execute";
|
|
3110
|
+
case "fresh_root_instruction": return "Report the actual outcome as uncertified";
|
|
3111
|
+
}
|
|
3112
|
+
}
|
|
2930
3113
|
|
|
2931
3114
|
//#endregion
|
|
2932
3115
|
//#region src/domain/confirm-parse.ts
|
|
@@ -5015,6 +5198,63 @@ const DEFAULT_RECOVERY_CHAR_BUDGET = 4e3;
|
|
|
5015
5198
|
const MIN_RECOVERY_CHAR_BUDGET = 512;
|
|
5016
5199
|
const COMPLETION_RULE = "Supported actions certify through matching durable evidence (checkpoint). Investigations and explanations outside the supported set can be delivered honestly but stay uncertified. A qualified safe end preserves pending work; it is not completion.";
|
|
5017
5200
|
/**
|
|
5201
|
+
* 0.6.2 D062-03: the standing condition a removal or cleanup outcome must keep.
|
|
5202
|
+
* The guard cannot observe another process's cwd or handles, so it states the
|
|
5203
|
+
* condition instead of inferring "no dependants" from a clean tree, an empty
|
|
5204
|
+
* `git worktree list`, or a directory that merely looks empty. This is one
|
|
5205
|
+
* shared wording, not an incident phrase list, and it never claims the plugin
|
|
5206
|
+
* can block a dangerous removal on its own.
|
|
5207
|
+
*/
|
|
5208
|
+
const CLEANUP_CONDITION_RULE = "A removal counts only for the objects PROVEN dependency-free; report metadata, content and directory removal separately from dependency status (" + DEPENDENCY_FREE_ONLY_CONDITION.join(", ") + "), keep unknown-dependency objects and failures visible, and never repeat a blocked delete, kill a holder, or restart to force it.";
|
|
5209
|
+
/**
|
|
5210
|
+
* The same condition at a medium budget (0.6.2 review): shorter than the full
|
|
5211
|
+
* rule, and still explicit that an unknown dependant forbids the claim.
|
|
5212
|
+
*/
|
|
5213
|
+
const CLEANUP_CONDITION_RULE_SHORT = "Removal counts only for objects PROVEN dependency-free; unknown dependants stay visible and are never deleted.";
|
|
5214
|
+
/**
|
|
5215
|
+
* The same condition at emergency budget (0.6.2 review). A packet with fewer
|
|
5216
|
+
* than 1000 characters cannot carry the longer sentences AND its own rules, so
|
|
5217
|
+
* the condition is compressed — but it is NEVER omitted: the one thing a compact
|
|
5218
|
+
* packet must not lose is that an unknown dependant forbids a removal claim.
|
|
5219
|
+
*/
|
|
5220
|
+
const CLEANUP_CONDITION_RULE_COMPACT = "Removal requires proven no-dependants.";
|
|
5221
|
+
/**
|
|
5222
|
+
* Pick the longest form of the condition the packet's budget can actually
|
|
5223
|
+
* afford. The caller reserves this line's length before any optional row, so
|
|
5224
|
+
* the condition is never the text that gets clipped.
|
|
5225
|
+
*/
|
|
5226
|
+
function cleanupConditionFor(budget) {
|
|
5227
|
+
if (budget >= DEFAULT_RECOVERY_CHAR_BUDGET) return CLEANUP_CONDITION_RULE;
|
|
5228
|
+
if (budget >= 1e3) return CLEANUP_CONDITION_RULE_SHORT;
|
|
5229
|
+
return CLEANUP_CONDITION_RULE_COMPACT;
|
|
5230
|
+
}
|
|
5231
|
+
/**
|
|
5232
|
+
* Whether this gap needs the cleanup condition spelled out. The condition
|
|
5233
|
+
* belongs to every uncertifiable lane that could describe removal-like work —
|
|
5234
|
+
* which the guard cannot identify from text — so it rides the CAPABILITY
|
|
5235
|
+
* limitation itself, never a vocabulary of destructive verbs.
|
|
5236
|
+
*/
|
|
5237
|
+
function carriesCleanupCondition(gap) {
|
|
5238
|
+
return gap === "missing_adapter" || gap === "legacy_migration_required" || gap === "historical_preevidence_missing" || gap === "operation_unattributable" || gap === "interpretation_unknown";
|
|
5239
|
+
}
|
|
5240
|
+
/** One reachable-remedy phrase per remedy kind, shared by every lane. */
|
|
5241
|
+
function remedyText(remedy, fallback) {
|
|
5242
|
+
switch (remedy) {
|
|
5243
|
+
case "collect_evidence": return "Collect matching evidence; checkpoint";
|
|
5244
|
+
case "readback_only": return "Read back observed state; do not re-execute";
|
|
5245
|
+
case "none": return "Recorded as unresolved; only a fresh explicit instruction resolves it";
|
|
5246
|
+
case "record_interpretation": return "Read the attachment; record context_guard_interpret; then answer";
|
|
5247
|
+
case "supply_target": return "Supply the exact target; then collect evidence and checkpoint";
|
|
5248
|
+
case "await_root_input": return "Wait for the trusted root input; keep the obligation pending";
|
|
5249
|
+
case "deliver_answer": return "Deliver the actual answer; a completed turn closes it";
|
|
5250
|
+
case "report_uncertified": return "Deliver honestly; stays uncertified unless a fresh instruction names a supported action";
|
|
5251
|
+
case "restore_host": return "Restore audited host/adapter capability";
|
|
5252
|
+
case "fresh_root_instruction": return "Report the actual outcome as uncertified; only a fresh explicit instruction reaches its migration lane";
|
|
5253
|
+
case "report_uncertified_capability_gap": return "Report the observable result as uncertified; this build has no adapter for the action";
|
|
5254
|
+
}
|
|
5255
|
+
return fallback;
|
|
5256
|
+
}
|
|
5257
|
+
/**
|
|
5018
5258
|
* An actionable one-line hint for how an open item's verification contract can
|
|
5019
5259
|
* be closed. It never weakens the contract; it only names the missing facet so
|
|
5020
5260
|
* the agent can produce the right evidence shape instead of reverse-engineering
|
|
@@ -5067,14 +5307,25 @@ function renderRecoveryPacket(projection, options = {}) {
|
|
|
5067
5307
|
const items = openItems(projection).sort((a, b) => Number(b.kind === "prohibition") - Number(a.kind === "prohibition") || b.revision - a.revision || a.id.localeCompare(b.id));
|
|
5068
5308
|
const rejected$1 = options.rejectedBindings ?? (projection.lastCheckpointRejectionRevision === projection.contractRevision ? projection.lastCheckpointRejections : []) ?? [];
|
|
5069
5309
|
const compact = budget < 1e3;
|
|
5070
|
-
const
|
|
5310
|
+
const COMPLETION_RULE_COMPACT = "Checkpoint required before completion. Qualified safe end preserves pending work; it is not completion.";
|
|
5311
|
+
const lines = [`Context Guard: ${items.length} pending; revision ${projection.contractRevision}.`, compact ? COMPLETION_RULE_COMPACT : COMPLETION_RULE];
|
|
5312
|
+
const completionRuleIndex = 1;
|
|
5313
|
+
if (items.some((item) => carriesCleanupCondition(deriveItemDiagnosis(projection, item).capability.gap))) lines.push(cleanupConditionFor(budget));
|
|
5071
5314
|
const pointer = "Details/omissions: context_guard_checkpoint (item_ids, evidence_scope=history, cursor).";
|
|
5072
5315
|
const evidence = [...projection.evidence.values()].filter((e) => items.some((item) => relevantEvidence(projection, item, e))).sort((a, b) => b.toolResultSeq - a.toolResultSeq || a.id.localeCompare(b.id));
|
|
5073
5316
|
const footer = (count$1, refusals$1, shown$1) => `${items.length - count$1} items folded; ${rejected$1.length - refusals$1} rejections folded; ${evidence.length - shown$1} relevant evidence rows folded. Full ledger remains enforced.`;
|
|
5074
|
-
|
|
5317
|
+
const reserve = () => lines.join("\n").length + 87 + footer(0, 0, 0).length + 3;
|
|
5318
|
+
let remaining = budget - reserve();
|
|
5075
5319
|
const add = (line, cap) => {
|
|
5076
5320
|
if (remaining < 30) return false;
|
|
5077
5321
|
const text = clip(line, Math.min(cap, remaining));
|
|
5322
|
+
if (!compact && remaining - (text.length + 1) < 246) {
|
|
5323
|
+
const current = lines[completionRuleIndex];
|
|
5324
|
+
if (current.length > 103) {
|
|
5325
|
+
remaining += current.length - 103;
|
|
5326
|
+
lines[completionRuleIndex] = COMPLETION_RULE_COMPACT;
|
|
5327
|
+
}
|
|
5328
|
+
}
|
|
5078
5329
|
lines.push(text);
|
|
5079
5330
|
remaining -= text.length + 1;
|
|
5080
5331
|
return true;
|
|
@@ -5091,8 +5342,9 @@ function renderRecoveryPacket(projection, options = {}) {
|
|
|
5091
5342
|
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++;
|
|
5092
5343
|
return;
|
|
5093
5344
|
}
|
|
5094
|
-
const remedy = diagnosis.
|
|
5095
|
-
|
|
5345
|
+
const remedy = remedyText(diagnosis.capability.remedy, diagnosis.next_action.resume_condition ?? "No further action needed.");
|
|
5346
|
+
const body = compact ? remedy : diagnosis.next_action.resume_condition ?? remedy;
|
|
5347
|
+
if (add(`[${clip(item.id, 20)}] ${diagnosis.reason_code}; ${body}; ${clip(item.normalizedText, 70)}`, compact ? 110 : 310)) count++;
|
|
5096
5348
|
};
|
|
5097
5349
|
if (constraints[0]) constraint(constraints[0]);
|
|
5098
5350
|
if (work[0]) requirement(work[0]);
|
|
@@ -9566,6 +9818,153 @@ function extractTerminalFacts(textContent) {
|
|
|
9566
9818
|
marked
|
|
9567
9819
|
};
|
|
9568
9820
|
}
|
|
9821
|
+
/**
|
|
9822
|
+
* 0.6.2 D062-02: one trusted structured producer declaration, if the host
|
|
9823
|
+
* rendered per-operation results. Absence is the honest common case: the
|
|
9824
|
+
* pinned DSH renderers declare a whole-result terminal marker only, so no
|
|
9825
|
+
* per-operation producer exists and the attribution stays `unknown`.
|
|
9826
|
+
*/
|
|
9827
|
+
function declaredOperationResults(meta) {
|
|
9828
|
+
const declared = asRecord$2(asRecord$2(meta)?.contextGuardProcess)?.operationResults;
|
|
9829
|
+
if (!Array.isArray(declared) || declared.length === 0 || declared.length > 64) return void 0;
|
|
9830
|
+
const rows = [];
|
|
9831
|
+
for (const raw of declared) {
|
|
9832
|
+
const row = asRecord$2(raw);
|
|
9833
|
+
const action = typeof row?.action === "string" ? row.action : void 0;
|
|
9834
|
+
const outcome = row?.outcome;
|
|
9835
|
+
if (!action || outcome !== "success" && outcome !== "failure" && outcome !== "unknown") return void 0;
|
|
9836
|
+
rows.push({
|
|
9837
|
+
action,
|
|
9838
|
+
outcome
|
|
9839
|
+
});
|
|
9840
|
+
}
|
|
9841
|
+
return rows;
|
|
9842
|
+
}
|
|
9843
|
+
/**
|
|
9844
|
+
* The trusted run-level declaration in `meta.contextGuardProcess`. This is the
|
|
9845
|
+
* highest-priority source: it is the run's own statement about the process, so
|
|
9846
|
+
* an explicit `exitCode` here outranks the generic `meta.exitCode`.
|
|
9847
|
+
*/
|
|
9848
|
+
function declaredStructuredTerminal(meta) {
|
|
9849
|
+
const record = asRecord$2(asRecord$2(meta)?.contextGuardProcess);
|
|
9850
|
+
if (!record) return void 0;
|
|
9851
|
+
const rawExit = record.exitCode ?? record.exit_code;
|
|
9852
|
+
const signal = record.signal;
|
|
9853
|
+
if (signal !== void 0 && signal !== null) return {
|
|
9854
|
+
...typeof rawExit === "number" ? { exitCode: rawExit } : {},
|
|
9855
|
+
signal: true
|
|
9856
|
+
};
|
|
9857
|
+
if (typeof rawExit === "number") return {
|
|
9858
|
+
exitCode: rawExit,
|
|
9859
|
+
signal: false
|
|
9860
|
+
};
|
|
9861
|
+
}
|
|
9862
|
+
/**
|
|
9863
|
+
* The HISTORICAL terminal-fact rule, unchanged since 0.6.1: the generic
|
|
9864
|
+
* structured `meta` fact, else the rendered text markers. It deliberately does
|
|
9865
|
+
* NOT read the trusted `contextGuardProcess` run declaration — that source is
|
|
9866
|
+
* new in 0.6.2 and reading it here would change the frozen `outcome` of
|
|
9867
|
+
* already-recorded evidence, which is a summary input and therefore historical
|
|
9868
|
+
* (0.6.2 review of D062-02).
|
|
9869
|
+
*/
|
|
9870
|
+
function legacyTerminalFacts(meta, textContent) {
|
|
9871
|
+
return structuredTerminalFacts(meta) ?? extractTerminalFacts(textContent);
|
|
9872
|
+
}
|
|
9873
|
+
/**
|
|
9874
|
+
* The terminal facts the DERIVED layer reads, in priority order (0.6.2 D062-02
|
|
9875
|
+
* review): the trusted run declaration first, then the generic structured fact,
|
|
9876
|
+
* then the rendered markers. This never feeds the frozen `outcome`; it feeds
|
|
9877
|
+
* `processFacts` only, which states its own `source` and whether it disagrees
|
|
9878
|
+
* with the frozen reading.
|
|
9879
|
+
*/
|
|
9880
|
+
function resolveDeclaredTerminalFacts(meta, textContent) {
|
|
9881
|
+
const namespace = declaredStructuredTerminal(meta);
|
|
9882
|
+
if (namespace) return {
|
|
9883
|
+
facts: {
|
|
9884
|
+
exitCode: namespace.exitCode,
|
|
9885
|
+
negative: namespace.signal,
|
|
9886
|
+
marked: true
|
|
9887
|
+
},
|
|
9888
|
+
source: "run_declaration"
|
|
9889
|
+
};
|
|
9890
|
+
const structured = structuredTerminalFacts(meta);
|
|
9891
|
+
if (structured) return {
|
|
9892
|
+
facts: structured,
|
|
9893
|
+
source: "structured_meta"
|
|
9894
|
+
};
|
|
9895
|
+
return {
|
|
9896
|
+
facts: extractTerminalFacts(textContent),
|
|
9897
|
+
source: "rendered_markers"
|
|
9898
|
+
};
|
|
9899
|
+
}
|
|
9900
|
+
/**
|
|
9901
|
+
* The one outcome rule for a shell result, shared by the frozen evidence field
|
|
9902
|
+
* and the derived reading. Their different fact sources may yield different verdicts.
|
|
9903
|
+
* The bundled DSH session shell renderers (`dsh-tool-bash` / `dsh-tool-pwsh`)
|
|
9904
|
+
* append markers only for negative terminal facts or non-zero exits, so a
|
|
9905
|
+
* completed foreground result with no marker is a clean success for those two
|
|
9906
|
+
* registered tools alone; the generic `shell` alias has no verified renderer
|
|
9907
|
+
* contract and an unclassifiable marker stays `unknown`.
|
|
9908
|
+
*/
|
|
9909
|
+
function shellOutcome(surface, terminal, resultError, backgrounded) {
|
|
9910
|
+
if (backgrounded) return "unknown";
|
|
9911
|
+
if (resultError || terminal.negative) return "failure";
|
|
9912
|
+
if (terminal.exitCode === void 0) return (surface === "bash" || surface === "pwsh") && !terminal.marked ? "success" : "unknown";
|
|
9913
|
+
return terminal.exitCode === 0 ? "success" : "failure";
|
|
9914
|
+
}
|
|
9915
|
+
/**
|
|
9916
|
+
* The layered shell reading (0.6.2 D062-02; source priority fixed by the
|
|
9917
|
+
* 0.6.2 review). Every field is derived from the same persisted result the
|
|
9918
|
+
* historical `outcome` was derived from, so replay is deterministic and no
|
|
9919
|
+
* historical fact is reinterpreted:
|
|
9920
|
+
*
|
|
9921
|
+
* - `hostToolReturned` is the host's own return, nothing more;
|
|
9922
|
+
* - `declaredExitCode` is `'unknown'` unless a real fact declared it, and an
|
|
9923
|
+
* unmarked success is NOT a read exit code of 0;
|
|
9924
|
+
* - `operationAttribution` stays `'unknown'` for an opaque compound runner, so
|
|
9925
|
+
* the last command's success can never cover an earlier failure;
|
|
9926
|
+
* - `outcome` uses the same evaluator with independently selected facts; a
|
|
9927
|
+
* disagreement with the historical field is explicitly reported.
|
|
9928
|
+
*
|
|
9929
|
+
* SOURCE PRIORITY for the process terminal facts, highest first:
|
|
9930
|
+
*
|
|
9931
|
+
* 1. the trusted `contextGuardProcess` namespace — the run's OWN declaration
|
|
9932
|
+
* of what the process did. An explicit `exitCode` here is read as declared
|
|
9933
|
+
* even when the generic `meta.exitCode` says something else; the namespace
|
|
9934
|
+
* is the more specific statement and never loses to the generic one.
|
|
9935
|
+
* 2. any other structured terminal fact the renderer put in `meta`
|
|
9936
|
+
* (`meta.exitCode` / `meta.exit_code` / `meta.signal`).
|
|
9937
|
+
* 3. the rendered text markers of the audited renderers.
|
|
9938
|
+
*
|
|
9939
|
+
* A namespace declaration never overrides the frozen `outcome`, because the
|
|
9940
|
+
* frozen value is the historical record and this batch must not rewrite it; the
|
|
9941
|
+
* derived layer records its source and conflict flag instead of changing history.
|
|
9942
|
+
*/
|
|
9943
|
+
function shellProcessFacts(meta, textContent, frozenOutcome, resultError, surface, backgrounded, parseStatus$1) {
|
|
9944
|
+
const { facts: terminal, source } = resolveDeclaredTerminalFacts(meta, textContent);
|
|
9945
|
+
const declaredOperations = declaredOperationResults(meta);
|
|
9946
|
+
const operationAttribution = declaredOperations ? "declared_per_operation" : parseStatus$1 === "supported" && !backgrounded ? "single_operation" : "unknown";
|
|
9947
|
+
const outcome = shellOutcome(surface, terminal, resultError, backgrounded);
|
|
9948
|
+
let outcomeReason;
|
|
9949
|
+
if (backgrounded) outcomeReason = "backgrounded";
|
|
9950
|
+
else if (resultError) outcomeReason = "host_error_flag";
|
|
9951
|
+
else if (terminal.negative) outcomeReason = "declared_negative_marker";
|
|
9952
|
+
else if (terminal.exitCode !== void 0) outcomeReason = "declared_exit_code";
|
|
9953
|
+
else if (outcome === "success") outcomeReason = "unmarked_renderer_success";
|
|
9954
|
+
else if (terminal.marked) outcomeReason = "marker_unclassified";
|
|
9955
|
+
else outcomeReason = "text_scan_inconclusive";
|
|
9956
|
+
return {
|
|
9957
|
+
hostToolReturned: resultError ? "error" : "result",
|
|
9958
|
+
declaredExitCode: terminal.exitCode ?? "unknown",
|
|
9959
|
+
terminalMarkerRead: terminal.marked,
|
|
9960
|
+
outcome,
|
|
9961
|
+
outcomeReason,
|
|
9962
|
+
source,
|
|
9963
|
+
frozenOutcomeConflict: outcome !== frozenOutcome,
|
|
9964
|
+
operationAttribution,
|
|
9965
|
+
...declaredOperations ? { declaredOperationResults: declaredOperations } : {}
|
|
9966
|
+
};
|
|
9967
|
+
}
|
|
9569
9968
|
function metaUrls(meta) {
|
|
9570
9969
|
const record = asRecord$2(meta);
|
|
9571
9970
|
if (!record) return [];
|
|
@@ -9775,19 +10174,21 @@ function extractToolSubject(call, result, defaultCwd, hostLock) {
|
|
|
9775
10174
|
case "shell":
|
|
9776
10175
|
case "pwsh": {
|
|
9777
10176
|
const command = typeof args.command === "string" ? args.command : "";
|
|
9778
|
-
const terminal = structuredTerminalFacts(result.meta) ?? extractTerminalFacts(result.textContent);
|
|
9779
10177
|
const backgrounded = args.run_in_background === true;
|
|
9780
10178
|
const commandDetails = analyzeCommand(command, typeof args.workdir === "string" ? args.workdir : defaultCwd, call.name);
|
|
9781
10179
|
const commandCwd = typeof args.workdir === "string" ? args.workdir : defaultCwd;
|
|
9782
10180
|
const action = structured?.semanticAction ?? semanticActionFromCommand(command);
|
|
9783
10181
|
const deterministic = commandDetails.status === "supported" && !backgrounded && isDeterministicCheck(command);
|
|
9784
|
-
const
|
|
9785
|
-
const
|
|
10182
|
+
const terminal = legacyTerminalFacts(result.meta, result.textContent);
|
|
10183
|
+
const surface = call.name;
|
|
10184
|
+
const outcome = shellOutcome(surface, terminal, result.error, backgrounded);
|
|
10185
|
+
const processFacts = shellProcessFacts(result.meta, result.textContent, outcome, result.error, surface, backgrounded, parseStatus(commandDetails).parseStatus);
|
|
9786
10186
|
const subject = {
|
|
9787
10187
|
capabilities: ["shell", ...deterministic ? ["deterministic-check"] : []],
|
|
9788
10188
|
subjects: unique(commandDetails.subjects),
|
|
9789
10189
|
surfaces: ["scope"],
|
|
9790
10190
|
outcome,
|
|
10191
|
+
processFacts,
|
|
9791
10192
|
executables: commandDetails.executables,
|
|
9792
10193
|
operations: commandDetails.operations,
|
|
9793
10194
|
semanticAction: action,
|
|
@@ -9849,6 +10250,15 @@ function evidenceFromPersistedToolResult(call, result, epoch, evidenceId, defaul
|
|
|
9849
10250
|
...subject.reasonCode ? { reasonCode: subject.reasonCode } : {},
|
|
9850
10251
|
...subject.adapterId ? { adapterId: subject.adapterId } : {},
|
|
9851
10252
|
...subject.adapterVersion ? { adapterVersion: subject.adapterVersion } : {},
|
|
10253
|
+
...subject.processFacts ? { processFacts: subject.processFacts.hostToolReturned === (result.error ? "error" : "result") ? subject.processFacts : {
|
|
10254
|
+
...subject.processFacts,
|
|
10255
|
+
hostToolReturned: result.error ? "error" : "result",
|
|
10256
|
+
...result.error ? {
|
|
10257
|
+
outcome: "failure",
|
|
10258
|
+
outcomeReason: "host_error_flag"
|
|
10259
|
+
} : {},
|
|
10260
|
+
frozenOutcomeConflict: (result.error ? "failure" : subject.processFacts.outcome) !== outcome
|
|
10261
|
+
} } : {},
|
|
9852
10262
|
...subject.externalOperationRef ? { externalOperationRef: {
|
|
9853
10263
|
...subject.externalOperationRef,
|
|
9854
10264
|
epoch
|
|
@@ -12816,4 +13226,4 @@ function verifyComposedHostLockDump(text, expected, roots) {
|
|
|
12816
13226
|
}
|
|
12817
13227
|
|
|
12818
13228
|
//#endregion
|
|
12819
|
-
export { extractToolSubject as $,
|
|
13229
|
+
export { extractToolSubject as $, proposeRebindV042 as $n, requestedTargetMatchesResolved as $r, proofDigest as $t, lifecyclePhase as A, NO_PROGRESS_RECORD_PREFIX as An, isOpenObligation as Ar, compareHostVersions as At, RELEASE_RESERVATION_PREFIX as B, observeAssistantOutcome as Bn, BOUNDED_ARTIFACT_TYPES as Br, certifyCheckpoint as Bt, gitCommandMatchesTarget as C, recoveryDigest as Cn, extractMethod as Cr, evaluateToolSurfaceCapability as Ct, FIRST_STEP_GUIDANCE as D, evidenceMatchesItem as Dn, interpretClause as Dr, MIN_SUPPORTED_HOST_VERSION as Dt, verifiedLinearCommitReadback as E, evidenceCoverage as En, segmentClauses as Er, LATEST_SUPPORTED_HOST_VERSION as Et, PROTOCOL_V4_NOTICE as F, decisionBoundaryKey as Fn, statefulActionsOfScope as Fr, RC015_HOST_PACKAGES as Ft, readbackSettlesContract as G, effectuateBoundary as Gn, STOP_PROTOCOL_VERSION as Gr, PROOF_PROTOCOL_VERSION as Gt, contractById as H, goalCompletionDenial as Hn, CERTIFICATE_VERSION_V2 as Hr, PROOF_KINDS as Ht, PROTOCOL_V5_NOTICE as I, isRootPauseRequest as In, canonicalRegistryBase as Ir, RC1_HOST_PACKAGES as It, releasePreEffectDecision as J, currentContractDigest as Jn, actionCompatible as Jr, bindProofV2ToProjection as Jt, releaseContractFor as K, isCurrentAcceptedBoundary as Kn, STOP_PROTOCOL_VERSION_V2 as Kr, PROOF_PROTOCOL_VERSION_V2 as Kt, deriveProjection as L, isWholeTaskCompletionClaim as Ln, npmEscapedPackageName as Lr, ALPHA3_HOST_PACKAGES as Lt, CAPTURE_V042_NOTICE as M, classifyCompletionClaim as Mn, maskCodeSpans as Mr, parseHostVersion as Mt, DEFAULT_DELEGATION_TOOL_NAMES as N, decideTurnBoundary as Nn, namedActions as Nr, satisfiesSupportedHostRange as Nt, claimedBatchHasRealRootInput as O, isVerifyingCapability as On, interpretMessage as Or, SUPPORTED_HOST_RANGE as Ot, PROTOCOL_V3_NOTICE as P, decideTurnStopping as Pn, semanticActionOfScope as Pr, RC015_RC2_HOST_PACKAGES as Pt, extractTextContent as Q, proposeRebindOutcome as Qn, requestedTargetAuthorizesMutation as Qr, proofCapabilityReport as Qt, RELEASE_OPERATIONS as R, latestAssistantText as Rn, ACTION_MANIFEST as Rr, authorityCaptureCounts as Rt, executeRevalidatedGitEffect as S, openItems as Sn, extractArtifactPaths as Sr, evaluateHostLock as St, revalidateGitPrestate as T, bindingSatisfies as Tn, isInformationalMessage as Tr, selectHostCohort as Tt, inFlightReservation as U, hasCurrentCertificate as Un, SEMANTIC_ACTIONS as Ur, PROOF_KINDS_V2 as Ut, RELEASE_SETTLEMENT_PREFIX as V, progressFingerprint as Vn, CERTIFICATE_VERSION as Vr, PROOF_CAPABILITY_MATRIX as Vt, normalizeReleaseContract as W, availableBoundaryQualifications as Wn, STATEFUL_ACTIONS as Wr, PROOF_MANIFEST_DOMAIN_V2 as Wt, supersedeItem as X, confirmRebind as Xn, isStatefulAction as Xr, createProofManifest as Xt, reservationFor as Y, createProjection as Yn, boundedArtifactChoiceMatches as Yr, canonicalProjection as Yt, evidenceFromPersistedToolResult as Z, proposeRebind as Zn, requestedIdentityKey as Zr, createProofManifestV2 as Zt, GIT_COMMAND_MANIFEST_IDS as _, DEFAULT_RECOVERY_CHAR_BUDGET as _n, removalIsComplete as _r, LEGACY_HOST_COHORTS as _t, injectActiveProfileHostLock as a, validateManifest as ai, requiredSubjectsOf as an, parseConfirmationMessage as ar, parseShellCommand as at, commitTreeSnapshotDigest as b, cleanupConditionFor as bn, captureItem as br, evaluateExternalWaitCapability as bt, packageRowsFromPnpmLock as c, canonicalizePath as ci, sessionQueryV2 as cn, evidenceAvailabilityReason as cr, ACTIVE_HOST_LAUNCHER_VERSION as ct, resolveInstalledHostLock as d, sanitizeClauseText as di, certifiableOpenItems as dn, DEPENDENCY_FREE_ONLY_CONDITION as dr, BASE_HOST_PACKAGES as dt, semanticActionFromCommand as ei, proofDigestV2 as en, rebindAttemptKey as er, isDeterministicCheck as et, verifyComposedHostLockDump as f, sanitizeUrl as fi, certificateClosure as fn, actionHasCertificationPath as fr, DEFAULT_HOST_LOCK as ft, snapshotSessionEvents as g, CLEANUP_CONDITION_RULE_SHORT as gn, partialFailureOf as gr, HOST_COHORTS as gt, SessionApiError as h, CLEANUP_CONDITION_RULE_COMPACT as hn, capabilityFactOf as hr, HOST_CAPABILITY_PACKAGE_GROUPS as ht, hostLockRowsFromComposedDump as i, COMMAND_SURFACE_MANIFEST as ii, proofV2Rejection as in, isFrozenV042RebindResponse as ir, parsePwshCommand as it, previewFirstStepInjection as j, NO_PROGRESS_TURNS_BEFORE_STOP as jn, kindOfScope as jr, evaluateMinimumHostVersion as jt, firstStepGuidance as k, CONTROL_RECORD_PREFIX as kn, isExecutableItem as kr, SUPPORTED_HOST_VERSIONS as kt, readActiveHostGraph as l, digestStrings as li, validateProofManifest as ln, itemDiagnosis as lr, ALPHA2_DSHMARKET_139_HOST_PACKAGES as lt, SESSION_EVENT_ENVELOPE_INVALID as m, CLEANUP_CONDITION_RULE as mn, capabilityConsequence as mr, GOAL_HOST_PACKAGES as mt, combineHostPolicy as n, validateActionManifest as ni, proofHostSurfacesOf as nn, replayRebindResult as nr, canonicalArgvFromCommand as nt, inspectTargetHostGraph as o, classifyTaskIntent as oi, scopeCoverageDigest as on, capabilityRemedyPhrase as or, ACTIVE_HOST_COHORT_ID as ot, SESSION_API_UNSUPPORTED as p, sha256 as pi, unitDescendantIds as pn, admissibleForRemoval as pr, EXPECTED_HOST_PACKAGES as pt, releaseCoverage as q, qualifyBoundary as qn, SUPPORTED_EVIDENCE_ADAPTERS as qr, bindProofToProjection as qt, hostLockContextFromComposedDump as r, validateActionTarget as ri, proofOperationMatches as rn, CONFIRM_LINE_PATTERN as rr, isRunExecutable as rt, packageRowsFromActiveGraph as s, classifyUserInteraction as si, sessionQuery as sn, deriveItemDiagnosis as sr, ACTIVE_HOST_COHORT_IDS as st, HostProfileError as t, semanticActionFromText as ti, proofEvidenceConstraints as tn, rebindResponse as tr, withDurability as tt, resolveActiveProfileHostLock as u, normalizeClause as ui, validateProofManifestV2 as un, relevantEvidence as ur, ALPHA2_HOST_PACKAGES as ut, GIT_COMMAND_TEMPLATES as v, MIN_RECOVERY_CHAR_BUDGET as vn, removalIsPartiallyKnown as vr, bindExecutableIdentity as vt, parseGitCommandManifest as w, renderRecoveryPacket as wn, extractOperation as wr, hostVersionFromPackages as wt, createGitPrestateEnvelope as x, closingHint as xn, classifyClause as xr, evaluateHostCapability as xt, commitIndexSnapshotDigest as y, carriesCleanupCondition as yn, captureClause as yr, bindLiveGoalCapability as yt, RELEASE_OPERATION_SURFACES as z, latestRootInstruction as zn, ACTION_MANIFEST_VERSION as zr, segmentAuthorityBlocks as zt };
|