Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 157 additions & 0 deletions dag/extdeps/vllm/usage_stats.dag
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
module extdeps.vllm.usage_stats

import std.types { NonEmptyStr, List }
import std.decl_ref { DeclarationRef, WholeDeclaration }
import extdeps.external_authority { ExternalAuthority, ExternalModelScope, ExternalSubjectRef }
import extdeps.uri { Uri, Https }
import extdeps.vllm.server { VllmSourceRevision, vllm_source_revision_read }

data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority {
uri: Uri {
scheme: Https
locator: "docs.vllm.ai/en/latest/usage/usage_stats.html"
}
}

data vllm_usage_stats_source_citation: ExternalAuthority = ExternalAuthority {
uri: Uri {
scheme: Https
locator: "github.com/vllm-project/vllm/blob/main/vllm/usage/usage_lib.py"
}
}

data vllm_usage_stats_server_default_citation: ExternalAuthority = ExternalAuthority {
uri: Uri {
scheme: Https
locator: "github.com/vllm-project/vllm/blob/main/vllm/envs.py"
}
}

data extdeps_model_scope: ExternalModelScope = ExternalModelScope {
subject: ExternalSubjectRef {
declaration: DeclarationRef {
module_path: "extdeps.vllm.usage_stats",
decl_name: "VllmUsageStatsReporting",
field: WholeDeclaration
}
},
first_citation: extdeps_external_authority_anchor,
further_citations: [vllm_usage_stats_source_citation, vllm_usage_stats_server_default_citation]
}

// ── THE ONE THING A vLLM SERVER SENDS OFF THE BOX BY DEFAULT ──────────────────────────────────
//
// WHY THIS MODULE EXISTS. Every other fact about our serving route says the material stays where
// the machine is. This is the exception, and it is an exception nobody in this repository had
// written down: vLLM reports usage statistics to an upstream service unless it is switched off, and
// nothing on the Spark serving launch switches it off. A data-path closure that answered "the
// operator's site" for telemetry would have been false about the one path that demonstrably leaves
// it -- and false in the direction that reads as clean.
//
// WHAT IT IS NOT. It is not a leak of route material. The documented payload is configuration and
// hardware metadata; upstream is explicit that request content, prompts and completions are not
// collected, and the field roster below carries no field derived from a request. That distinction
// is the whole reason a consumer can admit this path rather than refuse it, so it is modelled as a
// TYPED CONTENT CLASS rather than asserted in a sentence.
//
// REVISION-BOUND, like every other reading of this upstream. The roster is what upstream documents
// at the cited revision; a later revision that adds a field is a different fact, and the binding to
// vllm_source_revision_read is what makes that decidable instead of a surprise.

// THE TWO CLASSES ARE SEPARATE BECAUSE THEY AUTHORIZE DIFFERENT THINGS. A metadata-only egress can
// support an admission for a route whose material stays home; an egress carrying any request
// material cannot, and would have to refuse rather than be argued about. There is deliberately no
// "probably fine" arm.
type VllmUsageStatsContentClass
= ConfigurationAndHardwareMetadataOnly
| CarriesRequestMaterial

// THE DESTINATION IS A THIRD PARTY, AND ITS JURISDICTION IS NOT DOCUMENTED. Upstream publishes the
// default server and nothing about who operates it or under which legal system, so the jurisdiction
// is an UNREAD upstream fact rather than one this module may supply. It is a typed arm rather than
// a missing field for the reason this whole repository keeps repeating: an absent jurisdiction and
// a jurisdiction nobody looked up must not be the same value, and a consumer that needs one must be
// able to see that it does not exist here.
type VllmUsageStatsServiceJurisdiction
= ServiceJurisdictionDocumented { jurisdiction: NonEmptyStr }
| ServiceJurisdictionUndocumentedUpstream

// ── HOW UPSTREAM READS THE DISABLE VARIABLES, WHICH IS NOT "IS IT SET" ────────────────────────
//
// THE NAMES ALONE WERE NOT THE FACT, and modelling only the names pushed the reading into the
// consumer, where it was authored rather than cited: gunbc asked whether an assignment's value was
// anything other than "0", and upstream asks whether it EQUALS "1"
// (os.environ.get("VLLM_NO_USAGE_STATS", "0") == "1", and DO_NOT_TRACK the same way, in envs.py).
// Those disagree on VLLM_NO_USAGE_STATS=false, =no, =0.0 and every other spelling a person would
// expect to mean off: upstream keeps reporting and the consumer read "disabled" -- the admitting
// direction, on a launch that is still sending (review 64043).
//
// So the reading lives here, once, with the names it belongs to. A term is a variable AND the exact
// value that disables it, because separating them is what let the pair be recombined wrongly.
type VllmUsageStatsDisableTerm {
variable: NonEmptyStr
disabling_value: NonEmptyStr
}

// EXACT EQUALITY ON BOTH COMPONENTS, because that is what upstream performs. There is deliberately
// no truthiness, no case folding and no "anything non-empty": each of those is a consumer's guess
// about a reading this module can state.
fn vllm_usage_stats_assignment_disables(term: VllmUsageStatsDisableTerm, name: NonEmptyStr, value: String) -> Bool {
(name as String) == (term.variable as String) && value == (term.disabling_value as String)
}

type VllmUsageStatsReporting sole_constructor {
default_server: NonEmptyStr
server_override_env: NonEmptyStr
local_copy_path: NonEmptyStr
content_class: VllmUsageStatsContentClass
service_jurisdiction: VllmUsageStatsServiceJurisdiction
collected_fields: List<NonEmptyStr>
disable_terms: List<VllmUsageStatsDisableTerm>
disable_marker_path: NonEmptyStr
established_against: VllmSourceRevision
}

// THE ROSTER IS THE DOCUMENTED EXAMPLE PAYLOAD, transcribed as the field NAMES upstream publishes.
// Every one of them is a property of the host, the build or the engine configuration; none is
// derived from a request, which is what the content class above records and what a reader can check
// here rather than take on faith.
data vllm_usage_stats_reporting: VllmUsageStatsReporting = VllmUsageStatsReporting {
default_server: "https://stats.vllm.ai",
server_override_env: "VLLM_USAGE_STATS_SERVER",
local_copy_path: "~/.config/vllm/usage_stats.json",
content_class: ConfigurationAndHardwareMetadataOnly,
service_jurisdiction: ServiceJurisdictionUndocumentedUpstream,
collected_fields: [
"uuid", "provider", "num_cpu", "cpu_type", "cpu_family_model_stepping",
"total_memory", "architecture", "platform", "gpu_count", "gpu_type",
"gpu_memory_per_device", "model_architecture", "vllm_version", "context",
"log_time", "source", "dtype", "tensor_parallel_size", "block_size",
"gpu_memory_utilization", "quantization", "kv_cache_dtype", "enable_lora",
"enable_prefix_caching", "enforce_eager", "disable_custom_all_reduce",
],
disable_terms: [
VllmUsageStatsDisableTerm { variable: "VLLM_NO_USAGE_STATS", disabling_value: "1" },
VllmUsageStatsDisableTerm { variable: "DO_NOT_TRACK", disabling_value: "1" },
],
disable_marker_path: "~/.config/vllm/do_not_track",
established_against: vllm_source_revision_read,
}

// THE THIRD TERM OF UPSTREAM'S DISJUNCTION IS THE MARKER FILE, carried above as
// disable_marker_path and deliberately not folded by the launch standing below: a container
// environment cannot answer whether a path exists inside the image or the home directory, and
// guessing would be the same authored reading this module just moved out of the consumer. Its
// absence from the fold errs in the conservative direction -- a fleet that disabled reporting only
// by marker file reads as ENABLED here, which over-declares the egress rather than hiding it -- and
// the honest closure is a filesystem observation, not a bolder predicate.
//
// REPORTING IS ON UNLESS SOMETHING TURNS IT OFF, which is the shape of the upstream check
// (_USAGE_STATS_ENABLED = not (do_not_track or no_usage_stats or do_not_track_file)) and therefore
// the shape of the question a consumer must ask about a particular launch. The arms are what a
// launch's configuration can establish, and the unread arm exists because reading a running host's
// environment is an observation this module cannot make.
type VllmUsageStatsLaunchStanding
= UsageStatsDisabledByLaunch { mechanism: NonEmptyStr }
| UsageStatsEnabledByDefault { basis: NonEmptyStr }
| UsageStatsLaunchUnread { obligation: NonEmptyStr }
34 changes: 20 additions & 14 deletions dag/gunbc/harness/harness_seat.dag
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module gunbc.harness.harness_seat
import std.types { String, Bool, Int, NonEmptyStr, List, EpochSecs }
import std.nat { Nat, nat_range_inclusive, nat_min }
import std.measure { Measure, Count, One, money_amount_micro }
import gunbc.spark.fabric_switch_observed { FabricGroup, fabric_group_wire }
import gunbc.spark.fabric_switch_observed { FabricGroup, fabric_group_wire, fabric_group_hosts }
import gunbc.serving.serving_enrollment {
ServingRoute, ServingRouteResolved, ServingRouteUnresolved, ServingRouteEndpoint,
ServingRouteTurnCeiling, serving_enrolled_routes, serving_route_turn_ceiling_count,
Expand Down Expand Up @@ -434,25 +434,31 @@ fn harness_no_candidate(acc: HarnessCandidates, note: String, retryable: Bool) -
HarnessCandidates { candidates: acc.candidates, notes: concat(acc.notes, [note]), retryable: acc.retryable || retryable }
}

// NO CANDIDATE IS PRODUCED FROM A BOUND OFFER ANY MORE, AND THE MISSING PIECE IS ADMISSION RATHER
// THAN BINDING. A CandidateOffer now seals a ProviderUsePermit, so bind_candidate needs a
// ProviderUseAdmission over the offer's route -- and producing one through admit_provider_use
// requires a ProviderUseScope carrying a customer profile, a data-handling profile, an agreement
// and three cleared dispositions. Those are compliance claims about us; there is no producer for
// them, and writing plausible ones so the call typechecks is the fail-open this wall exists to
// close. So the SparkOfferBound arm reports what is missing and seats nobody.
// NO CANDIDATE IS PRODUCED FROM A BOUND OFFER YET, AND THE MISSING PIECE HAS MOVED ONE WALL BACK.
// Two of the three obstacles are now gone: spark_serving_route_standing carries the operator's
// dated site allocation rather than refusing, and gunbc.spark.first_party_serving
// spark_first_party_admission is the provider-use admission producer this note used to say did not
// exist. What remains is the offer's OTHER seal.
//
// That arm is unreachable today for a second, independent reason -- spark_serving_route_standing
// refuses above it -- and the two are deliberately separate: landing a region observer alone must
// not silently resume seating through a path nothing admitted.
// A CandidateOffer is sole_constructor through product.fabric.selection bind_candidate, which takes
// a DEMAND IDENTITY and a WORK IDENTITY and compares the permit against both. A WorkKey comes from
// exactly one place -- product.fabric.work derive_work_key, through work_for -- which needs a
// WorkContract, which needs a SourceManifestRef; and gunbc.serving.turn_demand refuses to produce
// one, because nothing in this repository observes the exact weights, tokenizer and runtime closure
// a launch loaded (serving_turn_source_obligation). Minting a key beside derive_work_key would
// fabricate the identity the fabric's deduplication and receipts are keyed on, so this arm reports
// what is missing and seats nobody rather than inventing it.
//
// THE CAPABILITY IS THE REQUIREMENT'S, NOT THE OBSERVED MODEL'S, and the two are reconciled before
// this is reached rather than here: the observed unit has already been checked against the
// requirement, so binding the requirement's capability states exactly what was established -- this
// route satisfies what the demand asked for -- and keeps the offer and the demand comparable by the
// equality the fabric uses.
//
// Restoration trigger: a provider-use admission producer for the spark serving route.
// Restoration trigger: a launch receipt that reads the weights, tokenizer and runtime closure off a
// running engine, SUFFICIENT FOR gunbc.serving.turn_demand serving_turn_work to return TurnWorkBound
// for a harness turn -- at which point the demand and work identities exist, the admission producer
// above is called with them, and bind_candidate has everything it compares.
fn harness_bind_candidate(acc: HarnessCandidates, group: FabricGroup, endpoint: ServingRouteEndpoint, launch: VllmEndpointProcessLaunch, standing: HarnessBackendStanding, requirement: ServingModelRequirement, seats: Nat, now: EpochSecs) -> HarnessCandidates {
match bind_spark_serving_offer(
principal: "gunbc" as NonEmptyStr,
Expand All @@ -463,7 +469,7 @@ fn harness_bind_candidate(acc: HarnessCandidates, group: FabricGroup, endpoint:
isolation: serving_isolation_profile(),
seats: seats as Int,
readiness: harness_serving_readiness(standing: standing, now: now),
route: spark_serving_route_standing(),
route: spark_serving_route_standing(hosts: fabric_group_hosts(g: group)),
) {
SparkOfferBindingRefused { group_wire: _, cause: why } =>
harness_no_candidate(acc: acc, note: seat_bind_detail(group: group, text: why as String), retryable: false)
Expand All @@ -472,7 +478,7 @@ fn harness_bind_candidate(acc: HarnessCandidates, group: FabricGroup, endpoint:
acc: acc,
note: seat_bind_detail(
group: group,
text: "the serving offer bound but no provider-use admission producer exists for its route, so it cannot become a candidate",
text: "the serving offer bound and its route is admissible, but a serving turn has no Work identity: nothing observes the weights, tokenizer and runtime closure a launch loaded, so gunbc.serving.turn_demand cannot bind a source manifest and product.fabric.selection bind_candidate has no work to compare the permit against",
),
retryable: false,
)
Expand Down
Loading
Loading