A missing secret silently switched Discord and Patreon member sign-in off.
Outside Development and Testing the validator now fails naming
Heimdall:AppSecretFile and Heimdall:AppSecret, never a value.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The file wins, is read once when the options are built, and a set-but-missing,
unreadable or empty file stops startup in every environment without naming the
secret. Heimdall__AppSecret still works and logs a deprecation warning.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
FixedWindowBudget times windows on the clock's monotonic timestamps so a wall-clock
step cannot stretch or reset one, expires windows from a start-ordered queue instead
of a periodic sweep, and holds at most MaxTrackedKeys keys: a new key at the cap is
denied with the true wait and a held key is never evicted. MintPermits is 30 per hour
per the operator ruling, and a 429 now carries a plain-text reason; a refused new
device is told it can sign in. Not yet built or tested at this commit.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
One FixedWindowBudget (injectable clock) owned by ConceptVoteRateLimits;
the vote page 429s with Retry-After before any row or cookie. Prefix
lengths and budgets are validated in every environment. Pins the empty
Origin branch of CastRequestGuard.
Unverified; not yet built.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GET /public/concepts/{collection}/tallies returns per-live-subject up, down and
member counts only, anonymous, Cache-Control public max-age=60. CORS policy
ConceptTallies is built from ConceptVotes:AllowedOrigins, GET only, no
credentials, required on this route alone. Production startup refuses an
allowed origin that is not an exact https origin.
Not yet built or tested when committed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ConceptAppraisalService is the only appraisal writer; tallies are derived from
rows. VoterIdentity.For decides voter key and class; NetworkPrefix is the only
prefix computation (HMAC tag). NetworkTagSecret is required in production.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
UseForwardedHeaders runs first with KnownProxies exactly loopback and
ForwardLimit 1; Data Protection always uses application name "Bifrost";
the startup validator refuses production without DataProtection:KeysPath.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>