Documentation
¶
Index ¶
- func AcceptanceRunHandler(repoDir string) http.HandlerFunc
- func BenchCompareGroupsHandler(w http.ResponseWriter, r *http.Request)
- func BenchCompareHandler(w http.ResponseWriter, r *http.Request)
- func BenchComparisonsHandler(w http.ResponseWriter, r *http.Request)
- func BenchExportHandler(w http.ResponseWriter, r *http.Request)
- func BenchImportHandler(w http.ResponseWriter, r *http.Request)
- func BenchProtocolHandler(repoDir string) http.HandlerFunc
- func BenchRunHistogramHandler(w http.ResponseWriter, r *http.Request)
- func BenchRunStatsHandler(w http.ResponseWriter, r *http.Request)
- func BenchRunsHandler(w http.ResponseWriter, r *http.Request)
- func DeployHandler(repoDir string) http.HandlerFunc
- func DeploysListHandler(w http.ResponseWriter, r *http.Request)
- func InitBenchDB(repoDir, schemaSQL string) error
- func InitSecrets(store *secrets.Store)
- func MetricsLiveHandler(w http.ResponseWriter, r *http.Request)
- func MetricsLiveRouter(w http.ResponseWriter, r *http.Request)
- func MetricsSnapshotHandler(w http.ResponseWriter, r *http.Request)
- func ParseK6JSON(path string) (latencies []float64, errorRate float64, err error)
- func RunHandler(repoDir string) http.HandlerFunc
- func SecretAuditHandler(w http.ResponseWriter, r *http.Request)
- func ServerDeleteAdminKeyHandler(w http.ResponseWriter, r *http.Request)
- func ServerFetchAdminKeyHandler(w http.ResponseWriter, r *http.Request)
- func ServerSecretStatusHandler(w http.ResponseWriter, r *http.Request)
- func ServerSetAdminKeyHandler(w http.ResponseWriter, r *http.Request)
- func ServersCreateHandler(w http.ResponseWriter, r *http.Request)
- func ServersDeleteHandler(w http.ResponseWriter, r *http.Request)
- func ServersListHandler(w http.ResponseWriter, r *http.Request)
- func ServersTestHandler(w http.ResponseWriter, r *http.Request)
- func StartMetricsScraper()
- type CompareResult
- type GroupCompareResult
- type MetricSample
- type RegisteredServer
- type RunStats
- type RunSummary
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AcceptanceRunHandler ¶
func AcceptanceRunHandler(repoDir string) http.HandlerFunc
AcceptanceRunHandler — GET /api/acceptance-run?server=<id>
Streams scripts/acceptance-test.sh against the chosen server over SSH tunnels (data-plane :engine_port and control-plane :9090). Each output line is delivered as an SSE "line" event; a final "done" event carries the exit code and pass/fail/info counts. Concurrent runs against the same server are rejected with 409 to prevent test interference.
func BenchCompareGroupsHandler ¶
func BenchCompareGroupsHandler(w http.ResponseWriter, r *http.Request)
BenchCompareGroupsHandler — POST /api/bench/compare-groups body: {"label_a":"baseline-x","label_b":"candidato-y"}
func BenchCompareHandler ¶
func BenchCompareHandler(w http.ResponseWriter, r *http.Request)
BenchCompareHandler — POST /api/bench/compare body: {"run_a":1,"run_b":2}
func BenchComparisonsHandler ¶
func BenchComparisonsHandler(w http.ResponseWriter, r *http.Request)
BenchComparisonsHandler — GET /api/bench/comparisons → comparison history.
func BenchExportHandler ¶
func BenchExportHandler(w http.ResponseWriter, r *http.Request)
BenchExportHandler — GET /api/bench/export?prefix=pub- Streams every run whose label starts with the prefix as CSV (raw evidence for published benchmarks; error_rate included because the saturation criterion depends on it).
func BenchImportHandler ¶
func BenchImportHandler(w http.ResponseWriter, r *http.Request)
BenchImportHandler — POST /api/bench/import body: {"path":"/tmp/k6-run.json","label":"...","rps":500,"duration":30}
func BenchProtocolHandler ¶
func BenchProtocolHandler(repoDir string) http.HandlerFunc
BenchProtocolHandler — POST /api/bench/protocol body: {"runs":3,"label":"ui-test","rate":50,"duration":"15s",
"script":"sustained_writes.js","server_id":2}
script is optional (default sustained_2krps.js) and must be one of the protocolScripts allowlist keys — never a path.
server_id is optional: when set, the run targets that registered server's engine (TARGET_URL) and the label is prefixed "{server_name}--" so groups from different servers stay distinguishable yet comparable. k6 ALWAYS runs on this box — the loader never competes for CPU with the system under test (S46 methodology).
Runs scripts/bench-protocol.sh and streams its stdout/stderr as SSE, ending with an `event: done` carrying the exit code.
SECURITY: every field is validated against a strict allowlist before use, and the validated values are passed as SEPARATE argv elements to exec.Command — never concatenated into a shell string. There is no path to `sh -c` here, so even if a regex were loosened the values still cannot break out into the shell.
func BenchRunHistogramHandler ¶
func BenchRunHistogramHandler(w http.ResponseWriter, r *http.Request)
BenchRunHistogramHandler — GET /api/bench/runs/{id}/histogram Returns 1ms-wide buckets aggregated in SQL (never ships raw datapoints).
func BenchRunStatsHandler ¶
func BenchRunStatsHandler(w http.ResponseWriter, r *http.Request)
BenchRunStatsHandler — GET /api/bench/runs/{id}/stats Quartile/boxplot summary for one run (cached). Never ships raw datapoints.
func BenchRunsHandler ¶
func BenchRunsHandler(w http.ResponseWriter, r *http.Request)
BenchRunsHandler — GET /api/bench/runs → list benchmark_runs (no datapoints).
func DeployHandler ¶
func DeployHandler(repoDir string) http.HandlerFunc
DeployHandler — POST /api/deploy body: {"server_id":2,"confirm":"58-prod"}
func DeploysListHandler ¶
func DeploysListHandler(w http.ResponseWriter, r *http.Request)
DeploysListHandler — GET /api/deploys?server_id=
func InitBenchDB ¶
InitBenchDB opens (creating if needed) the SQLite store at <repoDir>/tools/devhub/db/devhub.db and applies the embedded schema. The schema is idempotent (CREATE TABLE IF NOT EXISTS / INSERT OR IGNORE), so it is safe to run on every boot. schemaSQL is the contents of db/schema.sql, passed in from the main package (which can embed it — the api package cannot reach a sibling directory with go:embed).
func InitSecrets ¶
InitSecrets connects the age store and routes its usage audit into SQLite.
func MetricsLiveHandler ¶
func MetricsLiveHandler(w http.ResponseWriter, r *http.Request)
func MetricsLiveRouter ¶
func MetricsLiveRouter(w http.ResponseWriter, r *http.Request)
MetricsLiveRouter — GET /api/metrics/live?server={id} No server param (or a local server) → the existing local ring stream; a remote server id → the on-demand tunnel scrape stream.
func MetricsSnapshotHandler ¶
func MetricsSnapshotHandler(w http.ResponseWriter, r *http.Request)
func ParseK6JSON ¶
ParseK6JSON streams a k6 NDJSON file line by line (never loading the whole file — it can be >100MB) and returns the http_req_duration latencies in ms for successful requests, plus the error rate. A request is "successful" when its expected_response tag is not "false" (k6 tags failed responses expected_response:"false"); the error rate is failed / total over all http_req_duration points.
func RunHandler ¶
func RunHandler(repoDir string) http.HandlerFunc
func SecretAuditHandler ¶
func SecretAuditHandler(w http.ResponseWriter, r *http.Request)
SecretAuditHandler — GET /api/audit/secrets?server_id=
func ServerDeleteAdminKeyHandler ¶
func ServerDeleteAdminKeyHandler(w http.ResponseWriter, r *http.Request)
ServerDeleteAdminKeyHandler — DELETE /api/servers/{id}/admin-key (rotation).
func ServerFetchAdminKeyHandler ¶
func ServerFetchAdminKeyHandler(w http.ResponseWriter, r *http.Request)
ServerFetchAdminKeyHandler — POST /api/servers/{id}/fetch-admin-key The human's click IS the authorization: the DevHub reads ADMIN_KEY from the server's own secrets file over SSH (fixed command, validated path) and stores it encrypted. The value never appears in the response, logs or DB.
func ServerSecretStatusHandler ¶
func ServerSecretStatusHandler(w http.ResponseWriter, r *http.Request)
ServerSecretStatusHandler — GET /api/servers/{id}/secret-status The only thing the API reveals about a secret: whether one exists, and where it would come from. Never the value.
func ServerSetAdminKeyHandler ¶
func ServerSetAdminKeyHandler(w http.ResponseWriter, r *http.Request)
ServerSetAdminKeyHandler — PUT /api/servers/{id}/admin-key body {"value":"..."} Manual load for servers where the SSH fetch does not apply.
func ServersCreateHandler ¶
func ServersCreateHandler(w http.ResponseWriter, r *http.Request)
ServersCreateHandler — POST /api/servers
func ServersDeleteHandler ¶
func ServersDeleteHandler(w http.ResponseWriter, r *http.Request)
ServersDeleteHandler — DELETE /api/servers/{id}
func ServersListHandler ¶
func ServersListHandler(w http.ResponseWriter, r *http.Request)
ServersListHandler — GET /api/servers
func ServersTestHandler ¶
func ServersTestHandler(w http.ResponseWriter, r *http.Request)
ServersTestHandler — POST /api/servers/{id}/test Dials the server (TOFU-pinning the host key on first connect), runs the fixed identification commands and probes the engine's /health through an SSH tunnel. Pure read-only diagnostics.
func StartMetricsScraper ¶
func StartMetricsScraper()
Types ¶
type CompareResult ¶
type CompareResult struct {
RunA int64 `json:"run_a"`
RunB int64 `json:"run_b"`
U float64 `json:"u"`
PValue float64 `json:"p_value"`
CILowerMs float64 `json:"ci_lower_ms"`
CIUpperMs float64 `json:"ci_upper_ms"`
MinEffectMs float64 `json:"min_effect_ms"`
Significant bool `json:"significant"`
Direction string `json:"direction"`
DeltaPct float64 `json:"delta_pct"`
}
CompareResult is the outcome of CompareRuns, mirroring the comparisons table (plus min_effect_ms, which is reported for transparency but not persisted).
func CompareRuns ¶
func CompareRuns(runA, runB int64) (*CompareResult, error)
CompareRuns loads both runs' datapoints, classifies the comparison (see classify) and persists it. Returns the verdict.
type GroupCompareResult ¶
type GroupCompareResult struct {
LabelA string `json:"label_a"`
LabelB string `json:"label_b"`
ServerA string `json:"server_a"` // parsed from the "{server}--" label prefix
ServerB string `json:"server_b"`
NRunsA int `json:"n_runs_a"`
NRunsB int `json:"n_runs_b"`
NA int `json:"n_a"` // pooled datapoints after per-run IQR rejection
NB int `json:"n_b"`
CVBetweenRunsA float64 `json:"cv_between_runs_a"`
CVBetweenRunsB float64 `json:"cv_between_runs_b"`
U float64 `json:"u"`
PValue float64 `json:"p_value"`
CILowerMs float64 `json:"ci_lower_ms"`
CIUpperMs float64 `json:"ci_upper_ms"`
MinEffectMs float64 `json:"min_effect_ms"`
Significant bool `json:"significant"`
Direction string `json:"direction"`
DeltaPct float64 `json:"delta_pct"`
}
GroupCompareResult is the verdict for a label-vs-label comparison. It carries the same statistical fields as CompareResult plus group metadata: how many runs each label pooled, the pooled datapoint counts, and each group's between-run CV (the run-to-run reproducibility of the p50). This is the defensible "N runs vs M runs" comparison, as opposed to single run vs run.
func CompareGroups ¶
func CompareGroups(labelA, labelB string) (*GroupCompareResult, error)
CompareGroups pools every run of label A and label B (IQR-rejecting each run first) and runs the same verdict (Mann-Whitney + bootstrap CI + practical min-effect) on the two pools. Comparing a label against itself yields no_change (identical pools → zero median shift). Not persisted: the comparisons table is keyed on single run ids.
type MetricSample ¶
type RegisteredServer ¶
type RegisteredServer struct {
sshx.Server
EnginePort int
AdminKeyEnv string
IsProduction bool
BenchTenant string
SecretsPath string
StartScript string
BinaryPath string
LogPath string
CreatedAt string
}
RegisteredServer is a row of the servers table plus its sshx identity. The SSH key is exposed to API consumers as its basename only — the full path stays server-side and the key material never leaves the filesystem.
func LoadServer ¶
func LoadServer(id int64) (*RegisteredServer, error)
LoadServer fetches one registered server by id.
func (*RegisteredServer) AdminKey ¶
func (s *RegisteredServer) AdminKey() string
AdminKey resolves the server's engine admin key from the devhub process environment (admin_key_env names the variable; secrets never live in SQLite).
func (*RegisteredServer) EngineURL ¶
func (s *RegisteredServer) EngineURL() string
EngineURL is the direct (untunneled) base URL of the server's engine — what an external load generator should hit.
type RunStats ¶
type RunStats struct {
RunID int64 `json:"run_id"`
Min float64 `json:"min"`
Q1 float64 `json:"q1"`
Median float64 `json:"median"`
Q3 float64 `json:"q3"`
Max float64 `json:"max"`
P95 float64 `json:"p95"`
P99 float64 `json:"p99"`
N int `json:"n"`
OutliersIQR int `json:"outliers_iqr"`
}
RunStats is the five-number boxplot summary of a run plus the tail percentiles and IQR-outlier count. Computed in Go (SQLite has no native percentile) and cached: a run's datapoints are immutable, so the summary never changes.
type RunSummary ¶
type RunSummary struct {
RunID int64 `json:"run_id"`
Label string `json:"label"`
TargetRPS int `json:"target_rps"`
DurationS int `json:"duration_s"`
N int `json:"n_requests"`
P50 float64 `json:"p50_ms"`
P95 float64 `json:"p95_ms"`
P99 float64 `json:"p99_ms"`
ErrorRate float64 `json:"error_rate"`
CV float64 `json:"cv"`
}
RunSummary is the row written to benchmark_runs plus its id.