@sema-agent/client-core 0.111.0 → 0.112.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 +98 -0
- package/README.md +16 -7
- package/dist/agentSession/engineSessionBackgroundStop.js +2 -2
- package/dist/checkpointRowVerdict.d.ts +3 -0
- package/dist/checkpointRowVerdict.js +14 -1
- package/dist/consoleCaPin.d.ts +136 -0
- package/dist/consoleCaPin.js +827 -0
- package/dist/decideReceipt.d.ts +2 -1
- package/dist/deviceRebind.js +3 -3
- package/dist/effectiveFacts.d.ts +9 -0
- package/dist/effectiveFacts.js +33 -0
- package/dist/engineAddress.d.ts +1 -0
- package/dist/engineAddress.js +4 -1
- package/dist/engineCredentialRelease.d.ts +54 -0
- package/dist/engineCredentialRelease.js +146 -0
- package/dist/engineErrorCodes.d.ts +1 -0
- package/dist/engineErrorCodes.js +1 -0
- package/dist/engineHealthFacts.d.ts +0 -11
- package/dist/engineHealthFacts.js +0 -21
- package/dist/engineHealthProbeVerdict.d.ts +1 -0
- package/dist/engineHealthProbeVerdict.js +21 -13
- package/dist/engineUnavailable.d.ts +3 -2
- package/dist/engineUnavailable.js +16 -12
- package/dist/engineUrl.js +4 -2
- package/dist/gateFailureCodes.js +2 -2
- package/dist/generated/sdkFactTables.d.ts +1 -0
- package/dist/generated/sdkFactTables.js +13 -0
- package/dist/generated/settingsSchemaFns.d.ts +1 -0
- package/dist/generated/settingsSchemaFns.js +3 -0
- package/dist/generated/settingsSchemaHooksClassifier.js +38 -9
- package/dist/generated/settingsSchemaTables.d.ts +52 -0
- package/dist/generated/settingsSchemaTables.js +18 -0
- package/dist/generated/settingsSchemaTypes.d.ts +23 -13
- package/dist/generated/settingsSchemaUrlShape.d.ts +1 -0
- package/dist/generated/settingsSchemaUrlShape.js +17 -0
- package/dist/hitl/decisionRefusal.d.ts +4 -0
- package/dist/hitl/decisionRefusal.js +12 -2
- package/dist/hitl/hitlBridge.d.ts +1 -0
- package/dist/hitl/hitlBridge.js +17 -4
- package/dist/hitl/localAllowRedemption.d.ts +9 -6
- package/dist/hitl/localAllowRedemption.js +20 -0
- package/dist/hitl/parkOwnership.js +2 -1
- package/dist/hitl/parkResolver.js +7 -0
- package/dist/hitl/planReviewCard.d.ts +3 -2
- package/dist/hitl/planReviewCard.js +2 -0
- package/dist/hitl/planReviewWire.d.ts +4 -2
- package/dist/hitl/planReviewWire.js +134 -97
- package/dist/hitl/screenDecisionCards.js +3 -2
- package/dist/hitl/sessionPolicyWire.js +2 -2
- package/dist/hitl/standingRows.d.ts +4 -2
- package/dist/hitl/standingRows.js +10 -3
- package/dist/hooksReaderGenerations.js +1 -1
- package/dist/i18n/messages.en.d.ts +165 -0
- package/dist/i18n/messages.en.js +166 -1
- package/dist/i18n/messages.zh.js +177 -1
- package/dist/index.d.ts +30 -5
- package/dist/index.js +15 -2
- package/dist/liveModelCatalog.d.ts +4 -0
- package/dist/liveModelCatalog.js +10 -1
- package/dist/localConfig/documents.d.ts +61 -0
- package/dist/localConfig/documents.js +51 -0
- package/dist/localConfig/kernel.d.ts +149 -0
- package/dist/localConfig/kernel.js +597 -0
- package/dist/localConfig/mcp/edit.d.ts +161 -0
- package/dist/localConfig/mcp/edit.js +846 -0
- package/dist/localConfig/mcp/servers.d.ts +165 -0
- package/dist/localConfig/mcp/servers.js +776 -0
- package/dist/localConfig/mcp/views.d.ts +170 -0
- package/dist/localConfig/mcp/views.js +429 -0
- package/dist/localConfig/modelPool.d.ts +262 -0
- package/dist/localConfig/modelPool.js +1489 -0
- package/dist/localConfig/modelPoolWords.d.ts +13 -0
- package/dist/localConfig/modelPoolWords.js +20 -0
- package/dist/localConfig/receiptShape.d.ts +7 -0
- package/dist/localConfig/receiptShape.js +135 -0
- package/dist/localConfig/settingsWrite.d.ts +127 -0
- package/dist/localConfig/settingsWrite.js +237 -0
- package/dist/localConfig/skills.d.ts +124 -0
- package/dist/localConfig/skills.js +397 -0
- package/dist/localConfig/skillsWords.d.ts +10 -0
- package/dist/localConfig/skillsWords.js +5 -0
- package/dist/mcpProbeWire.js +2 -1
- package/dist/mcpWireCaps.js +1 -1
- package/dist/memoryVerbsWire.js +3 -2
- package/dist/model/onboardJudgement.d.ts +14 -4
- package/dist/model/onboardJudgement.js +91 -139
- package/dist/modelConfigGapNotice.d.ts +20 -0
- package/dist/modelConfigGapNotice.js +102 -0
- package/dist/modsKernelIdentity.js +2 -47
- package/dist/notifications.js +14 -12
- package/dist/ownKey.d.ts +1 -0
- package/dist/ownKey.js +40 -8
- package/dist/permissionsDeclaration.d.ts +2 -1
- package/dist/permissionsDeclaration.js +31 -17
- package/dist/planReviewOutcomeCause.d.ts +2 -0
- package/dist/planReviewOutcomeCause.js +12 -0
- package/dist/promptBlockedCopy.js +2 -2
- package/dist/resumeRefusalCopy.d.ts +3 -1
- package/dist/resumeRefusalCopy.js +12 -4
- package/dist/runLedgerSnapshot.js +3 -3
- package/dist/runPermissionModeSwitch.js +2 -3
- package/dist/seatContract.d.ts +154 -4
- package/dist/seatContract.js +228 -2
- package/dist/sessionIdSegment.d.ts +1 -0
- package/dist/sessionIdSegment.js +4 -1
- package/dist/sessionMemoryErase.js +2 -1
- package/dist/sha256Bytes.d.ts +1 -0
- package/dist/sha256Bytes.js +46 -0
- package/dist/skillOverrideChain.d.ts +83 -0
- package/dist/skillOverrideChain.js +378 -0
- package/dist/skillsWireCaps.d.ts +3 -0
- package/dist/skillsWireCaps.js +16 -1
- package/dist/turnFailurePresentation.js +4 -10
- package/docs/INTEGRATION-CLIENTS.md +680 -14
- package/package.json +3 -3
|
@@ -18,6 +18,7 @@ import { denyReasonForWire, isPlanReviewModeAfter } from './hitlBridge.js';
|
|
|
18
18
|
import { freshPlanReviewQuestionId, planReviewQuestionId, REOPEN_ID_TAIL, taskIdFromPlanReviewQuestionId } from './gateIdentity.js';
|
|
19
19
|
import { isPlanReviewPark, mintPlanReviewCardFacts, notePlanReviewCardIssued, pausedCheckpointIdOf, planReviewCardFactsFrom, planReviewFactsCurrent, registeredPlanReviewCardFacts, samePlanReviewCardFacts, unknownBody, _resetPlanReviewRunsForTest, } from '../planReviewCardFacts.js';
|
|
20
20
|
import { planReviewAskAgainKey, planReviewCardNoteRef, planReviewDecisionReasonRef, planReviewUnreadableNoteRef, takePlanReviewFacts, _resetPlanReviewFactsFlightsForTest, } from './planReviewCard.js';
|
|
21
|
+
import { planReviewOutcomeCauseOf } from '../planReviewOutcomeCause.js';
|
|
21
22
|
import { EN_MESSAGES } from '../i18n/messages.en.js';
|
|
22
23
|
import { msg, renderMessage, DATA_FACE_LANGUAGE } from '../i18n/translate.js';
|
|
23
24
|
import { notePlanReviewAnswered, notePlanReviewAnsweredFor, planReviewArmedKeyFor, waitForGateArmedFor, wasGateArmedFor, } from './armedGateRegistry.js';
|
|
@@ -666,11 +667,34 @@ function noteEngineRefusedGate(id) {
|
|
|
666
667
|
engineRefusedGateIds.delete(oldest.value);
|
|
667
668
|
}
|
|
668
669
|
}
|
|
670
|
+
function wireGateOf(decision, gate) {
|
|
671
|
+
if (gate === undefined)
|
|
672
|
+
return undefined;
|
|
673
|
+
if (decision === 'approve')
|
|
674
|
+
return gate;
|
|
675
|
+
return engineRefusedGateIds.has(gate) ? undefined : gate;
|
|
676
|
+
}
|
|
677
|
+
function planReviewWireBodyOf(decision, reason, mode, gate) {
|
|
678
|
+
const withReason = reason !== undefined ? { reason } : {};
|
|
679
|
+
const withMode = mode !== undefined ? { permissionModeAfter: mode } : {};
|
|
680
|
+
if (decision === 'approve')
|
|
681
|
+
return gate === undefined ? undefined : Object.freeze({ decision, ...withReason, ...withMode, checkpointId: gate });
|
|
682
|
+
return Object.freeze({ decision, ...withReason, ...withMode, ...(gate !== undefined ? { checkpointId: gate } : {}) });
|
|
683
|
+
}
|
|
669
684
|
function planReviewDecisionReasonSegment(reason, card) {
|
|
670
685
|
if (reason === undefined)
|
|
671
686
|
return '';
|
|
672
687
|
try {
|
|
673
|
-
|
|
688
|
+
const ref = planReviewDecisionReasonRef(reason, card);
|
|
689
|
+
return ref === undefined ? '' : ` ${renderMessage(ref, DATA_FACE_LANGUAGE)}`;
|
|
690
|
+
}
|
|
691
|
+
catch {
|
|
692
|
+
return '';
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
function planReviewSentWithoutGateSegment() {
|
|
696
|
+
try {
|
|
697
|
+
return ` ${renderMessage(msg('approval.planReview.decision.sentWithoutGateId'), DATA_FACE_LANGUAGE)}`;
|
|
674
698
|
}
|
|
675
699
|
catch {
|
|
676
700
|
return '';
|
|
@@ -741,9 +765,17 @@ function askAgainReasonOf(card, opts) {
|
|
|
741
765
|
return renderMessage(msg('approval.planReview.askAgain.unknown'), DATA_FACE_LANGUAGE);
|
|
742
766
|
}
|
|
743
767
|
}
|
|
768
|
+
function planReviewDecisionWordOf(raw) {
|
|
769
|
+
return raw === 'approve' || raw === 'reject' || raw === 'ask_again' ? raw : undefined;
|
|
770
|
+
}
|
|
744
771
|
async function decidePlanReviewFor(taskId, decision, permissionModeAfter, opts, card, cardId) {
|
|
772
|
+
const word = planReviewDecisionWordOf(decision);
|
|
773
|
+
if (word === undefined) {
|
|
774
|
+
hostLog('error', `planReviewWire: decision-word-refused typeof=${typeof decision}`);
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
745
777
|
if (typeof taskId === 'string' && planReviewOpsOf(taskId).some((op) => op.phase === 'posting')) {
|
|
746
|
-
hostLog('error', `planReviewWire: decidePlanReview(${
|
|
778
|
+
hostLog('error', `planReviewWire: decidePlanReview(${word}) for task ${taskId} REFUSED — a decision for this task is already in flight (duplicate delivery latched)`);
|
|
747
779
|
return;
|
|
748
780
|
}
|
|
749
781
|
let op = typeof taskId === 'string' ? claimablePlanReviewDecisionOp(taskId) : undefined;
|
|
@@ -770,11 +802,11 @@ async function decidePlanReviewFor(taskId, decision, permissionModeAfter, opts,
|
|
|
770
802
|
settleDecisionOp(mine, 'package');
|
|
771
803
|
};
|
|
772
804
|
const dispatchNo = ++decideDispatchSeq;
|
|
773
|
-
hostLog('debug', `planReviewWire: decidePlanReview dispatch #${dispatchNo} task=${taskId} decision=${
|
|
805
|
+
hostLog('debug', `planReviewWire: decidePlanReview dispatch #${dispatchNo} task=${taskId} decision=${word} mode=${permissionModeAfter ?? '-'}`);
|
|
774
806
|
try {
|
|
775
|
-
const wireDecision =
|
|
776
|
-
const wireOpts =
|
|
777
|
-
await decidePlanReviewInner(taskId, wireDecision, permissionModeAfter, dispatchNo, releaseLatch, settle, wireOpts, card,
|
|
807
|
+
const wireDecision = word === 'ask_again' ? 'reject' : word;
|
|
808
|
+
const wireOpts = word === 'ask_again' ? { ...opts, reason: askAgainReasonOf(card, opts) } : opts;
|
|
809
|
+
await decidePlanReviewInner(taskId, wireDecision, permissionModeAfter, dispatchNo, releaseLatch, settle, wireOpts, card, word, cardId);
|
|
778
810
|
}
|
|
779
811
|
finally {
|
|
780
812
|
releaseLatch();
|
|
@@ -797,14 +829,15 @@ function planReviewClientsFor(resolved) {
|
|
|
797
829
|
}
|
|
798
830
|
async function decidePlanReviewInner(taskId, decision, permissionModeAfter, dispatchNo, releaseLatch, settle, opts, card, semanticDecision, cardId) {
|
|
799
831
|
let outcome;
|
|
800
|
-
let
|
|
832
|
+
let cause;
|
|
833
|
+
let unsentProven = false;
|
|
801
834
|
const gateBefore = card?.checkpointId;
|
|
802
835
|
const approvalWithheld = decision !== 'approve' ? undefined : card === undefined ? 'card_missing' : card.body.kind !== 'shown' || card.checkpointId === undefined ? 'card_withholds' : undefined;
|
|
803
836
|
let effect = 'unconfirmed';
|
|
804
|
-
let stillParkedCause;
|
|
805
837
|
let statusSeen;
|
|
806
838
|
const wire = opts?.wire;
|
|
807
839
|
const resolved = engineWireFor(wire, DEFAULT_SESSION_KEY, usablePlanReviewWireClient);
|
|
840
|
+
const wireGate = wireGateOf(decision, gateBefore);
|
|
808
841
|
const badMode = permissionModeAfter !== undefined && !isPlanReviewModeAfter(permissionModeAfter);
|
|
809
842
|
if (badMode) {
|
|
810
843
|
hostLog('error', `planReviewWire: ${decision} NOT sent — permissionModeAfter must be "default" or "acceptEdits"`);
|
|
@@ -814,7 +847,7 @@ async function decidePlanReviewInner(taskId, decision, permissionModeAfter, disp
|
|
|
814
847
|
else if (approvalWithheld !== undefined) {
|
|
815
848
|
hostLog('debug', `planReviewWire: not-sent decision=${decision} reason=${approvalWithheld}`);
|
|
816
849
|
effect = 'not_sent';
|
|
817
|
-
|
|
850
|
+
cause = approvalWithheld;
|
|
818
851
|
outcome = renderMessage(msg('approval.planReview.decision.notSent', { decision }), DATA_FACE_LANGUAGE);
|
|
819
852
|
}
|
|
820
853
|
else if (resolved.kind === 'no-target') {
|
|
@@ -836,7 +869,6 @@ async function decidePlanReviewInner(taskId, decision, permissionModeAfter, disp
|
|
|
836
869
|
}
|
|
837
870
|
else {
|
|
838
871
|
const client = clients.decide;
|
|
839
|
-
const checkpointId = gateBefore !== undefined && !engineRefusedGateIds.has(gateBefore) ? gateBefore : undefined;
|
|
840
872
|
const repullRow = async () => {
|
|
841
873
|
const probe = clients.repull();
|
|
842
874
|
if (!probe)
|
|
@@ -854,87 +886,90 @@ async function decidePlanReviewInner(taskId, decision, permissionModeAfter, disp
|
|
|
854
886
|
try {
|
|
855
887
|
const mode = isPlanReviewModeAfter(permissionModeAfter) ? permissionModeAfter : undefined;
|
|
856
888
|
const reason = denyReasonForWire(opts?.reason, `plan-review ${taskId}`);
|
|
857
|
-
const
|
|
858
|
-
if (
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
if (checkpointId !== undefined)
|
|
863
|
-
reqBody.checkpointId = checkpointId;
|
|
864
|
-
let body;
|
|
865
|
-
try {
|
|
866
|
-
body = await sendOnce(undefined, () => client.assistant.planReview(taskId, reqBody));
|
|
889
|
+
const wireBody = planReviewWireBodyOf(decision, reason, mode, wireGate);
|
|
890
|
+
if (wireBody === undefined) {
|
|
891
|
+
effect = 'not_sent';
|
|
892
|
+
cause = 'card_withholds';
|
|
893
|
+
outcome = renderMessage(msg('approval.planReview.decision.notSent', { decision }), DATA_FACE_LANGUAGE);
|
|
867
894
|
}
|
|
868
|
-
|
|
869
|
-
const
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
body = await sendOnce(undefined, () => client.assistant.planReview(taskId, { decision, ...(reason !== undefined ? { reason } : {}), ...(checkpointId !== undefined ? { checkpointId } : {}) }));
|
|
895
|
+
else {
|
|
896
|
+
const firstSent = { ...wireBody };
|
|
897
|
+
let body;
|
|
898
|
+
try {
|
|
899
|
+
body = await sendOnce(undefined, () => client.assistant.planReview(taskId, firstSent));
|
|
874
900
|
}
|
|
875
|
-
|
|
876
|
-
|
|
901
|
+
catch (e1) {
|
|
902
|
+
const conflict = e1;
|
|
903
|
+
const defaultConflict = mode === 'default' && conflict?.status === 400 && conflict?.errorCode === REQUEST_FIELD_CONFLICT;
|
|
904
|
+
if (defaultConflict && !directFailureVerdictOf(e1, directSafetyStopOf(e1)).yields) {
|
|
905
|
+
hostLog('debug', 'planReviewWire: permissionModeAfter "default" refused as not applicable — re-sending the approval without the key (same meaning)');
|
|
906
|
+
const { permissionModeAfter: _modeDropped, ...resend } = wireBody;
|
|
907
|
+
body = await sendOnce(undefined, () => client.assistant.planReview(taskId, resend));
|
|
908
|
+
}
|
|
909
|
+
else {
|
|
910
|
+
throw e1;
|
|
911
|
+
}
|
|
877
912
|
}
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
913
|
+
finally {
|
|
914
|
+
releaseLatch();
|
|
915
|
+
}
|
|
916
|
+
hostLog('debug', `planReviewWire: ${decision} → ok (dispatch #${dispatchNo}) ${JSON.stringify(body).slice(0, 200)}`);
|
|
917
|
+
let postStatus;
|
|
918
|
+
let gateAfter;
|
|
919
|
+
let gateKindAfter;
|
|
920
|
+
try {
|
|
921
|
+
const post = await repullRow();
|
|
922
|
+
if (post !== undefined) {
|
|
923
|
+
postStatus = bodyWordOf(post, 'status');
|
|
924
|
+
gateAfter = pausedCheckpointIdOf(post?.result);
|
|
925
|
+
gateKindAfter = pausedGateKindOf(post?.result);
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
catch (e) {
|
|
929
|
+
hostLog('debug', `planReviewWire: post-decide status re-pull failed (fail-soft): ${String(e)}`);
|
|
930
|
+
}
|
|
931
|
+
const bodyStatus = bodyWordOf(body, 'status');
|
|
932
|
+
const effective = postStatus ?? bodyStatus;
|
|
933
|
+
statusSeen = effective;
|
|
934
|
+
effect = planReviewSettledVerdict({ decision, postStatus, bodyStatus, reparked: bodySaysReparked(body), gateBefore, gateAfter, gateKindAfter });
|
|
935
|
+
const code = bodyWordOf(body, 'errorCode');
|
|
936
|
+
if (effect === 'still_parked' && postStatus === 'needs_review' && !bodySaysReparked(body)) {
|
|
937
|
+
outcome =
|
|
938
|
+
`The plan_review ${decision} returned HTTP 200 but the session is STILL locked on the same review gate ` +
|
|
939
|
+
`(post-decide status: needs_review). The decision did NOT take effect (known engine issue, RB-471 family). ` +
|
|
940
|
+
`Tell the user plainly that the ${decision} did not go through; the reliable exits today are approving the plan or cancelling the task.`;
|
|
941
|
+
}
|
|
942
|
+
else if (effect === 'still_parked') {
|
|
943
|
+
outcome =
|
|
944
|
+
`The plan_review ${decision} was NOT applied: the engine could not continue the task and put the plan back to wait for a decision` +
|
|
945
|
+
`${code !== undefined ? ` (engine code: ${code})` : ''}. Tell the user plainly that the ${decision} did not go through.`;
|
|
946
|
+
}
|
|
947
|
+
else if (effect === 'advanced') {
|
|
948
|
+
outcome = planReviewAdvancedOutcome(decision, effective === 'needs_review' ? 'needs_review' : 'suspended');
|
|
949
|
+
}
|
|
950
|
+
else if (effect === 'took_effect') {
|
|
951
|
+
outcome =
|
|
952
|
+
`The plan was ${decision === 'approve' ? 'approved and the parked task resumed to completion' : 'rejected (plan discarded)'} — ${effective === 'completed' ? 'final status' : 'status'}: ${effective} ` +
|
|
953
|
+
`(${postStatus !== undefined ? 'post-decide re-checked: task left the review gate' : "from the decision's own reply; the post-decide re-check was unavailable"}).`;
|
|
954
|
+
}
|
|
955
|
+
else if (effective === 'needs_review' && (gateBefore === undefined || gateAfter === undefined || postStatus !== 'needs_review')) {
|
|
956
|
+
outcome =
|
|
957
|
+
`The plan_review ${decision} returned HTTP 200 and the task is waiting at a plan review gate again (post-decide status: needs_review), ` +
|
|
958
|
+
`but it could not be told whether this is the same review (the ${decision} did not take effect) or a new plan written after it (it did).`;
|
|
959
|
+
}
|
|
960
|
+
else if (effective === 'suspended' || effective === 'needs_review') {
|
|
961
|
+
outcome =
|
|
962
|
+
`The plan_review ${decision} was accepted by the engine (HTTP 200) and the task is paused again (post-decide status: ${effective}), ` +
|
|
963
|
+
`${gateKindAfter !== undefined ? `at a '${gateKindAfter}' pause that is not an approval card` : 'but the pause it stopped at was not reported'} — what the ${decision} led to could not be confirmed.`;
|
|
964
|
+
}
|
|
965
|
+
else if (effective !== undefined) {
|
|
966
|
+
outcome =
|
|
967
|
+
`The plan_review ${decision} was accepted by the engine (HTTP 200), but the task then reported status ${effective}` +
|
|
968
|
+
`${code !== undefined ? ` (engine code: ${code})` : ''} — not a completion; what the ${decision} led to could not be confirmed.`;
|
|
969
|
+
}
|
|
970
|
+
else {
|
|
971
|
+
outcome = `The plan_review ${decision} was accepted by the engine (HTTP 200) but its effect is unconfirmed — final status: unknown (post-decide verification unavailable). Do not treat this as ${decision === 'approve' ? 'an approval that resumed the task' : 'a discarded plan'}.`;
|
|
892
972
|
}
|
|
893
|
-
}
|
|
894
|
-
catch (e) {
|
|
895
|
-
hostLog('debug', `planReviewWire: post-decide status re-pull failed (fail-soft): ${String(e)}`);
|
|
896
|
-
}
|
|
897
|
-
const bodyStatus = bodyWordOf(body, 'status');
|
|
898
|
-
const effective = postStatus ?? bodyStatus;
|
|
899
|
-
statusSeen = effective;
|
|
900
|
-
effect = planReviewSettledVerdict({ decision, postStatus, bodyStatus, reparked: bodySaysReparked(body), gateBefore, gateAfter, gateKindAfter });
|
|
901
|
-
const code = bodyWordOf(body, 'errorCode');
|
|
902
|
-
if (effect === 'still_parked' && postStatus === 'needs_review' && !bodySaysReparked(body)) {
|
|
903
|
-
outcome =
|
|
904
|
-
`The plan_review ${decision} returned HTTP 200 but the session is STILL locked on the same review gate ` +
|
|
905
|
-
`(post-decide status: needs_review). The decision did NOT take effect (known engine issue, RB-471 family). ` +
|
|
906
|
-
`Tell the user plainly that the ${decision} did not go through; the reliable exits today are approving the plan or cancelling the task.`;
|
|
907
|
-
}
|
|
908
|
-
else if (effect === 'still_parked') {
|
|
909
|
-
outcome =
|
|
910
|
-
`The plan_review ${decision} was NOT applied: the engine could not continue the task and put the plan back to wait for a decision` +
|
|
911
|
-
`${code !== undefined ? ` (engine code: ${code})` : ''}. Tell the user plainly that the ${decision} did not go through.`;
|
|
912
|
-
}
|
|
913
|
-
else if (effect === 'advanced') {
|
|
914
|
-
outcome = planReviewAdvancedOutcome(decision, effective === 'needs_review' ? 'needs_review' : 'suspended');
|
|
915
|
-
}
|
|
916
|
-
else if (effect === 'took_effect') {
|
|
917
|
-
outcome =
|
|
918
|
-
`The plan was ${decision === 'approve' ? 'approved and the parked task resumed to completion' : 'rejected (plan discarded)'} — ${effective === 'completed' ? 'final status' : 'status'}: ${effective} ` +
|
|
919
|
-
`(${postStatus !== undefined ? 'post-decide re-checked: task left the review gate' : "from the decision's own reply; the post-decide re-check was unavailable"}).`;
|
|
920
|
-
}
|
|
921
|
-
else if (effective === 'needs_review' && (gateBefore === undefined || gateAfter === undefined || postStatus !== 'needs_review')) {
|
|
922
|
-
outcome =
|
|
923
|
-
`The plan_review ${decision} returned HTTP 200 and the task is waiting at a plan review gate again (post-decide status: needs_review), ` +
|
|
924
|
-
`but it could not be told whether this is the same review (the ${decision} did not take effect) or a new plan written after it (it did).`;
|
|
925
|
-
}
|
|
926
|
-
else if (effective === 'suspended' || effective === 'needs_review') {
|
|
927
|
-
outcome =
|
|
928
|
-
`The plan_review ${decision} was accepted by the engine (HTTP 200) and the task is paused again (post-decide status: ${effective}), ` +
|
|
929
|
-
`${gateKindAfter !== undefined ? `at a '${gateKindAfter}' pause that is not an approval card` : 'but the pause it stopped at was not reported'} — what the ${decision} led to could not be confirmed.`;
|
|
930
|
-
}
|
|
931
|
-
else if (effective !== undefined) {
|
|
932
|
-
outcome =
|
|
933
|
-
`The plan_review ${decision} was accepted by the engine (HTTP 200), but the task then reported status ${effective}` +
|
|
934
|
-
`${code !== undefined ? ` (engine code: ${code})` : ''} — not a completion; what the ${decision} led to could not be confirmed.`;
|
|
935
|
-
}
|
|
936
|
-
else {
|
|
937
|
-
outcome = `The plan_review ${decision} was accepted by the engine (HTTP 200) but its effect is unconfirmed — final status: unknown (post-decide verification unavailable). Do not treat this as ${decision === 'approve' ? 'an approval that resumed the task' : 'a discarded plan'}.`;
|
|
938
973
|
}
|
|
939
974
|
}
|
|
940
975
|
catch (e) {
|
|
@@ -960,7 +995,7 @@ async function decidePlanReviewInner(taskId, decision, permissionModeAfter, disp
|
|
|
960
995
|
}
|
|
961
996
|
else if (status === 409 && refusedCode === APPROVAL_STALE) {
|
|
962
997
|
let untrusted = false;
|
|
963
|
-
if (
|
|
998
|
+
if (wireGate !== undefined) {
|
|
964
999
|
const bag = readThrownExtra(e);
|
|
965
1000
|
const noCurrentPending = bag.state === 'object' &&
|
|
966
1001
|
(() => {
|
|
@@ -974,25 +1009,25 @@ async function decidePlanReviewInner(taskId, decision, permissionModeAfter, disp
|
|
|
974
1009
|
if (noCurrentPending) {
|
|
975
1010
|
try {
|
|
976
1011
|
const row = await repullRow();
|
|
977
|
-
untrusted = row !== undefined && pausedCheckpointIdOf(row?.result) ===
|
|
1012
|
+
untrusted = row !== undefined && pausedCheckpointIdOf(row?.result) === wireGate;
|
|
978
1013
|
}
|
|
979
1014
|
catch {
|
|
980
1015
|
untrusted = false;
|
|
981
1016
|
}
|
|
982
1017
|
}
|
|
983
1018
|
}
|
|
984
|
-
if (untrusted &&
|
|
985
|
-
noteEngineRefusedGate(
|
|
1019
|
+
if (untrusted && wireGate !== undefined)
|
|
1020
|
+
noteEngineRefusedGate(wireGate);
|
|
986
1021
|
hostLog('debug', `planReviewWire: approval-stale decision=${decision} reason=${untrusted ? 'gate_untrusted' : 'gate_moved'}`);
|
|
987
1022
|
effect = 'not_applied';
|
|
988
|
-
|
|
1023
|
+
cause = untrusted ? 'gate_untrusted' : 'gate_moved';
|
|
989
1024
|
outcome = renderMessage(msg('approval.planReview.decision.refused', { decision }), DATA_FACE_LANGUAGE);
|
|
990
1025
|
}
|
|
991
1026
|
else if (checkpointUnsupportedVersionFromError(e) !== null) {
|
|
992
1027
|
const cu = checkpointUnsupportedVersionFromError(e);
|
|
993
1028
|
hostLog('debug', `planReviewWire: ${decision} → 409 checkpoint.unsupported_version (the server cannot continue this parked review in its stored form; still pending)`);
|
|
994
1029
|
effect = 'still_parked';
|
|
995
|
-
|
|
1030
|
+
cause = 'stored_form_unsupported';
|
|
996
1031
|
outcome = `This ${decision} was not applied. ${checkpointUnsupportedVersionContent(cu, { parkKind: 'plan_review', runId: taskId })}`;
|
|
997
1032
|
}
|
|
998
1033
|
else if (resumeContextUnavailableFromError(e) !== null) {
|
|
@@ -1024,18 +1059,20 @@ async function decidePlanReviewInner(taskId, decision, permissionModeAfter, disp
|
|
|
1024
1059
|
else {
|
|
1025
1060
|
const failureTexts = wireFailureTextsOf(e);
|
|
1026
1061
|
hostLog('debug', `planReviewWire: ${decision} could not reach the engine: ${failureTexts.log}`);
|
|
1062
|
+
unsentProven = true;
|
|
1027
1063
|
outcome = `The plan_review decision could not reach the engine: ${failureTexts.reason}`;
|
|
1028
1064
|
}
|
|
1029
1065
|
}
|
|
1030
1066
|
}
|
|
1031
1067
|
}
|
|
1032
|
-
|
|
1033
|
-
|
|
1068
|
+
const outcomeCause = planReviewOutcomeCauseOf(effect, cause);
|
|
1069
|
+
outcome = `${outcome}${planReviewDecisionReasonSegment(outcomeCause, card)}${gateBefore !== undefined && wireGate === undefined && effect !== 'not_sent' && !unsentProven ? planReviewSentWithoutGateSegment() : ''}`;
|
|
1070
|
+
const tail = planReviewOutcomeTail(taskId, decision, effect, outcomeCause);
|
|
1034
1071
|
const prompt = `<plan-review-outcome>\n${outcome}\n${tail}\n</plan-review-outcome>`;
|
|
1035
1072
|
const onOutcome = opts?.onOutcome;
|
|
1036
1073
|
settle(effect === 'not_sent' || effect === 'still_parked');
|
|
1037
1074
|
try {
|
|
1038
|
-
const delivered = enqueuePlanReviewOutcome(prompt, { taskId, dispatchNo, decision: semanticDecision, effect, ...(
|
|
1075
|
+
const delivered = enqueuePlanReviewOutcome(prompt, { taskId, dispatchNo, decision: semanticDecision, effect, ...(outcomeCause !== undefined ? { cause: outcomeCause } : {}), ...(cardId !== undefined ? { questionId: cardId } : {}) });
|
|
1039
1076
|
if (!delivered) {
|
|
1040
1077
|
if (onOutcome !== undefined) {
|
|
1041
1078
|
hostLog('debug', `planReviewWire: outcome queue port not installed for task ${taskId} — outcome handed to the host's onOutcome callback only`);
|
|
@@ -1054,7 +1091,7 @@ async function decidePlanReviewInner(taskId, decision, permissionModeAfter, disp
|
|
|
1054
1091
|
dispatchNo,
|
|
1055
1092
|
decision: semanticDecision,
|
|
1056
1093
|
effect,
|
|
1057
|
-
...(
|
|
1094
|
+
...(outcomeCause !== undefined ? { cause: outcomeCause } : {}),
|
|
1058
1095
|
...(cardId !== undefined ? { questionId: cardId } : {}),
|
|
1059
1096
|
detail: outcome,
|
|
1060
1097
|
tail,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { SCREEN_CARD_ORIGINS } from './gateIdentity.js';
|
|
2
2
|
import { convergeEndedEngineGeneration, } from '../engineGenerationConvergence.js';
|
|
3
3
|
import { checkpointRowVerdictOf } from '../checkpointRowVerdict.js';
|
|
4
|
+
import { CHECKPOINT_INVALID_OUTCOME, CHECKPOINT_UNSUPPORTED_VERSION } from '../engineErrorCodes.js';
|
|
4
5
|
import { planReviewCardFactsFrom } from '../planReviewCardFacts.js';
|
|
5
6
|
import { slotReadOf } from '../wireFailureShape.js';
|
|
6
7
|
import { PARK_GATE_KEY } from './screenCardCarriers.js';
|
|
@@ -291,8 +292,8 @@ function deepFreeze(v) {
|
|
|
291
292
|
}
|
|
292
293
|
return v;
|
|
293
294
|
}
|
|
294
|
-
const GOLD_LACKING = { kind: 'lacking', code:
|
|
295
|
-
const GOLD_DAMAGED = { kind: 'damaged', code:
|
|
295
|
+
const GOLD_LACKING = { kind: 'lacking', code: CHECKPOINT_UNSUPPORTED_VERSION, reason: 'version_newer', sentence: 'Newer engine.' };
|
|
296
|
+
const GOLD_DAMAGED = { kind: 'damaged', code: CHECKPOINT_INVALID_OUTCOME, reason: 'requirements_damaged', sentence: 'Row damaged.' };
|
|
296
297
|
function goldenCases() {
|
|
297
298
|
const ALL = ['park-approval', 'park-question', 'plan-review', 'host-reopen-question'];
|
|
298
299
|
const ready = (name, cards, rows, pick, over = {}) => {
|
|
@@ -3,7 +3,7 @@ import { wireFailureShapeOf } from '../wireFailureShape.js';
|
|
|
3
3
|
import { hostLog } from '../host.js';
|
|
4
4
|
import { msg, renderMessage } from '../i18n/translate.js';
|
|
5
5
|
import { ruleToolNameVerdictOf } from '../protocolSegment.js';
|
|
6
|
-
import { RULES_INERT_ENTRY, RULES_INVALID_SHAPE, isRulesRefusalCode } from '../engineErrorCodes.js';
|
|
6
|
+
import { CORRUPT_ROW_ERROR_CODE, RULES_INERT_ENTRY, RULES_INVALID_SHAPE, isRulesRefusalCode } from '../engineErrorCodes.js';
|
|
7
7
|
import { deniedEntryToolName } from '../engineToolDirectory.js';
|
|
8
8
|
import { rosterMountedNames } from '../rosterMountedNames.js';
|
|
9
9
|
import { CORE_ALLOW_ENTRY_INERT_REASONS, CORE_RULE_TOOL_NAME_VERDICTS } from '../generated/engineFactTables.js';
|
|
@@ -64,7 +64,7 @@ export function classifySessionPolicyFailure(e) {
|
|
|
64
64
|
}
|
|
65
65
|
if (errorCode === 'loosen_forbidden')
|
|
66
66
|
return { kind: 'loosen-forbidden', message };
|
|
67
|
-
if (errorCode ===
|
|
67
|
+
if (errorCode === CORRUPT_ROW_ERROR_CODE)
|
|
68
68
|
return { kind: 'store-corrupt', message };
|
|
69
69
|
if (errorCode === 'conflict')
|
|
70
70
|
return { kind: 'cas-conflict', message };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type PermissionsKeptReason } from '../permissionsDeclaration.js';
|
|
2
2
|
import type { PermissionsAllowGrantReading } from '../permissionsAllowGrantCapability.js';
|
|
3
|
-
import { type LocalAllowOfferedFacts } from './localAllowRedemption.js';
|
|
3
|
+
import { type LocalAllowDeclaredFacts, type LocalAllowOfferedFacts, type LocalAllowRedeemability } from './localAllowRedemption.js';
|
|
4
4
|
export type StandingRowWhy = 'given' | 'card_unreadable' | 'remember_refused' | 'remember_unreadable' | 'route_cannot_carry' | 'classes_unreadable' | 'not_deployment_list_question' | 'evidence_unreadable' | 'offers_unreadable' | 'engine_lane_closed' | 'args_unavailable' | 'grant_binding' | 'tool_name_unreadable' | 'rule_cannot_clear' | 'host_fact_missing' | 'card_face_absent' | 'face_not_generic' | 'rule_not_sent' | 'redemption_closed' | 'redemption_unknown';
|
|
5
5
|
export type StandingPersistentRow = 'engine_offer' | 'local_whole_tool' | 'none';
|
|
6
6
|
export interface StandingRowsWhy {
|
|
@@ -17,6 +17,7 @@ export interface StandingRows {
|
|
|
17
17
|
export interface StandingRowsHostFacts {
|
|
18
18
|
readonly wholeToolRuleSent?: boolean;
|
|
19
19
|
readonly readOnlyRedemption?: LocalAllowOfferedFacts;
|
|
20
|
+
readonly wholeToolLanding?: LocalAllowDeclaredFacts;
|
|
20
21
|
}
|
|
21
22
|
export declare function standingRowsOf(card: object | null | undefined, host?: StandingRowsHostFacts | null): StandingRows;
|
|
22
23
|
export declare function seatSessionRowOf(card: object | null | undefined, requestId: string | undefined): boolean;
|
|
@@ -31,6 +32,7 @@ export declare function rememberOfferable(card: object | null | undefined, host?
|
|
|
31
32
|
export interface LocalAllowRuleEnforcement {
|
|
32
33
|
readonly enforceable: boolean;
|
|
33
34
|
readonly engine: 'sent' | 'kept' | 'unreadable';
|
|
35
|
+
readonly redemption: LocalAllowRedeemability;
|
|
34
36
|
readonly keptReason?: PermissionsKeptReason;
|
|
35
37
|
}
|
|
36
|
-
export declare function localAllowRuleEnforceable(rule: string, caps: PermissionsAllowGrantReading): LocalAllowRuleEnforcement;
|
|
38
|
+
export declare function localAllowRuleEnforceable(rule: string, caps: PermissionsAllowGrantReading, landing?: LocalAllowDeclaredFacts): LocalAllowRuleEnforcement;
|
|
@@ -6,7 +6,7 @@ import { inSlotReadOf, inValueOf } from '../wireFailureShape.js';
|
|
|
6
6
|
import { toolPermissionRequestIdDomain } from '../seatContract.js';
|
|
7
7
|
import { permissionsDeclarationReport } from '../permissionsDeclaration.js';
|
|
8
8
|
import { readCardUnreadableEvidence, sessionAllowCardReadable, sessionAllowEligible } from './sessionAllowRoute.js';
|
|
9
|
-
import { localAllowRedeemability } from './localAllowRedemption.js';
|
|
9
|
+
import { localAllowLandingRedeemability, localAllowRedeemability } from './localAllowRedemption.js';
|
|
10
10
|
const UNREADABLE = Symbol('unreadable');
|
|
11
11
|
function ownData(v, key) {
|
|
12
12
|
try {
|
|
@@ -103,6 +103,11 @@ function persistentRowOf(card, host, evidenceUnreadable) {
|
|
|
103
103
|
return { row: 'none', why: 'host_fact_missing' };
|
|
104
104
|
if (!sent)
|
|
105
105
|
return { row: 'none', why: 'rule_not_sent' };
|
|
106
|
+
const judged = localAllowLandingRedeemability(tool, ownData(host, 'wholeToolLanding'));
|
|
107
|
+
if (judged.kind === 'not_redeemable')
|
|
108
|
+
return { row: 'none', why: 'redemption_closed' };
|
|
109
|
+
if (judged.kind === 'unknown')
|
|
110
|
+
return { row: 'none', why: 'redemption_unknown' };
|
|
106
111
|
return { row: 'local_whole_tool', why: 'given' };
|
|
107
112
|
}
|
|
108
113
|
function enginePremiseOf(card) {
|
|
@@ -214,7 +219,7 @@ export function rememberOfferable(card, host) {
|
|
|
214
219
|
deploymentList: SESSION_OFFER[rows.why.deploymentList],
|
|
215
220
|
});
|
|
216
221
|
}
|
|
217
|
-
export function localAllowRuleEnforceable(rule, caps) {
|
|
222
|
+
export function localAllowRuleEnforceable(rule, caps, landing) {
|
|
218
223
|
let engine = 'unreadable';
|
|
219
224
|
let keptReason;
|
|
220
225
|
if (typeof rule === 'string' && rule.trim() !== '') {
|
|
@@ -234,9 +239,11 @@ export function localAllowRuleEnforceable(rule, caps) {
|
|
|
234
239
|
engine = 'unreadable';
|
|
235
240
|
}
|
|
236
241
|
}
|
|
242
|
+
const redemption = localAllowLandingRedeemability(rule, landing);
|
|
237
243
|
return Object.freeze({
|
|
238
|
-
enforceable: engine === 'sent',
|
|
244
|
+
enforceable: engine === 'sent' && redemption.kind === 'redeemable',
|
|
239
245
|
engine,
|
|
246
|
+
redemption,
|
|
240
247
|
...(keptReason !== undefined ? { keptReason } : {}),
|
|
241
248
|
});
|
|
242
249
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { engineVersionTier } from './supportFloor.js';
|
|
2
2
|
const HOOKS_READER_GENERATIONS = Object.freeze([
|
|
3
|
-
Object.freeze({ from: '7.139.0', below: '7.147.0', notRead: Object.freeze(['onFailure']) }),
|
|
3
|
+
Object.freeze({ from: '7.139.0', below: '7.147.0', notRead: Object.freeze(['onFailure', 'rewakeMessage', 'rewakeSummary', 'cloud', 'continueOnBlock']) }),
|
|
4
4
|
]);
|
|
5
5
|
const HOOKS_READER_FAIL_CLOSED = Object.freeze([...new Set(HOOKS_READER_GENERATIONS.flatMap((g) => g.notRead))]);
|
|
6
6
|
export function hooksReaderNotReadKeys(serverVersion) {
|