StepFun logo

Step 3.5 Flash

StepCurrent
byStepFunStepFun(ai lab)
Released January 29, 2026
Context262.1K tokens
Price (In / Out)$0.10/M / $0.30/M
CategoryLarge Language Model
Max Output65.5K tokens

About Step 3.5 Flash

Step 3.5 Flash is a large language model from StepFun. Supports up to 262,144 token context window. Available from $0.10/M input tokens.

Capabilities

textcode

Input Modalities

text

Output Modalities

text

Technical Details

API Identifier
stepfun/step-3.5-flash
Category
Large Language Model
Context Window
262,144 tokens
Max Output Tokens
65,536 tokens

Tags

budget-friendlylong-context

Run this model yourself

Local and cloud setup for Step 3.5 Flash, with exact configurations, sources and clear evidence limits.

Find a model for your hardware
Local hardwareDocumented setupSources checked Oct 17, 2026

Host full native Step 3.5 Flash reasoning and tools on an owned eight-H100 server

Serve the complete BF16 Step 3.5 Flash checkpoint, all experts and three MTP layers through a released native GPU runtime. Exact publisher template and Step reasoning/XML-tool parsers preserve the model-specific protocol. A bounded8192-context/4096-output two-turn inert-tool check records completion boundaries, not task quality. Eight H100 80 GB GPUs and 2048 GiB host RAM are planning allocations, not measured fit.

Hardware
Existing eight-H100 80 GB GPU server
Runtime
Released native Step3.5 Flash BF16 with three-layer MTP on vLLM vLLM 0.27.1 commit 6e448d0; exact official Linux amd64 image digest, reader preflight required · CUDA
Model format
Native HF sharded safetensors · Complete native BF16 weights, including every expert and MTP layers 45,46,47 · Unquantized native BF16; complete experts and all MTP tensors retained
Workload
8,192 token context · 1 concurrent

Based on source documentation; this setup has not been executed by OpenTools. Memory: unknown. No compatible measurement available.

Read the complete setup guide

Before you start

  • Use an existing dedicated Ubuntu 24.04 x86_64 server with eight working H100 80 GB GPUs, driver >=580.126.20, Docker and NVIDIA Container Toolkit. Reader GPU collective topology must support tensor-parallel8; exact owned hardware cost and performance are unknown.
  • Choose 2048 GiB host RAM,768 GiB disk and192 CPU threads. Require 600 GiB free disk before download. These are prescribed allocations, not minima or measured fit. All 44 weight parts, all experts and all three MTP layers remain required.
  • Review the full Apache 2.0 license and native repository terms/third-party rights. No terms acceptance, provisioning, model download or native execution was performed by the author.
  • Use 8192 total context and 4096 output cap per turn only as a bounded protocol walkthrough. Native config 262144 and tokenizer metadata131072 are retained as distinct evidence; no maximum-context fit or provider API byte identity is asserted.

Exact model and requirements

Artifact:
StepFun / Full native Step 3.5 Flash BF16 with three MTP layers · checkpoint stepfun-ai/Step-3.5-Flash
Publisher revision:
ab446a3de5e171ea341227e24bb1f090e1b771f7
Artifact digest:
Whole-composition digest not published. All 44 weight parts have exact native LFS SHA256 and sizes; nine auxiliary files use native Git blob SHA1 metadata and sizes in immutable manifest.
Download size:
371.38 GiB
Memory requirement (unknown):
Unknown — No measured per-device or whole-process peak for full BF16/MTP3 on eight H100s at8192 context.
System RAM / disk:
Unknown / Unknown
Placement:
supported sharding. Eight-way tensor parallelism plus expert parallelism; all target/expert/MTP weights retained, no aggregate-fit inference. All target and three MTP layers are sharded on eight GPUs; no CPU or disk weight offload. Host loading buffers and every target/draft cache remain additional and unmeasured.
KV cache:
BF16 attention KV across native full and sliding GQA groups; no Mamba or compressed KV substitution
Workload:
8,192 token context; Unknown; Unknown; concurrency 1; batch 1; cache cold; repetitions Unknown.
Tokenizer:
Exact native Step tokenizer and 5004-byte publisher Jinja · ab446a3de5e171ea341227e24bb1f090e1b771f7
Sampling / reasoning:
Publisher reasoning/agent recommendation temperature 1.0 and top_p 0.95; n=1 and nonstreaming. Raw generated token IDs and native EOS IDs 1/2/128007 are checked. Native template starts assistant thinking. Require raw closing-think 128799 and tool-call 128008/128009 delimiters on first turn, native non-length completion and nonempty final answer. Retain reasoning_content, tool call and inert result exactly; publisher template itself defines which history is rendered. This 8192/4096 demonstration is not the publisher full reasoning budget.
Runtime prerequisites:
Ubuntu 24.04 x86_64 host; pinned Ubuntu 22.04 / Python 3.12 source defaults container; NVIDIA Linux driver >=580.126.20, Working Docker GPU support with NVIDIA Container Toolkit; actual visibility preflight required.

Official artifact · License

Publisher native model card expressly grants Apache License 2.0; full linked license is archived. Review all conditions and applicable third-party rights. Preserve license and relevant notices on redistribution and state changes; patent termination and warranty/liability exclusions apply. No license acceptance or legal clearance is performed here.

  • 398,768,720,200 serialized weight bytes are retained in full. Nominal 196B and 11B active do not mean=11B resident weights; metadata reports 199,384,301,376 scalar parameters including auxiliary tensors.
  • Each GPU advertises80 GB; exact usable bytes, sharding balance, MTP buffers, attention KV, workspace and host loading overhead are unmeasured. Eight times advertised capacity is not a measured-fit guarantee.

One-time setup and hardware

hardware
Unknown — Existing owned GPU/host purchase and incremental cost are unknown.
Existing owned GPU/host purchase and incremental cost are unknown. Tax: unknown.
setup
Unknown — Reader setup and labor cost is unknown.
Reader setup, runtime pull and labor costs are unknown. Tax: unknown.

Recurring costs

electricity
Unknown — Actual wall power/rate/poweredhours unknown; no GPU TDP conversion.
Actual wall power/rate/poweredhours unknown; no GPU TDP conversion. Tax: unknown.
storage
Unknown — Incremental owned 768 GiB storage costs are unknown.
Incremental owned 768 GiB storage costs are unknown. Tax: unknown.
egress
Unknown — Actual transfer/allowance/traffic cost unknown.
Actual transfer/allowance/traffic cost unknown. Tax: unknown.
administration
Unknown — Maintenance time/rate unknown.
Maintenance time/rate unknown. Tax: unknown.

Install the runtime

  1. 1. Prepare an existing GPU host and private workspace

    Prepare the already provisioned dedicated eight-H100 Ubuntu 24.04 host with working NVIDIA driver >=580.126.20. Install host utilities and Docker; this guide does not install or claim compatibility of an arbitrary GPU driver. Record actual hardware and stop on any prerequisite failure.

    Command
    set -eu
    sudo apt-get update
    sudo apt-get install -y docker.io python3 curl ca-certificates openssl
    sudo systemctl enable --now docker
    mkdir -p "$HOME/step35-flash"
    cd "$HOME/step35-flash"
    nvidia-smi --query-gpu=name,memory.total,driver_version --format=csv,noheader
    python3 - <<'PYPREFLIGHT'
    import csv,subprocess,shutil
    r=list(csv.reader(subprocess.check_output(["nvidia-smi","--query-gpu=name,memory.total,driver_version","--format=csv,noheader,nounits"],text=True).splitlines()))
    assert len(r)==8 and all("H100" in x[0] and "80GB" in x[0].replace(" ","") for x in r)
    assert all(tuple(map(int,x[2].strip().split("."))) >= (580,126,20) for x in r)
    assert shutil.disk_usage(".").free >=600*1024**3
    print("Reader GPU/driver and prescribed600GiB free-disk preflight passed; no model fit measured.")
    PYPREFLIGHT
    sudo docker version

    Expected result: All eight H100 cards and required driver are visible, with prescribed host RAM/disk and free space recorded. Capacity is planning, not measured fit.

  2. 2. Configure NVIDIA GPU containers on this dedicated host

    Use the official production repository and exact documented Container Toolkit 1.20.1-1 packages. This modifies Docker daemon configuration and restarts Docker on this dedicated host; preserve its original configuration and do not apply on a shared production daemon without its owner review. Stop on repository/signature/package errors.

    Command
    set -euo pipefail
    sudo apt-get install -y gnupg2
    curl --fail --silent --show-error --location https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --batch --yes --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
    curl --fail --silent --show-error --location https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list >/dev/null
    sudo apt-get update
    sudo apt-get install -y nvidia-container-toolkit=1.20.1-1 nvidia-container-toolkit-base=1.20.1-1 libnvidia-container-tools=1.20.1-1 libnvidia-container1=1.20.1-1
    sudo nvidia-ctk runtime configure --runtime=docker
    sudo systemctl restart docker

    Expected result: The exact GPU container packages install and Docker is configured. The subsequent container nvidia-smi check must pass; this is not model inference or fit proof.

Download the model

  1. 1. Write pinned manifest block 1 of 4

    Keep every block in this order. These are exact metadata bytes only; the final block reconstructs the immutable53-entry manifest. No model body is embedded.

    Command
    set -eu
    cd "$HOME/step35-flash"
    cat > assets.b64 <<'ASSETBLOCK'
    eyJyZXBvc2l0b3J5Ijoic3RlcGZ1bi1haS9TdGVwLTMuNS1GbGFzaCIsInJldmlzaW9uIjoiYWI0NDZhM2RlNWUxNzFlYTM0MTIyN2UyNGJiMWYwOTBlMWI3NzFmNyIsImZpbGVzIjpbeyJwYXRoIjoiUkVBRE1FLm1kIiwiYnl0ZXMiOjI2MjQxLCJzaGEyNTYiOm51bGwsImdpdEJsb2JTaGExIjoiMzFjZWI5ZDg1YTg4MGFlNDAwODYzMTg0NzQwZTEzNDQ2YTg5OGY4NSIsInVybCI6Imh0dHBzOi8vaHVnZ2luZ2ZhY2UuY28vc3RlcGZ1bi1haS9TdGVwLTMuNS1GbGFzaC9yZXNvbHZlL2FiNDQ2YTNkZTVlMTcxZWEzNDEyMjdlMjRiYjFmMDkwZTFiNzcxZjcvUkVBRE1FLm1kIn0seyJwYXRoIjoiY2hhdF90ZW1wbGF0ZS5qaW5qYSIsImJ5dGVzIjo1MDA0LCJzaGEyNTYiOm51bGwsImdpdEJsb2JTaGExIjoiYzA5ZWE0OTdkYWRhNmZlMmMxZjk0MDY3YjQ3NjJkY2JhMTkzYzBmMCIsInVybCI6Imh0dHBzOi8vaHVnZ2luZ2ZhY2UuY28vc3RlcGZ1bi1haS9TdGVwLTMuNS1GbGFzaC9yZXNvbHZlL2FiNDQ2YTNkZTVlMTcxZWEzNDEyMjdlMjRiYjFmMDkwZTFiNzcxZjcvY2hhdF90ZW1wbGF0ZS5qaW5qYSJ9LHsicGF0aCI6ImNvbmZpZy5qc29uIiwiYnl0ZXMiOjQ5MzAsInNoYTI1NiI6bnVsbCwiZ2l0QmxvYlNoYTEiOiJmZmM0ZDcyNDUxMDA5NmFjNDkwYmIxMjg0MDIxMjc2MGYzMmJhZTE2IiwidXJsIjoiaHR0cHM6Ly9odWdnaW5nZmFjZS5jby9zdGVwZnVuLWFpL1N0ZXAtMy41LUZsYXNoL3Jlc29sdmUvYWI0NDZhM2RlNWUxNzFlYTM0MTIyN2UyNGJiMWYwOTBlMWI3NzFmNy9jb25maWcuanNvbiJ9LHsicGF0aCI6ImNvbmZpZ3VyYXRpb25fc3RlcDNwNS5weSIsImJ5dGVzIjoyMjg1LCJzaGEyNTYiOm51bGwsImdpdEJsb2JTaGExIjoiYWI4ZDA2OGVlODNjMjVkYzBmYjJiMGEyYmQyY2E3NmJkYzlmYWFjOSIsInVybCI6Imh0dHBzOi8vaHVnZ2luZ2ZhY2UuY28vc3RlcGZ1bi1haS9TdGVwLTMuNS1GbGFzaC9yZXNvbHZlL2FiNDQ2YTNkZTVlMTcxZWEzNDEyMjdlMjRiYjFmMDkwZTFiNzcxZjcvY29uZmlndXJhdGlvbl9zdGVwM3A1LnB5In0seyJwYXRoIjoibW9kZWwtMDAwMDEuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTYyODg5ODkxMiwic2hhMjU2IjoiN2Y4ZTI2NjJjNjIwYjdmMjFjYjhiMDA5NjE0NzExMjg3NDY0MjFjNmY2MWJhOTJhZDI0ZmY4NjUxZTk4Njc2NiIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDAxLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMDIuc2FmZXRlbnNvcnMiLCJieXRlcyI6ODYzMjU0NzM0NCwic2hhMjU2IjoiMjJlMTM4ZWNlNWRjZTNjMjYxMWY4YjY3MjhmOTY2ZTUwNmVkMTM5YzU3YjcyZWU0MTM5YmExZGVjYTkxZWFkNyIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDAyLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMDMuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5Njk5Miwic2hhMjU2IjoiZjg3MjZiM2IxNTUxNmJhYTYzZjAyOTU5MGM4YjVkYTQ0NTllZGQwZjUwZGE1N2UyNzNkMTNmYzJkZWZmMzFkOCIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDAzLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMDQuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5Njk5Miwic2hhMjU2IjoiMTk4YjJmMGMyMzcxMTBhZDliYmU2NWRlMTA3ZGQ0ZGZlNDUwYTg2Y2ZjNWYyNTBjNmI5Y2I2ODgzMjFlNTcxZCIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDA0LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMDUuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5Njk5Miwic2hhMjU2IjoiMmQzNzIxYTQ5MTkzYmViNTAyNjIxYjk3YjU1ZjIyZmY5Yjc0NThhNzFhOTEwZmZjMWZlNzQyNDNhYmMxOTc3NyIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDA1LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMDYuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5Njk5Miwic2hhMjU2IjoiYmMwMzVlMWFmY2M5Nzg1ZWU4OTVlZTEzNzI1MTlkMmJkMzI3Yzc2Mjg0NjI5Zjc0YzRkMTU3YmRmNTczYzUzZiIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDA2LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMDcuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5Njk5Miwic2hhMjU2IjoiZjJmZjFjN2JhZmY4MzMxNmZhZTEwMWQyNThiYjQ0OTI0MDMyZGYzMjc4ODQ5YzA5ZDIzNjQ0MWVhZDc3MTMzMCIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDA3LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMDguc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5Njk5Miwic2hhMjU2IjoiYTI2MTVhZWI0NjZhZmI2MmVjMWI3NDAzYjkwNDAwMTljMzAxOGE0NGQxNjc0MDU1NDdlNzU1OWIzZDhlMzRlOCIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDA4LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMDkuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5Njk5Miwic2hhMjU2IjoiZjU0NGY0Mzc1MDM3ZGE2Y2QwMjM2NjQyN2ZmNWU3NWU1MjQ0YzI0OTFhMDA5MGZiYTM1MDg2NzA1MGIyYmVkNyIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDA5LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMTAuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiZGM1Mjg4YjYwYWNmYzk2ZjRiZTY5Zjk5M2M5YmM2MDNiNzc4YTg1M2Q3YTRjZGQyNDU5MTA1NGFkZTQ5YmQ0MiIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDEwLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMTEuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiZjBmZDhhMTZiZGEzOWZiOGFlMjZhZDBkZDNhNWMzMmU3Y2U5MTViZTc3ODUwNWM0NDA2NmM3NGIzYzE3ZTM4NiIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDExLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9k
    ASSETBLOCK

    Expected result: Manifest metadata block is written; all blocks are required before the checker can pass.

  2. 2. Write pinned manifest block 2 of 4

    Keep every block in this order. These are exact metadata bytes only; the final block reconstructs the immutable53-entry manifest. No model body is embedded.

    Command
    set -eu
    cd "$HOME/step35-flash"
    cat >> assets.b64 <<'ASSETBLOCK'
    ZWwtMDAwMTIuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiNTNmMjczMTQ1NjZkYmY3ZTZjNDc1NTA5NDUxNWRjMGI3N2EyMGExNWVjZDgzZGRhYWJjNjFiYTBhNmY2NWVjZCIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDEyLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMTMuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiN2ExZDY2MDYyZDdlMjIwODM4NzJkODk0YWU2ZjQ0ZWM5ZmFlYTliYzAxZjAzMDY3NzhiNzA5ZTFlY2E4MzMxMyIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDEzLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMTQuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiM2RiMTAzMTAxMzk4MjRhMjk1MmJhYWVjNjZkYTVmOTM5NjhkZDc0ODVjNTEzMjcwOTQzZDJjNjQ5ODQzYjg3NCIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDE0LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMTUuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiNTJkYjYxMzA0ZDk4OWFlNTdkYzRiOGEwMWM3OGNiMDc5OGJlZjI2MjRhZmIxYzY0MjViZDlmOTI5NmE5MDQ5NCIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDE1LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMTYuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiZGI0YzZhZWY5Y2M3NDY4ZmY1NTg3NDk2ZTZkOTUwYjM5OTJlNWRlMDJmOWI3NzFhMGZjMWJhZTRhYTg3Mzg2NiIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDE2LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMTcuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiOGUzNzYyNzQ4ODZlMjMxNzUxZjQxZDcxYmNiYTY3YWQ2YzAyYTY4ZmVkOGJmYWU2YTYzMzViZDEwYTM3YjQxNCIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDE3LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMTguc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiZmM0ODA5NGVhYzlmNDUwYTliNzczODY5YWE4NTM5NGRiZWM4ZTMyZDMwN2U1MWRlOTRhNWJmNzJiNTc1NDk4YiIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDE4LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMTkuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiZTdmOTYyZjVhMmFiMjcyY2M0ZTkwZmZkMjJlYjYzOWY0YmViMTVlYWRkNmVjYTM5MWU4MDAwMjg2MTE2MWIzZiIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDE5LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMjAuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiZmZlNGI1ZDMwODNjN2E4NzRhMTAxMjljODA4NWFiMTAxMjA2Njk4MWYwZDcwMGQzMTU1NjNmNzU5ZDNkZmZmOSIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDIwLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMjEuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiZjBiOGYyZjMwYTAyNmFkYzFlNjkzNmY0YmJlMDgwN2Q0ZmM0ZTJjYWYzOTFmMDVjNTMzZmMzMmZiZWM3ZTBhYiIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDIxLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMjIuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiZTcwYzQ5ZjI2YjY5OTE2Y2ExZmMwMjY2ZGMyYjAzZjdkZDQ3YTI1MDhlZTQwYzY4NTg4OTkzYjMxODc5OTYyYiIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDIyLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMjMuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiNjNmZWYzMjU5Y2NmYmQxMzVhYjRkMjg5Y2E5NjJlOGVkMWMyYWM1NTIxNjU0NmU0OWUyNTllNjZhYzJjYzg3ZSIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDIzLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMjQuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiMjllZWIwZWQ4NTI1ZDNiY2RiYzE5NjQzZmY2NjI1MmNiZDY0MWY0NGFhNTQ1OTJmY2IwNjU0MjYwZTQyODYxMSIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDI0LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMjUuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiMjBjY2I0YjEzZWUwNGI2ZDc2ZDhkMzk3NDIwYzMxMDMxMmQ1MTRmNzE2ODhkNTVkZjU1MjkxMTRjN2FkZjc2OSIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDI1LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMjYuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiZGE5MzBiYTEyZWNiNWFjMGYxMTFlNTM1MWNlNGY0YTY5MWI5NWI5OWNjMzRkNjU3NDkwZWQwYzRlY2M2Y2UyOSIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQx
    ASSETBLOCK

    Expected result: Manifest metadata block is written; all blocks are required before the checker can pass.

  3. 3. Write pinned manifest block 3 of 4

    Keep every block in this order. These are exact metadata bytes only; the final block reconstructs the immutable53-entry manifest. No model body is embedded.

    Command
    set -eu
    cd "$HOME/step35-flash"
    cat >> assets.b64 <<'ASSETBLOCK'
    MjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDI2LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMjcuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiOGVmMGYzNzA4ZTQ4NGFhNGJlMDE1N2IwZTc4Nzk0MjgwODIwZTUxNjA0MDU2YjEyYTk2ZTQ3OGQzNDg2NTExYyIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDI3LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMjguc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiMDhmZWI4ZmViOGEyMzhlZmM0M2VhMzc2YjgzMTM5ZjBhMGIxMjEzODYwNDhjNjgyNjVkMmFmMmY5YmVlZTcxMiIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDI4LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMjkuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiMDVlNDQ4MmVjNDdhMWU3N2MyYTMzN2JlNTlhNTU5ODUxN2ZkYjIzZjVhY2ExZmMyOTVlNDRiMmQwMjgzYmE1OSIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDI5LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMzAuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiYzljYjI5YjBhNjM3NDhhZGNiMDU1ZTEwMDFlOTU1ZGY4MjI3OGRiOGM0MjQ0NzgyOWJjNmY2MWNkYjE2MjMwNSIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDMwLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMzEuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiZWJlMDBhYmFhMjU4ZWU3MTQyMjg5ZWYyNTlkYjRjZTMyNzJhMWZiZTFhM2YwOTZhY2JlZGZkZGViNmZjZjIxNCIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDMxLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMzIuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiMDIyNzA0NzcyNTk4M2ZkNTYwMWM1ZGZkYTAzY2Y2NWYyM2FlYzJmZDUyODI2MGIxYzMzZDQzYTcxZjQ3MzQ2MCIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDMyLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMzMuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiMTY3M2NlZjEzMDg4OTg2YjZmYWQ5MjZjYzcwNmZmM2UyOTQ3ODI0YzcxODI1YTU1NDc3ZTdiYWE4YjA5ZTIwMSIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDMzLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMzQuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiNTI5MzBkZGNkM2Y2YzhmOTkyMTI4ODM5NjdmMGJjYTgwZjFiMGJkMWUxMjY5ZTk3YjRhNWNjZTU2NjZkZGM4MiIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDM0LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMzUuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiNTgxYjk1Mzk3OTkyNjY1NDBhMmU3OGRlZTdhMmIyOTRjODgyMGI0MTJiMmQxNDhmY2E0N2MzMmM5MzQ3ZWUzMiIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDM1LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMzYuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiNTcxZGRkZTQ2MDM3MWNhYTk1ZTBlMmEwZjNjMThlNzk3NGQ4MGFkYTFjNWNkOWYwMGIxMjQyYmE4ODBmZGE0NyIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDM2LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMzcuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiYWJlZWEzN2E0MTgyMWIwN2RhZWQwZTk4YjQ0MzQ5YTA4OWQ3Y2I0MzAzMGNmY2M2NjA4ZGI4YmM2ZmNkOTI2YyIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDM3LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMzguc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiZGY5OThmOWFmMWMyMjUyNjMyMzlkOTIxMGZjNjZmY2RiNzZiMTEzNDgzM2FhMzE4YmMwZjE0NGU4ZDMzNDI2YiIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDM4LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMzkuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiOGQzMTZhM2Y3OTZkYjQ2YjEzYmZkOWRkZGMwODZmYTRjZDg2NmUxZTIzMzhmNjNlNjhiZjM1YmExODYyNzRhNyIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDM5LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwNDAuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiZTI4N2RiY2ZhYTJjOWM4ZWE3NzMzNGNkZDZmYzAxMWI4YzA1OGI4Zjc1MDg3MGZmMzA5ZmFmNjcxYjM4ZDY4OCIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDQwLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwNDEuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiOTMzYjA2ZWZhNTU1ZDgxYjc1MjViODdmM2I1NjM2Y2E4MmZjNWI3MzBhOGNjMGUzNWY3ZjBmZWRiNjU4ZGJmNCIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdm
    ASSETBLOCK

    Expected result: Manifest metadata block is written; all blocks are required before the checker can pass.

  4. 4. Write pinned manifest block 4 of 4

    Keep every block in this order. These are exact metadata bytes only; the final block reconstructs the immutable53-entry manifest. No model body is embedded.

    Command
    set -eu
    cd "$HOME/step35-flash"
    cat >> assets.b64 <<'ASSETBLOCK'
    YWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDQxLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwNDIuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiMDA1N2E2MzEyN2FlNzI4MmRjOWFhZjI4ZmM3OTQ4ZTMzNzdkOGQwNGJjN2FlYzU4MDc3MjUyMDI2NGE3ZjQ1MCIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDQyLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwNDMuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiMjliYjE4ODViNTcyMTc5OTQ0N2U2NWI0ZDY3MDU0YWJhMjkwY2JhMzJlMzhlNjkzNGMzNjkwYjQxZmYyMmM2YyIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDQzLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwNDQuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiN2Q0ZmViZTJjMjllYmI2N2VkOTdiOTk5MjIxMTNjMzUzZjk3OTM1YTdmNDI0M2Q3ODQzYzgzM2QwNjQ3MWI0MSIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDQ0LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwuc2FmZXRlbnNvcnMuaW5kZXguanNvbiIsImJ5dGVzIjo1OTE0OSwic2hhMjU2IjpudWxsLCJnaXRCbG9iU2hhMSI6IjljNTQ0ZDdlMmU5YzY5MGZlNjcxYjIwMjg4NzVlM2Q0MWFmNjU1MWMiLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLnNhZmV0ZW5zb3JzLmluZGV4Lmpzb24ifSx7InBhdGgiOiJtb2RlbGluZ19zdGVwM3A1LnB5IiwiYnl0ZXMiOjM4NTY3LCJzaGEyNTYiOm51bGwsImdpdEJsb2JTaGExIjoiNjdkOTkyNmMzYmRmNGZmN2I5NzBkMjE4YjQ5Mzg3MjIxMWE2NWIwOSIsInVybCI6Imh0dHBzOi8vaHVnZ2luZ2ZhY2UuY28vc3RlcGZ1bi1haS9TdGVwLTMuNS1GbGFzaC9yZXNvbHZlL2FiNDQ2YTNkZTVlMTcxZWEzNDEyMjdlMjRiYjFmMDkwZTFiNzcxZjcvbW9kZWxpbmdfc3RlcDNwNS5weSJ9LHsicGF0aCI6InNwZWNpYWxfdG9rZW5zX21hcC5qc29uIiwiYnl0ZXMiOjQ2OCwic2hhMjU2IjpudWxsLCJnaXRCbG9iU2hhMSI6IjcxZTE0YjM1NGM5ZDEzMTlkZjlhYzU1ZDM4NWMzM2U3NGMwMTEzYmQiLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L3NwZWNpYWxfdG9rZW5zX21hcC5qc29uIn0seyJwYXRoIjoidG9rZW5pemVyLmpzb24iLCJieXRlcyI6OTk3Njk3Miwic2hhMjU2IjpudWxsLCJnaXRCbG9iU2hhMSI6IjZjNGI1YjVkMDQ1ZDk1OTQwNzg1YWY0ZTM2ZmRlZmJiMTdiMjgzYTIiLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L3Rva2VuaXplci5qc29uIn0seyJwYXRoIjoidG9rZW5pemVyX2NvbmZpZy5qc29uIiwiYnl0ZXMiOjE2MzQwNSwic2hhMjU2IjpudWxsLCJnaXRCbG9iU2hhMSI6ImMyOWY4MDAwZjY0NGQzMGE1MzVmNzM4Y2IxZWZiYTRlOWFmZmYyNmMiLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L3Rva2VuaXplcl9jb25maWcuanNvbiJ9XX0K
    ASSETBLOCK
    python3 -c "import base64,pathlib; pathlib.Path('assets.json').write_bytes(base64.b64decode(pathlib.Path('assets.b64').read_bytes()))"

    Expected result: Manifest metadata block is written; all blocks are required before the checker can pass.

  5. 5. Write streaming integrity helper

    The helper binds the exact manifest before using any entries. Native LFS files use SHA256; native regular Git files use Git blob SHA1, explicitly not a fabricated SHA256. Missing or replaced manifests fail closed.

    Command
    set -eu
    cd "$HOME/step35-flash"
    cat > reader-assets.py <<'PYFILE'
    """Reader-run full checkpoint integrity; no model imports."""
    import hashlib
    import json
    import pathlib
    import sys
    import urllib.request
    ROOT = pathlib.Path(__file__).resolve().parent
    MANIFEST_SHA = '2621750ee5e425256187fd012585a2edef6f7eb8308f43214a6abedda3cb55b5'
    
    
    def verified_manifest():
        raw = (ROOT / 'assets.json').read_bytes()
        if hashlib.sha256(raw).hexdigest() != MANIFEST_SHA:
            raise ValueError('manifest_hash')
        d = json.loads(raw)
        if d['revision'] != 'ab446a3de5e171ea341227e24bb1f090e1b771f7' or d['repository'] != 'stepfun-ai/Step-3.5-Flash' or len(d['files']) != 53:
            raise ValueError('manifest_identity')
        return d['files']
    
    
    def check(path, entry):
        digest = hashlib.sha256() if entry['sha256'] else hashlib.sha1()
        if not entry['sha256']:
            digest.update(('blob ' + str(entry['bytes']) + '\0').encode())
        count = 0
        with path.open('rb') as f:
            while block := f.read(1024 * 1024):
                count += len(block)
                digest.update(block)
        if count != entry['bytes'] or digest.hexdigest() != (entry['sha256'] or entry['gitBlobSha1']):
            raise ValueError('asset_integrity_' + entry['path'])
    
    
    def main(download):
        files = verified_manifest()
        out = ROOT / 'model'
        out.mkdir(exist_ok=True)
        for entry in files:
            dest = out / entry['path']
            if pathlib.PurePosixPath(entry['path']).name != entry['path']:
                raise ValueError('asset_path')
            if download and not dest.exists():
                temp = dest.with_suffix(dest.suffix + '.partial')
                with urllib.request.urlopen(entry['url'], timeout=60) as r, temp.open('wb') as f:
                    total = 0
                    while block := r.read(1024 * 1024):
                        total += len(block)
                        if total > entry['bytes']:
                            raise ValueError('download_size')
                        f.write(block)
                check(temp, entry)
                temp.replace(dest)
            check(dest, entry)
        cfg = json.loads((out / 'config.json').read_text())
        if cfg['hidden_size'] != 4096 or cfg['num_hidden_layers'] != 45 or cfg['num_nextn_predict_layers'] != 3 or cfg['moe_num_experts'] != 288 or cfg['moe_top_k'] != 8 or cfg['sliding_window'] != 512:
            raise ValueError('native_config_identity')
        index = json.loads((out / 'model.safetensors.index.json').read_text())['weight_map']
        if set(index.values()) != {e['path'] for e in files if e['path'].endswith('.safetensors')} or not all(any(k.startswith('model.layers.' + str(i) + '.') for k in index) for i in (45,46,47)):
            raise ValueError('full_native_mtp_index')
        print('All53 assets passed exact size and streaming native LFS SHA256 or Git blob SHA1 checks. All44 weight parts and all3 MTP layers remain required.')
    
    
    if __name__ == '__main__':
        if sys.argv[1:] not in (['download'], ['verify']):
            raise SystemExit('Use download or verify')
        main(sys.argv[1] == 'download')
    
    PYFILE

    Expected result: Exact manifest and every complete native part are mandatory.

  6. 6. Download and verify all native assets

    Download the exact revision-addressed files. Any access, size, hash, native identity or complete three-MTP index failure stops before server startup. No checkpoint conversion occurs.

    Command
    set -eu
    cd "$HOME/step35-flash"
    python3 reader-assets.py download
    python3 reader-assets.py verify

    Expected result: All 53 exact assets pass streaming checks, including all 44 full-weight parts and MTP layers 45,46,47.

Configure

  1. 1. Create a private endpoint key

    Create a new private key and environment file in this dedicated reader workspace. Do not disclose it in logs or source control. These are local reader operations, not third-party credentials.

    Command
    set -eu
    cd "$HOME/step35-flash"
    umask 077
    python3 - <<'PYPREWRITE'
    import os,pathlib,stat
    paths=[pathlib.Path(n)for n in [".api-key","private.env"]]
    for p in paths:
     try:s=p.lstat()
     except FileNotFoundError:continue
     if not stat.S_ISREG(s.st_mode):raise ValueError('existing secret target must be a regular file; no links')
    for p in paths:
     if p.exists():os.chmod(p,0o600)
    PYPREWRITE
    openssl rand -hex 32 > .api-key
    printf 'VLLM_API_KEY=%s\n' "$(cat .api-key)" > private.env
    chmod 600 .api-key private.env

    Expected result: Private key files have owner-only permissions; no secret is printed.

  2. 2. Check the exact released native runtime image

    Use the immutable official Linux amd64 vLLM 0.27.1 image. It contains native Step3p5 target/MTP/config classes; no custom Transformers or remote Python code replacement is needed. Reader pull/version/package and GPU visibility checks are required; source qualification is not execution proof.

    Command
    set -eu
    cd "$HOME/step35-flash"
    sudo docker pull --platform linux/amd64 vllm/vllm-openai@sha256:c2f3b1b964e47809b722b5e75b61b1e7b39a50f70388cf2bf2418f16a9f31da2
    sudo docker run --rm --gpus all --entrypoint nvidia-smi vllm/vllm-openai@sha256:c2f3b1b964e47809b722b5e75b61b1e7b39a50f70388cf2bf2418f16a9f31da2 -L
    sudo docker run --rm --entrypoint python3 vllm/vllm-openai@sha256:c2f3b1b964e47809b722b5e75b61b1e7b39a50f70388cf2bf2418f16a9f31da2 -c "import vllm; assert vllm.__version__ == '0.27.1'"
    sudo docker run --rm --entrypoint python3 vllm/vllm-openai@sha256:c2f3b1b964e47809b722b5e75b61b1e7b39a50f70388cf2bf2418f16a9f31da2 -m pip check
    sudo docker run --rm --entrypoint python3 vllm/vllm-openai@sha256:c2f3b1b964e47809b722b5e75b61b1e7b39a50f70388cf2bf2418f16a9f31da2 -m pip freeze > realized-runtime-packages.txt

    Expected result: The exact image/version and dependencies pass; eight GPUs are visible. Any failure stops the walkthrough.

Start the model

  1. 1. Start full native BF16 target and three-layer MTP

    Run in a foreground terminal. Released 0.27.1 has its own Step-specific multi-layer proposer; unlike the older card example, retain native num_nextn_predict_layers 3 and select three speculative tokens. Tensor and expert parallelism use all eight GPUs. Do not override the model to one MTP layer or strip weights. The 1800-second demo process bound is not an inference SLA.

    Command
    set -eu
    cd "$HOME/step35-flash"
    python3 reader-assets.py verify
    [ "$(nvidia-smi -L | wc -l)" -eq 8 ]
    sudo docker network inspect step35-private >/dev/null 2>&1 || sudo docker network create --internal step35-private
    timeout --signal=TERM --kill-after=10s 1800s sudo docker run --rm --name step35-native --gpus all --shm-size 32g --network step35-private -p 127.0.0.1:8996:8000 --env-file private.env -e HF_HUB_OFFLINE=1 -e TRANSFORMERS_OFFLINE=1 -v "$PWD/model:/model:ro" --entrypoint /bin/bash vllm/vllm-openai@sha256:c2f3b1b964e47809b722b5e75b61b1e7b39a50f70388cf2bf2418f16a9f31da2 -lc 'exec vllm serve /model --served-model-name step35-flash-native --host 0.0.0.0 --port 8000 --dtype bfloat16 --kv-cache-dtype auto --tensor-parallel-size 8 --enable-expert-parallel --disable-cascade-attn --max-model-len 8192 --max-num-seqs 1 --gpu-memory-utilization 0.90 --enforce-eager --no-enable-prefix-caching --reasoning-parser step3p5 --enable-auto-tool-choice --tool-call-parser step3p5 --chat-template /model/chat_template.jinja --speculative-config "{\"method\":\"mtp\",\"num_speculative_tokens\":3}" --generation-config vllm'

    Expected result: Wait for actual readiness before verification. Stop on loader, NCCL, kernel, native parser or OOM errors; no measured startup/fit claim.

Connect to your endpoint

http://127.0.0.1:8996/v1/chat/completions

Owned server loopback only; internal Docker network plus host 127.0.0.1 binding. Use the fixed local client only.

Access: loopback. Private 64-character hexadecimal Bearer key protects native /v1 routes. Health/tokenize are source-exempt and stay loopback-only. This trusted serial research API is not hardened for public or arbitrary queued clients. max-num-seqs=1 limits scheduling, not admission.

Verify the setup

  1. 1. Write native protocol verifier block 1 of 2

    Keep both blocks in order. The exact corrected client rejects residual or malformed native control output and requires closed thinking, native EOS and integer token counts. No model operation was performed by the author.

    Command
    set -eu
    cd "$HOME/step35-flash"
    cat > reader-client.py <<'CLIENTBLOCK'
    """Fixed inert tool/reasoning check for exact native Step3.5 Flash; stdlib only."""
    import http.client
    import json
    import pathlib
    
    MODEL = 'step35-flash-native'
    CONTEXT = 8192
    OUTPUT = 4096
    KWARGS = {}  # Exact publisher template controls native thinking and history.
    TOOLS = [{'type': 'function', 'function': {'name': 'lookup_demo_constant',
        'description': 'Look up the inert demonstration constant; no external action.',
        'parameters': {'type': 'object', 'properties': {'key': {'type': 'string',
        'enum': ['alpha']}}, 'required': ['key'], 'additionalProperties': False}}}]
    
    
    def unique(pairs):
        out = {}
        for k, v in pairs:
            if k in out:
                raise ValueError('duplicate_json_key')
            out[k] = v
        return out
    
    
    def parse(raw):
        if type(raw) is not bytes or len(raw) > 2 * 1024 * 1024:
            raise ValueError('response_bytes')
        return json.loads(raw.decode('utf-8'), object_pairs_hook=unique,
            parse_constant=lambda _: (_ for _ in ()).throw(ValueError('nonfinite_json')))
    
    
    def budget(d):
        if type(d) is not dict or type(d.get('count')) is not int or not 1 <= d['count'] <= CONTEXT - OUTPUT:
            raise ValueError('prompt_budget')
        if d.get('max_model_len') != CONTEXT:
            raise ValueError('wrong_server_context')
        if type(d.get('max_model_len')) is not int:
            raise ValueError('server_context_type')
        return d['count']
    
    
    def checked(d, prompt, tool_turn):
        if type(d) is not dict or d.get('model') != MODEL or type(d.get('choices')) is not list or len(d['choices']) != 1:
            raise ValueError('response_identity')
        if type(prompt) is not int or not 1 <= prompt <= CONTEXT - OUTPUT:
            raise ValueError('prompt_count_type')
        choice = d['choices'][0]
        if type(choice) is not dict:
            raise ValueError('choice_shape')
        if choice.get('stop_reason') is not None and type(choice.get('stop_reason')) is not int:
            raise ValueError('stop_reason_type')
        expected = 'tool_calls' if tool_turn else 'stop'
        if choice.get('finish_reason') != expected or choice.get('stop_reason') not in (None, 1, 2, 128007):
            raise ValueError('not_native_complete')
        ids = choice.get('token_ids')
        if type(ids) is not list or not 1 <= len(ids) < OUTPUT or any(type(i) is not int or i < 0 for i in ids):
            raise ValueError('raw_output_tokens')
        # The native prompt already opens thinking. Generated output may echo one
        # opening token, but must close exactly once before the answer/tool segment.
        if ids.count(128799) != 1 or ids.count(128798) > 1:
            raise ValueError('native_thinking_boundary')
        close = ids.index(128799)
        if 128798 in ids and ids.index(128798) >= close:
            raise ValueError('reopened_thinking')
        eos = [i for i, token in enumerate(ids) if token in (1,2,128007)]
        # Released scheduler appends the sampled stop token before stopping; the
        # detokenizer retains it in raw IDs even when omitting its decoded text.
        if len(eos) != 1 or eos[0] != len(ids)-1:
            raise ValueError('nonterminal_native_eos')
        if choice.get('stop_reason') is not None and choice['stop_reason'] != ids[-1]:
            raise ValueError('native_stop_identity')
        prefix = ids[:close]
        if any(token >= 128000 and token != 128798 for token in prefix):
            raise ValueError('control_inside_reasoning')
        body = ids[close+1:]
        if tool_turn:
            if body.count(128008) != 1 or body.count(128009) != 1 or body.index(128008) >= body.index(128009):
                raise ValueError('native_tool_boundary')
            if body[0] != 128008 or body[-2] != 128009:
                raise ValueError('native_tool_only_body')
            allowed = {128008,128009,128007}
        else:
            allowed = {128007}
        if any(token >= 128000 and token not in allowed for token in body):
            raise ValueError('unexpected_native_control')
        usage = d.get('usage', {})
        if type(usage) is not dict or any(type(usage.get(k)) is not int for k in ('prompt_tokens','completion_tokens','total_tokens')):
            raise ValueError('usage_integer_types')
        if usage.get('prompt_tokens') != prompt or usage.get('completion_tokens') != len(ids) or usage.get('total_tokens') != prompt + len(ids):
            raise ValueError('usage_mismatch')
        if prompt + len(ids) > CONTEXT:
            raise ValueError('total_budget')
        message = choice.get('message')
        if type(message) is not dict or message.get('role') != 'assistant' or type(message.get('reasoning')) is not str or not message['reasoning'].strip():
            raise ValueError('native_reasoning_required')
        markers = ('<tool', '</tool', '<function', '</function', '<parameter',
                   '</parameter', '<think', '</think', '<|', '<|', '<im_', '<patch_')
        if any(x in message['reasoning'] for x in markers):
            raise ValueError('parsed_reasoning_control')
        content = message.get('content')
        if content is not None and type(content) is not str:
            raise ValueError('content_type')
        if content and any(x in content for x in markers):
            raise ValueError('parsed_content_control')
        if tool_turn:
            if content and content.strip():
                raise ValueError('unexpected_tool_turn_content')
            calls = message.get('tool_calls')
            if type(calls) is not list or len(calls) != 1 or 128008 not in ids or 128009 not in ids:
                raise ValueError('complete_one_native_tool')
            call = calls[0]
            if call.get('type') != 'function' or type(call.get('id')) is not str or not 1 <= len(call['id']) <= 128:
                raise ValueError('tool_identity')
            fn = call.get('function', {})
            if fn.get('name') != 'lookup_demo_constant' or type(fn.get('arguments')) is not str:
                raise ValueError('tool_name')
    CLIENTBLOCK

    Expected result: The complete exact helper is reconstructed and checksum-verified; it never executes tools or changes returned content.

  2. 2. Write native protocol verifier block 2 of 2

    Keep both blocks in order. The exact corrected client rejects residual or malformed native control output and requires closed thinking, native EOS and integer token counts. No model operation was performed by the author.

    Command
    set -eu
    cd "$HOME/step35-flash"
    cat >> reader-client.py <<'CLIENTBLOCK'
            args = parse(fn['arguments'].encode())
            if type(args) is not dict or args != {'key': 'alpha'}:
                raise ValueError('fixed_tool_arguments')
        elif message.get('tool_calls') or type(message.get('content')) is not str or not message['content'].strip():
            raise ValueError('final_answer_required')
        return message
    
    
    def call(path, body, key):
        payload = json.dumps(body, allow_nan=False).encode()
        if len(payload) > 65536:
            raise ValueError('fixed_client_body_bound')
        c = http.client.HTTPConnection('127.0.0.1', 8996, timeout=120)
        try:
            c.request('POST', path, payload, {'Authorization': 'Bearer ' + key,
                                            'Content-Type': 'application/json'})
            r = c.getresponse()
            if r.status != 200:
                raise RuntimeError('endpoint_status_' + str(r.status))
            return parse(r.read(2 * 1024 * 1024 + 1))
        finally:
            c.close()
    
    
    def run(request):
        messages = [{'role': 'user', 'content': 'Use lookup_demo_constant for key alpha, then explain in one sentence why its value plus one is eight. Treat this only as synthetic protocol testing.'}]
        outputs = []
        for tool_turn in (True, False):
            shared = {'model': MODEL, 'messages': messages, 'tools': TOOLS,
                      'chat_template_kwargs': KWARGS, 'add_special_tokens': False,
                      'add_generation_prompt': True}
            count = budget(request('/tokenize', shared))
            response = request('/v1/chat/completions', {**shared, 'tool_choice': 'auto' if tool_turn else 'none',
                'temperature': 1.0, 'top_p': 0.95, 'max_tokens': OUTPUT, 'n': 1,
                'stream': False, 'return_token_ids': True, 'stop_token_ids': [1, 2, 128007],
                'include_reasoning': True})
            msg = checked(response, count, tool_turn)
            outputs.append(response)
            if tool_turn:
                # Preserve complete native reasoning, final body and tool call history. No executor.
                messages.append({'role': 'assistant', 'content': msg.get('content') or '',
                    'reasoning_content': msg['reasoning'], 'tool_calls': msg['tool_calls']})
                messages.append({'role': 'tool', 'tool_call_id': msg['tool_calls'][0]['id'],
                                 'content': '{"key":"alpha","value":7,"synthetic":true}'})
        return outputs
    
    
    if __name__ == '__main__':
        key = (pathlib.Path(__file__).resolve().parent / '.api-key').read_text().strip()
        if len(key) != 64 or any(c not in '0123456789abcdef' for c in key):
            raise SystemExit('private_key_format')
        result = run(lambda path, body: call(path, body, key))
        pathlib.Path('protocol-result.json').write_text(json.dumps(result, indent=2, allow_nan=False) + '\n')
        print('Native raw closing-think/tool boundaries and token budgets passed. Inspect final answer and record semantic failures; this is not a quality or performance benchmark.')
    CLIENTBLOCK
    python3 -m py_compile reader-client.py
    sha256sum --check <<'CHECKSUM'
    d86637c87bf3b2e68a87a58b703c76eff32bb72cf6ea31b194b6f3febc0c5f56  reader-client.py
    CHECKSUM

    Expected result: The complete exact helper is reconstructed and checksum-verified; it never executes tools or changes returned content.

  3. 3. Check readiness, auth boundary and native completion

    Native health/tokenize routes are not Bearer-protected; the server remains bound to host loopback. Unauthenticated /v1/models must return 401. No public port is opened. The client has a 120-second socket timeout that does not cancel GPU work.

    Command
    set -eu
    cd "$HOME/step35-flash"
    curl --fail --silent http://127.0.0.1:8996/health
    [ "$(curl --silent -o /dev/null -w '%{http_code}' http://127.0.0.1:8996/v1/models)" = 401 ]
    python3 reader-client.py

    Expected result: Record actual protocol-result.json and human semantic assessment. Residual tool/role/thinking controls, repeated or unclosed thinking, malformed tool order, nonterminal or missing native EOS, noninteger usage, overbudget or length finish fail closed. Protocol validity is not task quality.

Performance evidence

No compatible measurement available. Documented support and estimated memory do not establish response speed.

Limits and troubleshooting

  • Native 45 target layers and three MTP layers are preserved; all 288 routed experts plus shared expert are retained. Only 8 routed experts activate per token, which does not reduce full resident checkpoint requirements.
  • Native full attention alternates with 512-window sliding attention. Config max_seq_len 262144 and tokenizer model_max_length 131072 differ; this 8192-position walkthrough establishes neither maximum nor fit.
  • Released vLLM 0.27.1 Step3p5MTP uses its own multi-group/per-step proposer and all three prediction layers. This source-qualified choice supersedes the older card one-layer override; no speculative acceptance, speed or quality has been measured.
  • Native reasoning and XML tool delimiters differ from generic JSON-only tool formatting. The exact publisher Jinja remains unchanged; only parsed inert lookup arguments are accepted by the client, and no tool executes.
  • The fixed client 120-second socket timeout does not cancel native work; 1800-second foreground lifetime is a chosen demonstration bound. Stop/kill the exact container when needed.
  • Weights, target/draft activations, per-GPU caches and NCCL/workspace overhead remain unmeasured. Advertised 8 × 80 GB capacity and 2048 GiB host allocation do not prove fit.
  • Original repository/date/provider alias is preserved; exact native checkpoint pin is not asserted byte-equal to any provider API. Broader FP8, long-context, alternate hardware/runtime and task scopes remain open.
Native loading, collective initialization or GPU out-of-memory fails
Stop the exact container. Recheck all assets, eight GPUs, driver/image versions and source-qualified flags. Record failure; do not strip MTP/experts, silently quantize or change the checkpoint.
Missing closing thinking/tool markers, wrong parsed arguments or length finish
Treat the run as failed. Keep the exact request/history/token budget and retain diagnostics. Do not execute model-generated calls or infer task correctness from valid JSON alone.

Stop the model

  1. 1. Stop the exact private container

    Stop the foreground process and remove only this exact named service container. Client timeout does not guarantee server cancellation.

    Command
    sudo docker stop --time 10 step35-native || true
    if [ "$(sudo docker inspect -f '{{.State.Running}}' step35-native 2>/dev/null || true)" = true ]; then sudo docker kill step35-native; fi
    curl --max-time 3 http://127.0.0.1:8996/v1/models || true

    Expected result: The exact service container and loopback endpoint stop. Owned-host power/storage costs may remain.

Uninstall

  1. 1. Remove dedicated reader assets and network

    Remove this dedicated reader directory, internal network and exact image only after preserving desired results. Do not prune shared Docker resources or uninstall shared GPU drivers/toolkit.

    Command
    sudo docker rm -f step35-native 2>/dev/null || true
    sudo docker network rm step35-private
    sudo docker image rm vllm/vllm-openai@sha256:c2f3b1b964e47809b722b5e75b61b1e7b39a50f70388cf2bf2418f16a9f31da2
    rm -r -- "$HOME/step35-flash"

    Expected result: Dedicated reader artifacts are removed; shared Docker, drivers and unrelated resources remain.

Sources and verification

Sources checked Oct 17, 2026. Verification source

Compare this configuration
Cloud serverDocumented setupSources checked Oct 17, 2026

Host full native Step 3.5 Flash reasoning and tools on AWS p5.48xlarge

Serve the complete BF16 Step 3.5 Flash checkpoint, all experts and three MTP layers through a released native GPU runtime. Exact publisher template and Step reasoning/XML-tool parsers preserve the model-specific protocol. A bounded8192-context/4096-output two-turn inert-tool check records completion boundaries, not task quality. Eight H100 80 GB GPUs and 2048 GiB host RAM are planning allocations, not measured fit.

Hardware
AWS p5.48xlarge eight-H100 instance
Runtime
Released native Step3.5 Flash BF16 with three-layer MTP on vLLM vLLM 0.27.1 commit 6e448d0; exact official Linux amd64 image digest, reader preflight required · CUDA
Model format
Native HF sharded safetensors · Complete native BF16 weights, including every expert and MTP layers 45,46,47 · Unquantized native BF16; complete experts and all MTP tensors retained
Workload
8,192 token context · 1 concurrent

Based on source documentation; this setup has not been executed by OpenTools. Memory: unknown. No compatible measurement available.

Read the complete setup guide

Before you start

  • Use an already provisioned dedicated AWS p5.48xlarge Ubuntu 24.04 x86_64 host in us-east-1:192 vCPUs,2048 GiB host RAM,eight H100 80 GB GPUs. Choose768 GiB gp3 root volume. Keep TCP 8996 closed publicly and restrict SSH; capacity/quota/driver setup and billing are reader responsibilities.
  • Choose 2048 GiB host RAM,768 GiB disk and192 CPU threads. Require 600 GiB free disk before download. These are prescribed allocations, not minima or measured fit. All 44 weight parts, all experts and all three MTP layers remain required.
  • Review the full Apache 2.0 license and native repository terms/third-party rights. No terms acceptance, provisioning, model download or native execution was performed by the author.
  • Use 8192 total context and 4096 output cap per turn only as a bounded protocol walkthrough. Native config 262144 and tokenizer metadata131072 are retained as distinct evidence; no maximum-context fit or provider API byte identity is asserted.

Exact model and requirements

Artifact:
StepFun / Full native Step 3.5 Flash BF16 with three MTP layers · checkpoint stepfun-ai/Step-3.5-Flash
Publisher revision:
ab446a3de5e171ea341227e24bb1f090e1b771f7
Artifact digest:
Whole-composition digest not published. All 44 weight parts have exact native LFS SHA256 and sizes; nine auxiliary files use native Git blob SHA1 metadata and sizes in immutable manifest.
Download size:
371.38 GiB
Memory requirement (unknown):
Unknown — No measured per-device or whole-process peak for full BF16/MTP3 on eight H100s at8192 context.
System RAM / disk:
Unknown / Unknown
Placement:
supported sharding. Eight-way tensor parallelism plus expert parallelism; all target/expert/MTP weights retained, no aggregate-fit inference. All target and three MTP layers are sharded on eight GPUs; no CPU or disk weight offload. Host loading buffers and every target/draft cache remain additional and unmeasured.
KV cache:
BF16 attention KV across native full and sliding GQA groups; no Mamba or compressed KV substitution
Workload:
8,192 token context; Unknown; Unknown; concurrency 1; batch 1; cache cold; repetitions Unknown.
Tokenizer:
Exact native Step tokenizer and 5004-byte publisher Jinja · ab446a3de5e171ea341227e24bb1f090e1b771f7
Sampling / reasoning:
Publisher reasoning/agent recommendation temperature 1.0 and top_p 0.95; n=1 and nonstreaming. Raw generated token IDs and native EOS IDs 1/2/128007 are checked. Native template starts assistant thinking. Require raw closing-think 128799 and tool-call 128008/128009 delimiters on first turn, native non-length completion and nonempty final answer. Retain reasoning_content, tool call and inert result exactly; publisher template itself defines which history is rendered. This 8192/4096 demonstration is not the publisher full reasoning budget.
Runtime prerequisites:
Ubuntu 24.04 x86_64 host; pinned Ubuntu 22.04 / Python 3.12 source defaults container; NVIDIA Linux driver >=580.126.20, Working Docker GPU support with NVIDIA Container Toolkit; actual visibility preflight required.

Official artifact · License

Publisher native model card expressly grants Apache License 2.0; full linked license is archived. Review all conditions and applicable third-party rights. Preserve license and relevant notices on redistribution and state changes; patent termination and warranty/liability exclusions apply. No license acceptance or legal clearance is performed here.

  • 398,768,720,200 serialized weight bytes are retained in full. Nominal 196B and 11B active do not mean=11B resident weights; metadata reports 199,384,301,376 scalar parameters including auxiliary tensors.
  • Each GPU advertises80 GB; exact usable bytes, sharding balance, MTP buffers, attention KV, workspace and host loading overhead are unmeasured. Eight times advertised capacity is not a measured-fit guarantee.

One-time setup and hardware

hardware
Unknown — Hardware acquisition is part of instance rental; separate purchase cost not applicable.
Hardware acquisition is part of instance rental; separate purchase cost not applicable. Tax: unknown.
setup
Unknown — Reader setup and labor cost is unknown.
Provisioning/imagebuild/labor cost unknown. Tax: unknown.

Recurring costs

compute
$55.04 / hour
Exact us-east-1 Linux On-Demand quote USD 55.04/hour; original publication 2026-10-15T19:13:16Z. Eight hours USD 440.32 compute only. Idle running hours bill. Storage, egress, IP, labor and taxes separate; capacity/quota unknown. Region: us-east-1. SKU: p5.48xlarge Linux On-Demand. Tax: excluded. Price dated Oct 15, 2026. Price source
storage
$0.08 / GB month
US East gp3 baseline USD 0.08 per AWS binary GB-month; chosen 768 GiB root volume USD 61.44 per full month, prorated separately. Baseline 3000 IOPS/125MB/s. Included 8×3840GB local instance storage is ephemeral, not retained EBS. Region: us-east-1. SKU: EBS gp3 baseline. Tax: excluded. Price dated Oct 17, 2026. Price source
egress
Unknown — Actual transfer, publicIPv4/IP and associated service charges depend on usage/resources; unknown.
Actual transfer, publicIPv4/IP and associated service charges depend on usage/resources; unknown. Tax: unknown.
administration
Unknown — Maintenance time/rate unknown.
Maintenance time/rate unknown. Tax: unknown.

Install the runtime

  1. 1. Prepare an existing GPU host and private workspace

    Prepare the already provisioned dedicated eight-H100 Ubuntu 24.04 host with working NVIDIA driver >=580.126.20. Install host utilities and Docker; this guide does not install or claim compatibility of an arbitrary GPU driver. Record actual hardware and stop on any prerequisite failure.

    Command
    set -eu
    sudo apt-get update
    sudo apt-get install -y docker.io python3 curl ca-certificates openssl
    sudo systemctl enable --now docker
    mkdir -p "$HOME/step35-flash"
    cd "$HOME/step35-flash"
    nvidia-smi --query-gpu=name,memory.total,driver_version --format=csv,noheader
    python3 - <<'PYPREFLIGHT'
    import csv,subprocess,shutil
    r=list(csv.reader(subprocess.check_output(["nvidia-smi","--query-gpu=name,memory.total,driver_version","--format=csv,noheader,nounits"],text=True).splitlines()))
    assert len(r)==8 and all("H100" in x[0] and "80GB" in x[0].replace(" ","") for x in r)
    assert all(tuple(map(int,x[2].strip().split("."))) >= (580,126,20) for x in r)
    assert shutil.disk_usage(".").free >=600*1024**3
    print("Reader GPU/driver and prescribed600GiB free-disk preflight passed; no model fit measured.")
    PYPREFLIGHT
    sudo docker version

    Expected result: All eight H100 cards and required driver are visible, with prescribed host RAM/disk and free space recorded. Capacity is planning, not measured fit.

  2. 2. Configure NVIDIA GPU containers on this dedicated host

    Use the official production repository and exact documented Container Toolkit 1.20.1-1 packages. This modifies Docker daemon configuration and restarts Docker on this dedicated host; preserve its original configuration and do not apply on a shared production daemon without its owner review. Stop on repository/signature/package errors.

    Command
    set -euo pipefail
    sudo apt-get install -y gnupg2
    curl --fail --silent --show-error --location https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --batch --yes --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
    curl --fail --silent --show-error --location https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list >/dev/null
    sudo apt-get update
    sudo apt-get install -y nvidia-container-toolkit=1.20.1-1 nvidia-container-toolkit-base=1.20.1-1 libnvidia-container-tools=1.20.1-1 libnvidia-container1=1.20.1-1
    sudo nvidia-ctk runtime configure --runtime=docker
    sudo systemctl restart docker

    Expected result: The exact GPU container packages install and Docker is configured. The subsequent container nvidia-smi check must pass; this is not model inference or fit proof.

Download the model

  1. 1. Write pinned manifest block 1 of 4

    Keep every block in this order. These are exact metadata bytes only; the final block reconstructs the immutable53-entry manifest. No model body is embedded.

    Command
    set -eu
    cd "$HOME/step35-flash"
    cat > assets.b64 <<'ASSETBLOCK'
    eyJyZXBvc2l0b3J5Ijoic3RlcGZ1bi1haS9TdGVwLTMuNS1GbGFzaCIsInJldmlzaW9uIjoiYWI0NDZhM2RlNWUxNzFlYTM0MTIyN2UyNGJiMWYwOTBlMWI3NzFmNyIsImZpbGVzIjpbeyJwYXRoIjoiUkVBRE1FLm1kIiwiYnl0ZXMiOjI2MjQxLCJzaGEyNTYiOm51bGwsImdpdEJsb2JTaGExIjoiMzFjZWI5ZDg1YTg4MGFlNDAwODYzMTg0NzQwZTEzNDQ2YTg5OGY4NSIsInVybCI6Imh0dHBzOi8vaHVnZ2luZ2ZhY2UuY28vc3RlcGZ1bi1haS9TdGVwLTMuNS1GbGFzaC9yZXNvbHZlL2FiNDQ2YTNkZTVlMTcxZWEzNDEyMjdlMjRiYjFmMDkwZTFiNzcxZjcvUkVBRE1FLm1kIn0seyJwYXRoIjoiY2hhdF90ZW1wbGF0ZS5qaW5qYSIsImJ5dGVzIjo1MDA0LCJzaGEyNTYiOm51bGwsImdpdEJsb2JTaGExIjoiYzA5ZWE0OTdkYWRhNmZlMmMxZjk0MDY3YjQ3NjJkY2JhMTkzYzBmMCIsInVybCI6Imh0dHBzOi8vaHVnZ2luZ2ZhY2UuY28vc3RlcGZ1bi1haS9TdGVwLTMuNS1GbGFzaC9yZXNvbHZlL2FiNDQ2YTNkZTVlMTcxZWEzNDEyMjdlMjRiYjFmMDkwZTFiNzcxZjcvY2hhdF90ZW1wbGF0ZS5qaW5qYSJ9LHsicGF0aCI6ImNvbmZpZy5qc29uIiwiYnl0ZXMiOjQ5MzAsInNoYTI1NiI6bnVsbCwiZ2l0QmxvYlNoYTEiOiJmZmM0ZDcyNDUxMDA5NmFjNDkwYmIxMjg0MDIxMjc2MGYzMmJhZTE2IiwidXJsIjoiaHR0cHM6Ly9odWdnaW5nZmFjZS5jby9zdGVwZnVuLWFpL1N0ZXAtMy41LUZsYXNoL3Jlc29sdmUvYWI0NDZhM2RlNWUxNzFlYTM0MTIyN2UyNGJiMWYwOTBlMWI3NzFmNy9jb25maWcuanNvbiJ9LHsicGF0aCI6ImNvbmZpZ3VyYXRpb25fc3RlcDNwNS5weSIsImJ5dGVzIjoyMjg1LCJzaGEyNTYiOm51bGwsImdpdEJsb2JTaGExIjoiYWI4ZDA2OGVlODNjMjVkYzBmYjJiMGEyYmQyY2E3NmJkYzlmYWFjOSIsInVybCI6Imh0dHBzOi8vaHVnZ2luZ2ZhY2UuY28vc3RlcGZ1bi1haS9TdGVwLTMuNS1GbGFzaC9yZXNvbHZlL2FiNDQ2YTNkZTVlMTcxZWEzNDEyMjdlMjRiYjFmMDkwZTFiNzcxZjcvY29uZmlndXJhdGlvbl9zdGVwM3A1LnB5In0seyJwYXRoIjoibW9kZWwtMDAwMDEuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTYyODg5ODkxMiwic2hhMjU2IjoiN2Y4ZTI2NjJjNjIwYjdmMjFjYjhiMDA5NjE0NzExMjg3NDY0MjFjNmY2MWJhOTJhZDI0ZmY4NjUxZTk4Njc2NiIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDAxLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMDIuc2FmZXRlbnNvcnMiLCJieXRlcyI6ODYzMjU0NzM0NCwic2hhMjU2IjoiMjJlMTM4ZWNlNWRjZTNjMjYxMWY4YjY3MjhmOTY2ZTUwNmVkMTM5YzU3YjcyZWU0MTM5YmExZGVjYTkxZWFkNyIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDAyLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMDMuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5Njk5Miwic2hhMjU2IjoiZjg3MjZiM2IxNTUxNmJhYTYzZjAyOTU5MGM4YjVkYTQ0NTllZGQwZjUwZGE1N2UyNzNkMTNmYzJkZWZmMzFkOCIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDAzLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMDQuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5Njk5Miwic2hhMjU2IjoiMTk4YjJmMGMyMzcxMTBhZDliYmU2NWRlMTA3ZGQ0ZGZlNDUwYTg2Y2ZjNWYyNTBjNmI5Y2I2ODgzMjFlNTcxZCIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDA0LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMDUuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5Njk5Miwic2hhMjU2IjoiMmQzNzIxYTQ5MTkzYmViNTAyNjIxYjk3YjU1ZjIyZmY5Yjc0NThhNzFhOTEwZmZjMWZlNzQyNDNhYmMxOTc3NyIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDA1LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMDYuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5Njk5Miwic2hhMjU2IjoiYmMwMzVlMWFmY2M5Nzg1ZWU4OTVlZTEzNzI1MTlkMmJkMzI3Yzc2Mjg0NjI5Zjc0YzRkMTU3YmRmNTczYzUzZiIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDA2LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMDcuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5Njk5Miwic2hhMjU2IjoiZjJmZjFjN2JhZmY4MzMxNmZhZTEwMWQyNThiYjQ0OTI0MDMyZGYzMjc4ODQ5YzA5ZDIzNjQ0MWVhZDc3MTMzMCIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDA3LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMDguc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5Njk5Miwic2hhMjU2IjoiYTI2MTVhZWI0NjZhZmI2MmVjMWI3NDAzYjkwNDAwMTljMzAxOGE0NGQxNjc0MDU1NDdlNzU1OWIzZDhlMzRlOCIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDA4LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMDkuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5Njk5Miwic2hhMjU2IjoiZjU0NGY0Mzc1MDM3ZGE2Y2QwMjM2NjQyN2ZmNWU3NWU1MjQ0YzI0OTFhMDA5MGZiYTM1MDg2NzA1MGIyYmVkNyIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDA5LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMTAuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiZGM1Mjg4YjYwYWNmYzk2ZjRiZTY5Zjk5M2M5YmM2MDNiNzc4YTg1M2Q3YTRjZGQyNDU5MTA1NGFkZTQ5YmQ0MiIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDEwLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMTEuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiZjBmZDhhMTZiZGEzOWZiOGFlMjZhZDBkZDNhNWMzMmU3Y2U5MTViZTc3ODUwNWM0NDA2NmM3NGIzYzE3ZTM4NiIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDExLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9k
    ASSETBLOCK

    Expected result: Manifest metadata block is written; all blocks are required before the checker can pass.

  2. 2. Write pinned manifest block 2 of 4

    Keep every block in this order. These are exact metadata bytes only; the final block reconstructs the immutable53-entry manifest. No model body is embedded.

    Command
    set -eu
    cd "$HOME/step35-flash"
    cat >> assets.b64 <<'ASSETBLOCK'
    ZWwtMDAwMTIuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiNTNmMjczMTQ1NjZkYmY3ZTZjNDc1NTA5NDUxNWRjMGI3N2EyMGExNWVjZDgzZGRhYWJjNjFiYTBhNmY2NWVjZCIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDEyLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMTMuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiN2ExZDY2MDYyZDdlMjIwODM4NzJkODk0YWU2ZjQ0ZWM5ZmFlYTliYzAxZjAzMDY3NzhiNzA5ZTFlY2E4MzMxMyIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDEzLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMTQuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiM2RiMTAzMTAxMzk4MjRhMjk1MmJhYWVjNjZkYTVmOTM5NjhkZDc0ODVjNTEzMjcwOTQzZDJjNjQ5ODQzYjg3NCIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDE0LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMTUuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiNTJkYjYxMzA0ZDk4OWFlNTdkYzRiOGEwMWM3OGNiMDc5OGJlZjI2MjRhZmIxYzY0MjViZDlmOTI5NmE5MDQ5NCIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDE1LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMTYuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiZGI0YzZhZWY5Y2M3NDY4ZmY1NTg3NDk2ZTZkOTUwYjM5OTJlNWRlMDJmOWI3NzFhMGZjMWJhZTRhYTg3Mzg2NiIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDE2LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMTcuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiOGUzNzYyNzQ4ODZlMjMxNzUxZjQxZDcxYmNiYTY3YWQ2YzAyYTY4ZmVkOGJmYWU2YTYzMzViZDEwYTM3YjQxNCIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDE3LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMTguc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiZmM0ODA5NGVhYzlmNDUwYTliNzczODY5YWE4NTM5NGRiZWM4ZTMyZDMwN2U1MWRlOTRhNWJmNzJiNTc1NDk4YiIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDE4LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMTkuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiZTdmOTYyZjVhMmFiMjcyY2M0ZTkwZmZkMjJlYjYzOWY0YmViMTVlYWRkNmVjYTM5MWU4MDAwMjg2MTE2MWIzZiIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDE5LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMjAuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiZmZlNGI1ZDMwODNjN2E4NzRhMTAxMjljODA4NWFiMTAxMjA2Njk4MWYwZDcwMGQzMTU1NjNmNzU5ZDNkZmZmOSIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDIwLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMjEuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiZjBiOGYyZjMwYTAyNmFkYzFlNjkzNmY0YmJlMDgwN2Q0ZmM0ZTJjYWYzOTFmMDVjNTMzZmMzMmZiZWM3ZTBhYiIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDIxLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMjIuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiZTcwYzQ5ZjI2YjY5OTE2Y2ExZmMwMjY2ZGMyYjAzZjdkZDQ3YTI1MDhlZTQwYzY4NTg4OTkzYjMxODc5OTYyYiIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDIyLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMjMuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiNjNmZWYzMjU5Y2NmYmQxMzVhYjRkMjg5Y2E5NjJlOGVkMWMyYWM1NTIxNjU0NmU0OWUyNTllNjZhYzJjYzg3ZSIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDIzLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMjQuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiMjllZWIwZWQ4NTI1ZDNiY2RiYzE5NjQzZmY2NjI1MmNiZDY0MWY0NGFhNTQ1OTJmY2IwNjU0MjYwZTQyODYxMSIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDI0LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMjUuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiMjBjY2I0YjEzZWUwNGI2ZDc2ZDhkMzk3NDIwYzMxMDMxMmQ1MTRmNzE2ODhkNTVkZjU1MjkxMTRjN2FkZjc2OSIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDI1LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMjYuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiZGE5MzBiYTEyZWNiNWFjMGYxMTFlNTM1MWNlNGY0YTY5MWI5NWI5OWNjMzRkNjU3NDkwZWQwYzRlY2M2Y2UyOSIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQx
    ASSETBLOCK

    Expected result: Manifest metadata block is written; all blocks are required before the checker can pass.

  3. 3. Write pinned manifest block 3 of 4

    Keep every block in this order. These are exact metadata bytes only; the final block reconstructs the immutable53-entry manifest. No model body is embedded.

    Command
    set -eu
    cd "$HOME/step35-flash"
    cat >> assets.b64 <<'ASSETBLOCK'
    MjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDI2LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMjcuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiOGVmMGYzNzA4ZTQ4NGFhNGJlMDE1N2IwZTc4Nzk0MjgwODIwZTUxNjA0MDU2YjEyYTk2ZTQ3OGQzNDg2NTExYyIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDI3LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMjguc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiMDhmZWI4ZmViOGEyMzhlZmM0M2VhMzc2YjgzMTM5ZjBhMGIxMjEzODYwNDhjNjgyNjVkMmFmMmY5YmVlZTcxMiIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDI4LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMjkuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiMDVlNDQ4MmVjNDdhMWU3N2MyYTMzN2JlNTlhNTU5ODUxN2ZkYjIzZjVhY2ExZmMyOTVlNDRiMmQwMjgzYmE1OSIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDI5LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMzAuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiYzljYjI5YjBhNjM3NDhhZGNiMDU1ZTEwMDFlOTU1ZGY4MjI3OGRiOGM0MjQ0NzgyOWJjNmY2MWNkYjE2MjMwNSIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDMwLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMzEuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiZWJlMDBhYmFhMjU4ZWU3MTQyMjg5ZWYyNTlkYjRjZTMyNzJhMWZiZTFhM2YwOTZhY2JlZGZkZGViNmZjZjIxNCIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDMxLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMzIuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiMDIyNzA0NzcyNTk4M2ZkNTYwMWM1ZGZkYTAzY2Y2NWYyM2FlYzJmZDUyODI2MGIxYzMzZDQzYTcxZjQ3MzQ2MCIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDMyLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMzMuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiMTY3M2NlZjEzMDg4OTg2YjZmYWQ5MjZjYzcwNmZmM2UyOTQ3ODI0YzcxODI1YTU1NDc3ZTdiYWE4YjA5ZTIwMSIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDMzLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMzQuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiNTI5MzBkZGNkM2Y2YzhmOTkyMTI4ODM5NjdmMGJjYTgwZjFiMGJkMWUxMjY5ZTk3YjRhNWNjZTU2NjZkZGM4MiIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDM0LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMzUuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiNTgxYjk1Mzk3OTkyNjY1NDBhMmU3OGRlZTdhMmIyOTRjODgyMGI0MTJiMmQxNDhmY2E0N2MzMmM5MzQ3ZWUzMiIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDM1LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMzYuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiNTcxZGRkZTQ2MDM3MWNhYTk1ZTBlMmEwZjNjMThlNzk3NGQ4MGFkYTFjNWNkOWYwMGIxMjQyYmE4ODBmZGE0NyIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDM2LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMzcuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiYWJlZWEzN2E0MTgyMWIwN2RhZWQwZTk4YjQ0MzQ5YTA4OWQ3Y2I0MzAzMGNmY2M2NjA4ZGI4YmM2ZmNkOTI2YyIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDM3LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMzguc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiZGY5OThmOWFmMWMyMjUyNjMyMzlkOTIxMGZjNjZmY2RiNzZiMTEzNDgzM2FhMzE4YmMwZjE0NGU4ZDMzNDI2YiIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDM4LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwMzkuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiOGQzMTZhM2Y3OTZkYjQ2YjEzYmZkOWRkZGMwODZmYTRjZDg2NmUxZTIzMzhmNjNlNjhiZjM1YmExODYyNzRhNyIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDM5LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwNDAuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiZTI4N2RiY2ZhYTJjOWM4ZWE3NzMzNGNkZDZmYzAxMWI4YzA1OGI4Zjc1MDg3MGZmMzA5ZmFmNjcxYjM4ZDY4OCIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDQwLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwNDEuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiOTMzYjA2ZWZhNTU1ZDgxYjc1MjViODdmM2I1NjM2Y2E4MmZjNWI3MzBhOGNjMGUzNWY3ZjBmZWRiNjU4ZGJmNCIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdm
    ASSETBLOCK

    Expected result: Manifest metadata block is written; all blocks are required before the checker can pass.

  4. 4. Write pinned manifest block 4 of 4

    Keep every block in this order. These are exact metadata bytes only; the final block reconstructs the immutable53-entry manifest. No model body is embedded.

    Command
    set -eu
    cd "$HOME/step35-flash"
    cat >> assets.b64 <<'ASSETBLOCK'
    YWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDQxLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwNDIuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiMDA1N2E2MzEyN2FlNzI4MmRjOWFhZjI4ZmM3OTQ4ZTMzNzdkOGQwNGJjN2FlYzU4MDc3MjUyMDI2NGE3ZjQ1MCIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDQyLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwNDMuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiMjliYjE4ODViNTcyMTc5OTQ0N2U2NWI0ZDY3MDU0YWJhMjkwY2JhMzJlMzhlNjkzNGMzNjkwYjQxZmYyMmM2YyIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDQzLnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwtMDAwNDQuc2FmZXRlbnNvcnMiLCJieXRlcyI6OTA1OTY5NzAwMCwic2hhMjU2IjoiN2Q0ZmViZTJjMjllYmI2N2VkOTdiOTk5MjIxMTNjMzUzZjk3OTM1YTdmNDI0M2Q3ODQzYzgzM2QwNjQ3MWI0MSIsImdpdEJsb2JTaGExIjpudWxsLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLTAwMDQ0LnNhZmV0ZW5zb3JzIn0seyJwYXRoIjoibW9kZWwuc2FmZXRlbnNvcnMuaW5kZXguanNvbiIsImJ5dGVzIjo1OTE0OSwic2hhMjU2IjpudWxsLCJnaXRCbG9iU2hhMSI6IjljNTQ0ZDdlMmU5YzY5MGZlNjcxYjIwMjg4NzVlM2Q0MWFmNjU1MWMiLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L21vZGVsLnNhZmV0ZW5zb3JzLmluZGV4Lmpzb24ifSx7InBhdGgiOiJtb2RlbGluZ19zdGVwM3A1LnB5IiwiYnl0ZXMiOjM4NTY3LCJzaGEyNTYiOm51bGwsImdpdEJsb2JTaGExIjoiNjdkOTkyNmMzYmRmNGZmN2I5NzBkMjE4YjQ5Mzg3MjIxMWE2NWIwOSIsInVybCI6Imh0dHBzOi8vaHVnZ2luZ2ZhY2UuY28vc3RlcGZ1bi1haS9TdGVwLTMuNS1GbGFzaC9yZXNvbHZlL2FiNDQ2YTNkZTVlMTcxZWEzNDEyMjdlMjRiYjFmMDkwZTFiNzcxZjcvbW9kZWxpbmdfc3RlcDNwNS5weSJ9LHsicGF0aCI6InNwZWNpYWxfdG9rZW5zX21hcC5qc29uIiwiYnl0ZXMiOjQ2OCwic2hhMjU2IjpudWxsLCJnaXRCbG9iU2hhMSI6IjcxZTE0YjM1NGM5ZDEzMTlkZjlhYzU1ZDM4NWMzM2U3NGMwMTEzYmQiLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L3NwZWNpYWxfdG9rZW5zX21hcC5qc29uIn0seyJwYXRoIjoidG9rZW5pemVyLmpzb24iLCJieXRlcyI6OTk3Njk3Miwic2hhMjU2IjpudWxsLCJnaXRCbG9iU2hhMSI6IjZjNGI1YjVkMDQ1ZDk1OTQwNzg1YWY0ZTM2ZmRlZmJiMTdiMjgzYTIiLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L3Rva2VuaXplci5qc29uIn0seyJwYXRoIjoidG9rZW5pemVyX2NvbmZpZy5qc29uIiwiYnl0ZXMiOjE2MzQwNSwic2hhMjU2IjpudWxsLCJnaXRCbG9iU2hhMSI6ImMyOWY4MDAwZjY0NGQzMGE1MzVmNzM4Y2IxZWZiYTRlOWFmZmYyNmMiLCJ1cmwiOiJodHRwczovL2h1Z2dpbmdmYWNlLmNvL3N0ZXBmdW4tYWkvU3RlcC0zLjUtRmxhc2gvcmVzb2x2ZS9hYjQ0NmEzZGU1ZTE3MWVhMzQxMjI3ZTI0YmIxZjA5MGUxYjc3MWY3L3Rva2VuaXplcl9jb25maWcuanNvbiJ9XX0K
    ASSETBLOCK
    python3 -c "import base64,pathlib; pathlib.Path('assets.json').write_bytes(base64.b64decode(pathlib.Path('assets.b64').read_bytes()))"

    Expected result: Manifest metadata block is written; all blocks are required before the checker can pass.

  5. 5. Write streaming integrity helper

    The helper binds the exact manifest before using any entries. Native LFS files use SHA256; native regular Git files use Git blob SHA1, explicitly not a fabricated SHA256. Missing or replaced manifests fail closed.

    Command
    set -eu
    cd "$HOME/step35-flash"
    cat > reader-assets.py <<'PYFILE'
    """Reader-run full checkpoint integrity; no model imports."""
    import hashlib
    import json
    import pathlib
    import sys
    import urllib.request
    ROOT = pathlib.Path(__file__).resolve().parent
    MANIFEST_SHA = '2621750ee5e425256187fd012585a2edef6f7eb8308f43214a6abedda3cb55b5'
    
    
    def verified_manifest():
        raw = (ROOT / 'assets.json').read_bytes()
        if hashlib.sha256(raw).hexdigest() != MANIFEST_SHA:
            raise ValueError('manifest_hash')
        d = json.loads(raw)
        if d['revision'] != 'ab446a3de5e171ea341227e24bb1f090e1b771f7' or d['repository'] != 'stepfun-ai/Step-3.5-Flash' or len(d['files']) != 53:
            raise ValueError('manifest_identity')
        return d['files']
    
    
    def check(path, entry):
        digest = hashlib.sha256() if entry['sha256'] else hashlib.sha1()
        if not entry['sha256']:
            digest.update(('blob ' + str(entry['bytes']) + '\0').encode())
        count = 0
        with path.open('rb') as f:
            while block := f.read(1024 * 1024):
                count += len(block)
                digest.update(block)
        if count != entry['bytes'] or digest.hexdigest() != (entry['sha256'] or entry['gitBlobSha1']):
            raise ValueError('asset_integrity_' + entry['path'])
    
    
    def main(download):
        files = verified_manifest()
        out = ROOT / 'model'
        out.mkdir(exist_ok=True)
        for entry in files:
            dest = out / entry['path']
            if pathlib.PurePosixPath(entry['path']).name != entry['path']:
                raise ValueError('asset_path')
            if download and not dest.exists():
                temp = dest.with_suffix(dest.suffix + '.partial')
                with urllib.request.urlopen(entry['url'], timeout=60) as r, temp.open('wb') as f:
                    total = 0
                    while block := r.read(1024 * 1024):
                        total += len(block)
                        if total > entry['bytes']:
                            raise ValueError('download_size')
                        f.write(block)
                check(temp, entry)
                temp.replace(dest)
            check(dest, entry)
        cfg = json.loads((out / 'config.json').read_text())
        if cfg['hidden_size'] != 4096 or cfg['num_hidden_layers'] != 45 or cfg['num_nextn_predict_layers'] != 3 or cfg['moe_num_experts'] != 288 or cfg['moe_top_k'] != 8 or cfg['sliding_window'] != 512:
            raise ValueError('native_config_identity')
        index = json.loads((out / 'model.safetensors.index.json').read_text())['weight_map']
        if set(index.values()) != {e['path'] for e in files if e['path'].endswith('.safetensors')} or not all(any(k.startswith('model.layers.' + str(i) + '.') for k in index) for i in (45,46,47)):
            raise ValueError('full_native_mtp_index')
        print('All53 assets passed exact size and streaming native LFS SHA256 or Git blob SHA1 checks. All44 weight parts and all3 MTP layers remain required.')
    
    
    if __name__ == '__main__':
        if sys.argv[1:] not in (['download'], ['verify']):
            raise SystemExit('Use download or verify')
        main(sys.argv[1] == 'download')
    
    PYFILE

    Expected result: Exact manifest and every complete native part are mandatory.

  6. 6. Download and verify all native assets

    Download the exact revision-addressed files. Any access, size, hash, native identity or complete three-MTP index failure stops before server startup. No checkpoint conversion occurs.

    Command
    set -eu
    cd "$HOME/step35-flash"
    python3 reader-assets.py download
    python3 reader-assets.py verify

    Expected result: All 53 exact assets pass streaming checks, including all 44 full-weight parts and MTP layers 45,46,47.

Configure

  1. 1. Create a private endpoint key

    Create a new private key and environment file in this dedicated reader workspace. Do not disclose it in logs or source control. These are local reader operations, not third-party credentials.

    Command
    set -eu
    cd "$HOME/step35-flash"
    umask 077
    python3 - <<'PYPREWRITE'
    import os,pathlib,stat
    paths=[pathlib.Path(n)for n in [".api-key","private.env"]]
    for p in paths:
     try:s=p.lstat()
     except FileNotFoundError:continue
     if not stat.S_ISREG(s.st_mode):raise ValueError('existing secret target must be a regular file; no links')
    for p in paths:
     if p.exists():os.chmod(p,0o600)
    PYPREWRITE
    openssl rand -hex 32 > .api-key
    printf 'VLLM_API_KEY=%s\n' "$(cat .api-key)" > private.env
    chmod 600 .api-key private.env

    Expected result: Private key files have owner-only permissions; no secret is printed.

  2. 2. Check the exact released native runtime image

    Use the immutable official Linux amd64 vLLM 0.27.1 image. It contains native Step3p5 target/MTP/config classes; no custom Transformers or remote Python code replacement is needed. Reader pull/version/package and GPU visibility checks are required; source qualification is not execution proof.

    Command
    set -eu
    cd "$HOME/step35-flash"
    sudo docker pull --platform linux/amd64 vllm/vllm-openai@sha256:c2f3b1b964e47809b722b5e75b61b1e7b39a50f70388cf2bf2418f16a9f31da2
    sudo docker run --rm --gpus all --entrypoint nvidia-smi vllm/vllm-openai@sha256:c2f3b1b964e47809b722b5e75b61b1e7b39a50f70388cf2bf2418f16a9f31da2 -L
    sudo docker run --rm --entrypoint python3 vllm/vllm-openai@sha256:c2f3b1b964e47809b722b5e75b61b1e7b39a50f70388cf2bf2418f16a9f31da2 -c "import vllm; assert vllm.__version__ == '0.27.1'"
    sudo docker run --rm --entrypoint python3 vllm/vllm-openai@sha256:c2f3b1b964e47809b722b5e75b61b1e7b39a50f70388cf2bf2418f16a9f31da2 -m pip check
    sudo docker run --rm --entrypoint python3 vllm/vllm-openai@sha256:c2f3b1b964e47809b722b5e75b61b1e7b39a50f70388cf2bf2418f16a9f31da2 -m pip freeze > realized-runtime-packages.txt

    Expected result: The exact image/version and dependencies pass; eight GPUs are visible. Any failure stops the walkthrough.

Start the model

  1. 1. Start full native BF16 target and three-layer MTP

    Run in a foreground terminal. Released 0.27.1 has its own Step-specific multi-layer proposer; unlike the older card example, retain native num_nextn_predict_layers 3 and select three speculative tokens. Tensor and expert parallelism use all eight GPUs. Do not override the model to one MTP layer or strip weights. The 1800-second demo process bound is not an inference SLA.

    Command
    set -eu
    cd "$HOME/step35-flash"
    python3 reader-assets.py verify
    [ "$(nvidia-smi -L | wc -l)" -eq 8 ]
    sudo docker network inspect step35-private >/dev/null 2>&1 || sudo docker network create --internal step35-private
    timeout --signal=TERM --kill-after=10s 1800s sudo docker run --rm --name step35-native --gpus all --shm-size 32g --network step35-private -p 127.0.0.1:8996:8000 --env-file private.env -e HF_HUB_OFFLINE=1 -e TRANSFORMERS_OFFLINE=1 -v "$PWD/model:/model:ro" --entrypoint /bin/bash vllm/vllm-openai@sha256:c2f3b1b964e47809b722b5e75b61b1e7b39a50f70388cf2bf2418f16a9f31da2 -lc 'exec vllm serve /model --served-model-name step35-flash-native --host 0.0.0.0 --port 8000 --dtype bfloat16 --kv-cache-dtype auto --tensor-parallel-size 8 --enable-expert-parallel --disable-cascade-attn --max-model-len 8192 --max-num-seqs 1 --gpu-memory-utilization 0.90 --enforce-eager --no-enable-prefix-caching --reasoning-parser step3p5 --enable-auto-tool-choice --tool-call-parser step3p5 --chat-template /model/chat_template.jinja --speculative-config "{\"method\":\"mtp\",\"num_speculative_tokens\":3}" --generation-config vllm'

    Expected result: Wait for actual readiness before verification. Stop on loader, NCCL, kernel, native parser or OOM errors; no measured startup/fit claim.

Connect to your endpoint

http://127.0.0.1:8996/v1/chat/completions

VM loopback only. Shown checks run on the VM. Optional existing-SSH tunnel: ssh -N -L8996:127.0.0.1:8996 USER@VM_IP from the client; it stays in its own terminal. Keep public TCP 8996 closed and restrict SSH.

Access: loopback. Private 64-character hexadecimal Bearer key protects native /v1 routes. Health/tokenize are source-exempt and stay loopback-only. This trusted serial research API is not hardened for public or arbitrary queued clients. max-num-seqs=1 limits scheduling, not admission.

Verify the setup

  1. 1. Write native protocol verifier block 1 of 2

    Keep both blocks in order. The exact corrected client rejects residual or malformed native control output and requires closed thinking, native EOS and integer token counts. No model operation was performed by the author.

    Command
    set -eu
    cd "$HOME/step35-flash"
    cat > reader-client.py <<'CLIENTBLOCK'
    """Fixed inert tool/reasoning check for exact native Step3.5 Flash; stdlib only."""
    import http.client
    import json
    import pathlib
    
    MODEL = 'step35-flash-native'
    CONTEXT = 8192
    OUTPUT = 4096
    KWARGS = {}  # Exact publisher template controls native thinking and history.
    TOOLS = [{'type': 'function', 'function': {'name': 'lookup_demo_constant',
        'description': 'Look up the inert demonstration constant; no external action.',
        'parameters': {'type': 'object', 'properties': {'key': {'type': 'string',
        'enum': ['alpha']}}, 'required': ['key'], 'additionalProperties': False}}}]
    
    
    def unique(pairs):
        out = {}
        for k, v in pairs:
            if k in out:
                raise ValueError('duplicate_json_key')
            out[k] = v
        return out
    
    
    def parse(raw):
        if type(raw) is not bytes or len(raw) > 2 * 1024 * 1024:
            raise ValueError('response_bytes')
        return json.loads(raw.decode('utf-8'), object_pairs_hook=unique,
            parse_constant=lambda _: (_ for _ in ()).throw(ValueError('nonfinite_json')))
    
    
    def budget(d):
        if type(d) is not dict or type(d.get('count')) is not int or not 1 <= d['count'] <= CONTEXT - OUTPUT:
            raise ValueError('prompt_budget')
        if d.get('max_model_len') != CONTEXT:
            raise ValueError('wrong_server_context')
        if type(d.get('max_model_len')) is not int:
            raise ValueError('server_context_type')
        return d['count']
    
    
    def checked(d, prompt, tool_turn):
        if type(d) is not dict or d.get('model') != MODEL or type(d.get('choices')) is not list or len(d['choices']) != 1:
            raise ValueError('response_identity')
        if type(prompt) is not int or not 1 <= prompt <= CONTEXT - OUTPUT:
            raise ValueError('prompt_count_type')
        choice = d['choices'][0]
        if type(choice) is not dict:
            raise ValueError('choice_shape')
        if choice.get('stop_reason') is not None and type(choice.get('stop_reason')) is not int:
            raise ValueError('stop_reason_type')
        expected = 'tool_calls' if tool_turn else 'stop'
        if choice.get('finish_reason') != expected or choice.get('stop_reason') not in (None, 1, 2, 128007):
            raise ValueError('not_native_complete')
        ids = choice.get('token_ids')
        if type(ids) is not list or not 1 <= len(ids) < OUTPUT or any(type(i) is not int or i < 0 for i in ids):
            raise ValueError('raw_output_tokens')
        # The native prompt already opens thinking. Generated output may echo one
        # opening token, but must close exactly once before the answer/tool segment.
        if ids.count(128799) != 1 or ids.count(128798) > 1:
            raise ValueError('native_thinking_boundary')
        close = ids.index(128799)
        if 128798 in ids and ids.index(128798) >= close:
            raise ValueError('reopened_thinking')
        eos = [i for i, token in enumerate(ids) if token in (1,2,128007)]
        # Released scheduler appends the sampled stop token before stopping; the
        # detokenizer retains it in raw IDs even when omitting its decoded text.
        if len(eos) != 1 or eos[0] != len(ids)-1:
            raise ValueError('nonterminal_native_eos')
        if choice.get('stop_reason') is not None and choice['stop_reason'] != ids[-1]:
            raise ValueError('native_stop_identity')
        prefix = ids[:close]
        if any(token >= 128000 and token != 128798 for token in prefix):
            raise ValueError('control_inside_reasoning')
        body = ids[close+1:]
        if tool_turn:
            if body.count(128008) != 1 or body.count(128009) != 1 or body.index(128008) >= body.index(128009):
                raise ValueError('native_tool_boundary')
            if body[0] != 128008 or body[-2] != 128009:
                raise ValueError('native_tool_only_body')
            allowed = {128008,128009,128007}
        else:
            allowed = {128007}
        if any(token >= 128000 and token not in allowed for token in body):
            raise ValueError('unexpected_native_control')
        usage = d.get('usage', {})
        if type(usage) is not dict or any(type(usage.get(k)) is not int for k in ('prompt_tokens','completion_tokens','total_tokens')):
            raise ValueError('usage_integer_types')
        if usage.get('prompt_tokens') != prompt or usage.get('completion_tokens') != len(ids) or usage.get('total_tokens') != prompt + len(ids):
            raise ValueError('usage_mismatch')
        if prompt + len(ids) > CONTEXT:
            raise ValueError('total_budget')
        message = choice.get('message')
        if type(message) is not dict or message.get('role') != 'assistant' or type(message.get('reasoning')) is not str or not message['reasoning'].strip():
            raise ValueError('native_reasoning_required')
        markers = ('<tool', '</tool', '<function', '</function', '<parameter',
                   '</parameter', '<think', '</think', '<|', '<|', '<im_', '<patch_')
        if any(x in message['reasoning'] for x in markers):
            raise ValueError('parsed_reasoning_control')
        content = message.get('content')
        if content is not None and type(content) is not str:
            raise ValueError('content_type')
        if content and any(x in content for x in markers):
            raise ValueError('parsed_content_control')
        if tool_turn:
            if content and content.strip():
                raise ValueError('unexpected_tool_turn_content')
            calls = message.get('tool_calls')
            if type(calls) is not list or len(calls) != 1 or 128008 not in ids or 128009 not in ids:
                raise ValueError('complete_one_native_tool')
            call = calls[0]
            if call.get('type') != 'function' or type(call.get('id')) is not str or not 1 <= len(call['id']) <= 128:
                raise ValueError('tool_identity')
            fn = call.get('function', {})
            if fn.get('name') != 'lookup_demo_constant' or type(fn.get('arguments')) is not str:
                raise ValueError('tool_name')
    CLIENTBLOCK

    Expected result: The complete exact helper is reconstructed and checksum-verified; it never executes tools or changes returned content.

  2. 2. Write native protocol verifier block 2 of 2

    Keep both blocks in order. The exact corrected client rejects residual or malformed native control output and requires closed thinking, native EOS and integer token counts. No model operation was performed by the author.

    Command
    set -eu
    cd "$HOME/step35-flash"
    cat >> reader-client.py <<'CLIENTBLOCK'
            args = parse(fn['arguments'].encode())
            if type(args) is not dict or args != {'key': 'alpha'}:
                raise ValueError('fixed_tool_arguments')
        elif message.get('tool_calls') or type(message.get('content')) is not str or not message['content'].strip():
            raise ValueError('final_answer_required')
        return message
    
    
    def call(path, body, key):
        payload = json.dumps(body, allow_nan=False).encode()
        if len(payload) > 65536:
            raise ValueError('fixed_client_body_bound')
        c = http.client.HTTPConnection('127.0.0.1', 8996, timeout=120)
        try:
            c.request('POST', path, payload, {'Authorization': 'Bearer ' + key,
                                            'Content-Type': 'application/json'})
            r = c.getresponse()
            if r.status != 200:
                raise RuntimeError('endpoint_status_' + str(r.status))
            return parse(r.read(2 * 1024 * 1024 + 1))
        finally:
            c.close()
    
    
    def run(request):
        messages = [{'role': 'user', 'content': 'Use lookup_demo_constant for key alpha, then explain in one sentence why its value plus one is eight. Treat this only as synthetic protocol testing.'}]
        outputs = []
        for tool_turn in (True, False):
            shared = {'model': MODEL, 'messages': messages, 'tools': TOOLS,
                      'chat_template_kwargs': KWARGS, 'add_special_tokens': False,
                      'add_generation_prompt': True}
            count = budget(request('/tokenize', shared))
            response = request('/v1/chat/completions', {**shared, 'tool_choice': 'auto' if tool_turn else 'none',
                'temperature': 1.0, 'top_p': 0.95, 'max_tokens': OUTPUT, 'n': 1,
                'stream': False, 'return_token_ids': True, 'stop_token_ids': [1, 2, 128007],
                'include_reasoning': True})
            msg = checked(response, count, tool_turn)
            outputs.append(response)
            if tool_turn:
                # Preserve complete native reasoning, final body and tool call history. No executor.
                messages.append({'role': 'assistant', 'content': msg.get('content') or '',
                    'reasoning_content': msg['reasoning'], 'tool_calls': msg['tool_calls']})
                messages.append({'role': 'tool', 'tool_call_id': msg['tool_calls'][0]['id'],
                                 'content': '{"key":"alpha","value":7,"synthetic":true}'})
        return outputs
    
    
    if __name__ == '__main__':
        key = (pathlib.Path(__file__).resolve().parent / '.api-key').read_text().strip()
        if len(key) != 64 or any(c not in '0123456789abcdef' for c in key):
            raise SystemExit('private_key_format')
        result = run(lambda path, body: call(path, body, key))
        pathlib.Path('protocol-result.json').write_text(json.dumps(result, indent=2, allow_nan=False) + '\n')
        print('Native raw closing-think/tool boundaries and token budgets passed. Inspect final answer and record semantic failures; this is not a quality or performance benchmark.')
    CLIENTBLOCK
    python3 -m py_compile reader-client.py
    sha256sum --check <<'CHECKSUM'
    d86637c87bf3b2e68a87a58b703c76eff32bb72cf6ea31b194b6f3febc0c5f56  reader-client.py
    CHECKSUM

    Expected result: The complete exact helper is reconstructed and checksum-verified; it never executes tools or changes returned content.

  3. 3. Check readiness, auth boundary and native completion

    Native health/tokenize routes are not Bearer-protected; the server remains bound to host loopback. Unauthenticated /v1/models must return 401. No public port is opened. The client has a 120-second socket timeout that does not cancel GPU work.

    Command
    set -eu
    cd "$HOME/step35-flash"
    curl --fail --silent http://127.0.0.1:8996/health
    [ "$(curl --silent -o /dev/null -w '%{http_code}' http://127.0.0.1:8996/v1/models)" = 401 ]
    python3 reader-client.py

    Expected result: Record actual protocol-result.json and human semantic assessment. Residual tool/role/thinking controls, repeated or unclosed thinking, malformed tool order, nonterminal or missing native EOS, noninteger usage, overbudget or length finish fail closed. Protocol validity is not task quality.

Performance evidence

No compatible measurement available. Documented support and estimated memory do not establish response speed.

Limits and troubleshooting

  • Native 45 target layers and three MTP layers are preserved; all 288 routed experts plus shared expert are retained. Only 8 routed experts activate per token, which does not reduce full resident checkpoint requirements.
  • Native full attention alternates with 512-window sliding attention. Config max_seq_len 262144 and tokenizer model_max_length 131072 differ; this 8192-position walkthrough establishes neither maximum nor fit.
  • Released vLLM 0.27.1 Step3p5MTP uses its own multi-group/per-step proposer and all three prediction layers. This source-qualified choice supersedes the older card one-layer override; no speculative acceptance, speed or quality has been measured.
  • Native reasoning and XML tool delimiters differ from generic JSON-only tool formatting. The exact publisher Jinja remains unchanged; only parsed inert lookup arguments are accepted by the client, and no tool executes.
  • The fixed client 120-second socket timeout does not cancel native work; 1800-second foreground lifetime is a chosen demonstration bound. Stop/kill the exact container when needed.
  • Weights, target/draft activations, per-GPU caches and NCCL/workspace overhead remain unmeasured. Advertised 8 × 80 GB capacity and 2048 GiB host allocation do not prove fit.
  • Original repository/date/provider alias is preserved; exact native checkpoint pin is not asserted byte-equal to any provider API. Broader FP8, long-context, alternate hardware/runtime and task scopes remain open.
Native loading, collective initialization or GPU out-of-memory fails
Stop the exact container. Recheck all assets, eight GPUs, driver/image versions and source-qualified flags. Record failure; do not strip MTP/experts, silently quantize or change the checkpoint.
Missing closing thinking/tool markers, wrong parsed arguments or length finish
Treat the run as failed. Keep the exact request/history/token budget and retain diagnostics. Do not execute model-generated calls or infer task correctness from valid JSON alone.

Stop the model

  1. 1. Stop the exact private container

    Stop the foreground process and remove only this exact named service container. Client timeout does not guarantee server cancellation.

    Command
    sudo docker stop --time 10 step35-native || true
    if [ "$(sudo docker inspect -f '{{.State.Running}}' step35-native 2>/dev/null || true)" = true ]; then sudo docker kill step35-native; fi
    curl --max-time 3 http://127.0.0.1:8996/v1/models || true

    Expected result: The exact service container and loopback endpoint stop. Owned-host power/storage costs may remain.

Uninstall

  1. 1. Remove dedicated reader assets and network

    Remove this dedicated reader directory, internal network and exact image only after preserving desired results. Do not prune shared Docker resources or uninstall shared GPU drivers/toolkit.

    Command
    sudo docker rm -f step35-native 2>/dev/null || true
    sudo docker network rm step35-private
    sudo docker image rm vllm/vllm-openai@sha256:c2f3b1b964e47809b722b5e75b61b1e7b39a50f70388cf2bf2418f16a9f31da2
    rm -r -- "$HOME/step35-flash"

    Expected result: Dedicated reader artifacts are removed; shared Docker, drivers and unrelated resources remain.

Shut down cloud resources

  1. 1. End all instance and retained-resource billing

    In EC2 us-east-1 stop for later reuse or terminate this exact p5.48xlarge. Review Delete on termination for its 768 GiB root volume; remove unwanted detached EBS volumes, snapshots and retained IP resources. Local NVMe is ephemeral. Inspect Bills/Cost Explorer for final use; no cloud actions were performed here.

    Expected result: Compute ends only after the actual instance transition. Retained volumes, snapshots and IP resources can still bill; container stop alone ends no VM bill.

Sources and verification

Sources checked Oct 17, 2026. Verification source

Compare this configuration

Pricing

Token pricing for Step 3.5 Flash API usage.

Input Tokens

$0.10/M

per million tokens

Output Tokens

$0.30/M

per million tokens

Competing Models

Same pricing tier — direct alternatives to Step 3.5 Flash

Efficiency