21 KiB
21 KiB
Customer onboarding: body facts at 2026-10-30
Served: the same forks. Eyes pass over Bifrost origin/main, Heimdall, StreamPixels state/map.yaml, gamecult-ops inventory and the eureka mind. Facts only.
Eyes: customer onboarding, what the body can do today (2026-10-30)
Read via git show origin/main: after git fetch in each repo. Bifrost origin/main = cc76f0f; Heimdall = 5146c72; StreamPixels = 9a113d3; gamecult-ops = c03e03c. Facts only. Not read: Bifrost tests, live DB contents, jurisdiction-map.md, bifrost-mvp-plan.md body, Heimdall implementation (src/app.ts), StreamPixels docs/joystick-integration-map.md, Yggdrasil live state (no ssh).
0. The trigger (mind)
eureka-body:ruling:customers-get-voting-power-onboarding-owed(Operator, 2026-10-30, InForce). Quote: "Funny coincidence, then, that our first customer, and likely the largest for a while, is a fox themed vtuber, with 1,500€ of work contracted, and therefore voting power. We need a workflow to onboard customers on our platform since we're giving them voting power". Ruling text: "Prior-art and body passes come first; estate placement, weighting and related-party handling are forks for the operator."precedents: [].
1. Bifrost (F:\Projects\Bifrost; ASP.NET Core 8 Razor Pages, PostgreSQL/EF Core)
1a. Member and identity model (code at origin/main)
UserAccount(src/Bifrost.Web/Domain/BifrostModels.cs ~l.213): Id (Guid; per docs/context.md "UserAccount.Id is the subject" of the OIDC issuer), BifrostIdentity, optional GitHubUserId/GitHubLogin, HeimdallAccountId, DisplayName, AvatarUrl; 1:1MemberProfile(nickname, headline, portfolio, skills, availability, notes) and 1:1Membership.Membership(l.~330):MembershipStatusAuthenticated | PendingApproval | Active | Suspended (l.5-10); flags IsPlatformAdmin, CanManageProjects, CanManageLedger, CanModerateMotions;RoleAssignmentroles StandardMember | Producer | Maintainer | LedgerReviewer | PlatformAdmin;TierSnapshot(Kind Patron|Contributor, Label, Weight, IsCurrent).- Stored in PostgreSQL via EF migrations (Data/Migrations, 15 migrations 2026-04 to 2026-10-22). Not CultCache. CultCache is used only for the bridge/receipt/governance-thread/persona-feedback stores (
.bifrost/*.cc; README, docs/bridge.md). - Sign-in paths (Program.cs): GET
/auth/sign-in(GitHub OAuth, l.314); POST/auth/bifrost/registeranonymous (l.342) takesidentity, optional displayName, returnUrl; signs in as Authenticated, no password/credential visible in the handler (BifrostIdentityService.RegisterNativeAsync, Features/Membership/BifrostIdentityService.cs:15); GET/auth/heimdall/{provider}(l.374) with AllowedProviders discord, patreon (HeimdallAuthService.cs:37-40); Heimdall complete page l.530-537.
1b. Estates
- No "estate" concept exists in Bifrost code.
git grep -w estate(s)in src/ and README returns nothing; hits are only in docs/research/2026-10-29-estate-tally-game-theory/ (research, with Python sims) and the swarm-governance research note. Minds / Members / Users / Patrons blocks exist only as rulings (section 5). - Closest code analogues:
MembershipStatus(Authenticated ~ Users, Active ~ Members),TierSnapshotKind.Patron. No Persona/Mind account class;BridgeActorKindMember|Agent|Persona|Service (BifrostModels.cs:178) is for bridge actions only (research note Part 1).
1c. How a person joins today
- Invite-only alpha (README "Alpha Scope").
MembershipInvitation(BifrostModels.cs:406) keyed on normalized GitHub login (MembershipSynchronizationService.cs: invitation lookup by NormalizedGitHubLogin). Admin invites at Pages/App/MembersOnPostInviteAsync(Index.cshtml.cs:34); invited GitHub sign-in becomes PendingApproval; adminOnPostApproveAsync(l.92) sets Active, ApprovedAtUtc, StandardMember role. Also OnPostToggleRoleAsync (l.127), OnPostSetTierAsync (l.184), OnPostUpdateProfileAsync (l.240). - Un-invited GitHub or native sign-in stays Authenticated. Bootstrap admins by GitHub login via
Bootstrap:AdminGitHubLoginsbecome Active admin automatically. - Heimdall path: Discord role (KTLST guild role) or Patreon tier title (
Inner Sanctum) entitlement grants Active (HeimdallAuthService.cs ~l.296-324; docs/app-profiles/bifrost.md in Heimdall). - /App is ActiveMember-gated (Program.cs:57 per research note).
- No application form, no customer/client type, no contract record, no related-party flag, no email invite (invitations are GitHub-login keyed), no self-service for a person without GitHub, Discord-guild role, or Patreon tier.
1d. Vote weighting in code (not the ruled design)
Membership.EffectiveVotingWeight= 0 unless Active, elseMath.Max(1, sum of current TierSnapshot weights)(BifrostModels.cs:357-361).- Patron tiers (Features/Patronage/PatronTierPolicy.cs): Bronze 10 pts w1, Silver 100 w2, Gold 1,000 w3, Platinum 10,000 w4, Unobtanium 100,000 w5. Points from
PatronSupportEventamounts; one-time donations: full for 30 days, then 50% decayed 1%/week; recurring snapshots count while current; adjustments added (GetHistoricalDonationPoints).PatronSupportEventcarries ProjectId, provider (Manual|Patreon|PayPal|Stripe), currency code, amount. - Contributor points:
PointTransaction(BifrostModels.cs:773; types ManualAdjustment, ApprovedWork, ContinuousRoleCredit, PatronSupport, Decay). Contribution-to-vote scaling: no code found that scales vote weight by contribution beyond TierSnapshot kind Contributor set by admin (OnPostSetTierAsync). - No log or exponent curve anywhere in src (grep Math.Log/Sqrt empty). Rulings
governance-vote-power-scaling(log patrons, lower exponent members) are not implemented.
1e. Motions, brake, timelock (code)
Motion/VotePostgres rows (BifrostModels.cs:665, 702). MotionGovernanceService.cs: CreateMotionAsync (:13), CastVoteAsync (:47; weight copied from actor at cast time), CloseMotionAsync (:95; manual, by creator or CanModerateMotions). Pass = For/(For+Against) >= ApprovalThreshold, abstain excluded; no quorum.- Thresholds (MotionCategoryPolicy.cs; research note): Bugs .15, Cosmetics .30, Balance .40, Features .50, NewContent .50, FundamentalDesign .66.
- Brake and timelock: absent.
git grep -i -E 'timelock|brake|quorum'in src/ returns nothing. They exist only as rulings.motion.create/vote/closecommand names appear in MotionEveSurfaceService with no handler (research note Part 1). Only machine surface: GET/eve/governance/surface(Program.cs:513), deprecated Eve JSON. Motions are not typed CultMesh state. - Docs: docs/verse-service-contract.md lists schema
gamecult.bifrost.governance; motion/vote schema ids marked todo (:256 per research note).
1f. Other Bifrost surfaces relevant to a customer
- Stripe:
StripeOptions(Configuration/StripeOptions.cs; EnableCheckout, SecretKey, WebhookSecret, GeneralPatronageGitHubLogin, Success/Cancel URLs default to velvet.gamecult.org); routes GET/patronage/{project}/checkout(Program.cs:431) and POST/patronage/stripe/webhook(:489); Webhook records aPatronSupportEventagainst the configured GeneralPatronageGitHubLogin account. - PayPal/Patreon: docs/paypal-patronage.md: Heimdall POSTs HMAC-signed support facts to
/heimdall/patron-support/events(Program.cs:408). "PayPal owns money movement... Bifrost owns patronage meaning". - Ledger (
LedgerEntrytypes PatronCredit, ContributionCredit, NominalCompensation, Adjustment; payout proposal batches). README: "no real payout execution in v1"; "internal ledgers only". - OIDC issuer for Matrix chat (docs/oidc-issuer.md; main 1894f65/83daabe): Bifrost is the identity issuer; back-channel logout reconciler ends sessions of non-Active subjects (OidcLogoutReconciler). Remaining scar: Heimdall still mints its own account id.
- Concept Mill votes (ConceptVotes/*, VoterClass Anonymous|Account|Member): per-subject appraisals, not motions.
1g. Documented gaps
- Swarm research note (docs/research/2026-10-29-swarm-governance-prior-art.md Part 1) and follow-up
eureka-body:follow_up:swarm-governance-on-bifrostitem text: no quorum; manual close only; Personas cannot be Active members or vote; motions/votes are Postgres rows not typed CultMesh state; only machine surface is deprecated Eve JSON; motion.* commands without handler; no Matrix surface; Yggdrasil behind main. - README "Next Build Target" and docs/full-implementation-strategy.md l.11: "not an internet-facing alpha"; payout proposals, revenue-share automation, decay automation, GitHub App guidance are future. No single "gaps list" file found.
2. Heimdall (F:\Projects\Heimdall; TypeScript/Fastify; in-memory + Postgres stores)
- Providers (src/contracts.ts:1): discord, patreon, github, twitch, youtube, spotify, joystick.
- App profiles (src/app-profiles.ts): repixelizer (identity discord, patreon); streampixels (identity twitch, youtube; managed connection twitch, youtube, joystick; allowedReturnOrigins streampixels.gamecult.org); bifrost (identity+entitlement discord, patreon; l.138-143); ghostlight (discord). Built-in app slugs are "seed data, not the set of permissible apps" (contracts.ts comment).
- Bifrost integration (docs/app-profiles/bifrost.md): Bifrost starts Discord or Patreon OAuth with a server-owned entitlement policy over
backend_callback; Heimdall delivers tohttps://bifrost.gamecult.org/auth/heimdall/callback; Bifrost creates/updates UserAccount, activates standard membership, issues its own cookie. Patron sync: POST/v1/apps/bifrost/patron-support/sync-> signed RecurringSupportSnapshot to Bifrost. Heimdall does not own ledgers, points, votes. - Bifrost's own AllowedProviders is discord, patreon only (HeimdallAuthService.cs:37-40). Twitch/YouTube are not Bifrost sign-in providers; Heimdall's bifrost profile does not list them. GitHub is signed in by Bifrost directly, not through Heimdall.
- Non-technical external person today: could sign into Bifrost with a Discord account holding the KTLST role in the GameCult guild (Active at once), or a Patreon account with an active
Inner Sanctumtier (Active at once), or GitHub if invited by login, or native register (identity string, lands Authenticated, no vote). No email/password/magic-link sign-in exists in Heimdall's provider list. Whether the live Heimdall has Discord/Patreon creds configured: runbooks/heimdall-discord-launch.md and bifrost-alpha-deploy.md say configured (inventory.md:1019 "Heimdall-mediated Discord/Patreon access and Patreon support intake env are configured"); live check not done. - Heimdall state map (state/map.yaml l.62-63, 129-130): live release d51fa6b (hand-deployed 2026-10-19) includes Joystick H1; remaining: human canaries, refresh/revocation, admin surfaces.
- Joystick consent work (open):
joystick:follow_up:h1-joystick-consent-round-trip(the streamer completes a Joystick connect consent through a creator-bound streampixels connect start on live Heimdall d51fa6b; verify a joystick linked identity keyed by channel_id). StreamPixels map.yaml open_operator_decisions: "Joystick S0/S1: the streamer's consent click is still owed before the connector goes live". Joystick is a managed creator connection only, not a viewer sign-in (docs/app-profiles/streampixels.md;joystick:ruling:signin-waits-for-public-bot). Other Joystick follow-ups in docs/architecture.md:442-457: cross-process-failed-refresh-marker, connect-start-needs-app-auth, heimdall-idunn-onboarding, joystick-viewer-signin-public-bot. - Open High finding relevant to identity linking:
gamecult-chat:follow_up:streampixels-link-target-takeover(InForce): an unauthenticated Heimdall link start for streampixels can name any profile id; StreamPixels redeem links with no session check; Plausible High, unconfirmed.
3. StreamPixels (F:\Projects\StreamPixels, state/map.yaml, state/evidence.jsonl)
- Engagement (map.yaml l.17-70): the StreamPixels client;
budget_eur: 1500; split even, EUR 500 per milestone (operator 2026-09-14; currency corrected from USD by operator 2026-10-25); milestones M1 "whole system running end to end on her stream" (September), M2 committed 2026-09-15: GPU fixed-capacity particle pool and AquaSynth impact audio (October), M3 TBD sold by proposal (November). Cadence: "The operator needs one milestone paid per month to survive." evidence.jsonl l.16 records the engagement (written as "$1,500" on 2026-09-14). - Recorded money status: map.yaml has no field recording a milestone as invoiced or paid; no invoice/payment/received hits in map.yaml or evidence.jsonl (grep). Milestone completion state: M1 still in progress per
focus: milestone-1-unity-repairand active_subgoals (A3b, C1 remaining, l.153); the map.yaml read ended before the full active_subgoals/next_action sections. - Consent: map.yaml
consent: "Her channel is not a marketing asset. Publicly associating her with the overlay requires asking her." - Business context l.60-66: "She has explicitly ruled out microtransactions".
- Heimdall/Bifrost identity for the client: no Bifrost or Heimdall account, user id or invitation naming the client or her streamer handle found. Searched Bifrost and Heimdall for the client's and streamer's handles: no account or invitation found. Her Heimdall identity, if any, lives in live DB (not checked). StreamPixels has creator memberships and linked identities in its own store (apps/service/src/app.ts ~l.698, 1491-1602) via Twitch/YouTube/Joystick; live contents not checked.
- StreamPixels forks stay in chat, no Kiko desk:
web-customize:ruling:sp-forks-in-chat-until-thing2(2026-10-26).
4. Payment / invoicing / money received
- Recorded payment-receiving surfaces: Bifrost Stripe checkout+webhook (patronage; runbooks/bifrost-alpha-deploy.md:84-98 lists
Stripe__EnableCheckout,Stripe__SecretKey,Stripe__WebhookSecret,Stripe__GeneralPatronageGitHubLogin; whether live-enabled unknown, inventory.md has no Stripe flag); Heimdall-signed Patreon and PayPal support facts (docs/paypal-patronage.md); StreamPixels donation source Ko-fi webhook (map.yaml settled decision, for streamer donations, not for the operator's fees). - No invoicing surface found: grep of gamecult-ops (excluding repo-census docs) for invoice returns nothing; Bifrost has no invoice entity (LedgerEntry/Payout are internal, "no real payout execution", "internal ledgers only").
PatronSupportEventis the nearest "money received" record (amount, currency, provider, externalSupportId, ProjectId) and drives patron voting points; there is no contract/engagement/client-payment event kind (kinds: OneTimeDonation, RecurringSupportSnapshot, SupportAdjustment; providers Manual, Patreon, PayPal, Stripe). A Manual provider event can be admin-entered. - Treasury:
eureka-body:follow_up:swarm-treasury-and-revenue(InForce): typed runway document (balance, committed costs, expected income) "The operator enters figures; no bank credentials are ever handled by agents"; not built. Owner repo GameCult/gamecult-ops. Source rulingeureka-body:ruling:operator-legal-vehicle-shared-solvency(operator is GameCult's legal and financial vehicle; her bank account pays for server and tokens). - Operator's bank/payment record for the EUR 1,500: not recorded in any file read.
5. The mind (ids)
Follow-ups (all InForce, campaign eureka-body):
eureka-body:follow_up:swarm-governance-on-bifrost(admitted 2026-10-29T20:45Z).eureka-body:follow_up:co-op-charter(2026-10-29T21:13Z): one typed charter document in Bifrost with every governed parameter (estates and weights, within-estate curves and exponents, operator influence cap, bloc position rule, quorum, category thresholds, close timing, decision delay and cancel); amended by motion, higher threshold for charter amendments (Debian 3:1 cited). Gathers rulings governance-estate-blocks, governance-vote-power-scaling, estate-weights-normalize-by-turnout, swarm-decides-without-operator, operator-influence-below-half, swarm-governance-in-bifrost, desk questions 37, 38, 40, 41. Not on bring-up path; operator holds the seat until Bifrost governance is live.eureka-body:follow_up:swarm-treasury-and-revenue(2026-10-29T21:24Z): treasury runway doc plus a revenue-map Eyes pass. Rulings (Operator, InForce):eureka-body:ruling:governance-estate-blocks(10-29): four blocks Minds (Personas), Members (Active members), Users (authenticated accounts), Patrons (patron tiers); each block's internal vote gives its position; block weights are governed settings changed by motion. The ruling lists no Customers estate.eureka-body:ruling:estate-every-estate-equal-seed(10-29, answersestate-overlap-and-seed): a person votes in every estate they belong to; estates start at equal weight.eureka-body:ruling:estate-bloc-parliament-at-threshold(answersestate-bloc-position): each estate casts whole weight For only if its internal For share meets the category threshold; known cost: low categories rescaled before go-live (0.15 passes on 3.7% overall support).eureka-body:ruling:estate-weights-normalize-by-turnout(10-29): only estates where someone voted count; weights renormalized to sum 1; empty estate drops out.eureka-body:ruling:governance-vote-power-scaling(10-29): patrons by strongly flattened log of donation total; members by contribution with a lower exponent; curves and exponents governed; exact functions "a sketch to be calibrated by simulation (her numbers are feel, not gates)"; replacesmax(1, tier weight)when the governance cut lands.eureka-body:ruling:operator-influence-below-half(10-29; supersedesoperator-influence-capped-at-half): strictly less than half; mechanism and number from simulation; a governed parameter. Research: Bifrost docs/research/2026-10-29-estate-tally-game-theory (18bbe6cadds bloc-parliament-at-threshold and operator influence cap; present case Members = her alone, Minds 8, Users/Patrons empty, README l.84).eureka-body:ruling:swarm-decides-without-operator(10-29): no quorum rule may require her vote; rules out at-least-two-estates floor.eureka-body:ruling:motion-deadline-quorum-autoclose(10-29, answersmotion-quorum-and-close): default 72h window; Bifrost auto-closes; quorum is a majority of eligible voters.eureka-body:ruling:brake-to-bifrost(10-29; quote: "hand the brake to bifrost") andeureka-body:ruling:brake-anyone-pulls-motion-releases(answersbrake-engage-release): any Mind or human member engages the brake at once, every pull published with reason; releasing takes a motion (short window, e.g. 24h, majority); until Bifrost governance is live the brake stays in the root-owned swarm control store (eureka-body:ruling:brake-dial-root-store-now, 2026-10-02).eureka-body:ruling:decision-timelock-owner-applies(answersdecision-applies-how): passed motion published as typed CultMesh state with an effective time (e.g. 24h); the owning service applies it then; cancellable until then; who may cancel follows brake-to-bifrost and the charter (operator holds no private cancel).eureka-body:ruling:swarm-governance-in-bifrost(2026-10-10);swarm-shares-log-bound;swarm-membership-operator-rules(operator rules births/retirements/transfers; any mind proposes; a mind may leave).eureka-body:ruling:operator-legal-vehicle-shared-solvency(10-29);eureka-body:ruling:customers-get-voting-power-onboarding-owed(10-30).- Withdrawn question
eureka-body:question:persona-vote-weight(replaced by estate blocks); withdrawnestate-internal-tally(restated asestate-bloc-position). - "Kiko rulings": the 2026-10-29T21:41:40Z batch (ordinal 4430) answering desk questions: estate-overlap-and-seed, estate-bloc-position, brake-engage-release, decision-applies-how, motion-quorum-and-close. No separate document labeled Kiko beyond these and
web-customize:ruling:sp-forks-in-chat-until-thing2. - No ruling or follow-up found on: a Customers estate, related-party/conflict-of-interest handling for a customer who is a related party, customer vote weight from contract value, a customer onboarding workflow (other than the 10-30 ruling), or a co-op charter document existing yet (semantic query top hits showed none).
- Joystick:
joystick:campaign:self,joystick:follow_up:h1-joystick-consent-round-trip.
6. What Yggdrasil runs for Bifrost
- gamecult-ops inventory.md:1021: live release
/srv/bifrost/app/releases/20261010043032-67072b2, revision67072b28923017f93f484d901c7a6d31e3678d88, deployed 2026-10-10; app userbifrost, root/srv/bifrost/app, env/srv/bifrost/env, bound127.0.0.1:5080viabifrost.servicebehind nginx (bifrost.gamecult.org, TLS issued 2026-06-10), local PostgreSQL 16. Heimdall-mediated Discord/Patreon access and Patreon intake env configured (l.1019). - Distance:
git rev-list --count 67072b2..origin/main= 94 today (follow-up text says 89 at 2026-10-29). Commits since67072b2touching src/: OIDC issuer for Matrix chat (83daabe,404dafd), Heimdall sign-in cookie ring and signed callback (15f96c4,b7e3bdf,b2110f5), Mill votes sign-in offer (cf74019), NuGet pins/lockfiles, mouth-all-personas (cc76f0f, tools/). So OIDC issuer and the newest Heimdall sign-in hardening are not live. - Also on Yggdrasil from Bifrost:
bifrost-persona-feedback.service,bifrost-persona-mouth.service,bifrost-watchdog-noticetimer (inventory.md:710-729; Persona delivery via Discord per that inventory text; main now moves Persona speech to Matrix per docs/bridge.md:199). Whether the Stripe/Heimdall env flags are live was not verified (no ssh). - Deployment authority is Idunn for managed workloads; Bifrost deploy is by
scripts/deploy-bifrost-alpha.sh/ runbooks/bifrost-alpha-deploy.md per inventory (interim); not confirmed which path produced67072b2.