Skip to content

ci(prod): record deployments again, and the sglake flag that starves the small indexes - #196

Merged
vaderyang merged 2 commits into
mainfrom
ci/prod-deployment-record
Aug 18, 2026
Merged

ci(prod): record deployments again, and the sglake flag that starves the small indexes#196
vaderyang merged 2 commits into
mainfrom
ci/prod-deployment-record

Conversation

@vaderyang

Copy link
Copy Markdown
Collaborator

Two unrelated fixes, both fallout from chasing why opening an agent turn felt
slow.

1. deploy-prod records a deployment again

The Environments panel has read production — failure since 2026-06-23, and
nothing failed. The deploy-prod run on 57ba003 named the production
environment, that environment required a reviewer, nobody approved, and GitHub
fails a deployment left waiting for 30 days — so it turned red on 2026-07-23, a
month after the release it was for had come and gone. No step ever ran.

#192 then dropped environment: production along with the approval it carried,
on the reasoning that cutting a tag is the approval and release.yml
already refuses to build a commit that is not both staging-soaked and
ebpf-soaked. That reasoning holds. What it missed is that naming an
environment is also the only thing that makes GitHub log a deployment at all —
so prod has deployed twice since (v0.7.2, v0.7.3) without recording either, and
the panel stayed frozen on the June entry, reporting a failure for a commit that
predates both.

This names the environment again, for the record and not for a gate.

Prerequisite, already applied: the production environment's
required-reviewers rule has been removed — protection_rules: []. It had to go
before this merges, not after: with the rule still on, the next release parks
for 30 days and then goes red exactly as before. The comment on the new line
says so, so nobody re-adds it.

Verification is the next release — deploy-prod should leave a success
deployment behind and the panel should move off the June entry. Until then it
stays red, which is expected.

2. --max-hot-span-hours — the size knob is global, the indexes are not

10-sglake.md said to raise --max-hot-raw-mib to 2048 and stopped there.
That is right for heron_bodies, which carries ~200 KB events and seals every
few hours on size alone. It is wrong for heron_spans, which carries scalars:
135 MB of raw spans in three days reaches 2048 MiB in about seven weeks, and the
--max-hot-span-hours default is 90 days. So the metadata index is the one
running with no on-disk index.tsidx — the opposite of what the bucket-count
analysis in that same section leads you to expect.

A hot bucket has no inverted index, so sglogd builds one in memory per search,
and Heron appends every flush_interval_ms, invalidating it about as fast as it
is built. Measured with both indexes hot, under live ingest:

index hot journal.sgj point lookup stats count
heron_traces 3.4 MB 65 ms, no outliers 82 ms
heron_spans 22 MB 12 ms, spiking to 2.2 s 4.2 s

Same code path and the same absent tsidx in both rows; the only variable is how
much journal the in-memory build has to cover. Polling once a second, ~40% of
lookups paid it, and at that point it is the dominant cost of opening an agent
turn.

The doc now names --max-hot-span-hours 6 as a third required flag, explains
why the size knob alone cannot cover an index whose events are small, and
records what makes this easy to misdiagnose: the cost is invariant in every way
that suggests the query is fine — the same for a 1-call turn as an 85-call one,
and the same whether the search window is the turn's own span, ±24 h, or
unbounded.


Docs and CI only; no Rust or console code changes.

Vader Yang added 2 commits August 18, 2026 14:29
The repo's Environments panel has shown `production — failure` since
2026-06-23. Nothing failed. deploy-prod run on 57ba003 named the
`production` environment, that environment requires a reviewer, nobody
approved, and GitHub fails a deployment left waiting for 30 days — so it
turned red on 2026-07-23, a month after the release it was for had come
and gone. No step ever ran.

#192 then removed `environment: production` along with the approval it
carried, on the reasoning that cutting a tag IS the approval and
release.yml already refuses to build a commit that is not both
`staging-soaked` and `ebpf-soaked`. That reasoning holds. What it missed
is that naming an environment is also the only thing that makes GitHub
log a deployment at all — so since #192 prod has shipped four releases
without recording one, and the panel has been frozen on the stale June
entry, reporting a failure for a commit two versions behind what is
actually running.

So: name the environment again, for the record and not for a gate. This
only works with the reviewer rule off the environment — with it on, the
next release parks for 30 days and then goes red exactly as before.

ORDERING: the `production` environment must have its required-reviewers
rule removed BEFORE this merges. Merging first re-arms the bug.
`--max-hot-raw-mib 2048` was documented as the bucket-sizing answer. It is
one, for `heron_bodies` — ~200 KB events reach it every few hours, so that
index is almost entirely warm and carries a tsidx.

`heron_spans` carries scalars. A production instance accumulated 135 MB of
raw spans in three days, so it reaches 2048 MiB in about seven weeks, and
`--max-hot-span-hours` defaults to 90 days. The metadata index is therefore
the one that never seals and never gets an on-disk inverted index — the
opposite of what the bucket-count analysis predicts.

A hot bucket has no tsidx, so sglogd builds one in memory per search, and
Heron appends every flush interval, which invalidates it about as fast. The
cost tracks how much journal that build covers, and nothing else:

  heron_traces  3.4 MB hot   point lookup  65 ms, no outliers   count 82 ms
  heron_spans    22 MB hot   point lookup  12 ms → 2.2 s spikes count 4.2 s

Same code path, same absent tsidx; the size is the only variable. At 22 MB
it was the dominant cost of opening an agent turn — polling once a second,
~40% of lookups paid ~2 s. It is invariant in every way that misleads: same
for a 1-call turn as an 85-call one, and same whether the window is the
turn's own span, ±24 h, or unbounded — which is why it reads as "the server
is fine" if you only ever measure a repeated request.

Document `--max-hot-span-hours 6` as the third required flag, with the
measurements and the reason the size knob alone cannot cover both shapes.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both files read, cross-references checked. This is a small PR: one workflow line re-adding environment: production for deployment bookkeeping, and a substantial sglake doc section documenting a new recommended sglogd flag. No console, no Rust, no SQL, no schema touched — most of the classic risk categories don't apply.

Summary

Re-adds environment: production to the deploy job (for the GitHub Environments panel record, not as a gate) and documents --max-hot-span-hours 6 as a third required sglogd flag in the sglake design doc, with behind-the-scenes measurements. The workflow change is correct and well-reasoned: re-naming the environment only matters for the record, and the comment correctly warns it re-arms the 30-day-red bug if a reviewer rule is re-added. The doc section is technically sound and the flag logic checks out. My take: APPROVE.

Suggestions

  • server/config/default.toml:137-150 — The design doc now calls --max-hot-span-hours 6 a "third required flag" (10-sglake.md:305,310), but default.toml still lists only three items under "Three things about the sglogd side that Heron cannot set for you" and none is --max-hot-span-hours. This is the other operator-facing surface for the same daemon config, and staying silent on the one flag whose omission is now documented as "produces a slow console" leaves a reader who configures from default.toml without the design doc unknowingly mis-tuned. Add it there (and to scripts/staging/soak doc references if ether reference it).

Questions

  • docs/design/10-sglake.md:310 — --max-hot-span-hours (default 2160 h) is asserted but never appears anywhere in the repo, and I can't verify the flag name/default against sglogd's own flag surface. Was the exact flag name and its 90-day default confirmed from sglogd herbinsdocs/shuj_init? A wrong name here becomes a trustworthy-but-wrong operator instruction.
  • docs/design/10-sglake.md:347 — "only --max-hot-span-hours does that for an index whose events are small." Is there no max-hot-buckets-style count cap that would act more uniformly than a per-index hours tuner, or was a per-daemon size tie confirmed unreachable for the metadata indexes (the 2048 MiB ≈ 7 weeks math)?
  • docs/design/10-sglake.md:331 — the measurements are single-instance ("against that instance"), and the "four buckets a day"@6 h, "120 buckets over 30 days" guidance drifts if retention is not 30 days. Intended that the numbers are only illustrative?

Verified

  • No leakage: the diff and the full working tree contain no private IPs, credentials, key material, or internal hostnames (grep over the diff and the doc for RFC1918/CGNAT ranges and -----BEGIN/PRIVATE KEY — empty). The HERON_PROD_* vars referenced at deploy-prod.yml:107–109 are configurable env, not secrets-in-repo.
  • environment: production at deploy-prod.yml:71 introduces the only environment-scoped resource in this job; it wraps no env-scoped secrets (only the always-present GITHUB_TOKEN), so re-adding the environment does not break secret access — consistent with its stated "for the record, not for a gate" purpose.
  • Commit 1's claim (#192 dropped the line; panel frozen on a stale failure) is consistent with the workflow's current diff — environment: production is the only line added, and the file documents #192 as having removed the approval.
  • Doc internals: the heron_bodies 2048 MiB / heron_spans 7-week math is internally consistent (135 MB/3 days × ~51 days ≈ 2048 MiB, 2×= time-over-Jan then reach to scale). No body-scan or schema-drift concerns — this PR touches no SQL and no schemas.
  • Cross-references to --max-hot-raw-mib numbers in default.toml and it.rs remain accurate; the new section copies the same 124k-span/12-warm-bucket figures already used at line 309.

🤖 Reviewed by the review botworkflow run

@vaderyang
vaderyang merged commit b9ea0d5 into main Aug 18, 2026
2 checks passed
@vaderyang
vaderyang deleted the ci/prod-deployment-record branch August 18, 2026 08:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant