@indexnetwork/protocol 22.0.0-rc.496.1 → 22.0.0-rc.498.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.
|
@@ -195,6 +195,12 @@ export class IndexNegotiator {
|
|
|
195
195
|
// via the domain contract, exactly like `configuredScreenMode()`. Under the
|
|
196
196
|
// `advocate` default every stance fragment below is the legacy string, so
|
|
197
197
|
// the rendered prompt is byte-identical to the pre-IND-611 build.
|
|
198
|
+
//
|
|
199
|
+
// `stanceActionRules` also takes the resolved `seat`: the responder
|
|
200
|
+
// verification rules are a duty of the seat that did NOT open, so they
|
|
201
|
+
// render only there. The resolved seat, not `input.seat`, so the v1
|
|
202
|
+
// `isDiscoverer` fallback decides it there too — under v1 the discoverer
|
|
203
|
+
// is likewise the side that opens.
|
|
198
204
|
const stance = configuredNegotiatorStance();
|
|
199
205
|
const schema = turnSchemaFor(version, seat, isFinalTurn, {
|
|
200
206
|
system: SystemNegotiationTurnSchema,
|
|
@@ -206,7 +212,7 @@ export class IndexNegotiator {
|
|
|
206
212
|
const networkContext = input.indexContext.prompt || "General discovery";
|
|
207
213
|
const actionRules = (version === "v2"
|
|
208
214
|
? (seat === "initiator" ? V2_INITIATOR_RULES : V2_COUNTERPARTY_RULES)
|
|
209
|
-
: V1_ACTION_RULES) + stanceActionRules(stance)
|
|
215
|
+
: V1_ACTION_RULES) + stanceActionRules(stance, seat)
|
|
210
216
|
+ (canAskUser
|
|
211
217
|
? ASK_USER_RULE
|
|
212
218
|
+ (preContactConsult ? PRE_CONTACT_ASK_USER_RULE + stancePreContactConsultRule(stance) : "")
|
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
*
|
|
10
10
|
* `NEGOTIATOR_STANCE` makes that stance configurable instead of hard-coded:
|
|
11
11
|
*
|
|
12
|
-
* | stance | framing | value bar | query rule | consult propensity | deadlock |
|
|
13
|
-
*
|
|
14
|
-
* | `advocate` | argue the case (today) | none | mandate (today) | none (today) | bargain |
|
|
15
|
-
* | `evaluator` | assess first, advocate if it survives | opportunity-cost | necessary-not-sufficient| prefer over assumption | bargain |
|
|
16
|
-
* | `skeptic` | + "most matches are not worth making" | opportunity-cost | necessary-not-sufficient| + unverified = don't proceed | stalemate |
|
|
12
|
+
* | stance | framing | value bar | query rule | consult propensity | evidence provenance | responder check | deadlock |
|
|
13
|
+
* |-------------|--------------------------------------|------------------|-------------------------|-------------------------|--------------------------|--------------------------|-----------|
|
|
14
|
+
* | `advocate` | argue the case (today) | none | mandate (today) | none (today) | none (today) | none (today) | bargain |
|
|
15
|
+
* | `evaluator` | assess first, advocate if it survives | opportunity-cost | necessary-not-sufficient| prefer over assumption | own record ≠ client's evidence | verify the opening | bargain |
|
|
16
|
+
* | `skeptic` | + "most matches are not worth making" | opportunity-cost | necessary-not-sufficient| + unverified = don't proceed | (same — no sharpening) | + probe before accepting | stalemate |
|
|
17
17
|
*
|
|
18
18
|
* Design constraints (hard):
|
|
19
19
|
* - **`advocate` is byte-identical.** Every fragment below is additive and
|
|
@@ -35,7 +35,22 @@
|
|
|
35
35
|
* Fragments deliberately never contain the literal `ask_user` or a quoted
|
|
36
36
|
* `"withdraw"`: they render into every seat and protocol version, and the seat
|
|
37
37
|
* specs pin that those tokens appear only where the seat legally holds them.
|
|
38
|
+
*
|
|
39
|
+
* One family of fragments is the exception to that seat-blindness by
|
|
40
|
+
* construction rather than by accident: the responder verification rules
|
|
41
|
+
* (`stanceVerifiesResponderFit`) address a duty only the RESPONDING seat has —
|
|
42
|
+
* reading someone else's opening — so `stanceActionRules` takes the seat and
|
|
43
|
+
* renders them only there. They still name no action and no mechanism, so the
|
|
44
|
+
* seat's own rules and the graph's grants stay the sole authority on what this
|
|
45
|
+
* turn may actually do.
|
|
46
|
+
*
|
|
47
|
+
* The seat parameter is a scoping tool, not a licence to fork: a duty both
|
|
48
|
+
* seats hold stays in the shared prefix even when the failure that motivated it
|
|
49
|
+
* showed up on one seat. `EVIDENCE_PROVENANCE_RULE` is the case in point — it
|
|
50
|
+
* was written for a responder accept, and it renders seat-blind, because an
|
|
51
|
+
* initiator can cite its own prior openings' claims exactly as readily.
|
|
38
52
|
*/
|
|
53
|
+
import type { NegotiationSeat } from "../shared/schemas/negotiation-state.schema.js";
|
|
39
54
|
export declare const NEGOTIATOR_STANCES: readonly ["advocate", "evaluator", "skeptic"];
|
|
40
55
|
export type NegotiatorStance = (typeof NEGOTIATOR_STANCES)[number];
|
|
41
56
|
export declare const DEFAULT_NEGOTIATOR_STANCE: NegotiatorStance;
|
|
@@ -55,6 +70,11 @@ export declare function stanceAppliesValueBar(stance: NegotiatorStance): boolean
|
|
|
55
70
|
* continuing to evaluate rather than as a mandate to connect.
|
|
56
71
|
*/
|
|
57
72
|
export declare function stanceQueryMatchIsNecessaryNotSufficient(stance: NegotiatorStance): boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Whether this stance asks the RESPONDING seat to verify the opening's account
|
|
75
|
+
* of the fit before accepting it, rather than reading that account as evidence.
|
|
76
|
+
*/
|
|
77
|
+
export declare function stanceVerifiesResponderFit(stance: NegotiatorStance): boolean;
|
|
58
78
|
/** Whether a detected deadlock resolves by stalemate rather than bargaining. */
|
|
59
79
|
export declare function stanceResolvesDeadlockByStalemate(stance: NegotiatorStance): boolean;
|
|
60
80
|
/**
|
|
@@ -68,8 +88,19 @@ export declare function stanceJobFraming(stance: NegotiatorStance): string;
|
|
|
68
88
|
/**
|
|
69
89
|
* Extra action-rule lines contributed by the stance, appended after the seat's
|
|
70
90
|
* own rules. Empty under `advocate` → byte-identical.
|
|
91
|
+
*
|
|
92
|
+
* `seat` scopes the responder verification rules to the seat that did NOT
|
|
93
|
+
* open. Everything else here is seat-blind: the value bar, the consult
|
|
94
|
+
* propensity and the evidence-provenance rule are duties of both seats, and
|
|
95
|
+
* the seat parameter must not become a reason to fork them.
|
|
96
|
+
*
|
|
97
|
+
* Order matters twice over. The seat-blind rules come first, so the initiator's
|
|
98
|
+
* rendering stays a strict PREFIX of the responder's — the invariant the stance
|
|
99
|
+
* spec checks by subtraction. And provenance lands immediately before the
|
|
100
|
+
* responder rules, so "ground the accept in what {userName} themselves stated"
|
|
101
|
+
* is already qualified by whose statements count when the responder reads it.
|
|
71
102
|
*/
|
|
72
|
-
export declare function stanceActionRules(stance: NegotiatorStance): string;
|
|
103
|
+
export declare function stanceActionRules(stance: NegotiatorStance, seat: NegotiationSeat): string;
|
|
73
104
|
/**
|
|
74
105
|
* Stance contribution to the pre-contact consultation rule. Empty under
|
|
75
106
|
* `advocate` and `evaluator` — the base seat-level rule already states when
|
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
*
|
|
10
10
|
* `NEGOTIATOR_STANCE` makes that stance configurable instead of hard-coded:
|
|
11
11
|
*
|
|
12
|
-
* | stance | framing | value bar | query rule | consult propensity | deadlock |
|
|
13
|
-
*
|
|
14
|
-
* | `advocate` | argue the case (today) | none | mandate (today) | none (today) | bargain |
|
|
15
|
-
* | `evaluator` | assess first, advocate if it survives | opportunity-cost | necessary-not-sufficient| prefer over assumption | bargain |
|
|
16
|
-
* | `skeptic` | + "most matches are not worth making" | opportunity-cost | necessary-not-sufficient| + unverified = don't proceed | stalemate |
|
|
12
|
+
* | stance | framing | value bar | query rule | consult propensity | evidence provenance | responder check | deadlock |
|
|
13
|
+
* |-------------|--------------------------------------|------------------|-------------------------|-------------------------|--------------------------|--------------------------|-----------|
|
|
14
|
+
* | `advocate` | argue the case (today) | none | mandate (today) | none (today) | none (today) | none (today) | bargain |
|
|
15
|
+
* | `evaluator` | assess first, advocate if it survives | opportunity-cost | necessary-not-sufficient| prefer over assumption | own record ≠ client's evidence | verify the opening | bargain |
|
|
16
|
+
* | `skeptic` | + "most matches are not worth making" | opportunity-cost | necessary-not-sufficient| + unverified = don't proceed | (same — no sharpening) | + probe before accepting | stalemate |
|
|
17
17
|
*
|
|
18
18
|
* Design constraints (hard):
|
|
19
19
|
* - **`advocate` is byte-identical.** Every fragment below is additive and
|
|
@@ -35,6 +35,20 @@
|
|
|
35
35
|
* Fragments deliberately never contain the literal `ask_user` or a quoted
|
|
36
36
|
* `"withdraw"`: they render into every seat and protocol version, and the seat
|
|
37
37
|
* specs pin that those tokens appear only where the seat legally holds them.
|
|
38
|
+
*
|
|
39
|
+
* One family of fragments is the exception to that seat-blindness by
|
|
40
|
+
* construction rather than by accident: the responder verification rules
|
|
41
|
+
* (`stanceVerifiesResponderFit`) address a duty only the RESPONDING seat has —
|
|
42
|
+
* reading someone else's opening — so `stanceActionRules` takes the seat and
|
|
43
|
+
* renders them only there. They still name no action and no mechanism, so the
|
|
44
|
+
* seat's own rules and the graph's grants stay the sole authority on what this
|
|
45
|
+
* turn may actually do.
|
|
46
|
+
*
|
|
47
|
+
* The seat parameter is a scoping tool, not a licence to fork: a duty both
|
|
48
|
+
* seats hold stays in the shared prefix even when the failure that motivated it
|
|
49
|
+
* showed up on one seat. `EVIDENCE_PROVENANCE_RULE` is the case in point — it
|
|
50
|
+
* was written for a responder accept, and it renders seat-blind, because an
|
|
51
|
+
* initiator can cite its own prior openings' claims exactly as readily.
|
|
38
52
|
*/
|
|
39
53
|
export const NEGOTIATOR_STANCES = ["advocate", "evaluator", "skeptic"];
|
|
40
54
|
export const DEFAULT_NEGOTIATOR_STANCE = "advocate";
|
|
@@ -63,6 +77,13 @@ export function stanceAppliesValueBar(stance) {
|
|
|
63
77
|
export function stanceQueryMatchIsNecessaryNotSufficient(stance) {
|
|
64
78
|
return stance !== "advocate";
|
|
65
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Whether this stance asks the RESPONDING seat to verify the opening's account
|
|
82
|
+
* of the fit before accepting it, rather than reading that account as evidence.
|
|
83
|
+
*/
|
|
84
|
+
export function stanceVerifiesResponderFit(stance) {
|
|
85
|
+
return stance !== "advocate";
|
|
86
|
+
}
|
|
66
87
|
/** Whether a detected deadlock resolves by stalemate rather than bargaining. */
|
|
67
88
|
export function stanceResolvesDeadlockByStalemate(stance) {
|
|
68
89
|
return stance === "skeptic";
|
|
@@ -141,17 +162,115 @@ const CONSULT_PROPENSITY_RULE = `
|
|
|
141
162
|
* reason not to proceed, and consulting the client is how it gets verified.
|
|
142
163
|
*/
|
|
143
164
|
const SKEPTIC_CONSULT_SHARPENING = ` For you this is a gate, not a preference: an UNVERIFIED assumption that the two sides' intents actually align is a reason NOT to proceed, and consulting {userName} is how that assumption gets verified.`;
|
|
165
|
+
/**
|
|
166
|
+
* Evidence provenance — assessing stances, BOTH seats.
|
|
167
|
+
*
|
|
168
|
+
* The third sibling of the consult-propensity and responder-verification
|
|
169
|
+
* fragments, and written for the way the second one was formally obeyed and
|
|
170
|
+
* substantively evaded. A responder accepted a first contact grounded — as the
|
|
171
|
+
* responder rule demands — in its OWN side's record rather than in the
|
|
172
|
+
* opening's characterization. But the record it reached for was its own prior
|
|
173
|
+
* conclusions, surfaced through memory and prior dialogue: "{userName}'s
|
|
174
|
+
* previous acceptances ... reinforce this strong alignment", from acceptances
|
|
175
|
+
* this same negotiator had made under a weaker bar. Circular verification —
|
|
176
|
+
* I accepted before, therefore accepting is grounded.
|
|
177
|
+
*
|
|
178
|
+
* So the rule the verification duty was missing: an agent's own output is not
|
|
179
|
+
* its client's evidence. Verification grounds in what a PERSON authored — never
|
|
180
|
+
* in what an agent concluded about them, on either side of the table. The
|
|
181
|
+
* fragment names exactly the client-authored sections this prompt actually
|
|
182
|
+
* renders (intents, profile, and the client's own answers between sessions),
|
|
183
|
+
* so the ground it points at is one the negotiator can see.
|
|
184
|
+
*
|
|
185
|
+
* Two boundaries it deliberately does not cross:
|
|
186
|
+
* - **It does not ban memory.** Memory keeps the job it has (advisory notes on
|
|
187
|
+
* how to argue, what has been asked, what each side said); what changes is
|
|
188
|
+
* only what may count as verification. A fragment that told the negotiator to
|
|
189
|
+
* ignore its memory would fight `renderNegotiatorMemorySection` rather than
|
|
190
|
+
* complete it.
|
|
191
|
+
* - **It does not forbid resolving a repeat signal quickly.** The continuation
|
|
192
|
+
* policy in `negotiation.agent.ts` ("materially the same as one you
|
|
193
|
+
* previously evaluated ... you may resolve quickly") governs how much EFFORT
|
|
194
|
+
* a re-run deserves; this governs what counts as GROUNDS. The nearest
|
|
195
|
+
* existing neighbor is the IND-569 attribution policy — "do not treat their
|
|
196
|
+
* conclusions as decisions about this opportunity" — which scopes conclusions
|
|
197
|
+
* across opportunities; this scopes them across the decision/evidence line.
|
|
198
|
+
*
|
|
199
|
+
* No `skeptic` sharpening: the prior that most matches are not worth making
|
|
200
|
+
* does not change what an unverified assertion is worth. It is worth nothing
|
|
201
|
+
* under either assessing stance, and a sharpening here would only restate the
|
|
202
|
+
* rule louder.
|
|
203
|
+
*
|
|
204
|
+
* Names no action and no mechanism, like every other fragment in this module.
|
|
205
|
+
*/
|
|
206
|
+
const EVIDENCE_PROVENANCE_RULE = `
|
|
207
|
+
- YOUR OWN RECORD IS DECISIONS, NOT EVIDENCE: your earlier turns, the connections you proposed or accepted on {userName}'s behalf, and the conclusions you carry in memory are YOUR record — decisions you made for them, reached under whatever bar you applied at the time. Leaning on one ("they have been open to this before", "the fit was already established") re-asserts a judgment instead of checking it, and reads your own past eagerness back as {userName}'s interest. Ground the fit in what a person stated for themselves: {userName}'s own intents, profile, and the answers they gave you directly on your side; the counterparty's own intents and profile on theirs. Prior dialogue and memory keep their job — what has already been asked, what each side actually said, how to pitch this one — but they are the history of the argument, not grounds for it. A fit that was not verified does not become verified by having been asserted before.`;
|
|
208
|
+
/**
|
|
209
|
+
* Responder verification — assessing stances, RESPONDING seat only.
|
|
210
|
+
*
|
|
211
|
+
* Two structural gaps this closes, both visible in the failure it was written
|
|
212
|
+
* for: a first-contact outreach accepted in one exchange, on reasoning that
|
|
213
|
+
* restated the opening's own fit claim back as the reason for accepting.
|
|
214
|
+
*
|
|
215
|
+
* 1. The opening enters the prompt as if it were evidence. It is not: it is
|
|
216
|
+
* advocacy authored by the counterparty's agent, and its most load-bearing
|
|
217
|
+
* move is characterizing what THIS client wants. Nothing else in the prompt
|
|
218
|
+
* tells the responding seat to treat that characterization as a claim.
|
|
219
|
+
* 2. `VALUE_BAR_RULE` has no bite in this seat. "Most matches are not worth
|
|
220
|
+
* making" reads as being about MAKING matches, and a responder frames its
|
|
221
|
+
* decision as "would my client be open to connecting?" — nearly costless,
|
|
222
|
+
* nearly certain to be yes. So the same opportunity-cost currency is
|
|
223
|
+
* restated in the terms this seat actually spends it: accepting puts a
|
|
224
|
+
* connection in front of the client for approval.
|
|
225
|
+
*
|
|
226
|
+
* Conditional by construction: the steer applies where the fit case RESTS on
|
|
227
|
+
* the initiator's interpretation. A match the client's own criteria and the
|
|
228
|
+
* counterparty's own evidence support independently may still be accepted on
|
|
229
|
+
* first contact — which is why no "always"/"never accept" wording appears here
|
|
230
|
+
* and a spec pins its absence.
|
|
231
|
+
*
|
|
232
|
+
* Names no action and no mechanism, like every other fragment in this module:
|
|
233
|
+
* "one more exchange" and "consulting {userName}" describe the move, and the
|
|
234
|
+
* seat's own rules decide which token carries it (and whether the grant for it
|
|
235
|
+
* is even live this turn).
|
|
236
|
+
*/
|
|
237
|
+
const RESPONDER_VERIFICATION_RULE = `
|
|
238
|
+
- THE OPENING IS ADVOCACY, NOT EVIDENCE: what reached {userName} was written by the other side's agent to make this match sound worth taking, and its account of the fit — what {userName} is looking for, why the two sides line up — is that agent's CLAIM about {userName}, not a fact you have checked. Test it against {userName}'s OWN intent and against what the counterparty's own profile and intents actually show. Restating the opening's fit claim back as your reason is agreement, not verification.
|
|
239
|
+
- WHAT ACCEPTING SPENDS: accepting is not the free or agreeable option — it puts a connection in front of {userName} for approval and spends the same finite attention the bar above governs. "Would {userName} be open to connecting?" is a bar almost anything clears, and it is not the bar. An accept on the first exchange has to be grounded in what {userName} themselves stated they were looking for, met by evidence about the counterparty that stands up without the opening's reading of it. Where the case for fit still rests on how the other agent characterized {userName}'s needs, the cheap move is one more exchange — put the specific gap to them, or counter with what would have to be true — and where the doubt is about {userName}'s own criteria rather than the counterparty's evidence, consulting {userName} settles it instead.`;
|
|
240
|
+
/**
|
|
241
|
+
* `skeptic` sharpening of the responder rule, appended to the same bullet (the
|
|
242
|
+
* same additive pattern as `SKEPTIC_CONSULT_SHARPENING`): under the
|
|
243
|
+
* not-worth-making prior, closing on the opening alone is the exception rather
|
|
244
|
+
* than the default. The escape hatch is restated explicitly here because this
|
|
245
|
+
* is where the pressure is highest and an over-read would turn a lean into a
|
|
246
|
+
* ban on first-contact accepts.
|
|
247
|
+
*/
|
|
248
|
+
const SKEPTIC_RESPONDER_SHARPENING = ` For you an accept on the first exchange is the exception, not the default: where the fit case still rests on the opening's own characterization, probe once before accepting — one exchange costs the counterparty nothing and {userName} very little, while an accept you cannot ground spends their attention on a match no one has checked. Where {userName}'s stated criteria and the counterparty's own evidence carry the fit without that characterization, accepting straight away is still the right call.`;
|
|
144
249
|
/**
|
|
145
250
|
* Extra action-rule lines contributed by the stance, appended after the seat's
|
|
146
251
|
* own rules. Empty under `advocate` → byte-identical.
|
|
252
|
+
*
|
|
253
|
+
* `seat` scopes the responder verification rules to the seat that did NOT
|
|
254
|
+
* open. Everything else here is seat-blind: the value bar, the consult
|
|
255
|
+
* propensity and the evidence-provenance rule are duties of both seats, and
|
|
256
|
+
* the seat parameter must not become a reason to fork them.
|
|
257
|
+
*
|
|
258
|
+
* Order matters twice over. The seat-blind rules come first, so the initiator's
|
|
259
|
+
* rendering stays a strict PREFIX of the responder's — the invariant the stance
|
|
260
|
+
* spec checks by subtraction. And provenance lands immediately before the
|
|
261
|
+
* responder rules, so "ground the accept in what {userName} themselves stated"
|
|
262
|
+
* is already qualified by whose statements count when the responder reads it.
|
|
147
263
|
*/
|
|
148
|
-
export function stanceActionRules(stance) {
|
|
264
|
+
export function stanceActionRules(stance, seat) {
|
|
149
265
|
if (!stanceAppliesValueBar(stance))
|
|
150
266
|
return "";
|
|
151
267
|
const consultRule = stance === "skeptic"
|
|
152
268
|
? CONSULT_PROPENSITY_RULE + SKEPTIC_CONSULT_SHARPENING
|
|
153
269
|
: CONSULT_PROPENSITY_RULE;
|
|
154
|
-
|
|
270
|
+
const responderRule = seat === "counterparty" && stanceVerifiesResponderFit(stance)
|
|
271
|
+
? RESPONDER_VERIFICATION_RULE + (stance === "skeptic" ? SKEPTIC_RESPONDER_SHARPENING : "")
|
|
272
|
+
: "";
|
|
273
|
+
return VALUE_BAR_RULE + consultRule + EVIDENCE_PROVENANCE_RULE + responderRule;
|
|
155
274
|
}
|
|
156
275
|
/**
|
|
157
276
|
* `skeptic` sharpening of the pre-contact consultation rule (the turn-0 third
|