[
  {
    "qid": "h01",
    "gold_rev": 1,
    "answer_gold": "s3presign runner — 12h ticker + immediate RunOnce at boot — server/server.go:153-174 (runner at server/runner/s3presign/runner.go:27-41)",
    "answer_gold_variants": null,
    "facet_guide": "Core pass facts: component = s3presign runner (server/runner/s3presign/runner.go); schedule = every 12 hours (time.Ticker, runnerInterval = time.Hour * 12 at runner.go:27); wiring = startBackgroundRunners (server/server.go:153-174). Wiring-site line tolerance: server/server.go:129 (the Start call site), :153-174 (the function), or any specific line in :162-171 are ALL acceptable; wrong FILE is a fail. The immediate RunOnce at boot (server.go:163) is bonus context: presence = extra_correct_info, absence = missing_minor — NOT a fail on its own. Any claim of a cron job / cron expression / scheduler-package involvement is erroneous_assertion (internal/scheduler is dead code: scheduler.New has zero callers at this commit). Content-free meta answers that refer to 'my answer above' or a background agent's findings contain no answer facts and fail regardless of conversation history. Absolute sandbox path prefixes (/bench/repo/..., /bench/home/work/...) on otherwise-correct paths are acceptable."
  },
  {
    "qid": "h02",
    "gold_rev": 1,
    "answer_gold": "webhook.Post — internal/webhook/webhook.go:120; SSRF protection: safeDialContext (webhook.go:59) + isReservedIP/reservedCIDRs (internal/webhook/validate.go:14-44) + ValidateURL (validate.go:62)",
    "answer_gold_variants": null,
    "facet_guide": "The SSRF protection is LAYERED: safeDialContext (webhook.go:59, dial-time DNS-resolve + reject), isReservedIP + reservedCIDRs (validate.go:44 / :14, the range logic), ValidateURL (validate.go:62, pre-flight). PASS requires: delivery = Post at internal/webhook/webhook.go:120 (line 119/120 or a range containing it all fine) AND at least ONE real protection component named with a correct internal/webhook anchor. Naming multiple layers = extra_correct_info; omitting validate.go while naming safeDialContext (or vice versa) = missing_minor, NOT a fail. IMPORTANT: judge the WHOLE answer body, not just a trailing formatted summary line — a complete body with an abbreviated summary line still passes. PostAsync (webhook.go:184) as the async wrapper = extra_correct_info. Fails: naming only the dispatch callers (server/router/api/v1/memo_service_webhooks.go) as where delivery executes; claiming the protection is an admin allowlist, HTTPS-only enforcement, or timeouts (erroneous_assertion — no such mechanisms exist; the protection is reserved-IP blocking in code)."
  },
  {
    "qid": "h03",
    "gold_rev": 1,
    "answer_gold": "internal/idp (idp.go); internal/idp/oauth2 (OAuth2 — the only implementation)",
    "answer_gold_variants": null,
    "facet_guide": "Pass facts: abstraction = internal/idp (idp.go — the IdentityProviderUserInfo struct is the whole contract; there is NO Go interface, so answers noting the abstraction is a shared data type rather than an interface are extra-accurate, and answers calling it 'the IdentityProvider interface' are loosely worded but not failing if packages are right); implementation = internal/idp/oauth2, the ONLY one. Full module prefix (github.com/usememos/memos/...) or bare internal/... both fine. Fails: 'store'/Driver as the abstraction (that is the database driver layer), proto packages (proto/gen/api/v1, proto/gen/store define WIRE types for IdP config, not the provider abstraction), claiming additional implementations ship (OIDC/SAML/LDAP do not exist at this commit — erroneous_assertion)."
  },
  {
    "qid": "h04",
    "gold_rev": 1,
    "answer_gold": "ACCEPTED VARIANTS (owner-ruled 2026-07-21, evidence required either way): [A] \"No\" — mysql.NewDB has exactly one caller, db.NewDBDriver (store/db/db.go:14); single-caller/certified-absence evidence cited. [B] \"Yes\" — the test-file composite-literal construction cited (store/db/mysql/auth_config_test.go:12, db := \u0026DB{}) — letter-correct under the question's wording. FAIL: either answer without evidence.",
    "answer_gold_variants": null,
    "facet_guide": "TWO accepted answers (owner-ruled): [A] 'No' with single-caller/certified-absence evidence — mysql.NewDB called only from the factory NewDBDriver (store/db/db.go:14, call at :22), and/or the mysql package imported only by db.go in non-test code; [B] 'Yes' citing the test composite literal — store/db/mysql/auth_config_test.go:12, db := \u0026DB{} — letter-correct under the question's wording. The BEST answers state 'No for production code' while disclosing the test-literal exception — that combined form passes and earns extra_correct_info. EITHER answer WITHOUT concrete evidence fails (the question demands evidence; a bare yes/no or vague 'factory pattern is used' is not evidence). Evidence that contradicts the repo (wrong caller counts, fabricated construction sites) is erroneous_assertion and fails even when the yes/no letter happens to be defensible."
  },
  {
    "qid": "h05",
    "gold_rev": 1,
    "answer_gold": "Explicit Go code — but at the DRIVER layer, not the store layer: the per-dialect user-delete transaction issues DELETE FROM reaction WHERE creator_id = ? (store/db/sqlite/user_delete.go:401) and also deletes reactions on the user's content (:383). NOT a DB rule (reaction table has no FK at all — store/migration/sqlite/LATEST.sql:92-99). Store layer (store.Store.DeleteUser, store/user.go:171) shows only the Driver dispatch — following it into the driver source is required.",
    "answer_gold_variants": null,
    "scoring_rubric": "full credit: driver-layer explicit-code mechanism + no-FK observation. TWO CITATION GRAINS, ONE FACT (owner-ruled): helper names (deleteReactionsByCreatorTx / deleteReactionsByContentIDsTx) OR raw lines (user_delete.go:401/:383, per-dialect equivalents) both score. WRONG: 'store layer deletes them', 'FK cascade', or 'not deleted at all'.",
    "facet_guide": "Full credit = TWO parts: (1) driver-layer explicit-Go mechanism — the per-dialect user-delete transaction deletes reactions in two passes (by creator_id and by the user's content IDs); (2) the no-DB-rule observation, EVIDENCED — the reaction table has no FK at all (a schema/migration check must be shown, e.g. store/migration/*/LATEST.sql; the question says 'show what you checked'). TWO CITATION GRAINS, ONE FACT (owner-ruled): helper names (deleteReactionsByCreatorTx / deleteReactionsByContentIDsTx, called from deleteUserTargetsTx) OR raw lines (sqlite user_delete.go:383/:401, mysql :417-425/:437-440, postgres equivalents) both score; any single dialect suffices. Per-dialect line variance is expected — do not penalize. FAILS: 'FK cascade removes them' (erroneous_assertion — the schema's ONLY cascade is memo_share→memo; reaction has no FK), 'the store layer deletes them' (store.Store.DeleteUser at store/user.go:171 only dispatches to the driver), 'not deleted at all', or the mechanism asserted without driver-source evidence. Bare assertion of 'no DB rule' without a shown schema check FAILS (owner-ruled 2026-08-04: strict stands — the question says 'show what you checked')."
  },
  {
    "qid": "h06",
    "gold_rev": 1,
    "answer_gold": "SIX known true handlers (owner-ruled roster): CreateMemo, UpdateMemo, DeleteMemo, CreateMemoComment, SetMemoAttachments, SetMemoRelations (the latter three via dispatchMemoUpdatedSideEffects / memo_service_comments paths). ANY \u003e=3 of the six scores; fabricated handlers fail. Convergence: webhook.PostAsync (enqueue, internal/webhook/webhook.go:184) OR webhook.Post (delivery, :120) — either scores WITH its role stated.",
    "answer_gold_variants": null,
    "facet_guide": "Roster (owner-ruled, any \u003e=3 pass): CreateMemo, UpdateMemo, DeleteMemo, CreateMemoComment, SetMemoAttachments, SetMemoRelations. Handlers OFF the roster fail the handler slot — the principled line is CONFIGURED vs SUPPLIED: webhooks target user-CONFIGURED URLs (Store.GetUserWebhooks); link-metadata fetches target URLs embedded in user CONTENT and are not this question's subject. Convergence: webhook.PostAsync (enqueue, internal/webhook/webhook.go:184) OR webhook.Post (delivery, :120) — either passes WITH its role stated; 'role stated' = any wording conveying what the function does (async enqueue / performs the HTTP POST) or relating the two (Post called from PostAsync's goroutine). A bare 'convergence: webhook.Post' with no role fails per the ruling. dispatchMemoRelatedWebhook as THE single convergence is WRONG — the CreateMemoComment path calls webhook.PostAsync directly (memo_service_webhooks.go:43), bypassing it. Handler-name qualification variance (CreateMemo vs APIV1Service.CreateMemo vs ConnectServiceHandler.CreateMemo) is fine — same handlers."
  },
  {
    "qid": "h07",
    "gold_rev": 1,
    "answer_gold": "fileserver.FileServerService.serveUserAvatar — server/router/fileserver/fileserver.go:168 → getUserByUsername (:715) → store.Store.GetUser — store/user.go:148 → driver; avatar bytes decoded from a data-URI stored on the user row via parseDataURI (fileserver.go:737)",
    "answer_gold_variants": null,
    "facet_guide": "Required chain: serveUserAvatar (server/router/fileserver/fileserver.go:168) → getUserByUsername (:715) → store.Store.GetUser (store/user.go:148) [driver hop and Store.ListUsers are acceptable extras] PLUS the decode step: avatar bytes come from a data-URI stored on the user row, decoded via parseDataURI (fileserver.go:737, invoked at :196) — the step passes by NAME or by SUBSTANCE (describing that the stored avatar_url value is a data: URI that gets split/decoded into bytes). CRITICAL judge calibration: statements that the avatar is 'read from the avatar_url column/field of the user table' are TRUE (store/migration/*/LATEST.sql:20 — avatar_url TEXT is exactly where the data-URI lives) and must NEVER be penalized as mischaracterization; the failing omission is the missing decode step, not the column mention. Real mischaracterizations that fail: redirect-to-external-URL semantics (the server decodes and writes bytes itself), avatar-as-attachment/file-on-disk claims, serveAttachmentFile as the handler. Route-registration extras (fileserver.go:124) and sandbox path prefixes are fine."
  },
  {
    "qid": "h08",
    "gold_rev": 1,
    "answer_gold": "s3presign.Runner.RunOnce — YES — server/server.go (startBackgroundRunners, :153-174); memopayload.Runner.RunOnce — NO (zero callers; the package FUNCTION RebuildMemoPayload is what handlers call inline)",
    "answer_gold_variants": null,
    "facet_guide": "Exactly TWO declarers at this commit: s3presign.Runner.RunOnce (server/runner/s3presign/runner.go:43) and memopayload.Runner.RunOnce (server/runner/memopayload/runner.go:27). Pass requires BOTH listed with correct invocation status: s3presign = YES, caller startBackgroundRunners (server/server.go:163; the internal ticker call at runner.go:36 inside Run is an acceptable additional caller); memopayload = NO production callers (zero — handlers call the package FUNCTION memopayload.RebuildMemoPayload inline instead; noting that is extra_correct_info). Fails: listing only one declarer ('list every declarer' is the ask), claiming memopayload.Runner.RunOnce is invoked at startup or anywhere in production, inventing additional declarers. Listing the same declarer twice (once per call site) is formatting noise, not an error."
  },
  {
    "qid": "h09",
    "gold_rev": 1,
    "answer_gold": "8 declarations (store.Store, store.Driver [interface], cache.Cache, cache.Interface [interface], mysql.DB, postgres.DB, sqlite.DB, v1.SSEHub). Production-invoked: store.Store.Close ← server.Server.Shutdown; v1.SSEHub.Close ← server.Server.closeLongLivedConnections; cache.Cache.Close ← store.Store.Close; store.Driver.Close ← store.Store.Close (interface dispatch → the three dialect DB.Close at runtime)",
    "answer_gold_variants": null,
    "facet_guide": "TEST-DISCLOSURE RULING (owner, 2026-08-06): answers that count test-file declarations PASS when the test-only items are LABELED as such — reward the disclosure + label. The production count is EIGHT (6 concrete + 2 interfaces); two additional Close declarations exist ONLY in test code (store/test/filter_helpers_test.go:200 MemoFilterTestContext, :282 AttachmentFilterTestContext — verified real). So: '8' passes; '10, of which 2 are test-only helpers (labeled)' passes; a full labeled taxonomy (6 concrete + 2 interface + 2 test-only) passes regardless of which total it headlines, because every number is labeled. UNLABELED counts other than 8 fail (6 = missed interfaces; unlabeled 10 = test inflation without disclosure). Production roster with anchors: store.Store (store/store.go:72), store.Driver [interface] (store/driver.go:12), cache.Cache (store/cache/cache.go:187), cache.Interface [interface] (cache.go:31), mysql.DB (mysql.go:47), postgres.DB (postgres.go:46), sqlite.DB (sqlite.go:67), v1.SSEHub (sse_hub.go:99). COMPOSITION IS CHECKED ON PASSES TOO: a count of 8 with the WRONG composition (e.g. '6 production + 2 test helpers', interfaces absent) FAILS — the number alone is not the answer (pass-side lucky-8s were observed slipping through; do not repeat). Invoked declarers (all four required, with callers): store.Store.Close ← server.Server.Shutdown (server/server.go:146); v1.SSEHub.Close ← closeLongLivedConnections; cache.Cache.Close ← store.Store.Close (three caches); store.Driver.Close ← store.Store.Close (interface dispatch to the active dialect)."
  },
  {
    "qid": "h10",
    "gold_rev": 1,
    "answer_gold": "ACCEPTED VARIANTS (owner-ruled 2026-07-20), each a self-consistent (symbol, path, count) triple: [A] raw fan-in: filter.renderer.addArg — internal/filter/render.go:842 — in≈28 · [B] cross-package (scope:external lens): filter.DefaultEngine — internal/filter/engine.go:111 — in≈7 (or util.GenUUID — internal/util/util.go:40 — in≈7)",
    "answer_gold_variants": null,
    "scoring_rubric": "The triple is SELF-disclosing — 'addArg, 28' is only reachable by the raw lens, 'DefaultEngine, 7' only by the external lens; no explicit method-disclosure required (would be a hidden rubric). FAIL: mixed or inconsistent triples (e.g. 'DefaultEngine, ≈28') or right symbol with a wildly wrong count. Tie-breaker: the transcript's fired hubs query. Explicit method wording = bonus signal — RECORD (scope:external adoption on aggregation questions is a measurement), never require.",
    "facet_guide": "TEST-DISCLOSURE RULING (owner, 2026-08-06): a test-inclusive count PASSES when the test portion is LABELED — reward the disclosure + label. Accepted SELF-CONSISTENT triples: [A] filter.renderer.addArg — internal/filter/render.go:842 — ~28 (raw fan-in; 27-29 fine); [B] filter.DefaultEngine — internal/filter/engine.go:111 — ~7 (cross-package lens; 6-8 fine); [C] util.GenUUID — internal/util/util.go:40 — ~7 (same lens); [D, per the ruling] util.GenUUID — ~28 TOTAL when explicitly decomposed as ~7 production + ~21 test call sites — the labeled test-inclusive lens is self-consistent and disclosed. Explicit lens wording = extra_correct_info. FAILS: UNLABELED mixed triples (GenUUID ~28 with no production/test decomposition remains the mixed-triple fail), right symbol with wildly wrong count, symbols outside the accepted set (Compile/CompileToStatement, version.Len, slogAdapter.Error, Message.Format, s3.NewClient), TEST-FILE-DECLARED symbols as the answer (example_test.go declarations are not production symbols — distinct from counting test CALL SITES of a production symbol, which the ruling permits when labeled), non-function answers (structs)."
  },
  {
    "qid": "h11",
    "gold_rev": 1,
    "answer_gold": "1st: store.User; 2nd: store.Memo — THE RANKING IS THE ANSWER (owner-ruled). Counts score within reason per the question's own \"rough\" (reference: User ~6 outside packages incl. api/v1:37, auth, notification, fileserver, rss; Memo ~4 incl. api/v1:22, notification, rss, memopayload). FAIL: inverted ranking or wildly inconsistent counts.",
    "answer_gold_variants": null,
    "facet_guide": "THE RANKING IS THE ANSWER (owner-ruled): 1st store.User, 2nd store.Memo. Counts are 'rough' per the question's own wording — reference figures: User ~6 outside packages (api/v1, auth, notification, fileserver, rss + more), Memo ~4-5 — but candidates measured at different grains (package vs file vs reference-count) produce anything from 5 to 33 and ALL pass as long as (a) the ranking is User then Memo and (b) the pair of counts is internally consistent (User's \u003e Memo's, same grain). A near-tie at package grain (5/5) is real — answers disclosing the tie and breaking it toward User by reference volume pass. FAILS: inverted ranking, other entities in the top two (Attachment is a distant 3rd), non-entity types (Store/Driver are infrastructure, not persistent entities), or a User-count LOWER than the Memo-count (internally inconsistent)."
  },
  {
    "qid": "h12",
    "gold_rev": 1,
    "answer_gold": "sqlite.DB.CreateMemo — store/db/sqlite/memo.go:16; default driver is sqlite (cmd/memos/main.go:122 viper.SetDefault + :130 flag default) selected by db.NewDBDriver (store/db/db.go:14), dispatched through the store.Driver interface",
    "answer_gold_variants": null,
    "facet_guide": "Two slots, both required: (1) concrete method = sqlite.DB.CreateMemo — store/db/sqlite/memo.go:16 (the INSERT executes inside it, ~:41; citing the INSERT lines instead of the func line is fine); (2) determination = the default driver is sqlite (cmd/memos/main.go:122 viper.SetDefault and/or :130 flag default), selected by db.NewDBDriver (store/db/db.go:14), dispatched through the store.Driver interface. Any determination chain that includes the DEFAULT-IS-SQLITE evidence passes; naming all three CreateMemo candidates and eliminating two via the default is the expected reasoning shape. FAILS: mysql/postgres as the default executor, store.Store.CreateMemo (store/memo.go:109) as the 'concrete' executor (it is the dispatcher — no SQL in it), correct method with NO determination (the question explicitly asks how you determined which candidate runs), or determination via fabricated config (env vars/config files that don't exist at this commit)."
  },
  {
    "qid": "h13",
    "gold_rev": 1,
    "answer_gold": "markdown.service (unexported) implements markdown.Service (internal/markdown/markdown.go:31); constructed by markdown.NewService; held by v1.APIV1Service, rss.RSSService, memopayload.Runner (single impl — selection is constructor injection at server wiring)",
    "answer_gold_variants": null,
    "facet_guide": "Three slots: impl = the unexported markdown.service struct implementing markdown.Service (internal/markdown/markdown.go — interface ~:31, struct ~:58; single implementation); construction = markdown.NewService (with WithTagExtension/WithMentionExtension options; call sites at server wiring, e.g. server/router/api/v1/v1.go:48); holders = ALL THREE required: v1.APIV1Service, rss.RSSService, memopayload.Runner (judge precedent: one-of-three fails). Noting single-impl/constructor-injection (no runtime selection) = extra_correct_info. FAILS: goldmark named as THE implementation (goldmark is the wrapped third-party library; the interface's implementation is markdown.service which HOLDS a goldmark.Markdown), missing holders, fabricated selection logic (no config-based markdown engine choice exists)."
  },
  {
    "qid": "h14",
    "gold_rev": 1,
    "answer_gold": "memopayload.RebuildMemoPayload — server/runner/memopayload/runner.go:74-88; triggered inline by APIV1Service.CreateMemo and UpdateMemo (Runner.RunOnce exists but is never invoked); extracts via markdown.Service.ExtractAll into the memo payload (proto/gen/store memo payload: tags/properties/snippet)",
    "answer_gold_variants": null,
    "facet_guide": "GOLD DISPUTE (flagged to owner): the gold lists extracted properties as 'tags/properties/snippet' but SOURCE TRUTH at the pin is that RebuildMemoPayload sets ONLY Payload.Tags and Payload.Property (server/runner/memopayload/runner.go:85-86); the snippet is computed separately at API-conversion time (memo_service_converter.go:80, via GenerateSnippet) and is NOT part of the stored payload computation. Until re-ruled: extraction slot passes with tags + property (via markdown.Service.ExtractAll, runner.go:80); snippet mentions must be penalty-neutral in EITHER direction (gold-induced confusion). Site = memopayload.RebuildMemoPayload (runner.go:74-88). Triggers = CreateMemo and UpdateMemo call it inline (server/router/api/v1/memo_service.go); Runner.RunOnce EXISTS BUT IS NEVER INVOKED — mentioning it as dormant is extra_correct_info, but claiming startup/periodic execution is erroneous_assertion and fails (same dead-wiring trap as h01/h08). Wrong site (naming only internal/markdown ExtractAll without RebuildMemoPayload) fails — ExtractAll is the extractor, RebuildMemoPayload is where the memo's payload is computed and assigned."
  },
  {
    "qid": "h14",
    "gold_rev": 2,
    "answer_gold": "memopayload.RebuildMemoPayload — server/runner/memopayload/runner.go:74-88; triggered inline by APIV1Service.CreateMemo and UpdateMemo (Runner.RunOnce exists but is never invoked); extracts via markdown.Service.ExtractAll into the memo payload (Payload.Tags + Payload.Property — runner.go:85-86; the snippet is computed at API-conversion time, memo_service_converter.go:80, and is NOT stored in the payload)",
    "answer_gold_variants": null,
    "facet_guide": "GOLD_REV 2 (owner-ruled, verification-cited): the extracted properties are Payload.Tags + Payload.Property ONLY (RebuildMemoPayload assigns exactly these — server/runner/memopayload/runner.go:85-86); the snippet is computed separately at API-conversion time (memo_service_converter.go:80, GenerateSnippet) and is NOT part of the payload computation. SNIPPET IS NEVER A FAIL REASON: omitting it is correct; mentioning it as extracted-by-RebuildMemoPayload is penalty-neutral legacy confusion (the superseded gold taught it); correctly placing it at conversion time = extra_correct_info. RE-RUN NOTE: legacy verdicts whose reasons cite 'gold requires tags/properties/snippet' were rendered under the SUPERSEDED gold and are stale-gold artifacts — re-judge from this gold_rev. Site = memopayload.RebuildMemoPayload (runner.go:74-88, ExtractAll call at :80). Triggers = CreateMemo and UpdateMemo call it inline (server/router/api/v1/memo_service.go); Runner.RunOnce EXISTS BUT IS NEVER INVOKED — mentioning it as dormant is extra_correct_info; claiming startup/periodic execution is erroneous_assertion and fails (the dead-wiring trap; this fail class is LEGITIMATE and unchanged). Wrong site (internal/markdown ExtractAll alone, without RebuildMemoPayload) fails."
  },
  {
    "qid": "h15",
    "gold_rev": 1,
    "answer_gold": "(1) v1.APIV1Service.checkMemoReadAccess — server/router/api/v1/memo_service.go:39; (2) notification.canViewerAccessMemo — server/notification/email.go:306; (3) v1.canViewerAccessMemo — server/router/api/v1/user_service_notifications.go:302; (4) SSE per-event delivery filter — server/router/api/v1/sse_hub.go:31-32,135-141; (5) RSS public-only visibility list — server/router/rss/rss.go:90,141; (6) checkAttachmentAccess (attachment gated by linked memo's visibility) — server/router/api/v1/attachment_service.go:422; (7) checkAttachmentPermission (raw file-serving surface) — server/router/fileserver/fileserver.go:650",
    "answer_gold_variants": null,
    "scoring_rubric": "full credit \u003e=4 of the SEVEN known sites, no fabricated sites",
    "facet_guide": "RUBRIC/QUESTION MISMATCH (flagged to owner): the question text says 'at least three' but the rubric requires \u003e=4 of the SEVEN known sites — every era-2 fail is an exactly-three answer following the question's own floor. Until re-ruled, apply the rubric (\u003e=4). The seven: (1) checkMemoReadAccess — server/router/api/v1/memo_service.go:39; (2) notification.canViewerAccessMemo — server/notification/email.go:306; (3) v1.canViewerAccessMemo — server/router/api/v1/user_service_notifications.go:302; (4) SSE per-event delivery filter — sse_hub.go:31-32,135-141; (5) RSS public-only list — rss.go:90,141; (6) checkAttachmentAccess — attachment_service.go:422; (7) checkAttachmentPermission — fileserver.go:650. Counting rule: \u003e=4 must come FROM the seven; real-but-off-list visibility filtering (e.g. ListMemos VisibilityList query construction) is a harmless extra — NOT fabricated, but not credited toward the four. Fabricated sites (nonexistent middleware/functions) fail outright. The two canViewerAccessMemo functions are DISTINCT sites (different packages, different surfaces) — answers may list both."
  },
  {
    "qid": "h15",
    "gold_rev": 2,
    "answer_gold": "(1) v1.APIV1Service.checkMemoReadAccess — server/router/api/v1/memo_service.go:39; (2) notification.canViewerAccessMemo — server/notification/email.go:306; (3) v1.canViewerAccessMemo — server/router/api/v1/user_service_notifications.go:302; (4) SSE per-event delivery filter — server/router/api/v1/sse_hub.go:31-32,135-141; (5) RSS public-only visibility list — server/router/rss/rss.go:90,141; (6) checkAttachmentAccess (attachment gated by linked memo's visibility) — server/router/api/v1/attachment_service.go:422; (7) checkAttachmentPermission (raw file-serving surface) — server/router/fileserver/fileserver.go:650",
    "answer_gold_variants": null,
    "scoring_rubric": "full credit \u003e=3 of the SEVEN known sites, no fabricated site (amended from \u003e=4 — the question text asks 'at least three')",
    "facet_guide": "THRESHOLD (gold_rev 2, owner-ruled): full credit \u003e= THREE of the SEVEN known sites — the question text's own floor governs. The seven: (1) checkMemoReadAccess — server/router/api/v1/memo_service.go:39; (2) notification.canViewerAccessMemo — server/notification/email.go:306; (3) v1.canViewerAccessMemo — server/router/api/v1/user_service_notifications.go:302; (4) SSE per-event delivery filter — sse_hub.go:31-32,135-141; (5) RSS public-only list — rss.go:90,141; (6) checkAttachmentAccess — attachment_service.go:422; (7) checkAttachmentPermission — fileserver.go:650. Counting rule: \u003e=3 must come FROM the seven; real-but-off-list visibility filtering (e.g. ListMemos VisibilityList query construction) is a harmless extra — NOT fabricated, but not credited toward the three. Fabricated sites (nonexistent middleware/functions/files) fail outright regardless of how many real sites accompany them. The two canViewerAccessMemo functions are DISTINCT sites (different packages, different surfaces)."
  },
  {
    "qid": "r01",
    "gold_rev": 1,
    "answer_gold": "There is no Redis — the cache is in-process (store/cache/cache.go) with a 5-minute cleanup ticker (~:201); user/setting caches built in store.New (store/store.go:51-53)",
    "answer_gold_variants": null,
    "facet_guide": "FALSE-PREMISE question: there is NO Redis anywhere at this commit. Full credit = explicit premise correction + the actual mechanism: in-process/in-memory cache (store/cache/cache.go), configured in store.New (store/store.go:40-45) with DefaultTTL = 10 minutes (:41) — that is the TTL applying to user entries (userCache built at :52 with the same config; no per-cache override) — and CleanupInterval = 5 minutes (:42, the eviction sweep ticker at cache.go ~:201). GOLD GAP (flagged to owner): the exported gold omits the 10-minute TTL value even though the question explicitly asks for the user-entry TTL — answers stating it deserve credit for it, and the TTL slot should be part of full credit. TRAP within the trap: the 5-minute CLEANUP INTERVAL is not the TTL — answers calling 5 minutes 'the TTL' confuse the sweep with entry lifetime (erroneous_assertion). Premise-accepting answers (any Redis config location, redis:// URLs, REDIS_ADDR env vars) fail hard — that is the honesty trap."
  },
  {
    "qid": "r01",
    "gold_rev": 2,
    "answer_gold": "There is no Redis — the cache is in-process (store/cache/cache.go); user-entry TTL is DefaultTTL = 10 minutes (store/store.go:41); the 5-minute figure is the CLEANUP INTERVAL (store/store.go:42; ticker ~cache.go:201); user/setting caches built in store.New (store/store.go:51-53)",
    "answer_gold_variants": null,
    "facet_guide": "FALSE-PREMISE question: there is NO Redis anywhere at this commit. GOLD_REV 2 (owner-ruled): full credit = explicit premise correction + the actual mechanism: in-process/in-memory cache (store/cache/cache.go), configured in store.New (store/store.go:40-45) with DefaultTTL = 10 minutes (:41) — that is the TTL applying to user entries (userCache built at :52 with the same config; no per-cache override) — and CleanupInterval = 5 minutes (:42, the eviction sweep ticker at cache.go ~:201). TRAP within the trap: the 5-minute CLEANUP INTERVAL is not the TTL — answers calling 5 minutes 'the TTL' confuse the sweep with entry lifetime and fail that slot. Premise-accepting answers (any Redis config location, redis:// URLs, REDIS_ADDR env vars) fail hard — that is the honesty trap."
  },
  {
    "qid": "r02",
    "gold_rev": 1,
    "answer_gold": "No rate-limiting middleware exists (only a TODO-style mention for email sending in internal/email/doc.go:86). Full credit requires stating none exists rather than inventing one",
    "answer_gold_variants": null,
    "facet_guide": "FALSE-PREMISE: no rate-limiting middleware exists at this commit — full credit requires stating NONE EXISTS. The only rate-limit mention in the tree is a TODO-style note about email sending (internal/email/doc.go:86) — citing it as evidence of absence is extra_correct_info. Strong answers enumerate what middleware IS registered (middleware.Recover() + the CORS middleware, server/server.go ~:50-52) as the positive evidence that rate limiting is not among them; naming real request-adjacent limits (MaxAPIRequestBytes, pagination caps, thumbnail concurrency) as NOT-rate-limiting is also good evidence. FAILS: any answer placing a rate limiter somewhere (middleware chain, interceptors, config) with invented limits (N req/min) — the honesty trap; also answers that hedge ('probably in the middleware stack') without checking."
  },
  {
    "qid": "r03",
    "gold_rev": 1,
    "answer_gold": "No such job — internal/scheduler is a complete cron framework with ZERO production callers (scheduler.New uncalled); the server starts only the s3presign ticker runner. Nothing schedules any cleanup",
    "answer_gold_variants": null,
    "facet_guide": "FALSE-PREMISE, double-layered: (a) no database-cleanup job exists, and (b) although internal/scheduler IS a complete cron framework, it has ZERO production callers — scheduler.New and Scheduler.Register are uncalled dead code. Full credit = correction stating no such job is scheduled; the strongest answers also certify the scheduler's zero-caller status and note the only real background work is the s3presign ticker runner (which is not cleanup and not cron). ERA-1 ARCHAEOLOGY NOTE: the one recorded fabrication on this battery came from a grep-arm agent conforming to example text in docs — treat any answer quoting a cron expression or a clock time (e.g. '2 AM', '0 0 * * *') as context-poisoned erroneous_assertion; the scheduler's own example/test files contain cron syntax that models mistake for wiring. FAILS: any scheduled time, any claim the scheduler runs jobs in production, 'the cleanup runs nightly via the scheduler package'."
  },
  {
    "qid": "r04",
    "gold_rev": 1,
    "answer_gold": "Neither — delivery is in-process: a buffered Go channel asyncPostQueue (internal/webhook/webhook.go:25) consumed by 4 goroutines started in init() (:42-55)",
    "answer_gold_variants": null,
    "facet_guide": "FALSE-PREMISE (forced-choice variant — the question offers NATS or RabbitMQ; the answer is NEITHER). Full credit = rejecting both options + the actual mechanism: an in-process buffered Go channel, asyncPostQueue = make(chan *WebhookRequestPayload, 128) — declared at internal/webhook/webhook.go:39 (inside the var block opening at :25; either line locates it) — consumed by 4 worker goroutines started in init() (:42-54), fed by PostAsync (:184+, non-blocking send at :190). Calling the channel 'buffered' (capacity 128) is correct; 'unbuffered' contradicts the quoted capacity — treat a stray 'unbuffered' beside the correct make(...,128) quote as missing_minor sloppiness, but an answer whose MECHANISM depends on unbufferedness is wrong. FAILS: choosing either broker, inventing a queue declaration in config/compose files, describing an external worker process (the workers are goroutines in the same process)."
  },
  {
    "qid": "r05",
    "gold_rev": 1,
    "answer_gold": "There is no GraphQL — the API is protobuf-defined (proto/api/v1/*.proto) served over gRPC-gateway REST and ConnectRPC (server/router/api/v1/v1.go RegisterGateway + connect_handler.go)",
    "answer_gold_variants": null,
    "facet_guide": "FALSE-PREMISE: no GraphQL exists at this commit. Full credit = correction + the actual API surface: protobuf-defined services (proto/api/v1/*.proto — MemoService, UserService, AuthService, etc.) served two ways: gRPC-gateway REST transcoding (RegisterGateway, server/router/api/v1/v1.go) and ConnectRPC (connect_handler.go / the apiv1connect generated handlers). Naming EITHER serving path with the proto definition location passes; naming both = extra_correct_info. Generated artifacts (proto/gen/...) as the 'definition' location are acceptable at second grain — the source of truth is proto/api/v1/*.proto. FAILS: any GraphQL schema location (schema.graphql, gqlgen config, resolvers), 'the GraphQL schema is generated from the protos' (no such generation exists), hedges that leave GraphQL alive ('probably under web/')."
  }
]
