Skip to content

Owner review 46 — lane D: the foundation of 신뢰 (2026-10-19) ​

Status: Reference · Date: 2026-10-19

Read-only research for owner review 46, mark M6: "let's work on the full foundation for the 신뢰 section. What are we measuring? Why does it matter? What would matter to people?" A migration is cited by number and line (00667:193-286 = supabase/migrations/00667_*.sql, lines 193–286); M26 is the owner's mark 26 in the same review. Hosted data was not queried.

1. Now ​

The tier ​

private.recalculate_trust_tier (00667:193-286) reads five inputs and nothing else: the sessions counter; COUNT(DISTINCT (tagger, tag_type)) of manner tags; account age; the lifetime global_attendance_rate; COUNT(DISTINCT reporter) of unresolved club reports.

  • veteran: 50 sessions, 6 months, 20 tags, fewer than 2 reports (no attendance clause);
  • trusted: 20 sessions, 10 tags, rate NULL or ≥ 0.90, fewer than 3 reports;
  • active: 5 sessions; otherwise sprout; 3+ reports cap a member at active (:235-254).

The TS mirror is trust-tier.rules.ts:33-38; the parity gate (check-trust-tier-parity.mjs:101-106) breaks on any rewrite.

Signals ​

  • Showing up. The cancel and completion triggers write attendance rows only where clubs.attendance_tracking_enabled (default false, 00086:149), yet the scoring is app-wide (00639:60-112): 24 h or more before is a free cancel; 12–24 h is late_cancel, 0.5; under 12 h is no_show, 1.0; a host cancel, an expired hold or leaving the club is excused, 0 (00406:299, 00698:58). At the session's end a confirmed RSVP on no match slot becomes no_show, and a session with no matches marks everyone attended (00444:269-310). Rate = attended / (attended + no_show + late_cancel), lifetime (00640:323-336). Strikes: the last 20 records; a flag at weighted 3, an RSVP block at count 2 (00640:95-107, 237, 254-308). No time decay: the block lifts only if a 총무 excuses a record (00128) or newer records displace it (the spec said a one-session cooldown, attendance-and-reviews.md:152).
  • Sessions. The counter goes up by one for any match slot (its status unchecked) or for a tracked session with no matches (00444:279). The GPS check-in RPC (00131) has no caller.
  • Manner tags. Praise only, five types; an insert needs both people confirmed in a completed session within 14 days (00145:41-68). Two friends giving each other all five tags meet trusted's 10-tag clause; four friends meet veteran's 20. The copy says "매너 태그 N개" (trust-tier-info.ts:20); the profile shows raw counts, read under RLS limited to the viewer's clubs (00124:175-187).
  • Reports come only through report_content from club and session chat (00667:97-138). Resolving one just sets resolved = true (:176): no upheld or dismissed, no expiry, so handling a report erases the demotion. The demotion push always blames "최근 출석 기록" (signals.ts:392-394).
  • Not read: payments and dues (expired holds are excused), lateness, 본인인증 (no column; EXT-19), score disputes (no per-player record; the honor-system review is designed, decision log :662).

Where it shows ​

The own profile (profile-screen.tsx:285-420) and the public profile (public-profile-screen.tsx:383-501): the badge, 출석률, tags; the own profile adds 연속 참석 and a strike callout. Also member rows, the partner suggester (trust and attendance, 30 of its 100 points), join review (00415:207-308), the venue-correction privilege (00423:227) and seven trust signals. The hub board's 신뢰 module (flat-v2-hub.jsx:1755-1896): the tier as a count, 등급 안내, a note, a Strip (출석률 92%, 연속 참석 7회, 매너 태그 27), a strike Notice, the explainer sheet; another person's profile adds the trust Tag and 출석률 (flat-v2-detail.jsx:5485-5509). Any signed-in viewer sees the tier, sessions and rate (00691:229-231); the anonymous share RPC returns the tier and sessions (00691:629-630, 670).

Contradictions ​

  • Spec against code: others should see "nothing" (spec :157-159) but see a public 출석률; "silent demotion" (:62) against a push; both-sides score confirmation, 총무 endorsement (:55-56) and recruitment filters are unbuilt; docs/canon/trust.md:30 cites a "dues-overdue strike path" that does not exist.
  • Four attendance formulas: the lifetime rate; attended / COUNT(*) (attendance-record.supabase.ts:249); since joining (00666); weighted strikes. The streak resets on free_cancel and excused records (00640:759).
  • A unit bug: the rate is 0–1 (profile.mapper.test.ts:206; formatPercent multiplies by 100), but computeAttendanceScore expects 0–100 (partner-matching.rules.ts:134), so its 15 points are about 0 live (handed to lane F).
  • Words: 신뢰 names the section, the tier 신뢰 멤버 and, as 신뢰도, the ELO calibration (ranking.ts:166); sessions.ts:770 threatens a 신뢰도 loss for late refunds, with no mechanism behind it; pushes say "strike N점" (signals.ts:365); the sprout copy "일정에 처음 참석했어요" is wrong at 0 sessions.
  • Privacy: the privacy policy lists 출석 기록 and GPS only (privacy.ko.ts:21, 37); records survive account deletion (00407:33-36).

2. References (read 2026-10-19; "search" = a search summary, the page blocked) ​

3. Proposal ​

Why it matters ​

The readers are the host or 총무 judging a stranger, the co-players, and the person (am I OK, what do I fix). Hypothesis: a stranger's real risk is the empty court, not skill. Rules: facts the person controls, no composite score; praise only from peers; consequences only from records; every record visible and contestable.

What is measured ​

  1. 참석 (shows up): strikes in the last 20 records within 12 months (no_show 1, late_cancel 0.5), shown as "최근 20회 중 19회 참석".
  2. 시간 (on time): a new rsvps.checked_in_at (a host's tap or the GPS RPC, wired) against the player's own start (the M26 windows); a private nudge first.
  3. 정산 (pays): payment expiry and dues; host and 총무 only; never in the tier.
  4. 공정 (fair): v1 is the existing 실력이 정확해요 tag; later, host-upheld score corrections (private). ELO reliability (신규, 측정 중, 안정) stays separate.
  5. 매너 (company): praise counted as distinct people who shared a match, capped per giver.

One fact, not a score: 본인인증 완료 (once at sign-up; a unique CI blocks duplicates; EXT-19, counsel).

Weights and decay ​

No composite. The strike weights stay 1.0 and 0.5; the window becomes 20 records and 12 months, so misses age out and the two-strike block is time-boxed. Reports count only once a 총무 marks them upheld, and expire at 12 months. The numbers are starting values to calibrate.

Tiers ​

Keep the four keys, the labels and the parity gate; change what earns them. active: 5 sessions; trusted: 20 sessions, fewer than 2 strikes (the RSVP-block bar), 5 distinct praisers, no upheld report; veteran: 50 sessions, 6 months, the same gates, 10 praisers. This closes the veteran gap, the NULL pass and the pair loophole. The tier is the glanceable badge; the facts explain it. Renaming 신뢰 멤버 (it collides with the section's name) is the owner's call; lane D would defer it.

Cold start ​

A sprout shows no badge; the module reads "일정에 참석하면 신뢰가 쌓여요"; no rate before 5 recorded sessions; hosts see a neutral "첫 참석".

Who sees what (the can_view_face pattern; the owner's call) ​

  • Self: the tier, "최근 20회 중 19회", 연속 참석 (a free cancel or an excused record neither breaks nor counts), "N명이 칭찬", a private Notice only when there is something to do, and 기록 보기.
  • A shared club or session, or a friend: the tier and that one fact.
  • A stranger or anonymous viewer: the tier only (drop the rate and sessions from 00691:229 and from the anonymous RPC).
  • List rows: the tier word. Officials: a club-scoped record like 00415's, plus payments and lateness.

One sentence each ​

참석 "참석한다고 한 일정에 실제로 왔는지, 최근 20회 기준이에요"; 취소 "하루 전까지는 자유롭게 취소할 수 있고, 12시간 안에는 불참으로 기록돼요"; 칭찬 "함께 친 사람들이 남긴 칭찬이에요".

Contest ​

내 기록 from attendance_records (the self-read RLS exists, 00086:76), naming the rule applied; "사유 인정 요청" to the host or 총무 (today an admin-only RPC, 00128); records age out at 12 months; tier-change pushes name the true cause; explanation requests go to a named contact (PIPA 37-2).

Never shown ​

Reporter identities and counts, other people's strikes and cancel history, payment and dues state, who tagged, club-private notes; nothing goes to lenders.

Migrations ​

  1. attendance_records for every club and pickup, the tracking flag becoming enforcement only (the owner's call: it reverses the spec's principle 5, club opt-in; the alternative is to label the rate "where tracked").
  2. rsvps.checked_in_at and the M26 window columns; "attended" means present, not on a match slot.
  3. member_reports.outcome and resolve_member_report(outcome), with a 12-month expiry.
  4. A shared-match check on manner-tag inserts, counting distinct taggers.
  5. One windowed SQL function replacing the four formulas, with the parity script updated.
  6. An append-only trust_events ledger feeding the tier, 내 기록 and the push reason (purpose_catalog rows, DATA-13).
  7. profiles.identity_verified_at and a unique CI hash.
  8. The privacy policy: criteria, retention, contact.
  9. Copy fixes (sessions.ts:770, signals.ts:365, 375, 392) and the partner-score unit bug.

Not verified ​

Hosted data (the share of tracked clubs, the tier mix); whether the share card draws the tier; whether voided matches clear their slots; Playtomic's and Meetup's official pages (blocked); 스매시's deposit mechanics; KREAM, 번개장터's 신뢰지수, 당근's 2025–26 formula (none found); that the block never lifts by itself (read, not run); the legal readings; first-party user research on trust (none found).

Markdown remains the source of truth. Run yarn docs:check before handoff.