xytara 2.7.0 → 2.9.0

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.
@@ -11,6 +11,27 @@ const PRICING_BAND_UNITS = {
11
11
  trust_critical: 8
12
12
  };
13
13
 
14
+ const PRICING_EXPERIMENT_REJECTION_CODES = [
15
+ "pricing_sample_too_sparse",
16
+ "experiment_not_registered",
17
+ "experiment_not_allowed_now",
18
+ "operator_approval_missing",
19
+ "baseline_metrics_missing",
20
+ "rollback_trigger_thresholds_missing",
21
+ "public_checkout_copy_review_missing",
22
+ "post_experiment_review_window_missing",
23
+ "target_surface_mismatch"
24
+ ];
25
+
26
+ const PRICING_EXPERIMENT_LAUNCH_REQUIREMENTS = [
27
+ "operator_approval_recorded",
28
+ "sample_maturity_is_mature_live_signals",
29
+ "baseline_metrics_recorded_before_change",
30
+ "rollback_trigger_thresholds_recorded",
31
+ "public_checkout_copy_reviewed_for_accuracy",
32
+ "post_experiment_review_window_defined"
33
+ ];
34
+
14
35
  function normalizeAmount(value) {
15
36
  const amount = Number(value || 0);
16
37
  return Number.isFinite(amount) ? amount : 0;
@@ -466,6 +487,195 @@ function buildOptimizationRecommendations(state) {
466
487
  };
467
488
  }
468
489
 
490
+ function buildPricingExperimentPlan(state) {
491
+ const revenueSignals = buildRevenueSignalSummary(state);
492
+ const decisionGuardrail = buildPricingDecisionGuardrail(state);
493
+ const quoteCohorts = buildQuoteCohorts(state);
494
+ const sampleMaturity = revenueSignals.sample_maturity;
495
+ const experimentReady = decisionGuardrail.allow_price_change;
496
+ const candidateExperiments = [
497
+ {
498
+ experiment_id: "starter_api_pack_entry_price_test",
499
+ target_surface: "hosted_checkout_starter_api_pack",
500
+ hypothesis: "starter_entry_conversion_can_improve_without_degrading_refund_or_grant_success_rates",
501
+ required_segments: [
502
+ "first_purchase",
503
+ "hosted_checkout",
504
+ "starter_api_pack"
505
+ ],
506
+ primary_metrics: [
507
+ "checkout_paid_rate",
508
+ "external_credit_grant_success_rate",
509
+ "execution_completion_rate"
510
+ ],
511
+ rollback_triggers: [
512
+ "refund_or_chargeback_rate_increases",
513
+ "grant_failure_rate_increases",
514
+ "execution_completion_rate_decreases"
515
+ ],
516
+ allowed_now: experimentReady
517
+ },
518
+ {
519
+ experiment_id: "utility_minimum_floor_test",
520
+ target_surface: "utility_pricing_band_minimum_charge_floor",
521
+ hypothesis: "utility_quote_abandonment_can_be_reduced_without_training_users_to_expect_free_execution",
522
+ required_segments: [
523
+ "pricing_band.utility",
524
+ "quote_created",
525
+ "quote_accepted_or_expired"
526
+ ],
527
+ primary_metrics: [
528
+ "quote_conversion_rate",
529
+ "quote_abandonment_rate",
530
+ "revenue_capture_rate"
531
+ ],
532
+ rollback_triggers: [
533
+ "revenue_capture_rate_decreases",
534
+ "support_or_refund_signal_increases",
535
+ "paid_execution_quality_decreases"
536
+ ],
537
+ allowed_now: experimentReady
538
+ },
539
+ {
540
+ experiment_id: "trust_critical_premium_review",
541
+ target_surface: "trust_critical_premium_multiplier",
542
+ hypothesis: "high_consequence_work_may_support_higher_margin_when_conversion_is_already_strong",
543
+ required_segments: [
544
+ "pricing_band.trust_critical",
545
+ "converted_quotes",
546
+ "completed_transactions"
547
+ ],
548
+ primary_metrics: [
549
+ "trust_critical_conversion_rate",
550
+ "completed_paid_execution_count",
551
+ "refund_or_dispute_rate"
552
+ ],
553
+ rollback_triggers: [
554
+ "trust_critical_conversion_rate_decreases",
555
+ "refund_or_dispute_rate_increases",
556
+ "operator_quality_review_fails"
557
+ ],
558
+ allowed_now: experimentReady
559
+ }
560
+ ];
561
+ return {
562
+ experiment_plan_version: "xytara-pricing-experiment-plan-v1",
563
+ sample_maturity: sampleMaturity,
564
+ experiment_state: experimentReady ? "operator_reviewed_experiments_allowed" : "blocked_collect_more_live_data",
565
+ allow_experiment_launch: experimentReady,
566
+ required_minimum_live_sample: {
567
+ quote_count: 100,
568
+ payment_ledger_count: 20,
569
+ execution_transaction_count: 20,
570
+ refund_monitoring_required: true
571
+ },
572
+ current_evidence: {
573
+ counts: revenueSignals.counts,
574
+ rates: revenueSignals.rates,
575
+ pricing_band_cohorts: quoteCohorts.by_pricing_band
576
+ },
577
+ candidate_experiments: candidateExperiments,
578
+ launch_requirements: PRICING_EXPERIMENT_LAUNCH_REQUIREMENTS.slice(),
579
+ deterministic_rejection_codes: PRICING_EXPERIMENT_REJECTION_CODES.slice(),
580
+ launch_request_template: {
581
+ experiment_id: "starter_api_pack_entry_price_test",
582
+ target_surface: "hosted_checkout_starter_api_pack",
583
+ operator_approval_ref: "ops.pricing.approval.<date>",
584
+ baseline_metrics_ref: "ops.pricing.baseline.<date>",
585
+ rollback_trigger_thresholds: {
586
+ refund_or_chargeback_rate_increases: "operator_defined_threshold",
587
+ grant_failure_rate_increases: "operator_defined_threshold",
588
+ execution_completion_rate_decreases: "operator_defined_threshold"
589
+ },
590
+ public_checkout_copy_review_ref: "ops.pricing.copy_review.<date>",
591
+ post_experiment_review_window_days: 14
592
+ },
593
+ blocked_actions: experimentReady
594
+ ? []
595
+ : [
596
+ "start_price_ab_test_from_sparse_signals",
597
+ "change_public_package_prices_without_operator_approval",
598
+ "change_minimum_floors_without_baseline_metrics",
599
+ "change_auto_topup_thresholds_without_repeat_usage_data"
600
+ ],
601
+ allowed_actions: experimentReady
602
+ ? [
603
+ "prepare_small_operator_reviewed_price_experiment",
604
+ "record_baseline_and_rollback_thresholds",
605
+ "run_one_surface_at_a_time"
606
+ ]
607
+ : [
608
+ "collect_more_live_quote_payment_execution_and_refund_data",
609
+ "review_cohort_instrumentation",
610
+ "keep_current_public_prices_and_thresholds"
611
+ ],
612
+ boundary: "pricing_experiments_are_operator_reviewed_and_data_gated_not_automatic_price_changes"
613
+ };
614
+ }
615
+
616
+ function validatePricingExperimentLaunchRequest(plan, request) {
617
+ const pricingPlan = plan || {};
618
+ const launchRequest = request || {};
619
+ const candidates = Array.isArray(pricingPlan.candidate_experiments)
620
+ ? pricingPlan.candidate_experiments
621
+ : [];
622
+ const experimentId = launchRequest.experiment_id ? String(launchRequest.experiment_id) : "";
623
+ const candidate = candidates.find((entry) => entry && entry.experiment_id === experimentId) || null;
624
+ const rollbackThresholds = launchRequest.rollback_trigger_thresholds || {};
625
+ const missingRollbackThreshold = candidate
626
+ ? (Array.isArray(candidate.rollback_triggers) ? candidate.rollback_triggers : [])
627
+ .some((trigger) => !rollbackThresholds || !rollbackThresholds[trigger])
628
+ : true;
629
+ const reviewWindowDays = Number(launchRequest.post_experiment_review_window_days || 0);
630
+ const rejectionCodes = [];
631
+
632
+ if (pricingPlan.allow_experiment_launch !== true || pricingPlan.sample_maturity !== "mature_live_signals") {
633
+ rejectionCodes.push("pricing_sample_too_sparse");
634
+ }
635
+ if (!candidate) {
636
+ rejectionCodes.push("experiment_not_registered");
637
+ } else {
638
+ if (candidate.allowed_now !== true) rejectionCodes.push("experiment_not_allowed_now");
639
+ if (launchRequest.target_surface && launchRequest.target_surface !== candidate.target_surface) {
640
+ rejectionCodes.push("target_surface_mismatch");
641
+ }
642
+ }
643
+ if (!launchRequest.operator_approval_ref) rejectionCodes.push("operator_approval_missing");
644
+ if (!launchRequest.baseline_metrics_ref) rejectionCodes.push("baseline_metrics_missing");
645
+ if (missingRollbackThreshold) rejectionCodes.push("rollback_trigger_thresholds_missing");
646
+ if (!launchRequest.public_checkout_copy_review_ref) rejectionCodes.push("public_checkout_copy_review_missing");
647
+ if (!Number.isFinite(reviewWindowDays) || reviewWindowDays < 1) {
648
+ rejectionCodes.push("post_experiment_review_window_missing");
649
+ }
650
+
651
+ return {
652
+ validation_version: "xytara-pricing-experiment-launch-validation-v1",
653
+ launch_allowed: rejectionCodes.length === 0,
654
+ experiment_id: experimentId || null,
655
+ sample_maturity: pricingPlan.sample_maturity || null,
656
+ rejection_codes: Array.from(new Set(rejectionCodes)),
657
+ required_requirements: PRICING_EXPERIMENT_LAUNCH_REQUIREMENTS.slice(),
658
+ boundary: "pricing_launch_validation_requires_mature_samples_operator_approval_baseline_metrics_and_rollback_thresholds"
659
+ };
660
+ }
661
+
662
+ function summarizePricingExperimentPlan(state) {
663
+ const plan = buildPricingExperimentPlan(state);
664
+ return {
665
+ product: "xytara",
666
+ category: "machine-commerce-pricing-experiment-plan-summary",
667
+ summary_version: "xytara-pricing-experiment-plan-summary-v1",
668
+ sample_maturity: plan.sample_maturity,
669
+ experiment_state: plan.experiment_state,
670
+ allow_experiment_launch: plan.allow_experiment_launch,
671
+ candidate_experiment_count: plan.candidate_experiments.length,
672
+ blocked_action_count: plan.blocked_actions.length,
673
+ launch_requirement_count: plan.launch_requirements.length,
674
+ deterministic_rejection_code_count: plan.deterministic_rejection_codes.length,
675
+ boundary: plan.boundary
676
+ };
677
+ }
678
+
469
679
  function buildPricingOptimizationPack(state) {
470
680
  const minimumChargeFloors = buildMinimumChargeFloors();
471
681
  const starterPricing = buildStarterPricing();
@@ -476,6 +686,7 @@ function buildPricingOptimizationPack(state) {
476
686
  const revenueSignalSummary = buildRevenueSignalSummary(state);
477
687
  const pricingDecisionGuardrail = buildPricingDecisionGuardrail(state);
478
688
  const packageThresholdRationale = buildPackageThresholdRationale(state);
689
+ const pricingExperimentPlan = buildPricingExperimentPlan(state);
479
690
  return {
480
691
  product: "xytara",
481
692
  category: "machine-commerce-pricing-optimization-pack",
@@ -501,6 +712,7 @@ function buildPricingOptimizationPack(state) {
501
712
  revenue_signal_summary: revenueSignalSummary,
502
713
  pricing_decision_guardrail: pricingDecisionGuardrail,
503
714
  package_threshold_rationale: packageThresholdRationale,
715
+ pricing_experiment_plan: pricingExperimentPlan,
504
716
  optimization_recommendations: recommendations,
505
717
  data_dependent_tuning: [
506
718
  "conversion_test_starter_pack_pricing",
@@ -516,7 +728,9 @@ function buildPricingOptimizationPack(state) {
516
728
  quote_cohorts_ref: "/v1/pricing-optimization/quote-cohorts",
517
729
  recommendations_ref: "/v1/pricing-optimization/recommendations",
518
730
  revenue_signal_summary_ref: "/v1/pricing-optimization/revenue-signal-summary",
519
- decision_guardrail_ref: "/v1/pricing-optimization/decision-guardrail"
731
+ decision_guardrail_ref: "/v1/pricing-optimization/decision-guardrail",
732
+ experiment_plan_ref: "/v1/pricing-optimization/experiment-plan",
733
+ experiment_plan_summary_ref: "/v1/pricing-optimization/experiment-plan/summary"
520
734
  }
521
735
  };
522
736
  }
@@ -541,6 +755,8 @@ function summarizePricingOptimizationPack(state) {
541
755
  refund_count: pack.revenue_signal_summary.counts.refund_count,
542
756
  execution_transaction_count: pack.revenue_signal_summary.counts.execution_transaction_count,
543
757
  recommendation_count: pack.optimization_recommendations.recommendations.length,
758
+ candidate_experiment_count: pack.pricing_experiment_plan.candidate_experiments.length,
759
+ allow_experiment_launch: pack.pricing_experiment_plan.allow_experiment_launch,
544
760
  linked_surfaces: pack.supported_surfaces
545
761
  };
546
762
  }
@@ -552,5 +768,8 @@ module.exports = {
552
768
  buildQuoteCohorts,
553
769
  buildRevenueSignalSummary,
554
770
  buildPricingDecisionGuardrail,
555
- buildOptimizationRecommendations
771
+ buildOptimizationRecommendations,
772
+ buildPricingExperimentPlan,
773
+ summarizePricingExperimentPlan,
774
+ validatePricingExperimentLaunchRequest
556
775
  };
@@ -10,6 +10,31 @@ function buildReleaseHistory() {
10
10
  current_version: packageJson.version,
11
11
  release_track: "public_release",
12
12
  history: [
13
+ {
14
+ version: "2.9.0",
15
+ channel: "public_release",
16
+ maturity_posture: "public_polish",
17
+ headline: "public-polish release with canonical Naxytra product URLs and safer quote-first runtime first contact",
18
+ milestone_refs: [
19
+ "canonical_naxytra_product_url",
20
+ "standalone_product_domain_guard",
21
+ "quote_first_public_first_contact",
22
+ "release_summary_secretless_first_contact"
23
+ ]
24
+ },
25
+ {
26
+ version: "2.8.0",
27
+ channel: "public_release",
28
+ maturity_posture: "release_boundary_hardened",
29
+ headline: "release-boundary hardening with provider promotion evidence gates, pricing experiment guardrails, treasury public-claim safety, and read-only operator observability boundaries",
30
+ milestone_refs: [
31
+ "framework_provider_promotion_evidence_gate",
32
+ "pricing_experiment_plan_gate",
33
+ "pricing_experiment_launch_gate",
34
+ "treasury_public_claim_boundary",
35
+ "operator_observability_read_only_boundary"
36
+ ]
37
+ },
13
38
  {
14
39
  version: "2.7.0",
15
40
  channel: "public_release",
@@ -172,7 +172,7 @@ function buildScenarioPack() {
172
172
  "run xytara-run for trust.verify",
173
173
  "inspect transaction, payment, and settlement records"
174
174
  ],
175
- entrypoint: "xytara-run --url https://xytara.onrender.com --account acct_demo --command \"cli-run\" --task trust.verify --body-json '{\"subject_id\":\"subject-1\"}' --wallet-id merchant_wallet_main --wallet-secret YOUR_LOCAL_SIGNED_SECRET --txid YOUR_BSV_TXID",
175
+ entrypoint: "xytara first-run --run-quote --account ACCOUNT_REF --pretty",
176
176
  surfaces: [
177
177
  "/v1/catalog/summary",
178
178
  "/x402/commands/execute",
@@ -349,7 +349,7 @@ function buildReleasePack() {
349
349
  },
350
350
  first_contact: {
351
351
  install: "npm install xytara",
352
- direct_run_cli: "xytara-run --url https://xytara.onrender.com --account acct_demo --command \"cli-run\" --task trust.verify --body-json '{\"subject_id\":\"subject-1\"}' --wallet-id merchant_wallet_main --wallet-secret YOUR_LOCAL_SIGNED_SECRET --txid YOUR_BSV_TXID",
352
+ direct_run_cli: "xytara first-run --run-quote --account ACCOUNT_REF --pretty",
353
353
  discovery_surface: "/v1/catalog/summary",
354
354
  transaction_center_surface: "/v1/transaction-center/summary",
355
355
  economics_surface: "/v1/transaction-center/economics/summary",
@@ -39,7 +39,7 @@ function buildSoftLaunchPack() {
39
39
  outreach_proof: "/v1/outreach-proof/summary",
40
40
  adapter_partners: "/v1/adapter-partners/summary",
41
41
  first_cli: "xytara-release --center --summary",
42
- first_run_cli: "xytara-run --url https://xytara.onrender.com --account acct_demo --command \"cli-run\" --task trust.verify --body-json '{\"subject_id\":\"subject-1\"}' --wallet-id merchant_wallet_main --wallet-secret YOUR_LOCAL_SIGNED_SECRET --txid YOUR_BSV_TXID"
42
+ first_run_cli: "xytara first-run --run-quote --account ACCOUNT_REF --pretty"
43
43
  },
44
44
  outreach_sequence: [
45
45
  "send the short pitch and first proof path to a small builder set",
@@ -177,6 +177,30 @@ const RAIL_PROFILES = [
177
177
  }
178
178
  ];
179
179
 
180
+ const TREASURY_PUBLIC_BOUNDARY_REJECTION_CODES = [
181
+ "public_custody_destination_leak",
182
+ "public_external_ref_leak",
183
+ "public_custody_ref_leak",
184
+ "public_reporting_ref_leak",
185
+ "public_wallet_ref_leak",
186
+ "public_provider_ref_leak",
187
+ "internal_rail_public_claimed",
188
+ "readiness_only_rail_public_claimed",
189
+ "claim_boundary_mismatch",
190
+ "unsupported_live_claim_rail",
191
+ "operator_visibility_rule_missing"
192
+ ];
193
+
194
+ const SENSITIVE_PUBLIC_DESTINATION_FIELDS = [
195
+ "external_ref",
196
+ "custody_ref",
197
+ "reporting_ref",
198
+ "wallet_ref",
199
+ "provider_ref",
200
+ "merchant_address",
201
+ "merchant_paymail"
202
+ ];
203
+
180
204
  function classifyDestinationSource(profile, paymentConfig) {
181
205
  const settlementMode = profile.settlement_mode;
182
206
  const mapEntry = paymentConfig.treasury_destinations_by_settlement_mode[settlementMode];
@@ -432,6 +456,7 @@ function buildOperatorTreasuryDestinationsPack() {
432
456
  ? "claim_only_the_rails_with_real_configured_destinations_as_live_landing_paths"
433
457
  : "no_multi-rail_operational_claims_until_real_destinations_exist",
434
458
  custody_visibility_rule: "do_not_expose_real_external_refs_or_custody_refs_on_public_surfaces",
459
+ deterministic_rejection_codes: TREASURY_PUBLIC_BOUNDARY_REJECTION_CODES.slice(),
435
460
  config_examples: Object.fromEntries(RAIL_PROFILES.map((profile) => [profile.settlement_mode, profile.config_template]))
436
461
  };
437
462
  }
@@ -458,6 +483,7 @@ function buildTreasuryDestinationsPack() {
458
483
  operator_rule: operatorPack.operator_rule,
459
484
  claim_discipline_rule: "unsupported_or_unconfigured_rails_may_be_listed_as_architecture_but_not_as_live_landing_paths",
460
485
  privacy_rule: "public_surfaces_must_not_expose_real_treasury_landing_refs_or_custody_provider_refs",
486
+ deterministic_rejection_codes: TREASURY_PUBLIC_BOUNDARY_REJECTION_CODES.slice(),
461
487
  config_examples: operatorPack.config_examples
462
488
  };
463
489
  }
@@ -475,6 +501,7 @@ function summarizeTreasuryDestinationsPack() {
475
501
  readiness_only_profile_count: pack.readiness_summary.readiness_only_profile_count,
476
502
  reporting_gap_count: pack.readiness_summary.reporting_gap_count,
477
503
  internal_only_profile_count: pack.profiles.filter((entry) => entry.compliance_posture === "internal_only_policy_gated").length,
504
+ deterministic_rejection_code_count: pack.deterministic_rejection_codes.length,
478
505
  public_claim_boundary: pack.public_claim_boundary,
479
506
  linked_surfaces: pack.supported_surfaces
480
507
  };
@@ -493,6 +520,7 @@ function summarizeOperatorTreasuryDestinationsPack() {
493
520
  readiness_only_profile_count: pack.readiness_summary.readiness_only_profile_count,
494
521
  reporting_gap_count: pack.readiness_summary.reporting_gap_count,
495
522
  internal_only_profile_count: pack.profiles.filter((entry) => entry.compliance_posture === "internal_only_policy_gated").length,
523
+ deterministic_rejection_code_count: pack.deterministic_rejection_codes.length,
496
524
  public_claim_boundary: pack.public_claim_boundary,
497
525
  linked_surfaces: pack.supported_surfaces
498
526
  };
@@ -534,10 +562,80 @@ function buildTreasuryDestinationValidationPreview(input) {
534
562
  }
535
563
  }
536
564
 
565
+ function arraysEqual(left, right) {
566
+ const leftSorted = (Array.isArray(left) ? left : []).slice().sort();
567
+ const rightSorted = (Array.isArray(right) ? right : []).slice().sort();
568
+ return leftSorted.length === rightSorted.length && leftSorted.every((entry, index) => entry === rightSorted[index]);
569
+ }
570
+
571
+ function validateTreasuryDestinationPublicBoundary(packInput) {
572
+ const pack = packInput || buildTreasuryDestinationsPack();
573
+ const profiles = Array.isArray(pack.profiles) ? pack.profiles : [];
574
+ const boundary = pack.public_claim_boundary || {};
575
+ const rejectionCodes = [];
576
+ const liveClaimableRails = profiles.filter((entry) => entry && entry.public_claim_allowed).map((entry) => entry.rail_id);
577
+ const internalOnlyRails = profiles
578
+ .filter((entry) => entry && entry.compliance_posture === "internal_only_policy_gated")
579
+ .map((entry) => entry.rail_id);
580
+ const readinessOnlyRails = profiles
581
+ .filter((entry) => entry && !entry.public_claim_allowed && entry.compliance_posture !== "internal_only_policy_gated")
582
+ .map((entry) => entry.rail_id);
583
+
584
+ for (const profile of profiles) {
585
+ if (!profile) continue;
586
+ if (profile.custody_destination != null) {
587
+ rejectionCodes.push("public_custody_destination_leak");
588
+ }
589
+ const visibility = profile.destination_visibility || {};
590
+ for (const fieldName of SENSITIVE_PUBLIC_DESTINATION_FIELDS) {
591
+ if (visibility[fieldName] != null) {
592
+ rejectionCodes.push(`public_${fieldName}_leak`);
593
+ }
594
+ if (profile[fieldName] != null) {
595
+ rejectionCodes.push(`public_${fieldName}_leak`);
596
+ }
597
+ }
598
+ if (profile.compliance_posture === "internal_only_policy_gated" && profile.public_claim_allowed === true) {
599
+ rejectionCodes.push("internal_rail_public_claimed");
600
+ }
601
+ if (boundary.readiness_only_rails && boundary.readiness_only_rails.includes(profile.rail_id) && profile.public_claim_allowed === true) {
602
+ rejectionCodes.push("readiness_only_rail_public_claimed");
603
+ }
604
+ }
605
+
606
+ const boundaryLiveRails = Array.isArray(boundary.live_claimable_rails) ? boundary.live_claimable_rails : [];
607
+ const boundaryReadinessRails = Array.isArray(boundary.readiness_only_rails) ? boundary.readiness_only_rails : [];
608
+ const boundaryInternalRails = Array.isArray(boundary.internal_only_rails) ? boundary.internal_only_rails : [];
609
+ if (
610
+ !arraysEqual(liveClaimableRails, boundaryLiveRails)
611
+ || !arraysEqual(readinessOnlyRails, boundaryReadinessRails)
612
+ || !arraysEqual(internalOnlyRails, boundaryInternalRails)
613
+ ) {
614
+ rejectionCodes.push("claim_boundary_mismatch");
615
+ }
616
+ if (boundaryLiveRails.some((railId) => !profiles.some((entry) => entry && entry.rail_id === railId && entry.public_claim_allowed === true))) {
617
+ rejectionCodes.push("unsupported_live_claim_rail");
618
+ }
619
+ if (pack.category === "machine-commerce-operator-treasury-destinations-pack"
620
+ && pack.custody_visibility_rule !== "do_not_expose_real_external_refs_or_custody_refs_on_public_surfaces") {
621
+ rejectionCodes.push("operator_visibility_rule_missing");
622
+ }
623
+
624
+ return {
625
+ validation_version: "xytara-treasury-public-boundary-validation-v1",
626
+ public_boundary_valid: rejectionCodes.length === 0,
627
+ rejection_codes: Array.from(new Set(rejectionCodes)),
628
+ deterministic_rejection_codes: TREASURY_PUBLIC_BOUNDARY_REJECTION_CODES.slice(),
629
+ public_claim_boundary: boundary,
630
+ boundary: "public_treasury_surfaces_must_not_expose_landing_or_custody_refs_and_must_match_claim_allowed_state"
631
+ };
632
+ }
633
+
537
634
  module.exports = {
538
635
  buildOperatorTreasuryDestinationsPack,
539
636
  summarizeOperatorTreasuryDestinationsPack,
540
637
  buildTreasuryDestinationsPack,
541
638
  summarizeTreasuryDestinationsPack,
542
- buildTreasuryDestinationValidationPreview
639
+ buildTreasuryDestinationValidationPreview,
640
+ validateTreasuryDestinationPublicBoundary
543
641
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xytara",
3
- "version": "2.7.0",
3
+ "version": "2.9.0",
4
4
  "description": "Agent-commerce runtime for quote, pay, execute, deliver, meter, and integrate.",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -10,10 +10,10 @@
10
10
  },
11
11
  "type": "commonjs",
12
12
  "license": "Apache-2.0",
13
- "homepage": "https://xytara.com",
13
+ "homepage": "https://naxytra.com/xytara",
14
14
  "funding": {
15
15
  "type": "individual",
16
- "url": "https://xytara.com"
16
+ "url": "https://naxytra.com/xytara"
17
17
  },
18
18
  "keywords": [
19
19
  "agent-commerce",
@@ -72,12 +72,16 @@
72
72
  "verify:package": "node scripts/verify_all.js",
73
73
  "verify:integrations": "node scripts/verify_integrations.js",
74
74
  "verify:adapters": "node scripts/verify_adapters.js",
75
+ "verify:framework-provider-promotion": "node scripts/verify_framework_provider_promotion.js",
76
+ "verify:operator-observability-boundary": "node scripts/verify_operator_observability_boundary.js",
77
+ "verify:pricing-experiment-plan": "node scripts/verify_pricing_experiment_plan.js",
78
+ "verify:treasury-public-boundary": "node scripts/verify_treasury_public_boundary.js",
75
79
  "verify:tooling": "node scripts/verify_tooling.js",
76
80
  "verify:examples": "node scripts/verify_examples.js",
77
81
  "verify:service": "node scripts/verify_service.js",
78
82
  "verify:release-candidate": "node scripts/verify_release_candidate.js",
79
83
  "verify:production-readiness": "node scripts/verify_production_readiness.js",
80
- "verify:all": "node scripts/verify_all.js && node scripts/verify_integrations.js && node scripts/verify_adapters.js && node scripts/verify_tooling.js && node scripts/verify_examples.js && node scripts/verify_service.js",
84
+ "verify:all": "node scripts/verify_all.js && node scripts/verify_integrations.js && node scripts/verify_adapters.js && node scripts/verify_framework_provider_promotion.js && node scripts/verify_operator_observability_boundary.js && node scripts/verify_pricing_experiment_plan.js && node scripts/verify_treasury_public_boundary.js && node scripts/verify_tooling.js && node scripts/verify_examples.js && node scripts/verify_service.js",
81
85
  "prepublishOnly": "npm run verify:release-candidate"
82
86
  }
83
87
  }
@@ -0,0 +1,152 @@
1
+ "use strict";
2
+
3
+ const assert = require("assert");
4
+ const {
5
+ FRAMEWORK_PROVIDER_CANDIDATES,
6
+ buildFrameworkProviderPromotionPack,
7
+ summarizeFrameworkProviderPromotionPack,
8
+ validateFrameworkProviderPromotionEvidence
9
+ } = require("../lib/framework_provider_promotion");
10
+
11
+ function normalizeUrl(baseUrl, healthPath) {
12
+ const url = new URL(baseUrl);
13
+ const normalizedPath = String(healthPath || "/health").startsWith("/")
14
+ ? String(healthPath || "/health")
15
+ : `/${healthPath}`;
16
+ url.pathname = normalizedPath;
17
+ return url.toString();
18
+ }
19
+
20
+ async function checkHealth(candidate, env) {
21
+ const endpoint = env[candidate.endpoint_env];
22
+ const token = env[candidate.auth_env];
23
+ const healthPath = env[candidate.health_path_env] || "/health";
24
+ const started = Date.now();
25
+ const response = await fetch(normalizeUrl(endpoint, healthPath), {
26
+ method: "GET",
27
+ headers: {
28
+ Authorization: `Bearer ${token}`,
29
+ Accept: "application/json"
30
+ }
31
+ });
32
+ const latencyMs = Date.now() - started;
33
+ let body = null;
34
+ try {
35
+ body = await response.json();
36
+ } catch (_error) {
37
+ body = null;
38
+ }
39
+ return {
40
+ framework_id: candidate.framework_id,
41
+ adapter_id: candidate.adapter_id,
42
+ status_code: response.status,
43
+ latency_ms: latencyMs,
44
+ health_ok: response.ok && (!body || ["ok", "ready", "auth_required"].includes(String(body.status || body.readiness || "ok"))),
45
+ body_status: body && (body.status || body.readiness || null)
46
+ };
47
+ }
48
+
49
+ function buildValidPromotionEvidence(candidateSummary) {
50
+ return {
51
+ framework_id: candidateSummary.framework_id,
52
+ adapter_id: candidateSummary.adapter_id,
53
+ task_ref: candidateSummary.task_ref,
54
+ operator_evidence_ref: `ops.framework_provider.${candidateSummary.framework_id}.2026-04-22`,
55
+ auth_boundary_ref: `ops.framework_provider.auth_boundary.${candidateSummary.framework_id}.2026-04-22`,
56
+ health_check: {
57
+ status_code: 200,
58
+ health_ok: true
59
+ },
60
+ latency_ms: 250,
61
+ latency_budget_ms: 2000,
62
+ failure_behavior_ref: `ops.framework_provider.failure_behavior.${candidateSummary.framework_id}.2026-04-22`,
63
+ proof_fact_shape_ref: `ops.framework_provider.proof_facts.${candidateSummary.framework_id}.2026-04-22`
64
+ };
65
+ }
66
+
67
+ function assertRejected(pack, evidence, expectedCode) {
68
+ const validation = validateFrameworkProviderPromotionEvidence(pack, evidence);
69
+ assert.strictEqual(validation.promotion_allowed, false, `expected ${expectedCode} to block framework provider promotion`);
70
+ assert.strictEqual(
71
+ validation.rejection_codes.includes(expectedCode),
72
+ true,
73
+ `missing deterministic rejection code ${expectedCode}`
74
+ );
75
+ return validation;
76
+ }
77
+
78
+ async function main() {
79
+ const pack = buildFrameworkProviderPromotionPack();
80
+ const summary = summarizeFrameworkProviderPromotionPack();
81
+ assert.strictEqual(pack.ok, true, "framework provider promotion pack failed");
82
+ assert.strictEqual(summary.framework_candidate_count, FRAMEWORK_PROVIDER_CANDIDATES.length, "framework candidate count mismatch");
83
+ assert.strictEqual(pack.promoted_provider_count, 0, "promotion pack must not auto-promote providers");
84
+ assert.strictEqual(pack.deterministic_rejection_codes.length >= 13, true, "framework promotion rejection codes missing");
85
+ assert.strictEqual(summary.deterministic_rejection_code_count, pack.deterministic_rejection_codes.length, "framework promotion summary rejection code count mismatch");
86
+ assert.strictEqual(
87
+ pack.strict_boundaries.includes("reference_framework_adapters_do_not_equal_live_provider_integrations"),
88
+ true,
89
+ "framework reference boundary missing"
90
+ );
91
+
92
+ assertRejected(pack, buildValidPromotionEvidence(pack.candidates[0]), "candidate_not_live_check_ready");
93
+ assertRejected(pack, { framework_id: "unknown_framework" }, "framework_not_registered");
94
+
95
+ const syntheticEnv = {
96
+ XYTARA_LANGGRAPH_PROVIDER_URL: "https://provider.example.test",
97
+ XYTARA_LANGGRAPH_PROVIDER_TOKEN: "configured-token-placeholder",
98
+ XYTARA_LANGGRAPH_PROVIDER_HEALTH_PATH: "/health"
99
+ };
100
+ const promotablePack = buildFrameworkProviderPromotionPack({ env: syntheticEnv });
101
+ const promotableCandidate = promotablePack.candidates.find((candidate) => candidate.framework_id === "langgraph");
102
+ const validEvidence = buildValidPromotionEvidence(promotableCandidate);
103
+ const validValidation = validateFrameworkProviderPromotionEvidence(promotablePack, validEvidence);
104
+ assert.strictEqual(promotableCandidate.state, "live_check_ready", "synthetic provider should be live-check ready");
105
+ assert.strictEqual(validValidation.promotion_allowed, true, "complete synthetic evidence should validate");
106
+ assert.deepStrictEqual(validValidation.rejection_codes, [], "complete synthetic evidence should not carry rejections");
107
+
108
+ assertRejected(promotablePack, { ...validEvidence, adapter_id: "wrong.adapter" }, "adapter_id_mismatch");
109
+ assertRejected(promotablePack, { ...validEvidence, task_ref: "wrong.task" }, "task_ref_mismatch");
110
+ assertRejected(promotablePack, { ...validEvidence, operator_evidence_ref: null }, "operator_evidence_missing");
111
+ assertRejected(promotablePack, { ...validEvidence, auth_boundary_ref: null }, "auth_boundary_evidence_missing");
112
+ assertRejected(promotablePack, { ...validEvidence, health_check: null }, "health_check_missing");
113
+ assertRejected(promotablePack, { ...validEvidence, health_check: { status_code: 503, health_ok: false } }, "health_check_failed");
114
+ assertRejected(promotablePack, { ...validEvidence, latency_ms: null }, "latency_measurement_missing");
115
+ assertRejected(promotablePack, { ...validEvidence, latency_ms: 3000, latency_budget_ms: 1000 }, "latency_budget_exceeded");
116
+ assertRejected(promotablePack, { ...validEvidence, failure_behavior_ref: null }, "failure_behavior_evidence_missing");
117
+ assertRejected(promotablePack, { ...validEvidence, proof_fact_shape_ref: null }, "proof_fact_shape_evidence_missing");
118
+ assertRejected(promotablePack, { ...validEvidence, provider_token: "sk_live_accidental_secret" }, "secret_material_forbidden");
119
+
120
+ const readyCandidates = pack.candidates.filter((candidate) => candidate.state === "live_check_ready");
121
+ if (pack.require_live) {
122
+ assert.strictEqual(readyCandidates.length > 0, true, "live provider promotion required but no endpoint/auth pair is configured");
123
+ }
124
+
125
+ const live_checks = [];
126
+ for (const candidate of FRAMEWORK_PROVIDER_CANDIDATES) {
127
+ const candidateSummary = pack.candidates.find((entry) => entry.framework_id === candidate.framework_id);
128
+ if (!candidateSummary || candidateSummary.state !== "live_check_ready") continue;
129
+ const result = await checkHealth(candidate, process.env);
130
+ assert.strictEqual(result.health_ok, true, `${candidate.framework_id} live health check failed`);
131
+ live_checks.push(result);
132
+ }
133
+
134
+ const result = {
135
+ ok: true,
136
+ product: "xytara",
137
+ category: "xytara-framework-provider-promotion-verification",
138
+ status: live_checks.length > 0 ? "live_provider_health_checks_passed" : "no_live_provider_evidence_configured",
139
+ live_check_count: live_checks.length,
140
+ promotion_allowed: false,
141
+ deterministic_rejection_code_count: pack.deterministic_rejection_codes.length,
142
+ adversarial_case_count: 13,
143
+ live_checks,
144
+ boundary: "this_verifier_checks_promotion_evidence_but_does_not_promote_reference_adapters_to_live_provider_claims"
145
+ };
146
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
147
+ }
148
+
149
+ main().catch((error) => {
150
+ console.error(error && error.stack ? error.stack : error);
151
+ process.exit(1);
152
+ });