@itpay/cli 2.1.18 → 2.1.22

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.
Files changed (75) hide show
  1. package/dist/src/commands/catalog.js +1 -0
  2. package/dist/src/commands/rail_catalog.js +160 -11
  3. package/dist/src/commands/services.js +289 -71
  4. package/dist/src/commands/skill.js +1 -1
  5. package/dist/src/main.js +54 -19
  6. package/dist/src/render/markdown.js +0 -3
  7. package/dist/src/state/account_auth.js +6 -2
  8. package/dist/src/state/cart_session.js +4 -1
  9. package/dist/src/state/config.js +1 -1
  10. package/dist/src/state/device_authority.js +69 -13
  11. package/dist/src/state/task_journal.js +2 -0
  12. package/docs/agent/buyer/cart-checkout.json +5 -4
  13. package/docs/agent/buyer/catalog-list.json +24 -6
  14. package/docs/agent/buyer/identity-and-sessions.json +15 -10
  15. package/docs/agent/buyer/install-and-setup.json +7 -6
  16. package/docs/agent/buyer/orders-refunds.json +4 -4
  17. package/docs/agent/buyer/payment-flow.json +3 -3
  18. package/docs/agent/buyer/purchased-content.json +17 -3
  19. package/docs/agent/buyer/quickstart.json +18 -11
  20. package/docs/agent/buyer/rail-booking.json +79 -167
  21. package/docs/agent/buyer/rail-fast-checkout.json +21 -43
  22. package/docs/agent/buyer/render-hosts.json +8 -5
  23. package/docs/agent/buyer/service-feedback.json +2 -1
  24. package/docs/cli-reference/agent-types.md +1 -1
  25. package/docs/cli-reference/commands/auth.md +2 -0
  26. package/docs/cli-reference/commands/buy.md +1 -1
  27. package/docs/cli-reference/commands/cart/add.md +1 -1
  28. package/docs/cli-reference/commands/cart/clear.md +1 -1
  29. package/docs/cli-reference/commands/cart/index.md +1 -1
  30. package/docs/cli-reference/commands/cart/next.md +1 -1
  31. package/docs/cli-reference/commands/cart/remove.md +1 -1
  32. package/docs/cli-reference/commands/cart/show.md +1 -1
  33. package/docs/cli-reference/commands/catalog/index.md +1 -1
  34. package/docs/cli-reference/commands/catalog/list.md +1 -1
  35. package/docs/cli-reference/commands/checkout.md +1 -1
  36. package/docs/cli-reference/commands/device.md +4 -2
  37. package/docs/cli-reference/commands/docs/index.md +1 -1
  38. package/docs/cli-reference/commands/docs/list.md +1 -1
  39. package/docs/cli-reference/commands/docs/search.md +1 -1
  40. package/docs/cli-reference/commands/docs/show.md +1 -1
  41. package/docs/cli-reference/commands/install.md +2 -2
  42. package/docs/cli-reference/commands/next.md +1 -1
  43. package/docs/cli-reference/commands/order.md +1 -1
  44. package/docs/cli-reference/commands/pay.md +1 -1
  45. package/docs/cli-reference/commands/readyz.md +1 -1
  46. package/docs/cli-reference/commands/refund/cancel.md +1 -1
  47. package/docs/cli-reference/commands/refund/create.md +1 -1
  48. package/docs/cli-reference/commands/refund/get.md +2 -2
  49. package/docs/cli-reference/commands/refund/index.md +1 -1
  50. package/docs/cli-reference/commands/refund/list.md +1 -1
  51. package/docs/cli-reference/commands/refund/watch.md +1 -1
  52. package/docs/cli-reference/commands/services/action.md +3 -3
  53. package/docs/cli-reference/commands/services/checkout.md +1 -1
  54. package/docs/cli-reference/commands/services/events.md +1 -1
  55. package/docs/cli-reference/commands/services/get.md +1 -1
  56. package/docs/cli-reference/commands/services/index.md +1 -1
  57. package/docs/cli-reference/commands/services/invoke.md +3 -11
  58. package/docs/cli-reference/commands/services/list.md +1 -1
  59. package/docs/cli-reference/commands/services/next.md +12 -10
  60. package/docs/cli-reference/commands/services/page.md +9 -7
  61. package/docs/cli-reference/commands/services/quote.md +1 -1
  62. package/docs/cli-reference/commands/services/read-result.md +8 -8
  63. package/docs/cli-reference/commands/services/run.md +2 -2
  64. package/docs/cli-reference/commands/services/start.md +1 -1
  65. package/docs/cli-reference/conventions.md +2 -2
  66. package/package.json +7 -5
  67. package/skills/itpay/SKILL.md +70 -186
  68. package/docs/reviews/agent-ux-handoff-2026-09-23/IMPLEMENTATION-EVIDENCE.md +0 -174
  69. package/docs/skill-bundle-rollout/01-mcp-authentication.md +0 -134
  70. package/docs/skill-bundle-rollout/02-platform-bundle-repositories.md +0 -210
  71. package/docs/skill-bundle-rollout/03-platform-publishing.md +0 -161
  72. package/docs/skill-bundle-rollout/04-first-wave-platforms.md +0 -70
  73. package/docs/skill-bundle-rollout/05-sync-operations.md +0 -62
  74. package/docs/skill-bundle-rollout/README.md +0 -151
  75. /package/bin/{itp → itp.mjs} +0 -0
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schema_version": "itp.agent_doc.v1",
3
3
  "role": "buyer",
4
- "product_scope": "itpay is the single public CLI entry point, and $itpay is its user-facing Skill invocation. Under that one product entry point, the two top-level commerce actions are buy and sell: Buyer workflows are available now; Seller workflows will use the same entry point and are not implemented yet.",
4
+ "product_scope": "itpay is the single public CLI entry point for Buyer services and the existing itpay sell Seller workflow; $itpay is its user-facing Skill invocation.",
5
5
  "topic": "payment-flow",
6
6
  "title": "Human Checkout Handoff And Payment Verification",
7
7
  "purpose": "Show the ItPay Checkout to the human and recover authoritative payment state without creating duplicate payment resources.",
@@ -13,7 +13,7 @@
13
13
  {
14
14
  "intent": "present the Checkout handoff",
15
15
  "command": "<execute the exact command returned by buy or services checkout>",
16
- "success_signal": "the human can see both the ItPay Checkout QR or image and the Checkout URL"
16
+ "success_signal": "the returned official URL and/or QR supported by the actual Host is visible to the human"
17
17
  },
18
18
  {
19
19
  "intent": "read authoritative Checkout state",
@@ -29,7 +29,7 @@
29
29
  "agent_rules": [
30
30
  "Normal buyer flow opens the ItPay Checkout page; itpay pay and buy --pay are operator escape hatches.",
31
31
  "Use only handoff fields returned for the current Host and make them actually visible to the human.",
32
- "Before creating a single-Service Checkout, send the exact price confirmation requested by the current instruction, stop, and wait for explicit human agreement.",
32
+ "Obtain only missing required agreement or material price/term changes. Reuse a valid explicit confirmation for unchanged terms; never invent it.",
33
33
  "After presenting a Checkout, stop. Run the returned next.command only after the human completes the payment action or asks to query the same Checkout.",
34
34
  "Use only the handoff fields returned for the current Host. Load render-hosts if the official handoff is not visible.",
35
35
  "Payment is verified only by Backend Checkout or Order state, never by QR rendering, redirect, or user claim.",
@@ -29,7 +29,7 @@
29
29
  "intent_routing": {
30
30
  "previous_content": "Use vault list, optionally with the subject as --query.",
31
31
  "purchase_history": "Use orders.",
32
- "new_service": "Use catalog only when the human asks for a new query or purchase.",
32
+ "new_service": "For a new railway request, read rail-booking; for other new services, use catalog. No previous-content match does not block a separately requested new railway query.",
33
33
  "ambiguous": "Ask whether the human wants an earlier purchase or a new query before calling ItPay."
34
34
  },
35
35
  "authorization_flow": [
@@ -41,8 +41,22 @@
41
41
  "Never rerun vault access as a status check."
42
42
  ],
43
43
  "human_language": {
44
- "prefer": ["previously purchased content", "past report", "purchase history", "已购内容", "以前购买的报告", "购买记录"],
45
- "avoid": ["Vault", "artifact", "Device", "Buyer", "grant", "start token"]
44
+ "prefer": [
45
+ "previously purchased content",
46
+ "past report",
47
+ "purchase history",
48
+ "已购内容",
49
+ "以前购买的报告",
50
+ "购买记录"
51
+ ],
52
+ "avoid": [
53
+ "Vault",
54
+ "artifact",
55
+ "Device",
56
+ "Buyer",
57
+ "grant",
58
+ "start token"
59
+ ]
46
60
  },
47
61
  "partial_results": {
48
62
  "available": "Explain the returned section normally.",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schema_version": "itp.agent_doc.v1",
3
3
  "role": "buyer",
4
- "product_scope": "itpay is the single public CLI entry point, and $itpay is its user-facing Skill invocation. Under that one product entry point, the two top-level commerce actions are buy and sell: Buyer workflows are available now; Seller workflows will use the same entry point and are not implemented yet.",
4
+ "product_scope": "itpay is the single public CLI entry point for Buyer services and the existing itpay sell Seller workflow; $itpay is its user-facing Skill invocation.",
5
5
  "topic": "quickstart",
6
6
  "title": "Route One Human Intent Through ItPay",
7
7
  "purpose": "Choose the correct first action from the human's words and continue through one authoritative CLI envelope at a time.",
@@ -12,7 +12,7 @@
12
12
  "required_state": {
13
13
  "needs": [
14
14
  "the real supported Agent Type",
15
- "one official Backend: production https://app.itpay.ai by default, or explicit test https://sandbox.itpay.ai"
15
+ "one allowed Backend: production https://app.itpay.ai by default; explicit https://sandbox.itpay.ai or https://dev.itpay.ai for the corresponding test environment"
16
16
  ],
17
17
  "must_not_need": [
18
18
  "Admin access",
@@ -21,18 +21,21 @@
21
21
  ]
22
22
  },
23
23
  "intent_routing": {
24
- "new_service": "Use catalog list only for a new service or query.",
24
+ "new_service": "For other new services, use itpay catalog list --json and the selected input contract.",
25
25
  "previous_content": "Use vault list, optionally with the subject as --query.",
26
26
  "purchase_history": "Use orders.",
27
27
  "refund_or_paid_problem": "Resume the known Order or Refund before creating anything new.",
28
28
  "service_feedback": "Finish the original order outcome first, then submit one safe Agent postmortem; include a rating or comment only when the human explicitly gives it.",
29
- "ambiguous": "Ask whether the human wants an earlier purchase or a new query before calling ItPay."
29
+ "ambiguous": "Ask whether the human wants an earlier purchase or a new query before calling ItPay.",
30
+ "railway": "Known railway intent: itpay docs show rail-booking --json. Read once, then follow its Exact/Smart route."
30
31
  },
31
- "commands": [{
32
- "intent": "continue the selected flow",
33
- "command": "<execute the exact next.command returned by the previous CLI envelope>",
34
- "success_signal": "the next envelope reports one current state and at most one preferred action"
35
- }],
32
+ "commands": [
33
+ {
34
+ "intent": "continue the selected flow",
35
+ "command": "<execute the exact next.command returned by the previous CLI envelope>",
36
+ "success_signal": "the next envelope reports one current state and at most one preferred action"
37
+ }
38
+ ],
36
39
  "agent_rules": [
37
40
  "Use the CLI as the control surface; infer the human's intent before the first command and never hardcode a service workflow.",
38
41
  "Treat result as current facts, instruction as how to use those facts, next as the preferred executable action, and recovery as exceptional paths.",
@@ -40,10 +43,10 @@
40
43
  "Keep the same explicit Agent Type through next and recovery commands; same-type windows reuse one Backend Agent Instance.",
41
44
  "When testing sandbox, execute every returned command unchanged so its ITPAY_BACKEND_URL=https://sandbox.itpay.ai prefix is preserved.",
42
45
  "Use --target only for a Host presentation destination. Put capability business values in --input key=value exactly as required by the schema.",
43
- "Start a separate Service Execution for each independent service intent; quota remains shared according to Backend identity policy.",
44
46
  "Ask the user for required email or contact values and explain their purpose; never invent them.",
45
47
  "Explain useful service facts in ordinary language; never ask the human to run commands or learn internal IDs.",
46
- "Normal payment uses the returned ItPay Checkout handoff."
48
+ "Normal payment uses the returned ItPay Checkout handoff.",
49
+ "A railway query execution and its separate booking execution may serve one purchase intent; keep both references."
47
50
  ],
48
51
  "forbidden": [
49
52
  "Do not invent catalog, variant, offer, capability, result item, order or refund IDs.",
@@ -51,6 +54,10 @@
51
54
  "Do not bypass a grant, refund lock, ownership error or compatibility gate."
52
55
  ],
53
56
  "next_docs": [
57
+ {
58
+ "condition": "Known railway request",
59
+ "topic": "rail-booking"
60
+ },
54
61
  {
55
62
  "condition": "Need service catalog language",
56
63
  "topic": "catalog-list"
@@ -4,115 +4,88 @@
4
4
  "product_scope": "itpay is the single public CLI entry point, and $itpay is its user-facing Skill invocation. Under that one product entry point, the two top-level commerce actions are buy and sell: Buyer workflows are available now; Seller workflows use the same entry point via itpay sell.",
5
5
  "topic": "rail-booking",
6
6
  "title": "Railway Query, Planning, and Ticket Booking",
7
- "purpose": "Choose the right railway service for the buyer's situation, submit the exact input contract each service expects, bridge a chosen train into booking via the server-issued selection, and follow the protected checkout flow without inventing field names.",
7
+ "purpose": "One railway route from understanding the request to saved results, booking, protected checkout, order status and refunds.",
8
8
  "when_to_use": [
9
- "The buyer wants train schedules, routes, or tickets.",
10
- "A railway service execution fails at the geo, search, catalog, or recommend step.",
11
- "The buyer only knows a city or fuzzy location rather than a station name.",
12
- "The buyer asks about seat preferences, refunds, or ticket issuance status.",
13
- "A query returned login_required or rate_limited."
9
+ "Any railway schedule, planning or ticket request; read this topic once before the first railway action."
14
10
  ],
15
- "service_selection": {
16
- "itpay-rail-exact": "Use when the buyer knows BOTH the exact departure and arrival railway station names (e.g. 古镇 → 广州南). It is one station-pair + one travel_date query: filter the returned list locally for remembered train numbers or time windows — do NOT re-query per train. Do NOT use it with only a city or fuzzy location.",
17
- "itpay-rail-smart": "Use when the buyer has a city name, an area, an address, or wants transfer planning and recommendations. The platform resolves locations to stations itself; never silently convert a city into its namesake station.",
18
- "itpay-rail-booking": "Purchase service — use ONLY after the buyer explicitly chose a train and seat from a query result. Starts quote → protected checkout → payment → asynchronous issuance on one execution. Never queried for schedules.",
19
- "svc_qizhidao_company_lookup": "Not a railway service; do not mix intents."
11
+ "goal_and_overview": {
12
+ "route": "Understand constraints → form a credible station-pair hypothesis → choose Exact or Smart → read saved results and select → create booking → obtain only missing human consent → show official entry → read the same order state.",
13
+ "query_vs_booking": "Exact/Smart returns a query execution and saved evidence. Booking creates a separate execution from a server-issued selection; it is not a repeated search.",
14
+ "comparison": "If the human only asked to compare, answer from the results and stop. A clear purchase delegation permits selection under their rules, subject to required human terms."
20
15
  },
21
- "input_contract": {
22
- "itpay-rail-exact": {
23
- "required": {
24
- "origin": "Departure railway station name only, e.g. 古镇. Not a city or an address.",
25
- "destination": "Arrival railway station name only, e.g. 广州南.",
26
- "travel_date": "Travel date in YYYY-MM-DD. The field name must be exactly travel_date; aliases like date are rejected."
27
- },
28
- "optional": "None. additionalProperties is false — extra fields are rejected by the provider.",
16
+ "flow_at_a_glance": [
17
+ { "step": "search Exact", "command": "itpay services run itpay-rail-exact --input-json <query-file> --json", "returns": "one station-pair query execution, resolved scope and either useful results or a same-execution wait action", "next": "follow the current next command when still working; compare results and stop if the request is satisfied" },
18
+ { "step": "search Smart", "command": "itpay services run itpay-rail-smart --input-json <query-file> --json", "returns": "one broader planning execution, observed coverage and either useful results or a same-execution wait action", "next": "follow the current next command when still working; compare results and stop if the request is satisfied" },
19
+ { "step": "read saved result", "command": "itpay services read-result <query_execution_id> --json (Exact), or --snapshot <snapshot_id> --json (Smart)", "returns": "saved rows with a stable detail.command for each train or journey", "next": "for a delegated purchase, run the chosen row's detail.command; do not resubmit the query" },
20
+ { "step": "book", "command": "itpay services run itpay-rail-booking --input-json <booking-file> --json", "returns": "a separate booking execution using the returned selection token, seat code and party size", "next": "follow its review or waiting action on that same booking execution" },
21
+ { "step": "review", "command": "itpay services next <booking_execution_id> --json", "returns": "current review revision, material terms and a non-executable confirm_booking input_template", "next": "submit the returned actor-type human template only after genuine consent; reuse an unchanged explicit consent for code-only correction" },
22
+ { "step": "checkout", "command": "use the returned next or handoff for the same booking execution", "returns": "an official protected payment entry", "next": "do not infer paid or issued from the handoff" },
23
+ { "step": "aftercare", "command": "itpay order <order_id> --json", "returns": "authoritative payment and ticket state", "next": "use orders-refunds for the same order when needed" }
24
+ ],
25
+ "understand_before_search": [
26
+ "Identify date, arrival deadline, party size, destination precision, speed versus broad coverage, and whether the human delegated buying.",
27
+ "Use existing knowledge or one brief official information lookup to form a credible station pair. It helps identify stations, not current trains, seats, prices or global optimality. Do not make external research mandatory.",
28
+ "For Shanghai to Changsha with a fast arrival before 15:00, Shanghai Hongqiao → Changsha South is a credible pair to verify first with Exact. State the intended scope in one sentence; do not re-ask the stated speed preference.",
29
+ "A city or district is an area, not necessarily the namesake station. Shanghai station and Shanghai city can look similar in text but have different scope."
30
+ ],
31
+ "choose_search": {
32
+ "exact": "Known or credible resolved station pair, direct trains for one station pair and date only. A zero result does not mean the whole city has no train. Another evidence-based pair may be checked under the original request.",
33
+ "smart": "Broad station comparison, transfers, uncertain places, or a concrete address with ground connections. Fastest does not automatically mean max_transfers=0.",
34
+ "scope": "Exact cannot claim a citywide or all-transfer optimum. Smart gives its observed scope and missing evidence; its first useful options may be shown before expansion finishes."
35
+ },
36
+ "input_and_expected_result": {
37
+ "exact": {
38
+ "command": "itpay services run itpay-rail-exact --input-json <query-file> --json",
29
39
  "example": {
30
- "origin": "古镇",
31
- "destination": "广州南",
32
- "travel_date": "2026-09-19"
33
- }
34
- },
35
- "itpay-rail-smart": {
36
- "required": {
37
- "origin": "Fullest known departure location: city, district, area, or address is all acceptable.",
38
- "destination": "Fullest known arrival location, same rule as origin.",
39
- "travel_date": "Travel date in YYYY-MM-DD. The field name must be exactly travel_date."
40
- },
41
- "optional": {
42
- "origin_city": "Departure city hint that helps location resolution.",
43
- "destination_city": "Arrival city hint.",
44
- "origin_location": "Known coordinate object (AMap GCJ-02).",
45
- "destination_location": "Destination coordinate object.",
46
- "depart_after": "Do not depart before this time.",
47
- "arrive_before": "Do not arrive after this time.",
48
- "priority": "One of balanced | fastest | cheapest | safest | flexible.",
49
- "max_transfers": "Integer 0-2, allowed transfer count.",
50
- "passengers": "Integer 1-5, default 1: adult passenger count reflected in per-leg inventory and amounts. NOT identity records.",
51
- "preference_context": "Bounded object, max 4 string-valued keys (<=200 chars each) of soft ranking preferences, e.g. {\"no_taxi\":\"true\"}. Validated allowlist; never carry passenger identity."
40
+ "origin": "上海虹桥",
41
+ "destination": "长沙南",
42
+ "travel_date": "2026-10-06"
52
43
  },
53
- "example": {
54
- "origin": "中山古镇",
55
- "destination": "广州南",
56
- "travel_date": "2026-09-19",
57
- "priority": "fastest"
58
- }
44
+ "contract": "Only origin, destination and travel_date are accepted. Use station names, not an undocumented station-code field. Filter time, seat and quantity against returned rows. Date is illustrative; use the actual requested queryable date."
59
45
  },
60
- "itpay-rail-booking": {
61
- "preferred": {
62
- "passengers": "Integer 1-5: number of passengers, NOT passenger identity records.",
63
- "selection": {
64
- "token": "The booking_offer.selection_token carried on the chosen result item.",
65
- "seat_type": "Seat code when the user picked a specific class, e.g. O."
66
- }
67
- },
68
- "explicit_legs": {
69
- "passengers": "Integer 1-5.",
70
- "legs": "Array with exactly ONE leg: from_station_code, to_station_code, travel_date, train_code, departure_time (HH:MM), arrival_time (HH:MM), arrival_days (int 0-7), seat_type. The public review accepts a single leg; only use when no booking_offer is available, and never guess these values. For v2 separate_legs_only journeys, book one leg at a time via that leg's own booking_offer — never a multi-leg basket."
46
+ "smart": {
47
+ "command": "itpay services run itpay-rail-smart --input-json <query-file> --json",
48
+ "example": {
49
+ "origin": "上海",
50
+ "destination": "长沙",
51
+ "travel_date": "2026-10-06",
52
+ "arrive_before": "15:00",
53
+ "priority": "fastest",
54
+ "passengers": 1
71
55
  },
72
- "boundary": "Identity fields (names, ID numbers, phones) never belong in this input; they are collected on the protected checkout page."
73
- }
56
+ "contract": "Origin/destination may be areas or precise places. Adult passengers is an integer 1–5. arrive_before maps to arrive_by; conflicting aliases are rejected. preference_context is currently unsupported; do not send it."
57
+ },
58
+ "result": "Read the resolved station pair or area scope, observed coverage, complete compact train rows, fare/inventory evidence and stable references. The recommendation card is not the full catalog. Unknown cost and unverified address ground facts remain unknown.",
59
+ "waiting": "A query run waits within a bound. To continue, use the same execution with itpay services next <execution_id> --timeout 120 --json; it is read-only. Do not sleep/get/events repeatedly or resubmit input.",
60
+ "followup": "Read the saved result for the original execution. Smart: itpay services read-result <execution_id> --snapshot <snapshot_id> --json. Exact: use its returned saved-result reader. Filter all existing rows before considering a new supplier query. Planning deadline does not erase saved facts; an old selection token is not refreshed by rereading."
74
61
  },
75
- "selection_flow": [
76
- "Exact results carry per-train candidates; smart results carry journeys. Bookable options carry booking_offer with a server-signed selection_token.",
77
- "The token binds the stored result snapshot and the chosen option. Submit it with passengers (and seat_type when the user picked a class); the server derives the authoritative legs and re-quotes live. Do NOT hand-build legs JSON from the visible result.",
78
- "An expired or foreign token returns a clear error; recover by running a fresh query or by explicit legs — never by guessing token contents.",
79
- "Repeating the same selection restores the same booking execution instead of creating a second one.",
80
- "v2 single-leg cards carry an opaque rsel_ selection_token bound to owner, execution, query revision, snapshot, journey/offer, policy and expiry; a stale or foreign token returns selection_stale — re-read the snapshot for a fresh offer instead of retrying.",
81
- "v2 separate_legs_only journeys never carry a whole-journey token: open the journey detail, pick one leg, and use that leg's owner-issued booking_offer; each leg is quoted and confirmed independently with no joint guarantee."
82
- ],
83
- "trial_and_login": {
84
- "policy": "itpay-rail-exact and itpay-rail-smart each allow 2 anonymous queries per enrolled device lineage — independent counters, not a shared pool of 4.",
85
- "login_required": "Trial for that service is exhausted. The query is paused BEFORE provider calls; the execution keeps its input. Offer itpay auth login; after binding, resume the SAME execution with services run --execution <id> (no input file). Do not start a new execution, do not make the user re-describe the trip, and do not burn the other service's quota to dodge the gate.",
86
- "rate_limited": "Registered accounts have no cumulative search cap but normal per-minute limits apply; wait retry_after_ms and resume the same execution.",
87
- "fourth_result": "The 4th result is delivered first; only the next new query requires authorization.",
88
- "purchase_after_trial": "Selecting a saved option and buying it does not consume search quota and works even when trial is exhausted."
62
+ "select_and_book": {
63
+ "delegation": "If the human delegated selection under clear rules, filter all eligible rows and pick accordingly. If no choice matches, report what was checked without loosening constraints. Never present a station-pair result as a global optimum.",
64
+ "input": "Use the returned booking_template selection token, passenger count and a seat_type code matched to seat_name (for example O may mean 二等座 in that returned offer). Never send the display name as the code or guess a code for another train.",
65
+ "command": "itpay services run itpay-rail-booking --input-json <booking-file> --json",
66
+ "single_leg": "Booking accepts one leg. Smart transfer options require separate leg purchases without a joint seat or connection guarantee; do not send a multi-leg basket.",
67
+ "identity": "Passenger name, ID and phone are entered on the official protected checkout page, not in query or booking JSON."
89
68
  },
90
- "flow": [
91
- "services start <service> --json returns input_required plus the guidance block for rail services.",
92
- "Submit input with services run <service> --execution <id> --input-json <file> --json on the SAME execution.",
93
- "itpay-rail-smart may stop at a location confirmation step; show the candidate places to the buyer, then continue the same execution after the human confirms.",
94
- "After the buyer explicitly picks a train/seat, run itpay-rail-booking with the selection token (preferred) or explicit legs. The execution then pauses at the booking review (workflow:confirm_booking): services next returns booking_review_required with human_action.context.review carrying draft_revision, legs, seat_options and notice_version.",
95
- "Whether or not the query was free, the answer is the same shape under compare: one preferred option, at most two meaningful alternatives, the key trade-offs — then stop and wait for the buyer. Do not stack more options or chain into purchase.",
96
- "Collect the review input and submit it with services action <id> --action workflow:confirm_booking --actor-type human --status approved --input-json <file> --json. Required fields: draft_revision (exact server value), passengers, seat_type, seat_preferences (one entry per passenger_index 0..n-1, values limited to that leg's seat_options), party_preference, fallback=automatic_assignment, notice_version, accept_non_guaranteed=true. Only after an accepted review does the server quote and offer checkout.",
97
- "The booking execution reaches a protected checkout: passenger identity data is entered by the human on that page, never through the CLI. Account authentication may happen inside checkout — do not force a separate auth login first (Path B).",
98
- "Payment success does not mean the ticket is issued. Issuance is asynchronous; keep reading the same execution with services next.",
99
- "If seat details are still syncing after issuance, advise the buyer to verify the itinerary on 12306 instead of repeating the query."
100
- ],
101
- "failure_handling": {
102
- "failed_step": "The CLI reports failed_step and failed_step_meaning in the result when a workflow fails.",
103
- "geo": "Location resolution failed: check origin/destination are real place names, or attach origin_city/coordinate hints, then start a NEW execution (a failed execution is terminal).",
104
- "search": "Supplier query failed: most commonly a wrong field name (must be travel_date) or a nonexistent station name; recheck input against this doc.",
105
- "catalog_or_recommend": "Location resolved but no feasible trains: change the date or stations.",
106
- "login_required_is_not_failure": "login_required / rate_limited pause the execution; they are NOT failures and never justify a replacement execution.",
107
- "general_rule": "Never replay a failed execution and never guess different field names; correct the input and start a new execution of the same service.",
108
- "booking_review_changed": "The submitted draft_revision is stale: re-read services next for the current review projection and resubmit the full input; do not bump the revision yourself.",
109
- "plan_conflict": "409: the action_request_id/expected_query_revision/snapshot_id no longer matches owner state. Re-read services next and reuse the fresh action handle; an identical replay of an accepted action still returns its original acceptance.",
110
- "stale_cursor": "The paging cursor was minted against an older snapshot; restart paging from the current snapshot_id.",
111
- "snapshot_not_found": "Unknown or superseded snapshot id; read the current projection for the latest snapshot.",
112
- "journey_not_in_snapshot": "The rj_ reference is not inside the saved snapshot; pick a journey from the current page/projection.",
113
- "plan_expired": "The 15-minute plan lifecycle ended: expansion stopped and the snapshot is read-only evidence; start a new execution for a fresh search. In-flight checkout/payment is unaffected.",
114
- "action_request_invalid": "The action payload failed validation (unknown patch fields, malformed handle); copy the command from available_actions instead of composing it.",
115
- "selection_stale": "The rsel_ token no longer matches the current snapshot/policy; re-read the journey and take the fresh booking_offer."
69
+ "review_and_checkout": {
70
+ "review": "Read the current booking review revision, actual train/date/stations, seat code and name, party, price state and notice terms. Submit workflow:confirm_booking with actor-type human only after real human consent to required terms, including seat assignment not guaranteed. Do not forge a human actor from agent delegation.",
71
+ "equivalent_correction": "If only seat code spelling changes while train, actual seat class, party, price and terms are identical, reuse an existing explicit human approval. Material draft changes or missing approval require human confirmation.",
72
+ "checkout": "Show the returned safe itinerary summary and official link/QR supported by the actual host. Do not repeat a price approval already valid for unchanged terms. The human completes identity and payment on that page. Handoff is not payment or ticket issuance."
73
+ },
74
+ "continue_and_aftercare": {
75
+ "same_execution": "Wait and read the same query or booking execution. Once an order exists, use itpay order <order_id> --json for its authoritative state. Paid can still be issuing; report issued only when confirmed.",
76
+ "saved_vs_live": "A saved snapshot remains historical evidence after expiry. Real-time booking or quote credentials may expire and require the documented fresh validation path; rereading an old token does not renew it.",
77
+ "refund": "Read itpay docs show orders-refunds --json and the current order policy. Railway supplier cancellation/return and platform refund have separate facts; a refund request is not completed railway return."
78
+ },
79
+ "exceptional_branches": {
80
+ "login_required": "Use itpay auth login --json, complete the official handoff, then execute the returned recovery command for the same paused query. Login returning a command does not execute it.",
81
+ "rate_limited": "Respect returned retry_after and continue the same execution.",
82
+ "booking_review_invalid": "Read the same booking review and use the returned seat code; reuse real consent only under the strict equivalent-correction rule.",
83
+ "booking_review_changed": "Read the current revision and compare material terms; confirm new terms only when changed.",
84
+ "selection_stale": "Saved result stays readable, but follow the current owner action for new live inventory and quote evidence; do not assume reread refreshes the token.",
85
+ "unknown_paid_outcome": "Read the same checkout/order before any mutation. Never repeat payment or create a new order on an unknown outcome.",
86
+ "lock": "Use the CLI returned device repair-lock recovery only for a lock proven stale; preserve active owners and identity.",
87
+ "empty": "Report verified scope, failures and missing evidence separately. Do not guess a new date or station as a generic repair.",
88
+ "ground_evidence_required": "If trains were found but a precise address deadline cannot be verified without ground or station-exit evidence, report the checked rail scope and missing fact. Ask for a precise location or verifiable connection fact; do not expand rail station pairs by default or call it no trains."
116
89
  },
117
90
  "seat_preferences": {
118
91
  "meaning": "A buyer's seat-letter preference may be planned per leg before payment. The plan is submitted to the supplier when encodable; unsupported combinations fall back to automatic assignment.",
@@ -121,44 +94,11 @@
121
94
  "review_contract": "Submitted inside the confirm_booking action via --input-json (nested JSON; --input key=value cannot express it and must not be combined with it). One preference per passenger slot, passenger_index 0-based. draft_revision must equal the server projection; a stale revision returns booking_review_changed — re-read services next and resubmit, never increment locally.",
122
95
  "revision": "While payment has not started, the same execution accepts a revised review: resubmit confirm_booking with the new draft_revision; the old unpaid quote/checkout is retired and re-quoted. After a payment attempt the review is closed — never create a replacement purchase."
123
96
  },
124
- "agent_rules": [
125
- "Pick the service by the buyer's input precision: exact station names → itpay-rail-exact; anything fuzzier → itpay-rail-smart; explicit purchase intent after a selection → itpay-rail-booking.",
126
- "Choose the goal first (see goals): compare presents one preferred option plus at most two meaningful alternatives then waits; prepare_checkout selects under the buyer's rules and continues to the official confirmation entry without re-asking.",
127
- "Never invent input field names. If the guidance block or this doc does not list a field, do not send it.",
128
- "Never ask the buyer for passenger names, ID numbers, or phone numbers in chat; those are collected only on the protected checkout page.",
129
- "Never reconstruct provider-shaped legs JSON when a booking_offer.selection_token is available; submit the token plus passengers.",
130
- "Seat preferences are requests, not guarantees: always repeat the notice that automatic assignment remains possible, and never claim a specific seat before the issued order shows it.",
131
- "Take draft_revision only from the current services next review projection; on booking_review_changed re-read instead of retrying the stale value.",
132
- "login_required and rate_limited are pauses, not failures: resume the same execution, never spawn a replacement.",
133
- "Do not repeat or replay a failed execution; correct the input and start a new one.",
134
- "Do not claim payment equals ticket issuance; issuance is asynchronous and confirmed only by the issued seat status.",
135
- "For v2 plans, act only on available_actions[] from the current projection: run the exact command the backend returned, then re-read; never invent action types, request ids, revisions or fields.",
136
- "expand_search is the only intent that may spend provider budget; refine_preferences re-ranks saved data first and does not by itself expand.",
137
- "A paused/expired/complete plan is still readable and selectable from its saved snapshot; never start a replacement execution to keep polling.",
138
- "stop_search pauses scheduling but keeps saved data and existing selections; booking stays reachable only through the allowed actions the owner reports.",
139
- "When since_snapshot returns result_not_updated, keep the previous snapshot and still surface the latest expansion status/end reason to the user."
140
- ],
141
- "human_language": {
142
- "prefer": [
143
- "车次",
144
- "出发站",
145
- "到达站",
146
- "出行日期",
147
- "座位",
148
- "余票",
149
- "出票中",
150
- "已出票",
151
- "登录后继续免费查询"
152
- ],
153
- "avoid": [
154
- "workflow",
155
- "execution",
156
- "provider",
157
- "seat_source",
158
- "candidate_id",
159
- "token",
160
- "quota"
161
- ]
97
+ "notifications": {
98
+ "channels": "Delivery notices reach the checkout-confirmed contact: email always works; a verified mainland SMS recipient is optional and checkout-scoped. The passenger phone, the login phone and the notification recipient are independent facts.",
99
+ "status_read": "The order read exposes masked per-leg notification entries (keys: issued, details_pending, seat_ready) with channel, status and masked recipient — never raw numbers.",
100
+ "truthfulness": "Provider acceptance is not delivery; an uncertain send outcome is reconciled, not silently retried. A notification failure never changes ticket or refund state; report it as a delivery detail, not an order failure.",
101
+ "unavailable": "If SMS is not configured or a recipient is unverified, email still satisfies the contact policy — never present an unverified phone as enabled."
162
102
  },
163
103
  "search_terms": [
164
104
  "rail",
@@ -173,33 +113,5 @@
173
113
  "seat",
174
114
  "booking",
175
115
  "rail-booking"
176
- ],
177
- "notifications": {
178
- "channels": "Delivery notices reach the checkout-confirmed contact: email always works; a verified mainland SMS recipient is optional and checkout-scoped. The passenger phone, the login phone and the notification recipient are independent facts.",
179
- "status_read": "The order read exposes masked per-leg notification entries (keys: issued, details_pending, seat_ready) with channel, status and masked recipient — never raw numbers.",
180
- "truthfulness": "Provider acceptance is not delivery; an uncertain send outcome is reconciled, not silently retried. A notification failure never changes ticket or refund state; report it as a delivery detail, not an order failure.",
181
- "unavailable": "If SMS is not configured or a recipient is unverified, email still satisfies the contact policy — never present an unverified phone as enabled."
182
- },
183
- "progressive_v2": {
184
- "capability": "New CLI declares client_context.features=[\"rail.progressive.v2\"] at service start. It is a response-format declaration only; quota, service version and provider credentials stay server-decided. Old clients keep the legacy projection; never create a second execution to probe.",
185
- "read_model": "While the plan workflow is active, services next carries rail_planning: schema_version, plan_id (jp_), query_revision, snapshot_id (rps_), readiness, expansion {status, reason, poll_after_ms, new_results_guaranteed}, coverage, budgets, recommendation + up to 4 alternatives (journey cards rj_), available_actions with concrete commands, result_item_id.",
186
- "expansion_states": "queued/running: automatic work remains; paused: batch sufficient or auto window ended, expand only on explicit intent; complete/cancelled: budget or frontier exhausted — snapshot stays read-only, expand action absent; failed: reason visible after a published snapshot, readiness stays ready; expired: 15-minute lifecycle end — evidence read-only, in-flight purchase unaffected.",
187
- "reads": "services next --since-snapshot <rps_…> suppresses the journey payload but always returns the latest expansion status. read-result gains --snapshot, --journey <rj_…> and an opaque --cursor bound to snapshot+filter+sort (stale -> stale_cursor). Reads never call the provider, never extend lifecycle, never invoke the model.",
188
- "actions": "Three allowlisted planning actions ride POST actions with action_type workflow:expand_search | workflow:refine_preferences | workflow:stop_search. input_snapshot carries server-issued action_request_id plus expected_query_revision and snapshot_id; refine adds a validated preference_patch. Always copy the concrete command from available_actions[]; never assemble fields. Same id + same payload returns the stored acceptance; same id + different payload -> plan_conflict.",
189
- "journey_card": "Cards carry station names, train codes, dated times, transfer/same-run notes, observed_at price time and handles. representative_offer.ticket_offers[] lists one purchasable segment per entry (leg_index, offer_id, service_ref, station codes, travel_date, seat_type, passengers, integer-minor amounts); per-item amounts sum to the total. rides[] (ridden legs) and ticket_offers[] (purchasable segments) are different lists — never infer transfers or fees from array lengths.",
190
- "selection": "booking_support=single_leg cards carry booking_offer {service_id: itpay-rail-booking, selection_token: rsel_…}; submit it to itpay-rail-booking with passengers as today. separate_legs_only cards expose no whole-journey token — each leg is quoted and confirmed separately via its protected detail; never assemble legs JSON yourself. booking_support=none has no selection action.",
191
- "honesty": "Coverage is bounded: repeat searched_scope/notices verbatim, never claim national-exhaustive search, and surface missing prices as unknown — never 0."
192
- },
193
- "goals": {
194
- "compare": "Buyer wants to see options and keeps the final choice. Present one preferred option plus at most two meaningful alternatives, then wait. A fully-specified query with no purchase delegation stays compare.",
195
- "prepare_checkout": "Buyer named the product, or delegated selection under explicit rules and asked for the purchase entry. Select under those rules, explain the match, and continue to the official confirmation/payment entry without re-asking '要不要买'. Clear delegation missing only the date asks for the date alone.",
196
- "boundaries": [
197
- "Decide locally from the whole conversation (negations, conditions, references, latest withdrawal); no trigger-word lists, no regex, no field-completeness classifier, no mode flag, never ask the human to name a mode.",
198
- "Explicit buyer rules outrank default recommendations; missing facts are unknown, never assumed satisfied.",
199
- "compare must not continue into selection; prepare_checkout must not silently downgrade to waiting.",
200
- "A pending/login/error state is never new intent; withdrawal updates the goal but never rewrites a completed payment.",
201
- "Neither goal authorizes payment or skips confirmation: payment, terms and passenger identity stay behind their own gates."
202
- ],
203
- "recipe": "For the query→booking→review→checkout continuity after a valid selection, load the rail-fast-checkout topic (itpay docs show rail-fast-checkout --json)."
204
- }
116
+ ]
205
117
  }
@@ -3,65 +3,43 @@
3
3
  "role": "buyer_agent",
4
4
  "product_scope": "itpay_rail",
5
5
  "topic": "rail-fast-checkout",
6
- "title": "Rail Fast Checkout — One Human Question, Owners Do The Rest",
7
- "purpose": "After the buyer has picked a train/seat (prepare_checkout delegation), carry one valid selection through booking review, protected checkout and issuance tracking with a single consolidated human interaction — using only existing commands and owner-issued handles.",
6
+ "title": "Rail Fast Checkout — Delegated Purchase Supplement",
7
+ "purpose": "Short delegated-purchase supplement to rail-booking; host presentation differences only.",
8
8
  "when_to_use": [
9
- "The buyer explicitly picked a train/seat or delegated selection under rules, and you hold a bookable option with booking_offer.selection_token from itpay-rail-exact or itpay-rail-smart.",
10
- "Do NOT use for a plain schedule query (compare goal) — present one preferred option plus up to two alternatives and wait instead."
9
+ "The buyer delegated railway selection and a current bookable result is available. Read rail-booking first."
11
10
  ],
12
11
  "steps": [
13
12
  {
14
- "step": "create_booking_input",
15
- "command": "printf '%s' '{\"passengers\":1,\"selection\":{\"token\":\"<token>\"}}' > /tmp/itpay-booking-input.json",
13
+ "step": "read_full_flow",
14
+ "command": "Use the rail-booking guide already read for this request",
16
15
  "notes": [
17
- "Fill <token> with the current result's booking_offer.selection_token; add selection.seat_type when the buyer picked a class. Create the file yourself under /tmp — the buyer never sees a path.",
18
- "Never reconstruct legs JSON when a token is available; the owner derives authoritative legs and re-quotes live."
16
+ "Use the current query result and booking_template; this topic does not replace the railway guide."
19
17
  ]
20
18
  },
21
19
  {
22
- "step": "start_booking",
23
- "command": "itpay services run itpay-rail-booking --input-json /tmp/itpay-booking-input.json --json",
24
- "then": "itpay services next <execution_id> --json",
25
- "expected_status": "booking_review_required"
26
- },
27
- {
28
- "step": "one_consolidated_review",
29
- "read": "human_action.context.review carries legs, seat_options, draft_revision and notice_version.",
30
- "ask_human_once": "Show the itinerary, seat options and the seat-preference disclaimer in one message; collect passengers count, seat_type, one seat preference per passenger slot, party_preference, and agreement to the notice_version terms.",
31
- "web_review": "If the review projection carries an official web entry (handoff.url in the envelope), prefer it: open it for the buyer and wait there; the chat fallback remains valid if the page is unavailable.",
32
- "submit": "itpay services action <execution_id> --action workflow:confirm_booking --actor-type human --status approved --input-json /tmp/itpay-review.json --json",
33
- "notes": [
34
- "draft_revision must equal the current server value; booking_review_changed means re-read services next and resubmit, never bump locally.",
35
- "accept_non_guaranteed is true only when the buyer actually agreed; never fabricate a human approval.",
36
- "Passenger names, ID numbers and phones are NOT in this input — they belong to the protected checkout page."
37
- ]
38
- },
39
- {
40
- "step": "checkout_handoff",
41
- "read": "services next returns checkout_required/payment_pending with handoff.url (the protected checkout page).",
42
- "command": "itpay checkout --id <checkout_id> --token <display_token> --present auto --json",
20
+ "step": "continue_delegated_booking",
21
+ "command": "Use the current result’s booking_template and returned next action",
43
22
  "notes": [
44
- "Show or open the checkout exactly once; pass --viewer mobile when the buyer is on a phone.",
45
- "The buyer completes identity and payment on that page (Path B — no forced separate login). Payment handoff is not payment success; wallet return is not confirmation."
23
+ "Select under the buyer’s unchanged rules. Required human terms still require real consent. Continue the same booking execution."
46
24
  ]
47
25
  },
48
26
  {
49
- "step": "track_issuance",
50
- "command": "itpay services next <execution_id> --json",
51
- "then": "itpay orders show <order_id> --json",
52
- "expected_status": ["paid_pending_issuance", "issued"],
27
+ "step": "present_host_handoff",
28
+ "command": "Use the current Host handoff",
53
29
  "notes": [
54
- "Issuance is asynchronous — paid does not mean ticketed. Keep reading the SAME execution; never create a replacement.",
55
- "On issued, report the order state; if seat details are still syncing, advise checking 12306 instead of re-querying."
30
+ "Show only the supported official entry. Read itpay order <order_id> --json after payment for authoritative status; issuing is not issued."
56
31
  ]
57
32
  }
58
33
  ],
59
34
  "never": [
60
- "Never build legs JSON from visible result fields while a selection_token exists.",
61
- "Never run a second services run for the same selection — repeat submission restores the same execution.",
62
- "Never ask for passenger identity, verification codes, or payment details in chat.",
63
- "Never claim payment equals issuance, or a displayed handoff equals human approval.",
64
- "Never invent command flags, action types, revisions or tokens; copy server-issued handles verbatim."
35
+ "Never invent consent, identity or a seat code.",
36
+ "Never duplicate a purchase or repeat an unknown-outcome payment.",
37
+ "Never show an internal command to the human."
65
38
  ],
66
- "search_terms": ["fast checkout", "快速下单", "一键购票", "rail checkout recipe"]
39
+ "search_terms": [
40
+ "fast checkout",
41
+ "快速下单",
42
+ "一键购票",
43
+ "rail checkout recipe"
44
+ ]
67
45
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schema_version": "itp.agent_doc.v1",
3
3
  "role": "buyer",
4
- "product_scope": "itpay is the single public CLI entry point, and $itpay is its user-facing Skill invocation. Under that one product entry point, the two top-level commerce actions are buy and sell: Buyer workflows are available now; Seller workflows will use the same entry point and are not implemented yet.",
4
+ "product_scope": "itpay is the single public CLI entry point for Buyer services and the existing itpay sell Seller workflow; $itpay is its user-facing Skill invocation.",
5
5
  "topic": "render-hosts",
6
6
  "title": "Agent Type And Human Handoff Rendering",
7
7
  "purpose": "Use only the handoff fields returned for the current Agent Type and make Checkout or read authorization genuinely visible on that surface.",
@@ -54,7 +54,9 @@
54
54
  "agent_type": "openclaw",
55
55
  "default_host": null,
56
56
  "host_required": true,
57
- "native_hosts": ["telegram"],
57
+ "native_hosts": [
58
+ "telegram"
59
+ ],
58
60
  "responsibility": "pass the native OpenClaw entry target explicitly; for Telegram execute handoff.agent_action unchanged, then treat itp:grant_confirmed callbacks only as permission to query the same Checkout and follow Backend grant state; otherwise show the returned HTTPS QR image and Checkout URL"
59
61
  }
60
62
  ],
@@ -72,15 +74,16 @@
72
74
  ],
73
75
  "agent_rules": [
74
76
  "Agent Type is stable identity; Host is presentation and may be explicitly overridden.",
75
- "A local QR path is not visible until a desktop Agent attaches or renders that file on the human-facing surface; WorkBuddy never receives a local QR path.",
77
+ "A local QR path is not visible until a desktop Agent attaches or renders that file on the human-facing surface; WorkBuddy Checkout handoff uses its returned Card Link and mobile URL; auth login may separately return a local QR path.",
76
78
  "For workbuddy with plain-chat, execute handoff.agent_action exactly once; it calls present_files with handoff.url as the only files element and opens the rendered Card Link in the right-side browser, then send handoff.mobile_url so phone users can tap straight into Alipay or WeChat Pay.",
77
79
  "For zcode with plain-chat, open handoff.url in the built-in browser and also send handoff.mobile_url as the phone entry; do not only paste text, download or rebuild a QR, or invent a private browser-tool payload; when the built-in browser is unavailable show both clickable links.",
78
80
  "For doubao-work with plain-chat, show two labeled official links: handoff.mobile_url for direct same-phone opening and handoff.qr_image_url for saving or scanning on another device; do not parse credentials, download or rebuild the QR, or create an alternative resource.",
79
81
  "If the WorkBuddy action fails, send the original handoff.url and handoff.mobile_url, report that it did not auto-open, and stop without creating another payment resource.",
80
82
  "handoff.mobile_url is the phone-friendly Checkout URL; when the current client cannot open links in place (for example a mobile mini program), send it and tell the human to copy it into the phone browser where it can jump into Alipay or WeChat Pay. It is only returned when the handoff carries the complete token pair; when absent, handoff.url remains the entry.",
81
- "Do not claim the handoff was shown until both a usable payment image or QR and the Checkout URL are visible.",
83
+ "Do not claim a handoff was shown until the official entry supported by this Host is genuinely visible. A link-only Host does not require a QR.",
82
84
  "IM Hosts that require a target must receive --target before Checkout creation. OpenClaw has no default Host; Kimi Code uses terminal.",
83
- "OpenClaw Telegram uses flat url/value buttons for deployed-version compatibility. A grant_confirmed callback carries only the Checkout ID, never a display token, and never proves payment or an active grant."
85
+ "OpenClaw Telegram uses flat url/value buttons for deployed-version compatibility. A grant_confirmed callback carries only the Checkout ID, never a display token, and never proves payment or an active grant.",
86
+ "Business flow is the same across hosts. Vault grants apply only to protected purchased-content access, not every railway step."
84
87
  ],
85
88
  "forbidden": [
86
89
  "Do not expose display tokens separately from the tokenized Checkout handoff.",