Repository navigation
Expand file tree
/
Copy pathwait-endpoint-bound.go.txt
More file actions
654 lines (637 loc) · 26.1 KB
/
Copy pathwait-endpoint-bound.go.txt
File metadata and controls
654 lines (637 loc) · 26.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
package production
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"reflect"
"sort"
"testing"
"time"
"cloud-clicker/server/decimal"
"cloud-clicker/server/economy"
"cloud-clicker/server/faction"
"cloud-clicker/server/guild"
"cloud-clicker/server/multiplier"
"cloud-clicker/server/prestige"
"cloud-clicker/server/save"
)
type endpointRegimeResearch struct{ lo, hi int64 }
type endpointBoundAnswerResearch struct {
at, last int64
points, nodes, regimes, fallbackPoints int
preparationRestores, preparationClears, preparationSchedules, preparationAssemblies int
preparationZeroPoints int
preparationZeroError string
guardRanges, guardAssemblies, guardCatalogs, guardReceiptTerms, guardSpanChecks, guardStockProbes int
factories []waitCellWorkResearch
selected endpointProjectionResearch
elapsed time.Duration
}
func logEndpointBoundResearch(t *testing.T, label string, exactPoints int, answer endpointBoundAnswerResearch) {
t.Helper()
models := len(answer.factories)
var aggregate waitCellWorkResearch
total := reflect.ValueOf(&aggregate).Elem()
for _, work := range answer.factories {
value := reflect.ValueOf(work)
for i := 0; i < value.NumField(); i++ {
total.Field(i).SetInt(total.Field(i).Int() + value.Field(i).Int())
}
}
answer.selected = endpointProjectionResearch{} // No raw states/payloads/opaque addresses in work logs.
answer.factories = nil
if models > 0 {
answer.factories = []waitCellWorkResearch{aggregate}
}
t.Logf("%s reference-points%d models%d work %+v", label, exactPoints, models, answer)
}
// Existing producer bounds remain origin-relative. These are endpoint-context
// boundaries, not settlements, renewed offline allowances or new save origins.
func endpointRegimesResearch(ctx *endpointContextResearch, original *save.State, horizon int64) ([]endpointRegimeResearch, int64, bool, error) {
base, err := prestige.AttendedMS(original, original.EvaluatedThrough)
if err != nil {
return nil, 0, false, err
}
runMS := original.EvaluatedThrough.Sub(original.RunStartedAt).Milliseconds()
limit := time.Duration(1<<63 - 1).Milliseconds()
shape := !original.RunStartedAt.IsZero() && runMS >= 0 && runMS <= limit-horizon
if !shape {
return []endpointRegimeResearch{{1, horizon}}, base, false, nil
}
starts := []int64{1, horizon + 1}
add := func(value int64) {
if value > 1 && value <= horizon {
starts = append(starts, value)
}
}
ceiling := ctx.bundle.Prestige.CatchupCeilingMS
for _, buff := range original.ActiveBuffs {
offset := buff.ExpiresAttendedMS - base
if offset <= ceiling {
add(offset)
}
}
add(ceiling + 1)
if ctx.mode == ModeOnline {
add(ctx.bundle.Economy.OfflinePolicy().AccrualCapMS + 1)
}
sort.Slice(starts, func(i, j int) bool { return starts[i] < starts[j] })
unique := starts[:0]
for _, value := range starts {
if len(unique) == 0 || unique[len(unique)-1] != value {
unique = append(unique, value)
}
}
regimes := []endpointRegimeResearch{}
for i := 0; i+1 < len(unique); i++ {
regimes = append(regimes, endpointRegimeResearch{unique[i], unique[i+1] - 1})
}
return regimes, base, true, nil
}
func endpointNoDueResearch(ctx *endpointContextResearch, original *save.State, base, lo, hi int64) bool {
maxAttended := base
ceiling := ctx.bundle.Prestige.CatchupCeilingMS
if lo <= ceiling {
end := hi
if end > ceiling {
end = ceiling
}
maxAttended += end
}
if original.PendingOpportunity != nil {
return original.PendingOpportunity.ExpiresAttendedMS > maxAttended
}
return original.NextOpportunityAttendedMS == 0 || original.NextOpportunityAttendedMS > maxAttended
}
// Scheduling proof is deliberately sufficient: no due transition in the range.
// Unknown/due schedules execute actual chronological leaves, never fake errors.
type endpointRangeGuardResearch struct {
*closedWaitDomainResearch
ctx *endpointContextResearch
original *save.State
base int64
}
func (guard endpointRangeGuardResearch) certify(lo, hi int64) (bool, error) {
if !endpointNoDueResearch(guard.ctx, guard.original, guard.base, lo, hi) {
return false, nil
}
return guard.closedWaitDomainResearch.certify(lo, hi)
}
func (owner *endpointOwnerResearch) queryBound(horizon int64, price decimal.Decimal, budget int) (answer endpointBoundAnswerResearch, resultErr error) {
return owner.queryBoundFrom(0, horizon, price, budget)
}
func (owner *endpointOwnerResearch) queryBoundFrom(from, horizon int64, price decimal.Decimal, budget int) (answer endpointBoundAnswerResearch, resultErr error) {
started := time.Now()
defer func() { answer.elapsed = time.Since(started) }()
answer.at, answer.last = -1, -1
if from < 0 || from > horizon || horizon < 0 || horizon > 86_460_000 || !price.IsStateValue() || price.Lt(decimal.Zero) {
return answer, fmt.Errorf("invalid endpoint bound query")
}
ctx := owner.context
var last endpointProjectionResearch
var actualErr error
point := func(at int64) (decimal.Decimal, error) {
answer.points++
answer.last = at
var err error
last, err = owner.project(at)
if err != nil {
actualErr = err
return decimal.NaN, err
}
cash, exists := last.state.Ledger.Balance("company.cash")
if !exists {
actualErr = ErrInvalidEngineState
return decimal.NaN, actualErr
}
return cash, nil
}
actual := func(at int64) (bool, error) {
if answer.nodes >= budget {
return false, fmt.Errorf("endpoint bound node budget exhausted")
}
answer.nodes++
cash, err := point(at)
if err != nil {
return false, err
}
if cash.Gte(price) {
answer.at, answer.selected = at, last
return true, nil
}
return false, nil
}
if found, err := actual(from); err != nil || found {
return answer, err
}
if horizon == from {
return answer, nil
}
zero := last
fallback := func() (endpointBoundAnswerResearch, error) {
for at := from + 1; at <= horizon; at++ {
answer.fallbackPoints++
if found, err := actual(at); err != nil || found {
return answer, err
}
}
return answer, nil
}
if from > 0 {
if answer.nodes >= budget {
return answer, fmt.Errorf("endpoint bound node budget exhausted")
}
answer.nodes++
answer.preparationZeroPoints++
var err error
zero, err = owner.project(0)
if err != nil {
answer.preparationZeroError = err.Error()
return fallback() // A prep-only error is not an error in [from,horizon].
}
}
answer.preparationRestores++
originalSource, err := save.RestoreState(ctx.origin, 19, ctx.bundle.Economy, economy.ScopeCompany, time.Time{})
if err != nil {
return answer, err
}
// Zero-time clearing/scheduling is a validated deterministic prefix. It
// changes no production cursor, balance or allowance. Use its schedule
// state for the no-FURTHER-due proof, not as a new calculation origin.
original := zero.state
if len(zero.stages) != 1 || zero.stages[0].kind != "ordinary" || zero.stages[0].evaluation.ElapsedMS != 0 ||
!original.EvaluatedThrough.Equal(originalSource.EvaluatedThrough) ||
!reflect.DeepEqual(original.Ledger.Snapshot(), originalSource.Ledger.Snapshot()) ||
original.ComputeCreditMS != originalSource.ComputeCreditMS || original.ComputeBurstRemainingMS != originalSource.ComputeBurstRemainingMS {
if from == 0 {
return answer, fmt.Errorf("endpoint zero prefix is not a non-producing schedule prefix")
}
answer.preparationZeroError = "zero prefix is not a non-producing schedule prefix"
return fallback()
}
regimes, base, shape, err := endpointRegimesResearch(ctx, original, horizon)
if err != nil {
return answer, err
}
for _, regime := range regimes {
if regime.lo <= from {
regime.lo = from + 1
}
if regime.lo > regime.hi {
continue
}
answer.regimes++
// At an unknown source clock or an already-due schedule, don't build
// an invalid fixed-context stand-in. Preserve the real projector.
if !shape || !endpointNoDueResearch(ctx, original, base, regime.lo, regime.lo) {
for at := regime.lo; at <= regime.hi; at++ {
answer.fallbackPoints++
if found, err := actual(at); err != nil || found {
return answer, err
}
}
continue
}
answer.preparationRestores++
source, err := save.RestoreState(ctx.origin, 19, ctx.bundle.Economy, economy.ScopeCompany, time.Time{})
if err != nil {
return answer, err
}
answer.preparationClears++
if err := guild.ApplySettlements(source, ctx.batch, ctx.bundle.Faction.StockCap); err != nil {
return answer, err
}
modelMode := ctx.mode
modelExternal := append([]multiplier.Contribution(nil), ctx.external...)
catchup := ctx.mode == ModeOnline && regime.lo > ctx.bundle.Economy.OfflinePolicy().AccrualCapMS
// Separate schedule scratch: catchup's producer must see BASE context,
// whereas ordinary endpoint assembly sees expired/retained buffs.
answer.preparationRestores++
scheduled, err := save.RestoreState(ctx.origin, 19, ctx.bundle.Economy, economy.ScopeCompany, time.Time{})
if err != nil {
return answer, err
}
answer.preparationClears++
if err := guild.ApplySettlements(scheduled, ctx.batch, ctx.bundle.Faction.StockCap); err != nil {
return answer, err
}
now := scheduled.EvaluatedThrough.Add(time.Duration(regime.lo) * time.Millisecond)
answer.preparationSchedules++
active, err := resolveActivePlaySchedule(scheduled, ctx.bundle.Opportunities, ctx.bundle.Prestige, ctx.revision.OwnerID, now)
if err == nil {
_, err = applyActivePlaySchedule(scheduled, ctx.bundle.Opportunities, ctx.bundle.Prestige, ctx.revision.OwnerID, now, active)
}
if err != nil {
if found, realErr := actual(regime.lo); realErr != nil || found {
return answer, realErr
}
return answer, fmt.Errorf("endpoint schedule preparation disagrees with actual success: %w", err)
}
activeRows, err := activePlayContributions(scheduled, ctx.bundle.Opportunities, active.AttendedNowMS)
if err != nil {
if found, realErr := actual(regime.lo); realErr != nil || found {
return answer, realErr
}
return answer, fmt.Errorf("endpoint context preparation disagrees: %w", err)
}
endpointInputs := append(append([]multiplier.Contribution(nil), ctx.external...), activeRows...)
policy, err := simulationPolicyFor(ctx.bundle.Economy, ctx.mask)
if err != nil {
return answer, err
}
answer.preparationAssemblies++
if _, err := assembleContributionsWithPolicy(scheduled, ctx.bundle.Economy, endpointInputs, policy); err != nil {
if found, realErr := actual(regime.lo); realErr != nil || found {
return answer, realErr
}
return answer, fmt.Errorf("endpoint assembly preparation disagrees: %w", err)
}
if catchup {
modelMode = ModeOffline
} else {
source = scheduled
modelExternal = endpointInputs
}
encoded, err := save.EncodeState(source)
if err != nil {
return answer, fmt.Errorf("endpoint proof source encoding: %w", err)
}
proofOwner := &closedWaitReferenceResearch{bundle: ctx.bundle, origin: encoded, mode: modelMode, mask: ctx.mask, external: modelExternal, weight: ctx.weight, revision: ctx.revision}
guard := endpointRangeGuardResearch{&closedWaitDomainResearch{owner: proofOwner, initial: source}, ctx, original, base}
remaining := budget - answer.nodes
if remaining <= 0 {
return answer, fmt.Errorf("endpoint bound node budget exhausted")
}
found, factory, queryErr := queryWaitContextResearch(source, ctx.bundle.Economy, modelMode, regime.hi, ctx.mask, SimulationDependencies{Routes: ctx.bundle.Routes}, price, remaining, point,
waitSourceContextResearch{modern: true, external: modelExternal, preHookEncoding: true, fromMS: regime.lo}, guard)
if factory != nil {
answer.nodes += factory.work.QueryNodes
answer.factories = append(answer.factories, factory.work)
}
answer.guardRanges += guard.ranges
answer.guardAssemblies += guard.assemblies
answer.guardCatalogs += guard.catalogLoads
answer.guardReceiptTerms += guard.receiptTerms
answer.guardSpanChecks += guard.spanChecks
if guard.stock != nil {
answer.guardStockProbes += guard.stock.probes
}
answer.preparationRestores += proofOwner.restores
if queryErr != nil {
if actualErr != nil {
return answer, actualErr
}
return answer, fmt.Errorf("endpoint bound instrument: %w", queryErr)
}
if found >= 0 {
answer.at, answer.selected = found, last
return answer, nil
}
}
return answer, nil
}
func TestWaitEndpointBoundResearch(t *testing.T) {
queries, late, pruned, cutoffWindows := 0, 0, 0, 0
referencePoints, boundPoints := 0, 0
for _, profile := range []string{"none", "combined"} {
for _, mode := range []EvaluationMode{ModeOnline, ModeOffline} {
for _, masked := range []bool{false, true} {
t.Run(fmt.Sprintf("%s/%s/masked%t", profile, mode, masked), func(t *testing.T) {
fixture := loadEndpointFixtureResearch(t, profile, mode)
mask := AblationMask{}
if masked {
mask.GeneratorIDs = []string{"generator.beige_tower"}
}
owner, err := newEndpointOwnerResearch(t, fixture.bundle, fixture.state, fixture.revision, mode, mask, fixture.external, fixture.weight, fixture.batch)
if err != nil {
t.Fatal(err)
}
before := mustEncodeState(t, fixture.state)
zero, err := owner.project(0)
if err != nil {
t.Fatal(err)
}
regimes, _, shape, err := endpointRegimesResearch(owner.context, zero.state, 6001)
starts := []int64{}
for _, regime := range regimes {
starts = append(starts, regime.lo)
}
wantStarts := []int64{1}
if profile == "combined" {
wantStarts = append(wantStarts, 1000, 1500)
}
if mode == ModeOnline {
wantStarts = append(wantStarts, 1501)
}
wantStarts = append(wantStarts, 5001)
if err != nil || !shape || !reflect.DeepEqual(starts, wantStarts) {
t.Fatal("actual semantic endpoint partition changed", starts, wantStarts, err)
}
a, err := referenceEndpointResearch(t, fixture, 500, mode, mask)
if err != nil {
t.Fatal(err)
}
b, err := referenceEndpointResearch(t, fixture, 1000, mode, mask)
if err != nil {
t.Fatal(err)
}
cash, _ := fixture.state.Ledger.Balance("company.cash")
early, _ := a.state.Ledger.Balance("company.cash")
later, _ := b.state.Ledger.Balance("company.cash")
prices := []decimal.Decimal{cash, early, later, decimal.New(1, 6)}
for _, price := range prices {
reference, err := owner.queryReference(2001, price, 2002)
if err != nil {
t.Fatal(err)
}
answer, err := owner.queryBound(2001, price, 2*2002)
if err != nil || answer.at != reference.at {
t.Fatal("bounded query loses earliest complete result", answer.at, reference.at, err)
}
if answer.at >= 0 {
if answer.selected.context != owner.context || !equalEndpointResearch(t, answer.selected, reference.selected) {
t.Fatal("bounded selected state/stages/events/roles mismatch")
}
} else if answer.selected.state != nil {
t.Fatal("unreachable returned success state")
}
if answer.points < reference.points {
pruned++
}
referencePoints += reference.points
boundPoints += answer.points
queries++
logEndpointBoundResearch(t, "short", reference.points, answer)
}
if (profile == "none" && mode == ModeOnline) || (profile == "combined" && mode == ModeOffline) {
reference, err := owner.queryReference(6001, decimal.New(1, 6), 6002)
if err != nil {
t.Fatal(err)
}
answer, err := owner.queryBound(6001, decimal.New(1, 6), 2*6002)
if err != nil || answer.at != reference.at || answer.at != -1 || answer.points >= reference.points {
t.Fatal("late catchup/absence query mismatch", answer.at, reference.at, answer.points, err)
}
late++
referencePoints += reference.points
boundPoints += answer.points
logEndpointBoundResearch(t, "late", reference.points, answer)
}
if profile == "combined" && mode == ModeOffline && !masked {
cutoff, err := referenceEndpointResearch(t, fixture, 5001, mode, mask)
if err != nil {
t.Fatal(err)
}
price, _ := cutoff.state.Ledger.Balance("company.cash")
reference, err := owner.queryReference(6001, price, 6002)
if err != nil || reference.at != 5001 {
t.Fatal("absence-restored affordable window does not discriminate", reference.at, err)
}
answer, err := owner.queryBound(6001, price, 2*6002)
if err != nil || answer.at != 5001 || !equalEndpointResearch(t, answer.selected, reference.selected) {
t.Fatal("bound lost selected result after attendance cutoff", answer.at, err)
}
referencePoints += reference.points
boundPoints += answer.points
cutoffWindows++
logEndpointBoundResearch(t, "cutoff-window", reference.points, answer)
}
answer, err := owner.queryBound(2001, decimal.New(1, 6), 1)
if err == nil || answer.at != -1 || answer.selected.state != nil {
t.Fatal("bound exhaustion disguised as unreachable/success")
}
if !bytes.Equal(before, mustEncodeState(t, fixture.state)) {
t.Fatal("bound preparation changed origin")
}
})
}
}
}
if queries != 32 || late != 4 || cutoffWindows != 1 || pruned == 0 || boundPoints >= referencePoints {
t.Fatal("incomplete/non-pruning bound population", queries, late, cutoffWindows, pruned, boundPoints, referencePoints)
}
t.Logf("endpoint-bound short%d late%d cutoff-window%d pruned%d actual-points%d reference-points%d", queries, late, cutoffWindows, pruned, boundPoints, referencePoints)
}
func capEndpointFixtureResearch(t *testing.T, fixture endpointFixtureResearch) endpointFixtureResearch {
t.Helper()
artifacts := map[string][]byte{}
for id, data := range fixture.bundle.Artifacts {
artifacts[id] = append([]byte(nil), data...)
}
var root map[string]any
if err := json.Unmarshal(artifacts["economy"], &root); err != nil {
t.Fatal(err)
}
root["provision_tick_ms"] = 1000
for _, raw := range root["resources"].([]any) {
row := raw.(map[string]any)
if row["id"] == "company.cash" {
row["hardcap"].(map[string]any)["amount"] = "1e4"
}
}
var err error
artifacts["economy"], err = json.Marshal(root)
if err != nil {
t.Fatal(err)
}
hash, err := save.ConstantsHashArtifacts(artifacts)
if err != nil {
t.Fatal(err)
}
fixture.bundle = loadCompleteReplayTestBundle(t, hash, artifacts)
fixture.revision.ConstantsHash = hash
return fixture
}
func TestWaitEndpointBoundErrorsResearch(t *testing.T) {
for _, fault := range []string{"stock", "schedule"} {
t.Run(fault, func(t *testing.T) {
fixture := capEndpointFixtureResearch(t, loadEndpointFixtureResearch(t, "none", ModeOnline))
if fault == "stock" {
fixture.state.GeneratorCounts["generator.beige_tower"] = decimal.MaxExactInteger
fixture.state.GeneratorPurchasedTotal = decimal.MaxExactInteger
} else {
fixture.state.NextOpportunityAttendedMS = 5001
fixture.state.OpportunitySpawnSeq = decimal.MaxExactInteger
}
owner, err := newEndpointOwnerResearch(t, fixture.bundle, fixture.state, fixture.revision, ModeOnline, AblationMask{}, fixture.external, fixture.weight, fixture.batch)
if err != nil {
t.Fatal("diagnostic source not admitted", err)
}
reference, cause := owner.queryReference(2001, decimal.New(1, 6), 2002)
if cause == nil || reference.last <= 0 {
t.Fatal("actual first-error control did not fire", reference.last, cause)
}
if fault == "stock" && !errors.Is(cause, faction.ErrInvalidStockState) {
t.Fatal("wrong stock failure", cause)
}
answer, err := owner.queryBound(2001, decimal.New(1, 6), 2*2002)
if !errors.Is(err, cause) || answer.last != reference.last || answer.at != -1 || answer.selected.state != nil {
t.Fatal("bound hid/relabelled actual first error", answer.last, reference.last, err, cause)
}
if _, err := owner.project(6001); err != nil {
t.Fatal("later-valid companion rejected", err)
}
logEndpointBoundResearch(t, fmt.Sprintf("%s first%d", fault, answer.last), reference.points, answer)
})
}
}
func TestWaitEndpointQueryFloorResearch(t *testing.T) {
fixture := capEndpointFixtureResearch(t, loadEndpointFixtureResearch(t, "none", ModeOnline))
before, _ := fixture.state.Ledger.Balance("company.cash")
last := int64(-1)
point := func(at int64) (decimal.Decimal, error) {
last = at
state := activationRestore(t, fixture.bundle, mustEncodeState(t, fixture.state), 19, time.Time{})
result, err := SimulateAdvance(state, fixture.bundle.Economy, SimulationDependencies{}, fixture.revision, ModeOnline, state.EvaluatedThrough.Add(time.Duration(at)*time.Millisecond), fixture.external, AblationMask{})
_ = result
cash, _ := state.Ledger.Balance("company.cash")
return cash, err
}
found, _, err := queryWaitContextResearch(fixture.state, fixture.bundle.Economy, ModeOnline, 1500, AblationMask{}, SimulationDependencies{}, before, 2*1501, point, waitSourceContextResearch{modern: true, external: fixture.external, fromMS: 1001}, nil)
if err != nil || found != 1001 || last != 1001 {
t.Fatal("floor shortcut returned an earlier endpoint", found, last, err)
}
last = -1
_, _, err = queryWaitContextResearch(fixture.state, fixture.bundle.Economy, ModeOnline, 3500, AblationMask{}, SimulationDependencies{}, decimal.New(1, 6), 2*3501, point, waitSourceContextResearch{modern: true, external: fixture.external, fromMS: 3200}, nil)
if !errors.Is(err, ErrInvalidEngineState) || last != 3200 {
t.Fatal("source stop escaped query floor", last, err)
}
_, _, err = queryWaitContextResearch(fixture.state, fixture.bundle.Economy, ModeOnline, 1000, AblationMask{}, SimulationDependencies{}, before, 2*1001, point, waitSourceContextResearch{modern: true, fromMS: 1001}, nil)
if err == nil {
t.Fatal("invalid floor admitted")
}
}
func TestWaitEndpointUnknownClockResearch(t *testing.T) {
fixture := loadEndpointFixtureResearch(t, "none", ModeOnline)
fixture.state.EvaluatedThrough = time.Date(2526, 10, 16, 12, 0, 0, 0, time.UTC)
fixture.state.RunStartedAt = fixture.state.EvaluatedThrough.AddDate(-500, 0, 0)
fixture.state.NextOpportunityAttendedMS = decimal.MaxExactInteger
owner, err := newEndpointOwnerResearch(t, fixture.bundle, fixture.state, fixture.revision, ModeOnline, AblationMask{}, fixture.external, fixture.weight, fixture.batch)
if err != nil {
t.Fatal("saturated-clock source not admitted", err)
}
reference, err := owner.queryReference(3, decimal.New(1, 6), 4)
if err != nil {
t.Fatal("valid saturated-clock primitive refused", err)
}
answer, err := owner.queryBound(3, decimal.New(1, 6), 2*4)
if err != nil || answer.at != reference.at || answer.points != 4 || answer.fallbackPoints != 3 || len(answer.factories) != 0 || answer.selected.state != nil {
t.Fatal("unknown clock became a fabricated refusal or false certificate", answer.at, answer.points, answer.fallbackPoints, err)
}
}
func TestWaitEndpointFromResearch(t *testing.T) {
checked := 0
for _, profile := range []string{"none", "combined"} {
for _, mode := range []EvaluationMode{ModeOnline, ModeOffline} {
fixture := loadEndpointFixtureResearch(t, profile, mode)
owner, err := newEndpointOwnerResearch(t, fixture.bundle, fixture.state, fixture.revision, mode, AblationMask{}, fixture.external, fixture.weight, fixture.batch)
if err != nil {
t.Fatal(err)
}
for _, from := range []int64{1000, 1501, 5001} {
view, err := owner.project(from)
if err != nil {
t.Fatal(err)
}
cash, _ := view.state.Ledger.Balance("company.cash")
for _, price := range []decimal.Decimal{cash, decimal.New(1, 6)} {
ref, err := owner.fork().queryReferenceFrom(from, from+3, price, 4)
if err != nil {
t.Fatal(err)
}
answer, err := owner.fork().queryBoundFrom(from, from+3, price, 9)
if err != nil || answer.at != ref.at {
t.Fatal("floor query missed/preceded exact requested domain", profile, mode, from, answer.at, ref.at, err)
}
if answer.at >= 0 && !equalEndpointResearch(t, answer.selected, ref.selected) {
t.Fatal("from-floor selected result changed")
}
if answer.at < 0 && answer.selected.state != nil {
t.Fatal("from-floor unreachable returned a state")
}
checked++
}
}
}
}
if checked != 24 {
t.Fatal("incomplete floor population", checked)
}
}
func TestWaitEndpointFromErrorsResearch(t *testing.T) {
fixture := capEndpointFixtureResearch(t, loadEndpointFixtureResearch(t, "none", ModeOnline))
fixture.state.NextOpportunityAttendedMS = 5001
fixture.state.OpportunitySpawnSeq = decimal.MaxExactInteger
owner, err := newEndpointOwnerResearch(t, fixture.bundle, fixture.state, fixture.revision, ModeOnline, AblationMask{}, fixture.external, fixture.weight, fixture.batch)
if err != nil {
t.Fatal(err)
}
_, cause := owner.project(1001)
if cause == nil {
t.Fatal("earlier actual schedule error did not fire")
}
ref, err := owner.queryReferenceFrom(6001, 6003, decimal.New(1, 6), 3)
if err != nil || ref.at != -1 {
t.Fatal("later valid domain refused", err)
}
answer, err := owner.queryBoundFrom(6001, 6003, decimal.New(1, 6), 7)
if err != nil || answer.at != ref.at {
t.Fatal("earlier error escaped into later query domain", err)
}
answer, err = owner.queryBoundFrom(1001, 1003, decimal.New(1, 6), 7)
if !errors.Is(err, cause) || answer.last != 1001 || answer.selected.state != nil {
t.Fatal("actual error at the floor was hidden", answer.last, err, cause)
}
for _, from := range []int64{-1, 1001} {
if answer, err := owner.queryBoundFrom(from, 1000, decimal.New(1, 6), 10); err == nil || answer.points != 0 {
t.Fatal("invalid floor executed/admitted", from, err)
}
}
for _, budget := range []int{1, 2} {
answer, err := owner.queryBoundFrom(6001, 6003, decimal.New(1, 6), budget)
if err == nil || answer.points != 1 || answer.preparationZeroPoints != budget-1 || answer.selected.state != nil {
t.Fatal("from-floor preparation escaped its bound or became unreachable", budget, answer.points, answer.preparationZeroPoints, err)
}
}
}